@polkadot-api/cli 0.19.5-canary.d6be873 → 0.20.0
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/dist/index.d.ts +2 -1
- package/dist/main/package.json.js +4 -0
- package/dist/main/package.json.js.map +1 -0
- package/dist/main/src/cli.js +49 -0
- package/dist/main/src/cli.js.map +1 -0
- package/dist/main/src/commands/add.js +91 -0
- package/dist/main/src/commands/add.js.map +1 -0
- package/dist/main/src/commands/generate.js +459 -0
- package/dist/main/src/commands/generate.js.map +1 -0
- package/dist/main/src/commands/ink.js +53 -0
- package/dist/main/src/commands/ink.js.map +1 -0
- package/dist/main/src/commands/remove.js +21 -0
- package/dist/main/src/commands/remove.js.map +1 -0
- package/dist/main/src/commands/sol.js +51 -0
- package/dist/main/src/commands/sol.js.map +1 -0
- package/dist/main/src/commands/update.js +56 -0
- package/dist/main/src/commands/update.js.map +1 -0
- package/dist/main/src/main.js +12 -0
- package/dist/main/src/main.js.map +1 -0
- package/dist/main/src/metadata.js +175 -0
- package/dist/main/src/metadata.js.map +1 -0
- package/dist/main/src/packageManager.js +70 -0
- package/dist/main/src/packageManager.js.map +1 -0
- package/dist/main/src/papiConfig.js +103 -0
- package/dist/main/src/papiConfig.js.map +1 -0
- package/dist/main/src/version.js +6 -0
- package/dist/main/src/version.js.map +1 -0
- package/dist/package.json.js +4 -0
- package/dist/package.json.js.map +1 -0
- package/dist/src/cli.js +49 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/commands/add.js +91 -0
- package/dist/src/commands/add.js.map +1 -0
- package/dist/src/commands/generate.js +459 -0
- package/dist/src/commands/generate.js.map +1 -0
- package/dist/src/commands/ink.js +53 -0
- package/dist/src/commands/ink.js.map +1 -0
- package/dist/src/commands/remove.js +21 -0
- package/dist/src/commands/remove.js.map +1 -0
- package/dist/src/commands/sol.js +51 -0
- package/dist/src/commands/sol.js.map +1 -0
- package/dist/src/commands/update.js +56 -0
- package/dist/src/commands/update.js.map +1 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/metadata.js +175 -0
- package/dist/src/metadata.js.map +1 -0
- package/dist/src/packageManager.js +70 -0
- package/dist/src/packageManager.js.map +1 -0
- package/dist/src/papiConfig.js +103 -0
- package/dist/src/papiConfig.js.map +1 -0
- package/dist/src/version.js +6 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +29 -26
- package/dist/chunk-YWAERR2C.js +0 -1127
- package/dist/chunk-YWAERR2C.js.map +0 -1
- package/dist/index.js +0 -21
- package/dist/index.js.map +0 -1
- package/dist/main.js +0 -15
- package/dist/main.js.map +0 -1
- /package/dist/{main.d.ts → main/main.d.ts} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -87,4 +87,5 @@ declare function getMetadata({ metadata: metadataFile, codeHash, genesis, ...ent
|
|
|
87
87
|
genesis?: HexString;
|
|
88
88
|
} | null>;
|
|
89
89
|
|
|
90
|
-
export {
|
|
90
|
+
export { add, generate, getCli, getMetadata, ink, readPapiConfig, remove, update };
|
|
91
|
+
export type { AddOptions, Commands, GenerateOptions, InkAddOptions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { program, Option } from '@commander-js/extra-typings';
|
|
2
|
+
import * as knownChains from '@polkadot-api/known-chains';
|
|
3
|
+
import { sol } from './commands/sol.js';
|
|
4
|
+
|
|
5
|
+
function getCli({
|
|
6
|
+
add,
|
|
7
|
+
generate,
|
|
8
|
+
remove,
|
|
9
|
+
update,
|
|
10
|
+
ink,
|
|
11
|
+
version
|
|
12
|
+
}) {
|
|
13
|
+
program.name("polkadot-api").description("Polkadot API CLI").version(version);
|
|
14
|
+
const config = new Option("--config <filename>", "Source for the config file");
|
|
15
|
+
const skipCodegen = new Option(
|
|
16
|
+
"--skip-codegen",
|
|
17
|
+
"Skip running codegen after adding"
|
|
18
|
+
);
|
|
19
|
+
const whitelist = new Option(
|
|
20
|
+
"--whitelist <filename>",
|
|
21
|
+
"Removed. The whitelist path is now .papi/whitelist.ts"
|
|
22
|
+
).hideHelp();
|
|
23
|
+
program.command("generate", {
|
|
24
|
+
isDefault: true
|
|
25
|
+
}).description("Generate descriptor files").addOption(config).addOption(whitelist).action(generate);
|
|
26
|
+
program.command("add").description("Add a new chain spec to the list").argument("<key>", "Key identifier for the chain spec").addOption(config).option("-f, --file <filename>", "Source from metadata encoded file").option("-w, --wsUrl <URL>", "Source from websocket url").option("-c, --chainSpec <filename>", "Source from chain spec file").addOption(
|
|
27
|
+
new Option("-n, --name <name>", "Source from a well-known chain").choices(
|
|
28
|
+
Object.keys(knownChains)
|
|
29
|
+
)
|
|
30
|
+
).option("--wasm <filename>", "Source from runtime wasm file").option(
|
|
31
|
+
"--at <block hash or number>",
|
|
32
|
+
"Only for -w/--wsUrl. Fetch the metadata for a specific block or hash"
|
|
33
|
+
).option("--no-persist", "Do not persist the metadata as a file").addOption(skipCodegen).addOption(whitelist).action(add);
|
|
34
|
+
program.command("update").description("Update the metadata files and generate descriptor files").argument(
|
|
35
|
+
"[keys]",
|
|
36
|
+
"Keys of the metadata files to update, separated by commas. Leave empty for all"
|
|
37
|
+
).addOption(config).addOption(skipCodegen).addOption(whitelist).action(update);
|
|
38
|
+
program.command("remove").description("Remove a chain spec from the list").argument("<key>", "Key identifier for the chain spec").addOption(config).addOption(skipCodegen).addOption(whitelist).action(remove);
|
|
39
|
+
const inkCommand = program.command("ink").description("Add, update or remove ink contracts");
|
|
40
|
+
inkCommand.command("add").description("Add or update an ink contract").argument("<file>", ".contract or .json metadata file for the contract").option("-k, --key <key>", "Key identifier for the contract").addOption(config).addOption(skipCodegen).addOption(whitelist).action(ink.add);
|
|
41
|
+
inkCommand.command("remove").description("Remove an ink contract").argument("<key>", "Key identifier for the contract to remove").addOption(config).addOption(skipCodegen).addOption(whitelist).action(ink.remove);
|
|
42
|
+
const solCommand = program.command("sol").description("Add, update or remove solidity contracts");
|
|
43
|
+
solCommand.command("add").description("Add or update a solidity contract").argument("<file>", ".abi file for the contract").argument("<key>", "Key identifier for the contract").addOption(config).addOption(skipCodegen).addOption(whitelist).action(sol.add);
|
|
44
|
+
solCommand.command("remove").description("Remove a solidity contract").argument("<key>", "Key identifier for the contract to remove").addOption(config).addOption(skipCodegen).addOption(whitelist).action(sol.remove);
|
|
45
|
+
return program;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { getCli };
|
|
49
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sources":["../../../src/cli.ts"],"sourcesContent":["import { Option, program } from \"@commander-js/extra-typings\"\nimport type { add, generate, ink, remove, update } from \"./commands\"\nimport * as knownChains from \"@polkadot-api/known-chains\"\nimport { sol } from \"./commands/sol\"\n\nexport type Commands = {\n add: typeof add\n generate: typeof generate\n remove: typeof remove\n update: typeof update\n ink: typeof ink\n version: string\n}\n\nexport function getCli({\n add,\n generate,\n remove,\n update,\n ink,\n version,\n}: Commands) {\n program.name(\"polkadot-api\").description(\"Polkadot API CLI\").version(version)\n\n const config = new Option(\"--config <filename>\", \"Source for the config file\")\n const skipCodegen = new Option(\n \"--skip-codegen\",\n \"Skip running codegen after adding\",\n )\n const whitelist = new Option(\n \"--whitelist <filename>\",\n \"Removed. The whitelist path is now .papi/whitelist.ts\",\n ).hideHelp()\n\n program\n .command(\"generate\", {\n isDefault: true,\n })\n .description(\"Generate descriptor files\")\n .addOption(config)\n .addOption(whitelist)\n .action(generate)\n\n program\n .command(\"add\")\n .description(\"Add a new chain spec to the list\")\n .argument(\"<key>\", \"Key identifier for the chain spec\")\n .addOption(config)\n .option(\"-f, --file <filename>\", \"Source from metadata encoded file\")\n .option(\"-w, --wsUrl <URL>\", \"Source from websocket url\")\n .option(\"-c, --chainSpec <filename>\", \"Source from chain spec file\")\n .addOption(\n new Option(\"-n, --name <name>\", \"Source from a well-known chain\").choices(\n Object.keys(knownChains),\n ),\n )\n .option(\"--wasm <filename>\", \"Source from runtime wasm file\")\n .option(\n \"--at <block hash or number>\",\n \"Only for -w/--wsUrl. Fetch the metadata for a specific block or hash\",\n )\n .option(\"--no-persist\", \"Do not persist the metadata as a file\")\n .addOption(skipCodegen)\n .addOption(whitelist)\n .action(add)\n\n program\n .command(\"update\")\n .description(\"Update the metadata files and generate descriptor files\")\n .argument(\n \"[keys]\",\n \"Keys of the metadata files to update, separated by commas. Leave empty for all\",\n )\n .addOption(config)\n .addOption(skipCodegen)\n .addOption(whitelist)\n .action(update)\n\n program\n .command(\"remove\")\n .description(\"Remove a chain spec from the list\")\n .argument(\"<key>\", \"Key identifier for the chain spec\")\n .addOption(config)\n .addOption(skipCodegen)\n .addOption(whitelist)\n .action(remove)\n\n const inkCommand = program\n .command(\"ink\")\n .description(\"Add, update or remove ink contracts\")\n inkCommand\n .command(\"add\")\n .description(\"Add or update an ink contract\")\n .argument(\"<file>\", \".contract or .json metadata file for the contract\")\n .option(\"-k, --key <key>\", \"Key identifier for the contract\")\n .addOption(config)\n .addOption(skipCodegen)\n .addOption(whitelist)\n .action(ink.add)\n inkCommand\n .command(\"remove\")\n .description(\"Remove an ink contract\")\n .argument(\"<key>\", \"Key identifier for the contract to remove\")\n .addOption(config)\n .addOption(skipCodegen)\n .addOption(whitelist)\n .action(ink.remove)\n\n const solCommand = program\n .command(\"sol\")\n .description(\"Add, update or remove solidity contracts\")\n solCommand\n .command(\"add\")\n .description(\"Add or update a solidity contract\")\n .argument(\"<file>\", \".abi file for the contract\")\n .argument(\"<key>\", \"Key identifier for the contract\")\n .addOption(config)\n .addOption(skipCodegen)\n .addOption(whitelist)\n .action(sol.add)\n solCommand\n .command(\"remove\")\n .description(\"Remove a solidity contract\")\n .argument(\"<key>\", \"Key identifier for the contract to remove\")\n .addOption(config)\n .addOption(skipCodegen)\n .addOption(whitelist)\n .action(sol.remove)\n\n return program\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { getMetadata, writeMetadataToDisk } from '../metadata.js';
|
|
2
|
+
import { readPapiConfig, defaultConfig, writePapiConfig, papiFolder } from '../papiConfig.js';
|
|
3
|
+
import { compactNumber } from '@polkadot-api/substrate-bindings';
|
|
4
|
+
import { fromHex } from '@polkadot-api/utils';
|
|
5
|
+
import { getMetadataFromRuntime } from '@polkadot-api/wasm-executor/node';
|
|
6
|
+
import * as fs from 'node:fs/promises';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import { generate } from './generate.js';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { existsSync } from 'node:fs';
|
|
11
|
+
|
|
12
|
+
async function add(key, options) {
|
|
13
|
+
const config = await readPapiConfig(options.config) ?? defaultConfig;
|
|
14
|
+
const entries = config.entries;
|
|
15
|
+
if (key in entries) {
|
|
16
|
+
console.warn(`Replacing existing ${key} config`);
|
|
17
|
+
}
|
|
18
|
+
if (options.file) {
|
|
19
|
+
entries[key] = {
|
|
20
|
+
metadata: options.file
|
|
21
|
+
};
|
|
22
|
+
} else if (options.wasm) {
|
|
23
|
+
const spinner = ora(`Loading metadata from runtime`).start();
|
|
24
|
+
const metadataHex = (await fs.readFile(options.wasm)).toString("hex");
|
|
25
|
+
const opaqueMeta = fromHex(getMetadataFromRuntime(`0x${metadataHex}`));
|
|
26
|
+
const metadataLen = compactNumber.dec(opaqueMeta);
|
|
27
|
+
const compactLen = compactNumber.enc(metadataLen).length;
|
|
28
|
+
if (opaqueMeta.length - compactLen !== metadataLen)
|
|
29
|
+
throw new Error("Not able to retrieve runtime metadata");
|
|
30
|
+
spinner.text = "Writing metadata";
|
|
31
|
+
const metadataRaw = opaqueMeta.slice(compactLen);
|
|
32
|
+
const filename = await storeMetadata(metadataRaw, key);
|
|
33
|
+
spinner.succeed(`Metadata saved as ${filename}`);
|
|
34
|
+
entries[key] = {
|
|
35
|
+
metadata: filename
|
|
36
|
+
};
|
|
37
|
+
} else {
|
|
38
|
+
const entry = entryFromOptions(options);
|
|
39
|
+
entries[key] = entry;
|
|
40
|
+
if (!options.noPersist) {
|
|
41
|
+
const spinner = ora(`Loading metadata`).start();
|
|
42
|
+
const { metadataRaw, genesis, codeHash } = await getMetadata(entry);
|
|
43
|
+
spinner.text = "Writing metadata";
|
|
44
|
+
const filename = await storeMetadata(metadataRaw, key);
|
|
45
|
+
spinner.succeed(`Metadata saved as ${filename}`);
|
|
46
|
+
entry.metadata = filename;
|
|
47
|
+
entry.genesis = genesis;
|
|
48
|
+
entry.codeHash = codeHash;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
await writePapiConfig(options.config, config);
|
|
52
|
+
console.log(`Saved new spec "${key}"`);
|
|
53
|
+
if (!options.skipCodegen) {
|
|
54
|
+
generate({
|
|
55
|
+
config: options.config
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function storeMetadata(metadata, key) {
|
|
60
|
+
const defaultFolder = join(papiFolder, "metadata");
|
|
61
|
+
if (!existsSync(defaultFolder)) {
|
|
62
|
+
await fs.mkdir(defaultFolder, { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
const filename = join(defaultFolder, `${key}.scale`);
|
|
65
|
+
await writeMetadataToDisk(metadata, filename);
|
|
66
|
+
return filename;
|
|
67
|
+
}
|
|
68
|
+
const entryFromOptions = (options) => {
|
|
69
|
+
if (options.wsUrl) {
|
|
70
|
+
return {
|
|
71
|
+
wsUrl: options.wsUrl,
|
|
72
|
+
at: options.at
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (options.chainSpec) {
|
|
76
|
+
return {
|
|
77
|
+
chainSpec: options.chainSpec
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (options.name) {
|
|
81
|
+
return {
|
|
82
|
+
chain: options.name
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
throw new Error(
|
|
86
|
+
"add command needs one source, specified by options -f -w -c or -n"
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export { add };
|
|
91
|
+
//# sourceMappingURL=add.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add.js","sources":["../../../../src/commands/add.ts"],"sourcesContent":["import { getMetadata, writeMetadataToDisk } from \"@/metadata\"\nimport {\n defaultConfig,\n EntryConfig,\n papiFolder,\n readPapiConfig,\n writePapiConfig,\n} from \"@/papiConfig\"\nimport { compactNumber } from \"@polkadot-api/substrate-bindings\"\nimport { fromHex } from \"@polkadot-api/utils\"\nimport { getMetadataFromRuntime } from \"@polkadot-api/wasm-executor/node\"\nimport * as fs from \"node:fs/promises\"\nimport ora from \"ora\"\nimport { CommonOptions } from \"./commonOptions\"\nimport { generate } from \"./generate\"\nimport { join } from \"node:path\"\nimport { existsSync } from \"node:fs\"\n\nexport interface AddOptions extends CommonOptions {\n file?: string\n wsUrl?: string\n chainSpec?: string\n // well-known chains\n name?: string\n wasm?: string\n noPersist?: boolean\n // only for wsUrl\n at?: string\n}\n\nexport async function add(key: string, options: AddOptions) {\n const config = (await readPapiConfig(options.config)) ?? defaultConfig\n const entries = config.entries\n\n if (key in entries) {\n console.warn(`Replacing existing ${key} config`)\n }\n\n if (options.file) {\n entries[key] = {\n metadata: options.file,\n }\n } else if (options.wasm) {\n const spinner = ora(`Loading metadata from runtime`).start()\n const metadataHex = (await fs.readFile(options.wasm)).toString(\"hex\")\n const opaqueMeta = fromHex(getMetadataFromRuntime(`0x${metadataHex}`))\n\n // metadata comes with compact length prepended\n const metadataLen = compactNumber.dec(opaqueMeta)\n const compactLen = compactNumber.enc(metadataLen).length\n // verify we got all data\n if (opaqueMeta.length - compactLen !== metadataLen)\n throw new Error(\"Not able to retrieve runtime metadata\")\n\n spinner.text = \"Writing metadata\"\n const metadataRaw = opaqueMeta.slice(compactLen)\n const filename = await storeMetadata(metadataRaw, key)\n spinner.succeed(`Metadata saved as ${filename}`)\n\n entries[key] = {\n metadata: filename,\n }\n } else {\n const entry = entryFromOptions(options)\n entries[key] = entry\n\n if (!options.noPersist) {\n const spinner = ora(`Loading metadata`).start()\n const { metadataRaw, genesis, codeHash } = (await getMetadata(entry))!\n\n spinner.text = \"Writing metadata\"\n const filename = await storeMetadata(metadataRaw, key)\n\n spinner.succeed(`Metadata saved as ${filename}`)\n entry.metadata = filename\n entry.genesis = genesis\n entry.codeHash = codeHash\n }\n }\n\n await writePapiConfig(options.config, config)\n console.log(`Saved new spec \"${key}\"`)\n\n if (!options.skipCodegen) {\n generate({\n config: options.config,\n })\n }\n}\n\nasync function storeMetadata(metadata: Uint8Array, key: string) {\n const defaultFolder = join(papiFolder, \"metadata\")\n if (!existsSync(defaultFolder)) {\n await fs.mkdir(defaultFolder, { recursive: true })\n }\n const filename = join(defaultFolder, `${key}.scale`)\n await writeMetadataToDisk(metadata, filename)\n return filename\n}\n\nconst entryFromOptions = (options: AddOptions): EntryConfig => {\n if (options.wsUrl) {\n return {\n wsUrl: options.wsUrl,\n at: options.at,\n }\n }\n if (options.chainSpec) {\n return {\n chainSpec: options.chainSpec,\n }\n }\n if (options.name) {\n return {\n chain: options.name,\n }\n }\n\n throw new Error(\n \"add command needs one source, specified by options -f -w -c or -n\",\n )\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { getMetadata } from '../metadata.js';
|
|
2
|
+
import { readPapiConfig } from '../papiConfig.js';
|
|
3
|
+
import { cliVersion } from '../version.js';
|
|
4
|
+
import { generateMultipleDescriptors, generateInkTypes, generateSolTypes, capitalize } from '@polkadot-api/codegen';
|
|
5
|
+
import { getInkLookup } from '@polkadot-api/ink-contracts';
|
|
6
|
+
import { EntryPointCodec, TypedefCodec } from '@polkadot-api/metadata-compatibility';
|
|
7
|
+
import { Blake2128, Binary, h64, Vector, Tuple } from '@polkadot-api/substrate-bindings';
|
|
8
|
+
import { toHex } from '@polkadot-api/utils';
|
|
9
|
+
import { spawn } from 'child_process';
|
|
10
|
+
import { existsSync } from 'fs';
|
|
11
|
+
import fsExists from 'fs.promises.exists';
|
|
12
|
+
import fs, { mkdtemp, rm } from 'fs/promises';
|
|
13
|
+
import { tmpdir } from 'os';
|
|
14
|
+
import path, { join } from 'path';
|
|
15
|
+
import process from 'process';
|
|
16
|
+
import { readPackage } from 'read-pkg';
|
|
17
|
+
import { rollup } from 'rollup';
|
|
18
|
+
import esbuild from 'rollup-plugin-esbuild';
|
|
19
|
+
import tsc from 'tsc-prog';
|
|
20
|
+
import { updatePackage } from 'write-package';
|
|
21
|
+
import { detectPackageManager } from '../packageManager.js';
|
|
22
|
+
|
|
23
|
+
async function generate(opts) {
|
|
24
|
+
if (process.env.PAPI_SKIP_GENERATE) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (opts.whitelist) {
|
|
28
|
+
console.error(
|
|
29
|
+
"The --whitelist option has been removed. The whitelist should be placed at `.papi/whitelist.ts`"
|
|
30
|
+
);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
const config = await readPapiConfig(opts.config);
|
|
34
|
+
if (!config) {
|
|
35
|
+
throw new Error("Can't find the Polkadot-API configuration");
|
|
36
|
+
}
|
|
37
|
+
const sources = config.entries;
|
|
38
|
+
if (Object.keys(sources).length == 0) {
|
|
39
|
+
console.log("No chains defined in config file");
|
|
40
|
+
}
|
|
41
|
+
console.log(`Reading metadata`);
|
|
42
|
+
const chains = await Promise.all(
|
|
43
|
+
Object.entries(sources).map(async ([key, source]) => ({
|
|
44
|
+
key,
|
|
45
|
+
...await getMetadata(source),
|
|
46
|
+
knownTypes: {}
|
|
47
|
+
}))
|
|
48
|
+
);
|
|
49
|
+
const contracts = Object.fromEntries(
|
|
50
|
+
await Promise.all(
|
|
51
|
+
["ink", "sol"].map(async (kind) => [
|
|
52
|
+
kind,
|
|
53
|
+
Object.fromEntries(
|
|
54
|
+
await Promise.all(
|
|
55
|
+
Object.entries(config[kind] ?? {}).map(async ([key, v]) => [
|
|
56
|
+
key,
|
|
57
|
+
toHex(Blake2128(Binary.fromText(await fs.readFile(v, "utf-8"))))
|
|
58
|
+
])
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
])
|
|
62
|
+
)
|
|
63
|
+
);
|
|
64
|
+
if (chains.length === 0) {
|
|
65
|
+
console.log("No entries in polkadot-api.json. Nothing to generate.");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const whitelist = await readWhitelist(".papi/whitelist.ts");
|
|
69
|
+
const descriptorsDir = join(process.cwd(), config.descriptorPath);
|
|
70
|
+
if (await alreadyGenerated(descriptorsDir, chains, contracts, whitelist)) {
|
|
71
|
+
console.log("Detected previous descriptors with no changes needed.");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
console.log(`Generating descriptors`);
|
|
75
|
+
await cleanDescriptorsPackage(config.descriptorPath);
|
|
76
|
+
if (!config.options?.noDescriptorsPackage) {
|
|
77
|
+
await addDescriptorsToPackageJson(config.descriptorPath);
|
|
78
|
+
}
|
|
79
|
+
const clientPath = opts.clientLibrary ?? "polkadot-api";
|
|
80
|
+
const descriptorSrcDir = join(descriptorsDir, "src");
|
|
81
|
+
const hash = await outputCodegen(
|
|
82
|
+
chains,
|
|
83
|
+
descriptorSrcDir,
|
|
84
|
+
clientPath,
|
|
85
|
+
whitelist
|
|
86
|
+
);
|
|
87
|
+
if (config.ink || config.sol) {
|
|
88
|
+
outputContractCodegen(config, descriptorSrcDir);
|
|
89
|
+
}
|
|
90
|
+
await replacePackageJson(descriptorsDir, hash);
|
|
91
|
+
const cleanCodegen = await compileCodegen(descriptorsDir);
|
|
92
|
+
if (cleanCodegen) {
|
|
93
|
+
await tagGenerated(descriptorsDir, chains, contracts, whitelist);
|
|
94
|
+
await fs.rm(descriptorSrcDir, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
if (!config.options?.noDescriptorsPackage) {
|
|
97
|
+
await runInstall();
|
|
98
|
+
await flushBundlerCache();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async function tagGenerated(descriptorsDir, chains, contracts, whitelist) {
|
|
102
|
+
const filePath = join(descriptorsDir, "generated.json");
|
|
103
|
+
await fs.writeFile(
|
|
104
|
+
filePath,
|
|
105
|
+
JSON.stringify({
|
|
106
|
+
cliVersion,
|
|
107
|
+
whitelist,
|
|
108
|
+
chains: Object.fromEntries(
|
|
109
|
+
chains.map(({ key, metadataRaw }) => [
|
|
110
|
+
key,
|
|
111
|
+
toHex(Blake2128(metadataRaw))
|
|
112
|
+
])
|
|
113
|
+
),
|
|
114
|
+
contracts
|
|
115
|
+
})
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
async function alreadyGenerated(descriptorsDir, chains, contracts, whitelist) {
|
|
119
|
+
const generatedJs\u00F4n = join(descriptorsDir, "generated.json");
|
|
120
|
+
if (!existsSync(generatedJs\u00F4n)) return false;
|
|
121
|
+
try {
|
|
122
|
+
const generated = JSON.parse(
|
|
123
|
+
await fs.readFile(generatedJs\u00F4n, {
|
|
124
|
+
encoding: "utf-8"
|
|
125
|
+
})
|
|
126
|
+
);
|
|
127
|
+
if ((generated.whitelist ?? ["*"]).join(",") != (whitelist ?? ["*"]).join(",") || generated.cliVersion !== cliVersion)
|
|
128
|
+
return false;
|
|
129
|
+
return chains.length === Object.entries(generated.chains).length && chains.every(({ key, metadataRaw }) => {
|
|
130
|
+
const hash = toHex(Blake2128(metadataRaw));
|
|
131
|
+
return hash === generated.chains[key];
|
|
132
|
+
}) && ["ink", "sol"].every(
|
|
133
|
+
(kind) => Object.entries(contracts[kind]).length === Object.entries(generated.contracts[kind]).length && Object.entries(contracts[kind]).every(
|
|
134
|
+
([k, hash]) => hash === generated.contracts[kind][k]
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
} catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function cleanDescriptorsPackage(path2) {
|
|
142
|
+
const descriptorsDir = join(process.cwd(), path2);
|
|
143
|
+
if (!existsSync(descriptorsDir)) {
|
|
144
|
+
await fs.mkdir(descriptorsDir, { recursive: true });
|
|
145
|
+
await fs.writeFile(
|
|
146
|
+
join(descriptorsDir, ".gitignore"),
|
|
147
|
+
"*\n!.gitignore\n!package.json\n"
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const distDir = join(descriptorsDir, "dist");
|
|
151
|
+
if (existsSync(distDir)) {
|
|
152
|
+
await fs.rm(distDir, { recursive: true });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function addDescriptorsToPackageJson(path2) {
|
|
156
|
+
const [packageJson, protocol] = await Promise.all([
|
|
157
|
+
readPackage(),
|
|
158
|
+
getPackageProtocol()
|
|
159
|
+
]);
|
|
160
|
+
const packageSource = `${protocol}:${path2}`;
|
|
161
|
+
const currentSource = packageJson.dependencies?.["@polkadot-api/descriptors"];
|
|
162
|
+
if (currentSource !== packageSource) {
|
|
163
|
+
await updatePackage({
|
|
164
|
+
dependencies: {
|
|
165
|
+
"@polkadot-api/descriptors": packageSource
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async function getPackageProtocol() {
|
|
171
|
+
const { packageManager, version } = await detectPackageManager();
|
|
172
|
+
switch (packageManager) {
|
|
173
|
+
case "yarn":
|
|
174
|
+
const yarnMajorVersion = Number(version.split(".").at(0));
|
|
175
|
+
return yarnMajorVersion >= 2 ? "portal" : "file";
|
|
176
|
+
default:
|
|
177
|
+
return "file";
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async function runInstall() {
|
|
181
|
+
const { executable } = await detectPackageManager();
|
|
182
|
+
console.log(`${executable} install`);
|
|
183
|
+
const child = spawn(executable, ["install"], {
|
|
184
|
+
stdio: "inherit",
|
|
185
|
+
shell: true,
|
|
186
|
+
env: {
|
|
187
|
+
...process.env,
|
|
188
|
+
PAPI_SKIP_GENERATE: "true"
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
await new Promise((resolve) => child.on("close", resolve));
|
|
192
|
+
}
|
|
193
|
+
const generateMetadataExportFile = (input) => `const binMeta: string = "${Buffer.from(input).toString("base64")}"; export default binMeta;`;
|
|
194
|
+
async function outputCodegen(chains, outputFolder, clientPath, whitelist) {
|
|
195
|
+
const {
|
|
196
|
+
commonFileContent,
|
|
197
|
+
descriptorsFileContent,
|
|
198
|
+
descriptorTypesFiles,
|
|
199
|
+
metadataTypes,
|
|
200
|
+
typesFileContent,
|
|
201
|
+
publicTypes
|
|
202
|
+
} = generateMultipleDescriptors(
|
|
203
|
+
chains,
|
|
204
|
+
{
|
|
205
|
+
client: clientPath,
|
|
206
|
+
metadataTypes: "./metadataTypes",
|
|
207
|
+
types: "./common-types",
|
|
208
|
+
descriptorValues: "./descriptors",
|
|
209
|
+
common: "./common"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
whitelist: whitelist ?? void 0
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
const hash = h64(
|
|
216
|
+
Binary.fromText(Array.from(metadataTypes.checksumToIdx.keys()).join(""))
|
|
217
|
+
);
|
|
218
|
+
const EntryPointsCodec = Vector(EntryPointCodec);
|
|
219
|
+
const TypedefsCodec = Vector(TypedefCodec);
|
|
220
|
+
const TypesCodec = Tuple(EntryPointsCodec, TypedefsCodec);
|
|
221
|
+
await fs.mkdir(outputFolder, { recursive: true });
|
|
222
|
+
await fs.writeFile(path.join(outputFolder, "common.ts"), commonFileContent);
|
|
223
|
+
const metadataTypesBase64 = Buffer.from(
|
|
224
|
+
TypesCodec.enc([metadataTypes.entryPoints, metadataTypes.typedefs])
|
|
225
|
+
).toString("base64");
|
|
226
|
+
await fs.writeFile(
|
|
227
|
+
path.join(outputFolder, "metadataTypes.ts"),
|
|
228
|
+
`
|
|
229
|
+
const content = "${metadataTypesBase64}"
|
|
230
|
+
export default content
|
|
231
|
+
`
|
|
232
|
+
);
|
|
233
|
+
await fs.writeFile(
|
|
234
|
+
path.join(outputFolder, "descriptors.ts"),
|
|
235
|
+
descriptorsFileContent
|
|
236
|
+
);
|
|
237
|
+
await fs.writeFile(
|
|
238
|
+
path.join(outputFolder, "common-types.ts"),
|
|
239
|
+
typesFileContent
|
|
240
|
+
);
|
|
241
|
+
await Promise.all(
|
|
242
|
+
chains.map((chain, i) => [
|
|
243
|
+
fs.writeFile(
|
|
244
|
+
join(outputFolder, `${chain.key}.ts`),
|
|
245
|
+
descriptorTypesFiles[i].content
|
|
246
|
+
),
|
|
247
|
+
fs.writeFile(
|
|
248
|
+
join(outputFolder, `${chain.key}_metadata.ts`),
|
|
249
|
+
generateMetadataExportFile(chain.metadataRaw)
|
|
250
|
+
)
|
|
251
|
+
]).flat()
|
|
252
|
+
);
|
|
253
|
+
await generateIndex(
|
|
254
|
+
outputFolder,
|
|
255
|
+
chains.map((chain) => chain.key),
|
|
256
|
+
publicTypes,
|
|
257
|
+
Object.fromEntries(
|
|
258
|
+
chains.filter((x) => x.codeHash).map((x) => [x.codeHash, x.key])
|
|
259
|
+
)
|
|
260
|
+
);
|
|
261
|
+
return hash;
|
|
262
|
+
}
|
|
263
|
+
async function outputContractCodegen(contracts, outputFolder) {
|
|
264
|
+
console.log("Generating smart contract types");
|
|
265
|
+
const contractsFolder = join(outputFolder, "contracts");
|
|
266
|
+
if (!existsSync(contractsFolder))
|
|
267
|
+
await fs.mkdir(contractsFolder, { recursive: true });
|
|
268
|
+
const imports = [];
|
|
269
|
+
for (const [key, metadata] of Object.entries(contracts.ink ?? {})) {
|
|
270
|
+
try {
|
|
271
|
+
const types = generateInkTypes(
|
|
272
|
+
getInkLookup(JSON.parse(await fs.readFile(metadata, "utf-8")))
|
|
273
|
+
);
|
|
274
|
+
await fs.writeFile(join(contractsFolder, `${key}.ts`), types);
|
|
275
|
+
imports.push(`export { descriptor as ${key} } from './${key}'`);
|
|
276
|
+
} catch (ex) {
|
|
277
|
+
console.error("Exception when generating descriptors for contract " + key);
|
|
278
|
+
console.error(ex);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
for (const [key, metadata] of Object.entries(contracts.sol ?? {})) {
|
|
282
|
+
try {
|
|
283
|
+
const types = generateSolTypes(
|
|
284
|
+
JSON.parse(await fs.readFile(metadata, "utf-8"))
|
|
285
|
+
);
|
|
286
|
+
await fs.writeFile(join(contractsFolder, `${key}.ts`), types);
|
|
287
|
+
imports.push(`export { descriptor as ${key} } from './${key}'`);
|
|
288
|
+
} catch (ex) {
|
|
289
|
+
console.error("Exception when generating descriptors for contract " + key);
|
|
290
|
+
console.error(ex);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
await fs.writeFile(
|
|
294
|
+
join(contractsFolder, `index.ts`),
|
|
295
|
+
imports.join("\n") + "\n"
|
|
296
|
+
);
|
|
297
|
+
fs.appendFile(
|
|
298
|
+
join(outputFolder, "index.ts"),
|
|
299
|
+
`
|
|
300
|
+
export * as contracts from './contracts';
|
|
301
|
+
`
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
async function compileCodegen(packageDir) {
|
|
305
|
+
const srcDir = join(packageDir, "src");
|
|
306
|
+
const outDir = join(packageDir, "dist");
|
|
307
|
+
if (await fsExists(outDir)) {
|
|
308
|
+
await fs.rm(outDir, { recursive: true });
|
|
309
|
+
}
|
|
310
|
+
const bundleSuccess = await bundleEsm(path.join(srcDir, "index.ts"), {
|
|
311
|
+
dir: outDir
|
|
312
|
+
});
|
|
313
|
+
const program = tsc.createProgramFromConfig({
|
|
314
|
+
basePath: srcDir,
|
|
315
|
+
compilerOptions: {
|
|
316
|
+
skipLibCheck: true,
|
|
317
|
+
declaration: true,
|
|
318
|
+
emitDeclarationOnly: true,
|
|
319
|
+
target: "esnext",
|
|
320
|
+
module: "esnext",
|
|
321
|
+
resolveJsonModule: true,
|
|
322
|
+
allowSyntheticDefaultImports: true,
|
|
323
|
+
outDir
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
tsc.emit(program);
|
|
327
|
+
const errors = [
|
|
328
|
+
program.getGlobalDiagnostics(),
|
|
329
|
+
program.getOptionsDiagnostics(),
|
|
330
|
+
program.getSemanticDiagnostics(),
|
|
331
|
+
program.getSyntacticDiagnostics(),
|
|
332
|
+
program.getDeclarationDiagnostics(),
|
|
333
|
+
program.getConfigFileParsingDiagnostics()
|
|
334
|
+
].flat();
|
|
335
|
+
return bundleSuccess && errors.length === 0;
|
|
336
|
+
}
|
|
337
|
+
const cacheMetadataStr = `
|
|
338
|
+
export const getMetadata: (codeHash: string) => Promise<Uint8Array | null> = async (
|
|
339
|
+
codeHash: string
|
|
340
|
+
)=> {
|
|
341
|
+
try {
|
|
342
|
+
return await metadatas[codeHash].getMetadata()
|
|
343
|
+
} catch {}
|
|
344
|
+
return null
|
|
345
|
+
}`;
|
|
346
|
+
const generateIndex = async (path2, keys, publicTypes, metadatas) => {
|
|
347
|
+
const indexTs = [
|
|
348
|
+
...keys.flatMap((key) => [
|
|
349
|
+
`import { default as ${key}, type ${capitalize(key)}WhitelistEntry } from "./${key}";`,
|
|
350
|
+
`export { ${key} }`,
|
|
351
|
+
`export type * from "./${key}";`
|
|
352
|
+
]),
|
|
353
|
+
`export {`,
|
|
354
|
+
publicTypes.join(", "),
|
|
355
|
+
`} from './common-types';`,
|
|
356
|
+
`const metadatas: Record<string, { getMetadata: () => Promise<Uint8Array> }> = {${Object.entries(
|
|
357
|
+
metadatas
|
|
358
|
+
).map(([codeHash, key]) => `["${codeHash}"]: ${key}`).join(",\n")}}`,
|
|
359
|
+
cacheMetadataStr,
|
|
360
|
+
`export type WhitelistEntry = ${keys.map((key) => `${capitalize(key)}WhitelistEntry`).join(" | ")};`,
|
|
361
|
+
`export type WhitelistEntriesByChain = Partial<{"*": WhitelistEntry[], ${keys.map((key) => `${key}: WhitelistEntry[]`).join(",\n")}}>`
|
|
362
|
+
].join("\n");
|
|
363
|
+
await fs.writeFile(join(path2, "index.ts"), indexTs);
|
|
364
|
+
};
|
|
365
|
+
async function replacePackageJson(descriptorsDir, version) {
|
|
366
|
+
await fs.writeFile(
|
|
367
|
+
join(descriptorsDir, "package.json"),
|
|
368
|
+
`{
|
|
369
|
+
"version": "0.1.0-autogenerated.${version}",
|
|
370
|
+
"name": "@polkadot-api/descriptors",
|
|
371
|
+
"files": [
|
|
372
|
+
"dist"
|
|
373
|
+
],
|
|
374
|
+
"type": "module",
|
|
375
|
+
"exports": {
|
|
376
|
+
".": {
|
|
377
|
+
"types": "./dist/index.d.ts",
|
|
378
|
+
"module": "./dist/index.js",
|
|
379
|
+
"import": "./dist/index.js",
|
|
380
|
+
"default": "./dist/index.js"
|
|
381
|
+
},
|
|
382
|
+
"./package.json": "./package.json"
|
|
383
|
+
},
|
|
384
|
+
"main": "./dist/index.js",
|
|
385
|
+
"module": "./dist/index.js",
|
|
386
|
+
"browser": "./dist/index.js",
|
|
387
|
+
"types": "./dist/index.d.ts",
|
|
388
|
+
"sideEffects": false,
|
|
389
|
+
"peerDependencies": {
|
|
390
|
+
"polkadot-api": ">=2.0.0-rc.1"
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
`
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
async function readWhitelist(filename) {
|
|
397
|
+
if (!await fsExists(filename)) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
const tmpDir = await mkdtemp(join(tmpdir(), "papi-"));
|
|
401
|
+
try {
|
|
402
|
+
await bundleEsm(filename, { file: join(tmpDir, "index.js") });
|
|
403
|
+
const { whitelist } = await import(join(tmpDir, "index.js"));
|
|
404
|
+
return whitelist;
|
|
405
|
+
} finally {
|
|
406
|
+
await rm(tmpDir, { recursive: true }).catch(console.error);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
async function flushBundlerCache() {
|
|
410
|
+
try {
|
|
411
|
+
const viteMetadata = join(
|
|
412
|
+
process.cwd(),
|
|
413
|
+
"node_modules",
|
|
414
|
+
".vite",
|
|
415
|
+
"deps",
|
|
416
|
+
"_metadata.json"
|
|
417
|
+
);
|
|
418
|
+
if (await fsExists(viteMetadata)) {
|
|
419
|
+
await rm(viteMetadata);
|
|
420
|
+
}
|
|
421
|
+
} catch (ex) {
|
|
422
|
+
console.error(ex);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const isExternal = (id) => !id.startsWith(".") && !path.isAbsolute(id);
|
|
426
|
+
const scaleBinaryPlugin = () => ({
|
|
427
|
+
name: "scale-binary",
|
|
428
|
+
async load(id) {
|
|
429
|
+
if (!id.endsWith(".scale")) return null;
|
|
430
|
+
const data = await fs.readFile(id);
|
|
431
|
+
const base64 = Buffer.from(data).toString("base64");
|
|
432
|
+
return `const base64 = "${base64}";
|
|
433
|
+
export default base64;`;
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
async function bundleEsm(entry, output) {
|
|
437
|
+
let bundle;
|
|
438
|
+
try {
|
|
439
|
+
bundle = await rollup({
|
|
440
|
+
input: entry,
|
|
441
|
+
external: isExternal,
|
|
442
|
+
plugins: [scaleBinaryPlugin(), esbuild({ target: "es2022" })],
|
|
443
|
+
logLevel: "silent"
|
|
444
|
+
});
|
|
445
|
+
await bundle.write({
|
|
446
|
+
...output,
|
|
447
|
+
format: "es"
|
|
448
|
+
});
|
|
449
|
+
return true;
|
|
450
|
+
} catch (ex) {
|
|
451
|
+
console.error(ex);
|
|
452
|
+
return false;
|
|
453
|
+
} finally {
|
|
454
|
+
await bundle?.close();
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export { generate };
|
|
459
|
+
//# sourceMappingURL=generate.js.map
|