diff --git a/capi.config.ts b/capi.config.ts index 64a3b80d4..e0896c81f 100644 --- a/capi.config.ts +++ b/capi.config.ts @@ -1,22 +1,23 @@ -import { binary, CapiConfig } from "./capn/mod.ts" +import { binary, CapiConfig } from "./mod.ts" -const polkadot = binary("polkadot", "v0.9.37") +const polkadot40 = binary("polkadot", "v0.9.40") +const polkadot37 = binary("polkadot", "v0.9.37") const polkadotParachain = binary("polkadot-parachain", "v0.9.370") const substrateContractsNode = binary("substrate-contracts-node", "v0.24.0") export const config: CapiConfig = { - server: "https://capi.dev/@capn/", + server: "http://localhost:4646/", chains: { polkadot: { url: "wss://rpc.polkadot.io/", version: "v0.9.40", }, polkadotDev: { - binary: polkadot, + binary: polkadot40, chain: "polkadot-dev", }, westendDev: { - binary: polkadot, + binary: polkadot40, chain: "westend-dev", }, contractsDev: { @@ -27,7 +28,7 @@ export const config: CapiConfig = { networks: { rococoDev: { relay: { - binary: polkadot, + binary: polkadot37, chain: "rococo-local", nodes: 4, }, diff --git a/capn/CapiConfig.ts b/capn/CapiConfig.ts new file mode 100644 index 000000000..c60a9a0eb --- /dev/null +++ b/capn/CapiConfig.ts @@ -0,0 +1,24 @@ +import { Binary } from "./binary.ts" + +export interface ProxyChain { + url: string + binary?: never + version: string +} + +export interface BinaryChain { + url?: never + binary: Binary + chain: string +} + +export interface CapiConfig { + server: string + chains?: Record + networks?: Record +} + +export interface NetworkConfig { + relay: BinaryChain & { nodes?: number } + parachains: Record +} diff --git a/capn/foo.ts b/capn/foo.ts deleted file mode 100644 index a533438ea..000000000 --- a/capn/foo.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { config } from "../capi.config.ts" -import { serve } from "../deps/std/http.ts" -import { assertRejects } from "../deps/std/testing/asserts.ts" -import { handler } from "../server/handler.ts" -import { InMemoryCache } from "../util/cache/memory.ts" -import { withSignal } from "../util/withSignal.ts" -import { $api } from "./api.ts" -import { connectScald, ScaldError, serveScald, WsConnection } from "./scald.ts" -import { createApi } from "./server.ts" - -const signal = new AbortController().signal -serve(handler(new InMemoryCache(signal), new InMemoryCache(signal)), { port: 4646 }) - -// await withSignal(async (signal) => { -// const _api = createApi(config, signal) - -// serve((request) => { -// const { response, socket } = Deno.upgradeWebSocket(request) -// serveScald($api, _api, new WsConnection(socket, signal), signal) -// return response -// }, { port: 4646, signal }) - -// const api = await connectScald( -// $api, -// new WsConnection(new WebSocket("ws://localhost:4646"), signal), -// signal, -// ) - -// const polkadotDev = (await api.getNetwork("rococoDev")).get("statemine")! -// console.log(polkadotDev) - -// console.log(await polkadotDev.nextUsers(10)) -// console.log(await polkadotDev.nextUsers(10)) -// console.log(await polkadotDev.nextUsers(10)) -// await assertRejects(() => polkadotDev.nextUsers(10000000000), ScaldError) -// }) diff --git a/capn/getMetadata.ts b/capn/getMetadata.ts index 58189453a..ffa94e2d6 100644 --- a/capn/getMetadata.ts +++ b/capn/getMetadata.ts @@ -3,14 +3,15 @@ import { WsConnection } from "../rpc/mod.ts" import { getFreePort, portReady } from "../util/port.ts" import { withSignal } from "../util/withSignal.ts" import { resolveBinary } from "./binary.ts" -import { BinaryChain } from "./mod.ts" +import { BinaryChain } from "./CapiConfig.ts" export async function getBinaryMetadata({ binary, chain }: BinaryChain, signal: AbortSignal) { const bin = await resolveBinary(binary, signal) const port = getFreePort() return await withSignal(async (signal) => { + console.log(bin) new Deno.Command(bin, { - args: ["--chain", chain, "--ws-port", `${port}`], + args: ["--tmp", "--chain", chain, "--ws-port", `${port}`], stdin: "null", stdout: "piped", stderr: "piped", diff --git a/capn/mod.ts b/capn/mod.ts index 9ea1d06c1..699209f29 100644 --- a/capn/mod.ts +++ b/capn/mod.ts @@ -1,103 +1,11 @@ -export * from "./binary.ts" - -import { blake2_512, blake2_64, Hasher } from "../crypto/hashers.ts" -import { hex } from "../crypto/mod.ts" -import { $codegenSpec, CodegenEntry, CodegenSpec } from "../server/codegenSpec.ts" -import { normalizePackageName, withSignal } from "../util/mod.ts" -import { Binary } from "./binary.ts" -import { getBinaryMetadata, getUrlMetadata } from "./getMetadata.ts" -import { startNetwork } from "./startNetwork.ts" - -export interface ProxyChain { - url: string - binary?: never - version: string -} - -export interface BinaryChain { - url?: never - binary: Binary - chain: string -} - -export interface CapiConfig { - server: string - chains?: Record - networks?: Record -} +// moderate -export interface NetworkConfig { - relay: BinaryChain & { nodes?: number } - parachains: Record -} - -export async function processConfig(config: CapiConfig) { - return withSignal(async (signal) => { - const { server } = config - const entries = (await Promise.all([ - ...Object.entries(config.chains ?? {}).map( - async ([name, chain]): Promise<[string[], CodegenEntry][]> => { - const metadata = chain.url !== undefined - ? await getUrlMetadata(chain, signal) - : await getBinaryMetadata(chain, signal) - const metadataHash = await uploadMetadata(server, metadata) - return [[[normalizePackageName(name)], { - type: "frame", - metadata: metadataHash, - chainName: name.replace(/^./, (x) => x.toUpperCase()), - connection: chain.url !== undefined - ? { type: "ws", discovery: chain.url } - : { type: "capnChain", name }, - }]] - }, - ), - ...Object.entries(config.networks ?? {}).map(async ([networkName, network]) => { - const chains = await startNetwork(network, signal) - return await Promise.all( - Object.entries(chains).map( - async ([name, [port]]): Promise<[string[], CodegenEntry]> => { - const metadata = await getUrlMetadata({ url: `ws://localhost:${port}` }, signal) - const metadataHash = await uploadMetadata(server, metadata) - return [[ - normalizePackageName(networkName), - normalizePackageName(name), - ], { - type: "frame", - metadata: metadataHash, - chainName: name.replace(/^./, (x) => x.toUpperCase()), - connection: { type: "capnNetworkChain", network: networkName, name }, - }] - }, - ), - ) - }), - ])).flat() - const codegenHash = await uploadCodegenSpec(server, { - type: "v0", - codegen: new Map(entries), - }) - console.log( - entries.map(([key]) => - new URL(codegenHash + "/" + key.join("/") + "/mod.js", server).toString() - ).join("\n"), - ) - }) -} - -async function _upload(server: string, kind: string, data: Uint8Array, hasher: Hasher) { - const hash = hasher.hash(data) - const url = new URL(`upload/${kind}/${hex.encode(hash)}`, server) - const exists = await fetch(url, { method: "HEAD" }) - if (exists.ok) return hash - const response = await fetch(url, { method: "PUT", body: data }) - if (!response.ok) throw new Error(await response.text()) - return hash -} - -export async function uploadMetadata(server: string, metadata: Uint8Array) { - return await _upload(server, "metadata", metadata, blake2_512) -} - -export async function uploadCodegenSpec(server: string, spec: CodegenSpec) { - return hex.encode(await _upload(server, "codegen", $codegenSpec.encode(spec), blake2_64)) -} +export * from "./api.ts" +export * from "./binary.ts" +export * from "./CapiConfig.ts" +export * from "./getMetadata.ts" +export * from "./processConfig.ts" +export * from "./scald.ts" +export * from "./server.ts" +export * from "./startNetwork.ts" +export * from "./testUsers.ts" diff --git a/capn/processConfig.ts b/capn/processConfig.ts new file mode 100644 index 000000000..f3a9b6949 --- /dev/null +++ b/capn/processConfig.ts @@ -0,0 +1,77 @@ +export * from "./binary.ts" + +import { blake2_512, blake2_64, Hasher } from "../crypto/hashers.ts" +import { hex } from "../crypto/mod.ts" +import { $codegenSpec, CodegenEntry, CodegenSpec } from "../server/codegenSpec.ts" +import { normalizePackageName, withSignal } from "../util/mod.ts" +import { CapiConfig } from "./CapiConfig.ts" +import { getBinaryMetadata, getUrlMetadata } from "./getMetadata.ts" +import { startNetwork } from "./startNetwork.ts" + +export async function processConfig(config: CapiConfig) { + return withSignal(async (signal) => { + const { server } = config + const entries = (await Promise.all([ + ...Object.entries(config.chains ?? {}).map( + async ([name, chain]): Promise<[string[], CodegenEntry][]> => { + const metadata = chain.url !== undefined + ? await getUrlMetadata(chain, signal) + : await getBinaryMetadata(chain, signal) + const metadataHash = await uploadMetadata(server, metadata) + console.log(name, metadataHash) + return [[[normalizePackageName(name)], { + type: "frame", + metadata: metadataHash, + chainName: name.replace(/^./, (x) => x.toUpperCase()), + connection: chain.url !== undefined + ? { type: "ws", discovery: chain.url } + : { type: "capnChain", name }, + }]] + }, + ), + ...Object.entries(config.networks ?? {}).map(async ([networkName, network]) => { + const chains = await startNetwork(network, signal) + return await Promise.all( + Object.entries(chains).map( + async ([name, [port]]): Promise<[string[], CodegenEntry]> => { + const metadata = await getUrlMetadata({ url: `ws://localhost:${port}` }, signal) + const metadataHash = await uploadMetadata(server, metadata) + return [[ + normalizePackageName(networkName), + normalizePackageName(name), + ], { + type: "frame", + metadata: metadataHash, + chainName: name.replace(/^./, (x) => x.toUpperCase()), + connection: { type: "capnNetworkChain", network: networkName, name }, + }] + }, + ), + ) + }), + ])).flat() + const codegenHash = await uploadCodegenSpec(server, { + type: "v0", + codegen: new Map(entries), + }) + return new URL(codegenHash + "/", server).toString() + }) +} + +async function _upload(server: string, kind: string, data: Uint8Array, hasher: Hasher) { + const hash = hasher.hash(data) + const url = new URL(`upload/${kind}/${hex.encode(hash)}`, server) + const exists = await fetch(url, { method: "HEAD" }) + if (exists.ok) return hash + const response = await fetch(url, { method: "PUT", body: data }) + if (!response.ok) throw new Error(await response.text()) + return hash +} + +async function uploadMetadata(server: string, metadata: Uint8Array) { + return await _upload(server, "metadata", metadata, blake2_512) +} + +async function uploadCodegenSpec(server: string, spec: CodegenSpec) { + return hex.encode(await _upload(server, "codegen", $codegenSpec.encode(spec), blake2_64)) +} diff --git a/capn/scald.ts b/capn/scald.ts index 574db25d4..15be48c7f 100644 --- a/capn/scald.ts +++ b/capn/scald.ts @@ -25,13 +25,13 @@ const $message = $.taggedUnion("type", [ type ResolutionMessage = Extract -export interface Connection { +export interface Link { send(data: Uint8Array): void recv(cb: (data: Uint8Array) => void, signal: AbortSignal): void } class Scald { - constructor(readonly connection: Connection, readonly signal: AbortSignal) { + constructor(readonly connection: Link, readonly signal: AbortSignal) { this.connection.recv((data) => { const message = $message.decode(data) this.recv(message) @@ -141,7 +141,7 @@ export function $fn( }) } -export class WsConnection implements Connection { +export class WsLink implements Link { ready = deferred() constructor(readonly ws: WebSocket, signal: AbortSignal) { ws.binaryType = "arraybuffer" @@ -169,7 +169,7 @@ export class WsConnection implements Connection { export function serveScald( $api: $.Codec, api: T, - connection: Connection, + connection: Link, signal: AbortSignal, ) { const scald = new Scald(connection, signal) @@ -178,7 +178,7 @@ export function serveScald( export async function connectScald( $api: $.Codec, - connection: Connection, + connection: Link, signal: AbortSignal, ): Promise { const scald = new Scald(connection, signal) diff --git a/capn/server.ts b/capn/server.ts index 0ee00d253..69cd606bb 100644 --- a/capn/server.ts +++ b/capn/server.ts @@ -1,10 +1,11 @@ +import * as path from "../deps/std/path.ts" import { PermanentMemo } from "../util/memo.ts" import { getFreePort, portReady } from "../util/port.ts" import { Api, DevChain } from "./api.ts" import { resolveBinary } from "./binary.ts" -import { CapiConfig } from "./mod.ts" -import { startNetwork } from "./startNetwork.ts" -import { testUserPublicKeys } from "./testUsers.ts" +import { CapiConfig } from "./CapiConfig.ts" +import { createCustomChainSpec, ParaChainSpec, startNetwork } from "./startNetwork.ts" +import { addTestUsers, testUserPublicKeys } from "./testUsers.ts" export function createApi(config: CapiConfig, signal: AbortSignal): Api { const chainMemo = new PermanentMemo() @@ -17,11 +18,20 @@ export function createApi(config: CapiConfig, signal: AbortSignal): Api { return chainMemo.run(chainName, async () => { const bin = await resolveBinary(chain.binary, signal) const port = getFreePort() + const spec = await createCustomChainSpec( + path.resolve("target"), + chainName, + bin, + chain.chain, + async (chainSpec: ParaChainSpec) => { + await addTestUsers(chainSpec.genesis.runtime.balances.balances) + }, + ) new Deno.Command(bin, { - args: ["--chain", chain.chain, "--ws-port", `${port}`], + args: ["--tmp", "--alice", "--ws-port", `${port}`, "--chain", spec], stdin: "null", - stdout: "inherit", - stderr: "inherit", + stdout: "piped", + stderr: "piped", signal, }).spawn() await portReady(port) @@ -43,7 +53,7 @@ export function createApi(config: CapiConfig, signal: AbortSignal): Api { function createDevChain(port: number): DevChain { let userCount = 0 return { - url: `ws://localhost:${port}`, + url: `ws://localhost:${port}/`, async nextUsers(count) { const index = userCount const newCount = index + count diff --git a/capn/startNetwork.ts b/capn/startNetwork.ts index 52b1754cc..32c80bdaf 100644 --- a/capn/startNetwork.ts +++ b/capn/startNetwork.ts @@ -2,41 +2,13 @@ import { Narrow } from "../deps/scale.ts" import * as path from "../deps/std/path.ts" import { writableStreamFromWriter } from "../deps/std/streams.ts" import { getFreePort, portReady } from "../util/port.ts" -import { binary, resolveBinary } from "./binary.ts" -import { NetworkConfig } from "./mod.ts" +import { resolveBinary } from "./binary.ts" +import { NetworkConfig } from "./CapiConfig.ts" import { addTestUsers } from "./testUsers.ts" -if (import.meta.main) { - const controller = new AbortController() - Deno.addSignalListener("SIGINT", () => controller.abort()) - Deno.addSignalListener("SIGTERM", () => controller.abort()) - - const polkadot = binary("polkadot", "v0.9.37") - const polkadotParachain = binary("polkadot-parachain", "v0.9.370") - - startNetwork({ - relay: { - binary: polkadot, - chain: "rococo-local", - }, - parachains: { - statemine: { - id: 1000, - binary: polkadotParachain, - chain: "statemine-local", - }, - contracts: { - id: 2000, - binary: polkadotParachain, - chain: "contracts-rococo-local", - }, - }, - }, controller.signal) -} - export async function startNetwork(network: NetworkConfig, signal: AbortSignal) { const tempDir = await Deno.makeTempDir({ - dir: path.join(Deno.cwd(), "tmp"), + dir: path.resolve("target"), prefix: `capn-${new Date().toISOString()}-`, }) @@ -141,7 +113,7 @@ function generateBootnodeString(port: number, peerId: string) { return `/ip4/127.0.0.1/tcp/${port}/p2p/${peerId}` } -interface ChainSpec { +export interface ChainSpec { bootNodes: string[] genesis: { runtime: { @@ -162,7 +134,7 @@ interface ChainSpec { } } -interface ParaChainSpec { +export interface ParaChainSpec { bootNodes: string[] para_id: number genesis: { @@ -191,7 +163,7 @@ async function generateNodeKey(binary: string, signal?: AbortSignal) { return { nodeKey, peerId } } -async function createCustomChainSpec( +export async function createCustomChainSpec( tempDir: string, id: string, binary: string, diff --git a/cli/bin.ts b/cli/bin.ts index 5dae91c5a..f0c0238cd 100644 --- a/cli/bin.ts +++ b/cli/bin.ts @@ -1,24 +1,15 @@ import { download } from "../deps/capi_binary_builds.ts" +import * as path from "../deps/std/path.ts" export default async function( binary: string, version: string, - dashDash?: string, ...args: string[] ) { if (!binary || !version) throw new Error("Must specify binary and version") const binaryPath = await download(binary, version) - if (!dashDash) { - console.log(binaryPath) - Deno.exit(0) - } - - if (dashDash !== "--") { - throw new Error("Arguments to bin must begin with --") - } - const child = new Deno.Command(binaryPath, { args, stdin: "inherit", diff --git a/cli/serve.ts b/cli/serve.ts index 3558996f7..5fe37fbef 100644 --- a/cli/serve.ts +++ b/cli/serve.ts @@ -1,44 +1,34 @@ import * as flags from "../deps/std/flags.ts" import { serve } from "../deps/std/http.ts" -import { - ContractsDevProvider, - PolkadotDevProvider, - ProjectProvider, - WssProvider, - ZombienetProvider, -} from "../providers/frame/mod.ts" +import * as path from "../deps/std/path.ts" +import { $api, createApi, serveScald, WsLink } from "../mod.ts" import { handler } from "../server/handler.ts" -import { Env } from "../server/mod.ts" +import { InMemoryCache } from "../util/cache/memory.ts" import { FsCache } from "../util/cache/mod.ts" export default async function(...args: string[]) { - const { port: portStr, "--": cmd, out } = flags.parse(args, { - string: ["port", "out"], + const { config: configFile, port: portStr, "--": cmd, out } = flags.parse(args, { + string: ["port", "out", "config"], default: { + config: "./capi.config.ts", port: "4646", out: "target/capi", }, "--": true, }) + const configPath = path.resolve(configFile) + await Deno.stat(configPath) + const configModule = await import(path.toFileUrl(configPath).toString()) + const config = configModule.config + if (typeof config !== "object") throw new Error("config file must have a config export") const href = `http://localhost:${portStr}/` const controller = new AbortController() const { signal } = controller - const cache = new FsCache(out, signal) - const modSpecifier = JSON.stringify(import.meta.resolve("./mod.ts")) - cache.getString("mod.ts", 0, async () => `export * from ${modSpecifier}`) - - const env = new Env(href, cache, signal, (env) => ({ - frame: { - wss: new WssProvider(env), - dev: new PolkadotDevProvider(env), - zombienet: new ZombienetProvider(env), - project: new ProjectProvider(env), - contracts_dev: new ContractsDevProvider(env), - }, - })) + const dataCache = new FsCache(out, signal) + const tempCache = new InMemoryCache(signal) const running = await fetch(`${href}capi_cwd`) .then((r) => r.text()) @@ -46,7 +36,16 @@ export default async function(...args: string[]) { .catch(() => false) if (!running) { - await serve(handler(env), { + const h = handler(dataCache, tempCache) + const api = createApi(config, signal) + await serve((request, connInfo) => { + if (new URL(request.url).pathname === "/api") { + const { response, socket } = Deno.upgradeWebSocket(request) + serveScald($api, api, new WsLink(socket, signal), signal) + return response + } + return h(request, connInfo) + }, { hostname: "[::]", port: +portStr, signal, @@ -68,14 +67,8 @@ export default async function(...args: string[]) { if (bin) { const command = new Deno.Command(bin, { args, signal }) const status = await command.spawn().status - console.log("inner command exited with status code", status.code) self.addEventListener("unload", () => Deno.exit(status.code)) controller.abort() - Deno.unrefTimer(setTimeout(() => { - // todo: fix - console.log("failed to exit gracefully") - Deno.exit(status.code) - }, 30_000)) } } } diff --git a/cli/sync.ts b/cli/sync.ts new file mode 100644 index 000000000..3b37b63d3 --- /dev/null +++ b/cli/sync.ts @@ -0,0 +1,34 @@ +import { processConfig } from "../capn/processConfig.ts" +import * as flags from "../deps/std/flags.ts" +import * as path from "../deps/std/path.ts" + +export default async function(...args: string[]) { + const { config: configFile, "import-map": importMapFile, "package-json": packageJsonFile } = flags + .parse( + args, + { + string: ["config", "import-map", "package-json"], + default: { + config: "./capi.config.ts", + }, + }, + ) + const configPath = path.resolve(configFile) + await Deno.stat(configPath) + const configModule = await import(path.toFileUrl(configPath).toString()) + const config = configModule.config + if (typeof config !== "object") throw new Error("config file must have a config export") + + const baseUrl = await processConfig(config) + console.log(baseUrl) + + if (importMapFile) { + const importMap = JSON.parse(await Deno.readTextFile(importMapFile)) + importMap.imports["@capi/"] = baseUrl + await Deno.writeTextFile(importMapFile, JSON.stringify(importMap, null, 2)) + } + + if (packageJsonFile) { + throw new Error("not yet supported") + } +} diff --git a/crypto/test_pairs.ts b/crypto/test_pairs.ts index bfc0785f5..49885b67c 100644 --- a/crypto/test_pairs.ts +++ b/crypto/test_pairs.ts @@ -36,18 +36,12 @@ function pair(secret: string) { export function testUser(userId: number) { return Sr25519.fromSeed(blake2_256.hash(new TextEncoder().encode(`capi-test-user-${userId}`))) } -export function testUserFactory(url: string) { +export function testUserFactory(getIndex: (count: number) => Promise) { return createUsers function createUsers(): Promise> function createUsers(count: N): Promise> async function createUsers(count?: number): Promise | Sr25519[]> { - const response = await fetch(url, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ count: count ?? NAMES.length }), - }) - if (!response.ok) throw new Error(await response.text()) - const { index }: { index: number } = await response.json() + const index = await getIndex(count ?? NAMES.length) return typeof count === "number" ? Array.from({ length: count }, (_, i) => testUser(index + i)) : Object.fromEntries(NAMES.map((name, i) => [name, testUser(index + i)])) diff --git a/deno.jsonc b/deno.jsonc index dec3346f5..21dffb24d 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -32,15 +32,15 @@ "debug": "deno run -A --inspect-brk", "udd": "deno run -A _tasks/udd.ts", "dnt": "deno task run _tasks/dnt.ts", - "test": "deno task capi -- deno test -A -L=info --ignore=target --parallel -r=http://localhost:4646/", + "test": "deno task capi serve -- deno test -A -L=info --ignore=target --parallel -r=http://localhost:4646/", "test:examples": "deno task test _tasks/test_examples.ts", "test:update": "deno task test -- --update", "moderate": "deno run -A https://deno.land/x/moderate@0.0.5/mod.ts --exclude '*.test.ts' && dprint fmt", "dev": "deno run -A --watch=deno.jsonc,docs/ main.ts --serve", "capi": "deno run -A main.ts", - "cache": "deno task capi -- deno cache -r=http://localhost:4646/", - "check": "deno task capi -- deno cache --check", + "cache": "deno task capi serve -- deno cache -r=http://localhost:4646/", + "check": "deno task capi serve -- de no cache --check", "star": "deno task run _tasks/star.ts && deno task check target/star.ts", - "run": "deno task capi -- deno run -A -r=http://localhost:4646/" + "run": "deno task capi serve -- deno run -A -r=http://localhost:4646/" } } diff --git a/examples/batch.ts b/examples/batch.ts index 5238291a7..433e57a80 100644 --- a/examples/batch.ts +++ b/examples/batch.ts @@ -1,6 +1,6 @@ +import { Balances, createUsers, System, Utility } from "@capi/westend-dev /mod.js" import { Rune } from "capi" import { signature } from "capi/patterns/signature/polkadot.ts" -import { Balances, createUsers, System, Utility } from "westend_dev/mod.js" import { mapEntries } from "../deps/std/collections/map_entries.ts" const { alexa, billy, carol, david } = await createUsers() diff --git a/examples/bonded.ts b/examples/bonded.ts index cab1e9ff9..c156f5cdc 100644 --- a/examples/bonded.ts +++ b/examples/bonded.ts @@ -1,5 +1,5 @@ +import { Staking } from "@capi/polkadot-dev /mod.js" import { aliceStash } from "capi" -import { Staking } from "polkadot_dev/mod.js" const result = await Staking.Bonded.value(aliceStash.publicKey).run() diff --git a/examples/derived.ts b/examples/derived.ts index 9d952f65b..213794ea1 100644 --- a/examples/derived.ts +++ b/examples/derived.ts @@ -1,5 +1,5 @@ import { ArrayRune, ValueRune } from "capi" -import { Paras } from "polkadot/mod.js" +import { Paras } from "@capi/polkadot/mod.js" const result = await Paras.Parachains .value() diff --git a/examples/error_unhandling.ts b/examples/error_unhandling.ts index c5b2be4fc..304cbcaf2 100644 --- a/examples/error_unhandling.ts +++ b/examples/error_unhandling.ts @@ -1,6 +1,6 @@ // import { alice, bob } from "capi" // import { signature } from "capi/patterns/signature/polkadot.ts" -// import { Balances, chain } from "westend_dev/mod.ts" +// import { Balances, chain } from "@capi/westend-dev /mod.ts" // import { assertRejects } from "../deps/std/testing/asserts.ts" // assertRejects(() => diff --git a/examples/fee_estimate.ts b/examples/fee_estimate.ts index 3b11b9e3e..74158acd0 100644 --- a/examples/fee_estimate.ts +++ b/examples/fee_estimate.ts @@ -1,4 +1,4 @@ -import { Balances, createUsers } from "westend_dev/mod.js" +import { Balances, createUsers } from "@capi/westend-dev /mod.js" const { alexa } = await createUsers() diff --git a/examples/identity_cr.ts b/examples/identity_cr.ts index 5a10a6263..a273b9816 100644 --- a/examples/identity_cr.ts +++ b/examples/identity_cr.ts @@ -1,7 +1,7 @@ +import { createUsers, Identity } from "@capi/polkadot-dev /mod.js" import { $ } from "capi" import { IdentityInfoTranscoders } from "capi/patterns/identity.ts" import { signature } from "capi/patterns/signature/polkadot.ts" -import { createUsers, Identity } from "polkadot_dev/mod.js" const { alexa } = await createUsers() diff --git a/examples/indices.ts b/examples/indices.ts index 62fe2f801..006c6b32e 100644 --- a/examples/indices.ts +++ b/examples/indices.ts @@ -1,5 +1,5 @@ +import { chain, createUsers, Indices } from "@capi/polkadot-dev /mod.js" import { PublicKeyRune } from "capi" -import { chain, createUsers, Indices } from "polkadot_dev/mod.js" import { signature } from "../patterns/signature/polkadot.ts" const { alexa } = await createUsers() diff --git a/examples/key_page.ts b/examples/key_page.ts index 285558be7..c00ec6565 100644 --- a/examples/key_page.ts +++ b/examples/key_page.ts @@ -1,4 +1,4 @@ -import { System } from "polkadot_dev/mod.js" +import { System } from "@capi/polkadot-dev /mod.js" const result = await System.Account.keyPage(10, null).run() diff --git a/examples/metadata.ts b/examples/metadata.ts index 9cb3c756d..aa9e37b34 100644 --- a/examples/metadata.ts +++ b/examples/metadata.ts @@ -1,4 +1,4 @@ -import { chain } from "polkadot_dev/mod.js" +import { chain } from "@capi/polkadot-dev /mod.js" const result = await chain.metadata.run() diff --git a/examples/multisig_pure_proxy_stash.ts b/examples/multisig_pure_proxy_stash.ts index 9d5efbea5..720af6a80 100644 --- a/examples/multisig_pure_proxy_stash.ts +++ b/examples/multisig_pure_proxy_stash.ts @@ -1,9 +1,9 @@ +import { Balances, chain, createUsers, Proxy, System } from "@capi/polkadot-dev /mod.js" +import { MultiAddress } from "@capi/polkadot-dev /types/sp_runtime/multiaddress.js" import { Rune } from "capi" import { MultisigRune } from "capi/patterns/multisig/mod.ts" import { filterPureCreatedEvents } from "capi/patterns/proxy/mod.ts" import { signature } from "capi/patterns/signature/polkadot.ts" -import { Balances, chain, createUsers, Proxy, System } from "polkadot_dev/mod.js" -import { MultiAddress } from "polkadot_dev/types/sp_runtime/multiaddress.js" const { alexa, billy, carol } = await createUsers() diff --git a/examples/polkadot_js_signer.ts b/examples/polkadot_js_signer.ts index 21d873532..8433a5209 100644 --- a/examples/polkadot_js_signer.ts +++ b/examples/polkadot_js_signer.ts @@ -1,9 +1,9 @@ +import { Balances, chain, createUsers } from "@capi/polkadot-dev /mod.js" import { ss58 } from "capi" import { pjsSender } from "capi/patterns/compat/pjs_sender.ts" import { signature } from "capi/patterns/signature/polkadot.ts" import { createPair } from "https://deno.land/x/polkadot@0.2.25/keyring/mod.ts" import { TypeRegistry } from "https://deno.land/x/polkadot@0.2.25/types/mod.ts" -import { Balances, chain, createUsers } from "polkadot_dev/mod.js" const { alexa, billy } = await createUsers() diff --git a/examples/size_tree.ts b/examples/size_tree.ts index ae809dc2f..1cc8ccbd9 100644 --- a/examples/size_tree.ts +++ b/examples/size_tree.ts @@ -1,5 +1,5 @@ +import { chain } from "@capi/polkadot-dev /mod.js" import { sizeTree } from "capi/patterns/sizeTree.ts" -import { chain } from "polkadot_dev/mod.js" const result = await sizeTree(chain).run() diff --git a/examples/transfer.ts b/examples/transfer.ts index 3a7676549..64a0a130d 100644 --- a/examples/transfer.ts +++ b/examples/transfer.ts @@ -1,5 +1,5 @@ -import { Balances, createUsers } from "westend_dev/mod.js" -import { signature } from "../patterns/signature/polkadot.ts" +import { Balances, createUsers } from "@capi/westend-dev/mod.js" +import { signature } from "capi/patterns/signature/polkadot.ts" const { alexa, billy } = await createUsers() diff --git a/examples/virtual_multisig.ts b/examples/virtual_multisig.ts index 1067e2c21..1f354450e 100644 --- a/examples/virtual_multisig.ts +++ b/examples/virtual_multisig.ts @@ -1,8 +1,8 @@ +import { Balances, chain, createUsers, System, Utility } from "@capi/polkadot-dev /mod.js" +import { MultiAddress } from "@capi/polkadot-dev /types/sp_runtime/multiaddress.js" import { Rune, Sr25519 } from "capi" import { VirtualMultisigRune } from "capi/patterns/multisig/mod.ts" import { signature } from "capi/patterns/signature/polkadot.ts" -import { Balances, chain, createUsers, System, Utility } from "polkadot_dev/mod.js" -import { MultiAddress } from "polkadot_dev/types/sp_runtime/multiaddress.js" import { parse } from "../deps/std/flags.ts" const { alexa, billy, carol, david } = await createUsers() diff --git a/fluent/SignedExtrinsicRune.ts b/fluent/SignedExtrinsicRune.ts index 19f3b8ecc..0b2ab393f 100644 --- a/fluent/SignedExtrinsicRune.ts +++ b/fluent/SignedExtrinsicRune.ts @@ -11,7 +11,7 @@ export class SignedExtrinsicRune extends PatternRune sent() { return this - .hex() + .hex().dbg("hex") .map((hex) => this.chain.connection.subscribe( "author_submitAndWatchExtrinsic", diff --git a/foo b/foo deleted file mode 100644 index 635a7d097..000000000 --- a/foo +++ /dev/null @@ -1 +0,0 @@ -0x000000000000000000000000000000000000000000000000000000000000000000529cd5d329fc57f32b62f37026842d459e4ef87bcf0c371116b1f91c8a343fbb03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131400 \ No newline at end of file diff --git a/import_map.json b/import_map.json index 4ff064fb7..1df9cb008 100644 --- a/import_map.json +++ b/import_map.json @@ -1,5 +1,15 @@ { "imports": { - "@capi/polkadot/": "https://capi.dev/polkadot-abcdserfd12345/" + "@capi/": "http://localhost:4646/18ba013ae5947088/" + }, + "scopes": { + "examples/": { + "capi": "./mod.ts", + "capi/": "./", + "asserts": "./deps/std/testing/asserts.ts" + }, + "http://localhost:4646/": { + "http://localhost:4646/capi/": "./" + } } -} +} \ No newline at end of file diff --git a/main.ts b/main.ts index 4b7b10893..abd489375 100644 --- a/main.ts +++ b/main.ts @@ -1,10 +1,11 @@ import bin from "./cli/bin.ts" import serve from "./cli/serve.ts" +import sync from "./cli/sync.ts" -const commands: Record void> = { bin, serve } +const commands: Record void> = { bin, serve, sync } if (Deno.args[0]! in commands) { commands[Deno.args[0]!]!(...Deno.args.slice(1)) } else { - serve(...Deno.args) + throw new Error("Unrecognized command") } diff --git a/patterns/consensus/babeBlockAuthor.ts b/patterns/consensus/babeBlockAuthor.ts index 77907526b..d873f3886 100644 --- a/patterns/consensus/babeBlockAuthor.ts +++ b/patterns/consensus/babeBlockAuthor.ts @@ -1,4 +1,4 @@ -import { $preDigest } from "polkadot/types/sp_consensus_babe/digests.js" +import { $preDigest } from "@capi/polkadot/types/sp_consensus_babe/digests.js" import { AddressPrefixChain, ChainRune } from "../../fluent/mod.ts" import { PublicKeyRune } from "../../fluent/mod.ts" import { Rune, RunicArgs, ValueRune } from "../../rune/mod.ts" diff --git a/patterns/identity.ts b/patterns/identity.ts index ef9a9c303..c486eae69 100644 --- a/patterns/identity.ts +++ b/patterns/identity.ts @@ -1,4 +1,4 @@ -import { Data, type IdentityInfo } from "polkadot_dev/types/pallet_identity/types.js" +import { Data, type IdentityInfo } from "@capi/polkadot-dev/types/pallet_identity/types.js" import * as $ from "../deps/scale.ts" import { Rune, RunicArgs } from "../rune/mod.ts" diff --git a/patterns/multisig/MultisigRune.ts b/patterns/multisig/MultisigRune.ts index 974d488a9..a194a0b4a 100644 --- a/patterns/multisig/MultisigRune.ts +++ b/patterns/multisig/MultisigRune.ts @@ -1,4 +1,4 @@ -import { MultiAddress } from "polkadot/types/sp_runtime/multiaddress.js" +import { MultiAddress } from "@capi/polkadot/types/sp_runtime/multiaddress.js" import * as bytes from "../../deps/std/bytes.ts" import { Chain, diff --git a/patterns/multisig/VirtualMultisigRune.ts b/patterns/multisig/VirtualMultisigRune.ts index 433c8576a..8521e8e75 100644 --- a/patterns/multisig/VirtualMultisigRune.ts +++ b/patterns/multisig/VirtualMultisigRune.ts @@ -1,4 +1,4 @@ -import { MultiAddress } from "polkadot/types/sp_runtime/multiaddress.js" +import { MultiAddress } from "@capi/polkadot/types/sp_runtime/multiaddress.js" import { equals } from "../../deps/std/bytes.ts" import { $, diff --git a/patterns/proxy/events.ts b/patterns/proxy/events.ts index 719694116..e76a3edca 100644 --- a/patterns/proxy/events.ts +++ b/patterns/proxy/events.ts @@ -1,5 +1,5 @@ -import { type Event as ProxyEvent } from "polkadot/types/pallet_proxy/pallet.js" -import { type RuntimeEvent } from "polkadot/types/polkadot_runtime.js" +import { type Event as ProxyEvent } from "@capi/polkadot/types/pallet_proxy/pallet.js" +import { type RuntimeEvent } from "@capi/polkadot/types/polkadot_runtime.js" import { Rune, RunicArgs } from "../../mod.ts" export function filterPureCreatedEvents(...[events]: RunicArgs) { diff --git a/patterns/proxy/replaceDelegateCalls.ts b/patterns/proxy/replaceDelegateCalls.ts index 236f45d1b..a29bcae9c 100644 --- a/patterns/proxy/replaceDelegateCalls.ts +++ b/patterns/proxy/replaceDelegateCalls.ts @@ -1,4 +1,4 @@ -import { MultiAddress } from "polkadot/types/sp_runtime/multiaddress.js" +import { MultiAddress } from "@capi/polkadot/types/sp_runtime/multiaddress.js" import { Chain, ChainRune, Rune, RunicArgs } from "../../mod.ts" // TODO: constrain diff --git a/patterns/signature/polkadot.ts b/patterns/signature/polkadot.ts index a9a8629b7..b8993738d 100644 --- a/patterns/signature/polkadot.ts +++ b/patterns/signature/polkadot.ts @@ -1,4 +1,4 @@ -import { Polkadot } from "polkadot/mod.js" +import { Polkadot } from "@capi/polkadot/mod.js" import { AddressPrefixChain, Chain, ChainRune } from "../../fluent/ChainRune.ts" import { ExtrinsicSender, SignatureData } from "../../fluent/ExtrinsicRune.ts" import { $, hex, ss58, ValueRune } from "../../mod.ts" diff --git a/server/handler.ts b/server/handler.ts index 247832d95..684e83b9c 100644 --- a/server/handler.ts +++ b/server/handler.ts @@ -31,22 +31,21 @@ export function handler(dataCache: CacheBase, generatedCache: CacheBase): Handle const path = match[2] ?? "/" return handleCodegen(request, hash, path) } - for (const dir of staticDirs) { - try { - const url = new URL(pathname.slice(1), dir) + if (pathname.startsWith("/capi/")) { + return f.code(generatedCache, request, async () => { + const url = new URL(pathname.slice(1), import.meta.resolve("../")) const response = await fetch(url) - if (!response.ok) continue - if (f.acceptsHtml(request) && /\.[jt]s$/.test(pathname)) { - return f.html(await f.renderCode(await response.text())) - } - return new Response(response.body, { - headers: { - "Content-Type": mime.getType(pathname) ?? "text/plain", - }, - }) - } catch {} + if (!response.ok) throw f.notFound() + return response.text() + }) } - return f.notFound() + const response = await fetch(new URL(pathname.slice(1), import.meta.resolve("./static/"))) + if (!response.ok) return f.notFound() + return new Response(response.body, { + headers: { + "Content-Type": mime.getType(pathname) ?? "text/plain", + }, + }) }) async function handleUpload(request: Request, key: string) { @@ -92,7 +91,6 @@ export function handler(dataCache: CacheBase, generatedCache: CacheBase): Handle let match: [string[], CodegenEntry] | undefined = undefined for (const [key, value] of codegenSpec.codegen) { - console.log(path, key, value) if ( path.startsWith(`/${key.map((x) => x + "/").join("")}`) && key.length >= (match?.[0].length ?? 0) @@ -116,6 +114,55 @@ export function handler(dataCache: CacheBase, generatedCache: CacheBase): Handle const codegen = new FrameCodegen(metadata, entry.chainName) const files = new Map() codegen.write(files) + files.set("capi.js", `export * from "${"../".repeat(key.length + 1)}capi/mod.ts"`) + files.set("capi.d.ts", `export * from "${"../".repeat(key.length + 1)}capi/mod.ts"`) + files.set( + "connection.js", + ` +import * as C from "./capi.js" + +export const connectionCtor = C.WsConnection + +${ + entry.connection.type === "ws" + ? `export const discoveryValue = ${JSON.stringify(entry.connection.discovery)}` + : ` +const controller = new AbortController() +const signal = controller.signal +const api = await C.connectScald(C.$api, new C.WsLink(new WebSocket("ws://localhost:4646/api"), signal), signal) +const devChain = ${ + entry.connection.type === "capnChain" + ? `await api.getChain(${JSON.stringify(entry.connection.name)})` + : `(await api.getNetwork(${JSON.stringify(entry.connection.network)}))[${ + JSON.stringify(entry.connection.network) + }]` + } + +export const discoveryValue = devChain.url +export const createUsers = C.testUserFactory(devChain.nextUsers) + +// TODO: fix +setTimeout(() => controller.abort(), 5000) +` + } + +`, + ) + files.set( + "connection.d.ts", + ` +import * as C from "./capi.js" + +export const connectionCtor: typeof C.WsConnection +export const discoveryValue: string + +${ + entry.connection.type === "ws" ? "" : ` +export const createUsers: ReturnType +` + } +`, + ) return files }) @@ -128,8 +175,6 @@ export function handler(dataCache: CacheBase, generatedCache: CacheBase): Handle } } -const staticDirs = ["../", "./static/"].map((p) => import.meta.resolve(p)) - export function handleErrors(handler: (request: Request) => Promise) { return async (request: Request) => { try {