ic-mops 0.0.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/.eslintrc.json +28 -0
- package/README.md +16 -0
- package/cli.js +123 -0
- package/commands/import-identity.js +30 -0
- package/commands/init.js +32 -0
- package/commands/install-all.js +20 -0
- package/commands/install.js +61 -0
- package/commands/publish.js +212 -0
- package/commands/sources.js +101 -0
- package/commands/uninstall.js +38 -0
- package/commands/whoami.js +14 -0
- package/declarations/main/index.js +38 -0
- package/declarations/main/main.did +89 -0
- package/declarations/main/main.did.d.ts +68 -0
- package/declarations/main/main.did.js +77 -0
- package/mops.js +90 -0
- package/package.json +25 -0
- package/parallel.js +25 -0
- package/pem.js +17 -0
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"env": {
|
|
3
|
+
"node": true,
|
|
4
|
+
"es2021": true
|
|
5
|
+
},
|
|
6
|
+
"extends": "eslint:recommended",
|
|
7
|
+
"parserOptions": {
|
|
8
|
+
"sourceType": "module"
|
|
9
|
+
},
|
|
10
|
+
"rules": {
|
|
11
|
+
"indent": [
|
|
12
|
+
"error",
|
|
13
|
+
"tab"
|
|
14
|
+
],
|
|
15
|
+
"linebreak-style": [
|
|
16
|
+
"error",
|
|
17
|
+
"unix"
|
|
18
|
+
],
|
|
19
|
+
"quotes": [
|
|
20
|
+
"error",
|
|
21
|
+
"single"
|
|
22
|
+
],
|
|
23
|
+
"semi": [
|
|
24
|
+
"error",
|
|
25
|
+
"always"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
}
|
package/README.md
ADDED
package/cli.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import {program} from 'commander';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import TOML from '@iarna/toml';
|
|
8
|
+
|
|
9
|
+
import {init} from './commands/init.js';
|
|
10
|
+
import {install} from './commands/install.js';
|
|
11
|
+
import {publish} from './commands/publish.js';
|
|
12
|
+
import {importPem} from './commands/import-identity.js';
|
|
13
|
+
import {sources} from './commands/sources.js';
|
|
14
|
+
import {getLastVersion, getNetwork, setNetwork} from './mops.js';
|
|
15
|
+
import {whoami} from './commands/whoami.js';
|
|
16
|
+
import {installAll} from './commands/install-all.js';
|
|
17
|
+
import logUpdate from 'log-update';
|
|
18
|
+
|
|
19
|
+
let cwd = process.cwd();
|
|
20
|
+
let configFile = path.join(cwd, 'mops.toml');
|
|
21
|
+
|
|
22
|
+
function wirteConfig(config) {
|
|
23
|
+
fs.writeFileSync(configFile, TOML.stringify(config).trim());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
program.name('mops');
|
|
27
|
+
|
|
28
|
+
// init
|
|
29
|
+
program
|
|
30
|
+
.command('init [name]')
|
|
31
|
+
.description('Create mops.toml')
|
|
32
|
+
.action(async (name) => {
|
|
33
|
+
await init(name);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// install
|
|
37
|
+
program
|
|
38
|
+
.command('install [pkg]')
|
|
39
|
+
.alias('i')
|
|
40
|
+
.alias('add')
|
|
41
|
+
.description('Install package and save it as a dependency in the mops.toml file')
|
|
42
|
+
.option('--verbose', '')
|
|
43
|
+
.action(async (pkg, options) => {
|
|
44
|
+
let config = {};
|
|
45
|
+
let exists = fs.existsSync(configFile);
|
|
46
|
+
if (exists) {
|
|
47
|
+
let text = fs.readFileSync(configFile).toString();
|
|
48
|
+
config = TOML.parse(text);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.log(chalk.red('Error: ') + `mops.toml not found. Please run ${chalk.green('mops init')} first`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (!config.dependencies) {
|
|
55
|
+
config.dependencies = {};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!pkg) {
|
|
59
|
+
installAll(options);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
let version = await getLastVersion(pkg);
|
|
63
|
+
await install(pkg, version, options.verbose);
|
|
64
|
+
|
|
65
|
+
config.dependencies[pkg] = version;
|
|
66
|
+
wirteConfig(config);
|
|
67
|
+
logUpdate.clear();
|
|
68
|
+
console.log(chalk.green('Package installed ') + `${pkg} = '${version}'`);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// publish
|
|
73
|
+
program
|
|
74
|
+
.command('publish')
|
|
75
|
+
.description('Publish package to the mops registry')
|
|
76
|
+
.action(async () => {
|
|
77
|
+
await publish();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// set-network
|
|
81
|
+
program
|
|
82
|
+
.command('set-network <network>')
|
|
83
|
+
.description('Set network local|dev|ic')
|
|
84
|
+
.action(async (network) => {
|
|
85
|
+
await setNetwork(network);
|
|
86
|
+
console.log(`Selected '${network}' network`);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// get-network
|
|
90
|
+
program
|
|
91
|
+
.command('get-network')
|
|
92
|
+
.description('Get network')
|
|
93
|
+
.action(async () => {
|
|
94
|
+
console.log(getNetwork().network);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// import-identity
|
|
98
|
+
program
|
|
99
|
+
.command('import-identity <data>')
|
|
100
|
+
.description('Import .pem file data to use as identity')
|
|
101
|
+
.action(async (data) => {
|
|
102
|
+
await importPem(data);
|
|
103
|
+
whoami();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// sources
|
|
107
|
+
program
|
|
108
|
+
.command('sources')
|
|
109
|
+
.description('for dfx packtool')
|
|
110
|
+
.option('--verbose', '')
|
|
111
|
+
.action(async (options) => {
|
|
112
|
+
await sources(options);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// whoami
|
|
116
|
+
program
|
|
117
|
+
.command('whoami')
|
|
118
|
+
.description('prints your principal')
|
|
119
|
+
.action(async () => {
|
|
120
|
+
whoami();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
program.parse();
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
export async function importPem(data) {
|
|
5
|
+
try {
|
|
6
|
+
let url = new URL('../identity.pem', import.meta.url);
|
|
7
|
+
fs.writeFileSync(url, data);
|
|
8
|
+
console.log(chalk.green('Success'));
|
|
9
|
+
}
|
|
10
|
+
catch (err) {
|
|
11
|
+
console.log(chalk.red('Error: ') + err);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// export async function pemFile(file) {
|
|
16
|
+
// try {
|
|
17
|
+
// if (!file.endsWith('.pem')) {
|
|
18
|
+
// throw 'Please specify .pem file';
|
|
19
|
+
// }
|
|
20
|
+
// if (!fs.existsSync(file)) {
|
|
21
|
+
// throw 'File not found ' + file;
|
|
22
|
+
// }
|
|
23
|
+
// let url = new URL('./pem-file', import.meta.url);
|
|
24
|
+
// fs.writeFileSync(url, file);
|
|
25
|
+
// console.log(chalk.green('Success'));
|
|
26
|
+
// }
|
|
27
|
+
// catch (e) {
|
|
28
|
+
// console.log(chalk.red('Error: ') + e);
|
|
29
|
+
// }
|
|
30
|
+
// }
|
package/commands/init.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import TOML from '@iarna/toml';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
|
|
6
|
+
export async function init(name = {}) {
|
|
7
|
+
let configFile = path.join(process.cwd(), 'mops.toml');
|
|
8
|
+
let exists = fs.existsSync(configFile);
|
|
9
|
+
if (exists) {
|
|
10
|
+
console.log(chalk.yellow('mops.toml already exists'));
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
let config = {};
|
|
14
|
+
if (name) {
|
|
15
|
+
config = {
|
|
16
|
+
package: {
|
|
17
|
+
name: name,
|
|
18
|
+
version: '0.1.0',
|
|
19
|
+
description: '',
|
|
20
|
+
repository: '',
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
// TODO: add last version of 'base' package?
|
|
25
|
+
// else {
|
|
26
|
+
// config.dependencies = {};
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
fs.writeFileSync(configFile, TOML.stringify(config).trim());
|
|
30
|
+
|
|
31
|
+
console.log(chalk.green('mops.toml has been created'));
|
|
32
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import logUpdate from 'log-update';
|
|
3
|
+
import {checkConfigFile, readConfig} from '../mops.js';
|
|
4
|
+
import {install} from './install.js';
|
|
5
|
+
|
|
6
|
+
export async function installAll({verbose} = {}) {
|
|
7
|
+
if (!checkConfigFile()) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let config = readConfig();
|
|
12
|
+
let deps = Object.entries(config.dependencies || {});
|
|
13
|
+
|
|
14
|
+
for (let [pkg, ver] of deps) {
|
|
15
|
+
await install(pkg, ver, verbose);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
logUpdate.clear();
|
|
19
|
+
console.log(chalk.green('All packages installed'));
|
|
20
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import logUpdate from 'log-update';
|
|
4
|
+
import {checkConfigFile, getLastVersion, mainActor, progressBar, readConfig} from '../mops.js';
|
|
5
|
+
import {parallel} from '../parallel.js';
|
|
6
|
+
|
|
7
|
+
export async function install(pkg, version = '', verbose = false, dep = false) {
|
|
8
|
+
if (!checkConfigFile()) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (!version) {
|
|
13
|
+
version = await getLastVersion(pkg);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let dir = path.join(process.cwd(), '.mops', `${pkg}@${version}`);
|
|
17
|
+
let actor = await mainActor();
|
|
18
|
+
|
|
19
|
+
// cache
|
|
20
|
+
if (fs.existsSync(dir)) {
|
|
21
|
+
logUpdate(`${dep ? 'Dependency' : 'Installing'} ${pkg}@${version} (cache)`);
|
|
22
|
+
}
|
|
23
|
+
// no cache
|
|
24
|
+
else {
|
|
25
|
+
fs.mkdirSync(dir, {recursive: true});
|
|
26
|
+
|
|
27
|
+
let filesIds = await actor.getFileIds(pkg, version);
|
|
28
|
+
|
|
29
|
+
// progress
|
|
30
|
+
let total = filesIds.length + 1;
|
|
31
|
+
let step = 0;
|
|
32
|
+
let progress = () => {
|
|
33
|
+
step++;
|
|
34
|
+
logUpdate(`${dep ? 'Dependency' : 'Installing'} ${pkg}@${version} ${progressBar(step, total)}`);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// download files
|
|
38
|
+
progress();
|
|
39
|
+
await parallel(8, filesIds, async (fileId) => {
|
|
40
|
+
let file = await actor.getFile(fileId);
|
|
41
|
+
fs.mkdirSync(path.join(dir, path.dirname(file.path)), {recursive: true});
|
|
42
|
+
fs.writeFileSync(path.join(dir, file.path), Buffer.from(file.content));
|
|
43
|
+
progress();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// TODO: slow (update call)
|
|
47
|
+
// if (!dep) {
|
|
48
|
+
// await actor.notifyInstall(pkg, version);
|
|
49
|
+
// }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (verbose) {
|
|
53
|
+
logUpdate.done();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// install dependencies
|
|
57
|
+
let config = readConfig(path.join(dir, 'mops.toml'));
|
|
58
|
+
for (let [name, version] of Object.entries(config.dependencies || {})) {
|
|
59
|
+
await install(name, version, verbose, true);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import logUpdate from 'log-update';
|
|
4
|
+
import {Principal} from '@dfinity/principal';
|
|
5
|
+
import {globbySync} from 'globby';
|
|
6
|
+
import minimatch from 'minimatch';
|
|
7
|
+
import prompts from 'prompts';
|
|
8
|
+
import {checkConfigFile, getIdentity, mainActor, progressBar, readConfig} from '../mops.js';
|
|
9
|
+
import {parallel} from '../parallel.js';
|
|
10
|
+
|
|
11
|
+
export async function publish() {
|
|
12
|
+
if (!checkConfigFile()) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let config = readConfig();
|
|
17
|
+
|
|
18
|
+
// validate
|
|
19
|
+
for (let key of Object.keys(config)) {
|
|
20
|
+
if (!['package', 'dependencies', 'permissions', 'scripts'].includes(key)) {
|
|
21
|
+
console.log(chalk.red('Error: ') + `Unknown config section [${key}]`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// required fields
|
|
27
|
+
if (!config.package) {
|
|
28
|
+
console.log(chalk.red('Error: ') + 'Please specify [package] section in your mops.toml');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
for (let key of ['name', 'version']) {
|
|
32
|
+
if (!config.package[key]) {
|
|
33
|
+
console.log(chalk.red('Error: ') + `Please specify "${key}" in [config] section in your mops.toml`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// desired fields
|
|
39
|
+
for (let key of ['description', 'repository']) {
|
|
40
|
+
if (!config.package[key]) {
|
|
41
|
+
let res = await prompts({
|
|
42
|
+
type: 'confirm',
|
|
43
|
+
name: 'ok',
|
|
44
|
+
message: `Missing recommended config key "${key}", publish anyway?`,
|
|
45
|
+
});
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let packageKeys = [
|
|
53
|
+
'name',
|
|
54
|
+
'version',
|
|
55
|
+
'keywords',
|
|
56
|
+
'description',
|
|
57
|
+
'repository',
|
|
58
|
+
'documentation',
|
|
59
|
+
'homepage',
|
|
60
|
+
'readme',
|
|
61
|
+
'license',
|
|
62
|
+
'isPrivate',
|
|
63
|
+
'files',
|
|
64
|
+
'dfx',
|
|
65
|
+
'moc',
|
|
66
|
+
'donation',
|
|
67
|
+
];
|
|
68
|
+
for (let key of Object.keys(config.package)) {
|
|
69
|
+
if (!packageKeys.includes(key)) {
|
|
70
|
+
console.log(chalk.red('Error: ') + `Unknown config key 'package.${key}'`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// check lengths
|
|
76
|
+
let keysMax = {
|
|
77
|
+
name: 50,
|
|
78
|
+
version: 20,
|
|
79
|
+
keywords: 5,
|
|
80
|
+
description: 200,
|
|
81
|
+
repository: 300,
|
|
82
|
+
documentation: 300,
|
|
83
|
+
homepage: 300,
|
|
84
|
+
readme: 100,
|
|
85
|
+
license: 30,
|
|
86
|
+
files: 20,
|
|
87
|
+
dfx: 10,
|
|
88
|
+
moc: 10,
|
|
89
|
+
donation: 64,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
for (let [key, max] of Object.entries(keysMax)) {
|
|
93
|
+
if (config.package[key] && config.package[key].length > max) {
|
|
94
|
+
console.log(chalk.red('Error: ') + `package.${key} value max length is ${max}`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (config.package.dependencies && Object.keys(config.package.dependencies).length > 100) {
|
|
100
|
+
console.log(chalk.red('Error: ') + 'max dependencies is 100');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (config.package.permissions && Object.keys(config.package.permissions).length > 50) {
|
|
105
|
+
console.log(chalk.red('Error: ') + 'max permissions is 50');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (config.package.keywords) {
|
|
110
|
+
for (let keyword of config.package.keywords) {
|
|
111
|
+
if (keyword.length > 20) {
|
|
112
|
+
console.log(chalk.red('Error: ') + 'max keyword length is 20');
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (config.package.files) {
|
|
119
|
+
for (let file of config.package.files) {
|
|
120
|
+
if (file.startsWith('/') || file.startsWith('../')) {
|
|
121
|
+
console.log(chalk.red('Error: ') + 'file path cannot start with \'/\' or \'../\'');
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// map fields
|
|
128
|
+
let backendPkgConfig = {
|
|
129
|
+
name: config.package.name,
|
|
130
|
+
version: config.package.version,
|
|
131
|
+
keywords: config.package.keywords || [],
|
|
132
|
+
description: config.package.description || '',
|
|
133
|
+
repository: config.package.repository || '',
|
|
134
|
+
homepage: config.package.homepage || '',
|
|
135
|
+
documentation: config.package.documentation || '',
|
|
136
|
+
readme: 'README.md',
|
|
137
|
+
license: config.package.license || '',
|
|
138
|
+
isPrivate: false,
|
|
139
|
+
owner: getIdentity()?.getPrincipal() || Principal.anonymous(),
|
|
140
|
+
dfx: config.package.dfx || '',
|
|
141
|
+
moc: config.package.moc || '',
|
|
142
|
+
donation: config.package.donation || '',
|
|
143
|
+
dependencies: (Object.entries(config.dependencies || {})).map(([name, version]) => {
|
|
144
|
+
return {name, version};
|
|
145
|
+
}),
|
|
146
|
+
permissions: [],
|
|
147
|
+
scripts: [],
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
let defaultFiles = [
|
|
151
|
+
'mops.toml',
|
|
152
|
+
'README.md',
|
|
153
|
+
'LICENSE',
|
|
154
|
+
'!.mops/**',
|
|
155
|
+
];
|
|
156
|
+
let files = config.package.files || ['**/*.mo'];
|
|
157
|
+
files = [...files, ...defaultFiles];
|
|
158
|
+
files = globbySync([...files, ...defaultFiles]);
|
|
159
|
+
|
|
160
|
+
// check required files
|
|
161
|
+
if (!files.includes('mops.toml')) {
|
|
162
|
+
console.log(chalk.red('Error: ') + ' please add mops.toml file');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (!files.includes('README.md')) {
|
|
166
|
+
console.log(chalk.red('Error: ') + ' please add README.md file');
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// check allowed exts
|
|
171
|
+
for (let file of files) {
|
|
172
|
+
if (!minimatch(file, '**/*.{mo,did,md,toml}')) {
|
|
173
|
+
console.log(chalk.red('Error: ') + `file ${file} has unsupported extension. Allowed: .mo, .did, .md, .toml`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// progress
|
|
179
|
+
let total = files.length + 2;
|
|
180
|
+
let step = 0;
|
|
181
|
+
function progress() {
|
|
182
|
+
step++;
|
|
183
|
+
logUpdate(`Publishing ${config.package.name}@${config.package.version} ${progressBar(step, total)}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// upload config
|
|
187
|
+
progress();
|
|
188
|
+
let actor = await mainActor();
|
|
189
|
+
let publishing = await actor.startPublish(backendPkgConfig);
|
|
190
|
+
if (publishing.err) {
|
|
191
|
+
console.log(chalk.red('Error: ') + publishing.err);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
let puiblishingId = publishing.ok;
|
|
195
|
+
|
|
196
|
+
// upload files
|
|
197
|
+
await parallel(8, files, async (file) => {
|
|
198
|
+
progress();
|
|
199
|
+
let content = fs.readFileSync(file);
|
|
200
|
+
await actor.uploadFile(puiblishingId, file, Array.from(content));
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// finish
|
|
204
|
+
progress();
|
|
205
|
+
let res = await actor.finishPublish(puiblishingId);
|
|
206
|
+
if (res.err) {
|
|
207
|
+
console.log(chalk.red('Error: ') + res.err);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
console.log(chalk.green('Published ') + `${config.package.name}@${config.package.version}`);
|
|
212
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import {install} from './install.js';
|
|
5
|
+
import {getLastVersion, readConfig} from '../mops.js';
|
|
6
|
+
|
|
7
|
+
function rootDir(cwd = process.cwd()) {
|
|
8
|
+
let configFile = path.join(cwd, 'mops.toml');
|
|
9
|
+
if (fs.existsSync(configFile)) {
|
|
10
|
+
return cwd;
|
|
11
|
+
}
|
|
12
|
+
if (!path.basename(cwd)) {
|
|
13
|
+
console.log(chalk.red('Error: ') + 'Cannot find mops.toml');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
return rootDir(path.join(cwd, '..'));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// TODO: resolve deps for a specific file to avoid conflicts
|
|
20
|
+
// TODO: remove base-unofficial
|
|
21
|
+
export async function sources({verbose} = {}) {
|
|
22
|
+
let root = rootDir();
|
|
23
|
+
if (!root) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let packages = {};
|
|
28
|
+
let versions = {};
|
|
29
|
+
|
|
30
|
+
let compareVersions = (a, b) => {
|
|
31
|
+
let ap = a.split('.').map(x => x |0);
|
|
32
|
+
let bp = b.split('.').map(x => x |0);
|
|
33
|
+
if (ap[0] - bp[0]) {
|
|
34
|
+
return Math.sign(ap[0] - bp[0]);
|
|
35
|
+
}
|
|
36
|
+
if (ap[0] === bp[0] && ap[1] - bp[1]) {
|
|
37
|
+
return Math.sign(ap[1] - bp[1]);
|
|
38
|
+
}
|
|
39
|
+
if (ap[0] === bp[0] && ap[1] === bp[1] && ap[2] - bp[2]) {
|
|
40
|
+
return Math.sign(ap[2] - bp[2]);
|
|
41
|
+
}
|
|
42
|
+
return 0;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
let collectDeps = (config, isRoot = false) => {
|
|
46
|
+
for (let [dep, ver] of Object.entries(config.dependencies || {})) {
|
|
47
|
+
// take root dep ver or bigger one
|
|
48
|
+
if (isRoot || !packages[dep] || compareVersions(packages[dep], ver) === -1) {
|
|
49
|
+
packages[dep] = ver;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let config = readConfig(path.join(root, `.mops/${dep}@${ver}/mops.toml`));
|
|
53
|
+
collectDeps(config);
|
|
54
|
+
|
|
55
|
+
if (!versions[dep]) {
|
|
56
|
+
versions[dep] = [];
|
|
57
|
+
}
|
|
58
|
+
versions[dep].push(ver);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
let config = readConfig(path.join(root, 'mops.toml'));
|
|
63
|
+
collectDeps(config, true);
|
|
64
|
+
|
|
65
|
+
// install base-unofficial
|
|
66
|
+
if (!packages['base-unofficial']) {
|
|
67
|
+
let dirs = fs.readdirSync(path.join(root, '.mops'));
|
|
68
|
+
let downloadedPackages = Object.fromEntries(dirs.map((dir) => {
|
|
69
|
+
return dir.split('@');
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
if (downloadedPackages['base-unofficial']) {
|
|
73
|
+
packages['base-unofficial'] = downloadedPackages['base-unofficial'];
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
let version = await getLastVersion('base-unofficial');
|
|
77
|
+
await install('base-unofficial', version, false, true);
|
|
78
|
+
packages['base-unofficial'] = version;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// show conflicts
|
|
83
|
+
if (verbose) {
|
|
84
|
+
for (let [dep, vers] of Object.entries(versions)) {
|
|
85
|
+
if (vers.length > 1) {
|
|
86
|
+
console.log(chalk.yellow('WARN:'), `Conflicting package versions "${dep}" - ${vers.join(', ')}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// sources
|
|
92
|
+
for (let [name, ver] of Object.entries(packages)) {
|
|
93
|
+
let pkgDir = path.relative(process.cwd(), path.join(root, `.mops/${name}@${ver}`));
|
|
94
|
+
console.log(`--package ${name} ${pkgDir}`);
|
|
95
|
+
|
|
96
|
+
// fallback base to base-unofficial
|
|
97
|
+
if (name == 'base-unofficial' && !packages.base) {
|
|
98
|
+
console.log(`--package base ${pkgDir}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import {checkConfigFile} from '../mops.js';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import del from 'del';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
|
|
7
|
+
export async function uninstall(pkg, version) {
|
|
8
|
+
if (!checkConfigFile()) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// TODO: check if deps relate on this package
|
|
13
|
+
let pkgDir = path.join(process.cwd(), '.mops', `${pkg}@${version}`);
|
|
14
|
+
|
|
15
|
+
if (!fs.existsSync(pkgDir)) {
|
|
16
|
+
console.log(`No cache to remove ${pkg} = '${version}'`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// don't remove if there are dependents
|
|
21
|
+
// let dependents = getDependents(pkg, version);
|
|
22
|
+
// if (dependents.length) {
|
|
23
|
+
// console.log(`Cache left ${pkg} = '${version}' (dependents: ${dependents})`)
|
|
24
|
+
// return;
|
|
25
|
+
// }
|
|
26
|
+
|
|
27
|
+
del.sync([`${pkgDir}/**`]);
|
|
28
|
+
|
|
29
|
+
console.log(chalk.green('Package removed ') + `${pkg} = '${version}'`);
|
|
30
|
+
|
|
31
|
+
// remove dependencies
|
|
32
|
+
// let text = fs.readFileSync(path.join(pkgDir, 'mops.toml')).toString();
|
|
33
|
+
// let config = TOML.parse(text);
|
|
34
|
+
|
|
35
|
+
// for (let [name, version] of Object.entries(config.dependencies)) {
|
|
36
|
+
// remove(name, version);
|
|
37
|
+
// }
|
|
38
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import {getIdentity} from '../mops.js';
|
|
4
|
+
|
|
5
|
+
export function whoami() {
|
|
6
|
+
let identityPem = new URL('../identity.pem', import.meta.url);
|
|
7
|
+
if (fs.existsSync(identityPem)) {
|
|
8
|
+
let identity = getIdentity();
|
|
9
|
+
console.log(identity.getPrincipal().toText());
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
console.log(chalk.red('Error: ') + 'identity not found. Run ' + chalk.greenBright('mops import-identity') + ' command.');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Actor, HttpAgent } from "@dfinity/agent";
|
|
2
|
+
|
|
3
|
+
// Imports and re-exports candid interface
|
|
4
|
+
import { idlFactory } from './main.did.js';
|
|
5
|
+
export { idlFactory } from './main.did.js';
|
|
6
|
+
// CANISTER_ID is replaced by webpack based on node environment
|
|
7
|
+
export const canisterId = process.env.MAIN_CANISTER_ID;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param {string | import("@dfinity/principal").Principal} canisterId Canister ID of Agent
|
|
12
|
+
* @param {{agentOptions?: import("@dfinity/agent").HttpAgentOptions; actorOptions?: import("@dfinity/agent").ActorConfig}} [options]
|
|
13
|
+
* @return {import("@dfinity/agent").ActorSubclass<import("./main.did.js")._SERVICE>}
|
|
14
|
+
*/
|
|
15
|
+
export const createActor = (canisterId, options) => {
|
|
16
|
+
const agent = new HttpAgent({ ...options?.agentOptions });
|
|
17
|
+
|
|
18
|
+
// Fetch root key for certificate validation during development
|
|
19
|
+
if(process.env.NODE_ENV !== "production") {
|
|
20
|
+
agent.fetchRootKey().catch(err=>{
|
|
21
|
+
console.warn("Unable to fetch root key. Check to ensure that your local replica is running");
|
|
22
|
+
console.error(err);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Creates an actor with using the candid interface and the HttpAgent
|
|
27
|
+
return Actor.createActor(idlFactory, {
|
|
28
|
+
agent,
|
|
29
|
+
canisterId,
|
|
30
|
+
...options?.actorOptions,
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A ready-to-use agent for the main canister
|
|
36
|
+
* @type {import("@dfinity/agent").ActorSubclass<import("./main.did.js")._SERVICE>}
|
|
37
|
+
*/
|
|
38
|
+
export const main = createActor(canisterId);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
type Version = text;
|
|
2
|
+
type Time = int;
|
|
3
|
+
type Text = text;
|
|
4
|
+
type Script =
|
|
5
|
+
record {
|
|
6
|
+
name: text;
|
|
7
|
+
value: text;
|
|
8
|
+
};
|
|
9
|
+
type Result_1 =
|
|
10
|
+
variant {
|
|
11
|
+
err: PublishingErr;
|
|
12
|
+
ok: PublishingId;
|
|
13
|
+
};
|
|
14
|
+
type Result =
|
|
15
|
+
variant {
|
|
16
|
+
err: Err;
|
|
17
|
+
ok;
|
|
18
|
+
};
|
|
19
|
+
type PublishingId = text;
|
|
20
|
+
type PublishingErr = text;
|
|
21
|
+
type Permission =
|
|
22
|
+
record {
|
|
23
|
+
access: Access;
|
|
24
|
+
user: principal;
|
|
25
|
+
};
|
|
26
|
+
type PackageSummary =
|
|
27
|
+
record {
|
|
28
|
+
description: text;
|
|
29
|
+
downloadsInLast30Days: nat;
|
|
30
|
+
downloadsTotal: nat;
|
|
31
|
+
keywords: vec text;
|
|
32
|
+
name: PackageName;
|
|
33
|
+
updatedAt: Time;
|
|
34
|
+
version: text;
|
|
35
|
+
};
|
|
36
|
+
type PackageName__1 = text;
|
|
37
|
+
type PackageName = text;
|
|
38
|
+
type PackageConfig =
|
|
39
|
+
record {
|
|
40
|
+
dependencies: vec Dependency;
|
|
41
|
+
description: text;
|
|
42
|
+
dfx: text;
|
|
43
|
+
documentation: text;
|
|
44
|
+
donation: text;
|
|
45
|
+
homepage: text;
|
|
46
|
+
isPrivate: bool;
|
|
47
|
+
keywords: vec text;
|
|
48
|
+
license: text;
|
|
49
|
+
moc: text;
|
|
50
|
+
name: PackageName;
|
|
51
|
+
owner: principal;
|
|
52
|
+
permissions: vec Permission;
|
|
53
|
+
readme: text;
|
|
54
|
+
repository: text;
|
|
55
|
+
scripts: vec Script;
|
|
56
|
+
version: text;
|
|
57
|
+
};
|
|
58
|
+
type FileId = text;
|
|
59
|
+
type File =
|
|
60
|
+
record {
|
|
61
|
+
content: blob;
|
|
62
|
+
id: FileId;
|
|
63
|
+
path: Text;
|
|
64
|
+
};
|
|
65
|
+
type Err = text;
|
|
66
|
+
type Dependency =
|
|
67
|
+
record {
|
|
68
|
+
name: PackageName;
|
|
69
|
+
version: text;
|
|
70
|
+
};
|
|
71
|
+
type Access =
|
|
72
|
+
variant {
|
|
73
|
+
readOnly;
|
|
74
|
+
readWrite;
|
|
75
|
+
};
|
|
76
|
+
service : {
|
|
77
|
+
finishPublish: (PublishingId) -> (Result);
|
|
78
|
+
getConfig: (PackageName__1, Version) -> (PackageConfig) query;
|
|
79
|
+
getFile: (FileId) -> (File) query;
|
|
80
|
+
getFileIds: (PackageName__1, Version) -> (vec FileId) query;
|
|
81
|
+
getLastConfig: (PackageName__1) -> (PackageConfig) query;
|
|
82
|
+
getLastVersion: (PackageName__1) -> (Version) query;
|
|
83
|
+
getReadmeFile: (PackageName__1, Version) -> (File) query;
|
|
84
|
+
notifyInstall: (PackageName__1, Version) -> () oneway;
|
|
85
|
+
search: (Text) -> (vec PackageSummary) query;
|
|
86
|
+
startPublish: (PackageConfig) -> (Result_1);
|
|
87
|
+
uploadFile: (PublishingId, Text, blob) -> (Result);
|
|
88
|
+
whoami: () -> (Text) query;
|
|
89
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Principal } from '@dfinity/principal';
|
|
2
|
+
import type { ActorMethod } from '@dfinity/agent';
|
|
3
|
+
|
|
4
|
+
export type Access = { 'readOnly' : null } |
|
|
5
|
+
{ 'readWrite' : null };
|
|
6
|
+
export interface Dependency { 'name' : PackageName, 'version' : string }
|
|
7
|
+
export type Err = string;
|
|
8
|
+
export interface File {
|
|
9
|
+
'id' : FileId,
|
|
10
|
+
'content' : Array<number>,
|
|
11
|
+
'path' : Text,
|
|
12
|
+
}
|
|
13
|
+
export type FileId = string;
|
|
14
|
+
export interface PackageConfig {
|
|
15
|
+
'dfx' : string,
|
|
16
|
+
'moc' : string,
|
|
17
|
+
'permissions' : Array<Permission>,
|
|
18
|
+
'scripts' : Array<Script>,
|
|
19
|
+
'owner' : Principal,
|
|
20
|
+
'documentation' : string,
|
|
21
|
+
'name' : PackageName,
|
|
22
|
+
'homepage' : string,
|
|
23
|
+
'description' : string,
|
|
24
|
+
'version' : string,
|
|
25
|
+
'keywords' : Array<string>,
|
|
26
|
+
'donation' : string,
|
|
27
|
+
'isPrivate' : boolean,
|
|
28
|
+
'repository' : string,
|
|
29
|
+
'dependencies' : Array<Dependency>,
|
|
30
|
+
'license' : string,
|
|
31
|
+
'readme' : string,
|
|
32
|
+
}
|
|
33
|
+
export type PackageName = string;
|
|
34
|
+
export type PackageName__1 = string;
|
|
35
|
+
export interface PackageSummary {
|
|
36
|
+
'name' : PackageName,
|
|
37
|
+
'downloadsTotal' : bigint,
|
|
38
|
+
'downloadsInLast30Days' : bigint,
|
|
39
|
+
'description' : string,
|
|
40
|
+
'version' : string,
|
|
41
|
+
'keywords' : Array<string>,
|
|
42
|
+
'updatedAt' : Time,
|
|
43
|
+
}
|
|
44
|
+
export interface Permission { 'access' : Access, 'user' : Principal }
|
|
45
|
+
export type PublishingErr = string;
|
|
46
|
+
export type PublishingId = string;
|
|
47
|
+
export type Result = { 'ok' : null } |
|
|
48
|
+
{ 'err' : Err };
|
|
49
|
+
export type Result_1 = { 'ok' : PublishingId } |
|
|
50
|
+
{ 'err' : PublishingErr };
|
|
51
|
+
export interface Script { 'value' : string, 'name' : string }
|
|
52
|
+
export type Text = string;
|
|
53
|
+
export type Time = bigint;
|
|
54
|
+
export type Version = string;
|
|
55
|
+
export interface _SERVICE {
|
|
56
|
+
'finishPublish' : ActorMethod<[PublishingId], Result>,
|
|
57
|
+
'getConfig' : ActorMethod<[PackageName__1, Version], PackageConfig>,
|
|
58
|
+
'getFile' : ActorMethod<[FileId], File>,
|
|
59
|
+
'getFileIds' : ActorMethod<[PackageName__1, Version], Array<FileId>>,
|
|
60
|
+
'getLastConfig' : ActorMethod<[PackageName__1], PackageConfig>,
|
|
61
|
+
'getLastVersion' : ActorMethod<[PackageName__1], Version>,
|
|
62
|
+
'getReadmeFile' : ActorMethod<[PackageName__1, Version], File>,
|
|
63
|
+
'notifyInstall' : ActorMethod<[PackageName__1, Version], undefined>,
|
|
64
|
+
'search' : ActorMethod<[Text], Array<PackageSummary>>,
|
|
65
|
+
'startPublish' : ActorMethod<[PackageConfig], Result_1>,
|
|
66
|
+
'uploadFile' : ActorMethod<[PublishingId, Text, Array<number>], Result>,
|
|
67
|
+
'whoami' : ActorMethod<[], Text>,
|
|
68
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export const idlFactory = ({ IDL }) => {
|
|
2
|
+
const PublishingId = IDL.Text;
|
|
3
|
+
const Err = IDL.Text;
|
|
4
|
+
const Result = IDL.Variant({ 'ok' : IDL.Null, 'err' : Err });
|
|
5
|
+
const PackageName__1 = IDL.Text;
|
|
6
|
+
const Version = IDL.Text;
|
|
7
|
+
const Access = IDL.Variant({ 'readOnly' : IDL.Null, 'readWrite' : IDL.Null });
|
|
8
|
+
const Permission = IDL.Record({ 'access' : Access, 'user' : IDL.Principal });
|
|
9
|
+
const Script = IDL.Record({ 'value' : IDL.Text, 'name' : IDL.Text });
|
|
10
|
+
const PackageName = IDL.Text;
|
|
11
|
+
const Dependency = IDL.Record({ 'name' : PackageName, 'version' : IDL.Text });
|
|
12
|
+
const PackageConfig = IDL.Record({
|
|
13
|
+
'dfx' : IDL.Text,
|
|
14
|
+
'moc' : IDL.Text,
|
|
15
|
+
'permissions' : IDL.Vec(Permission),
|
|
16
|
+
'scripts' : IDL.Vec(Script),
|
|
17
|
+
'owner' : IDL.Principal,
|
|
18
|
+
'documentation' : IDL.Text,
|
|
19
|
+
'name' : PackageName,
|
|
20
|
+
'homepage' : IDL.Text,
|
|
21
|
+
'description' : IDL.Text,
|
|
22
|
+
'version' : IDL.Text,
|
|
23
|
+
'keywords' : IDL.Vec(IDL.Text),
|
|
24
|
+
'donation' : IDL.Text,
|
|
25
|
+
'isPrivate' : IDL.Bool,
|
|
26
|
+
'repository' : IDL.Text,
|
|
27
|
+
'dependencies' : IDL.Vec(Dependency),
|
|
28
|
+
'license' : IDL.Text,
|
|
29
|
+
'readme' : IDL.Text,
|
|
30
|
+
});
|
|
31
|
+
const FileId = IDL.Text;
|
|
32
|
+
const Text = IDL.Text;
|
|
33
|
+
const File = IDL.Record({
|
|
34
|
+
'id' : FileId,
|
|
35
|
+
'content' : IDL.Vec(IDL.Nat8),
|
|
36
|
+
'path' : Text,
|
|
37
|
+
});
|
|
38
|
+
const Time = IDL.Int;
|
|
39
|
+
const PackageSummary = IDL.Record({
|
|
40
|
+
'name' : PackageName,
|
|
41
|
+
'downloadsTotal' : IDL.Nat,
|
|
42
|
+
'downloadsInLast30Days' : IDL.Nat,
|
|
43
|
+
'description' : IDL.Text,
|
|
44
|
+
'version' : IDL.Text,
|
|
45
|
+
'keywords' : IDL.Vec(IDL.Text),
|
|
46
|
+
'updatedAt' : Time,
|
|
47
|
+
});
|
|
48
|
+
const PublishingErr = IDL.Text;
|
|
49
|
+
const Result_1 = IDL.Variant({ 'ok' : PublishingId, 'err' : PublishingErr });
|
|
50
|
+
return IDL.Service({
|
|
51
|
+
'finishPublish' : IDL.Func([PublishingId], [Result], []),
|
|
52
|
+
'getConfig' : IDL.Func(
|
|
53
|
+
[PackageName__1, Version],
|
|
54
|
+
[PackageConfig],
|
|
55
|
+
['query'],
|
|
56
|
+
),
|
|
57
|
+
'getFile' : IDL.Func([FileId], [File], ['query']),
|
|
58
|
+
'getFileIds' : IDL.Func(
|
|
59
|
+
[PackageName__1, Version],
|
|
60
|
+
[IDL.Vec(FileId)],
|
|
61
|
+
['query'],
|
|
62
|
+
),
|
|
63
|
+
'getLastConfig' : IDL.Func([PackageName__1], [PackageConfig], ['query']),
|
|
64
|
+
'getLastVersion' : IDL.Func([PackageName__1], [Version], ['query']),
|
|
65
|
+
'getReadmeFile' : IDL.Func([PackageName__1, Version], [File], ['query']),
|
|
66
|
+
'notifyInstall' : IDL.Func([PackageName__1, Version], [], ['oneway']),
|
|
67
|
+
'search' : IDL.Func([Text], [IDL.Vec(PackageSummary)], ['query']),
|
|
68
|
+
'startPublish' : IDL.Func([PackageConfig], [Result_1], []),
|
|
69
|
+
'uploadFile' : IDL.Func(
|
|
70
|
+
[PublishingId, Text, IDL.Vec(IDL.Nat8)],
|
|
71
|
+
[Result],
|
|
72
|
+
[],
|
|
73
|
+
),
|
|
74
|
+
'whoami' : IDL.Func([], [Text], ['query']),
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
export const init = ({ IDL }) => { return []; };
|
package/mops.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {Actor, HttpAgent} from '@dfinity/agent';
|
|
2
|
+
import TOML from '@iarna/toml';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import fetch from 'node-fetch';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
|
|
8
|
+
import {idlFactory} from './declarations/main/main.did.js';
|
|
9
|
+
import {decodeFile} from './pem.js';
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
global.fetch = fetch;
|
|
13
|
+
|
|
14
|
+
let networkFile = new URL('./network.txt', import.meta.url);
|
|
15
|
+
|
|
16
|
+
export function setNetwork(network) {
|
|
17
|
+
fs.writeFileSync(networkFile, network);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getNetwork() {
|
|
21
|
+
let network = 'ic';
|
|
22
|
+
if (fs.existsSync(networkFile)) {
|
|
23
|
+
network = fs.readFileSync(networkFile).toString() || 'ic';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (network === 'local') {
|
|
27
|
+
let ids = JSON.parse(fs.readFileSync(new URL('../.dfx/local/canister_ids.json', import.meta.url)).toString());
|
|
28
|
+
return {
|
|
29
|
+
network,
|
|
30
|
+
host: 'http://127.0.0.1:8000',
|
|
31
|
+
canisterId: ids.main.local,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
else if (network === 'ic') {
|
|
35
|
+
return {
|
|
36
|
+
network,
|
|
37
|
+
host: 'https://mainnet.dfinity.network',
|
|
38
|
+
canisterId: 'oknww-riaaa-aaaam-qaf6a-cai',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export let getIdentity = () => {
|
|
44
|
+
let identityPem = new URL('./identity.pem', import.meta.url);
|
|
45
|
+
if (fs.existsSync(identityPem)) {
|
|
46
|
+
return decodeFile(identityPem);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export let mainActor = async () => {
|
|
51
|
+
let network = getNetwork().network;
|
|
52
|
+
let host = getNetwork().host;
|
|
53
|
+
let canisterId = getNetwork().canisterId;
|
|
54
|
+
|
|
55
|
+
let identity = getIdentity();
|
|
56
|
+
let agent = new HttpAgent({host, identity});
|
|
57
|
+
|
|
58
|
+
if (network === 'local') {
|
|
59
|
+
await agent.fetchRootKey();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return Actor.createActor(idlFactory, {
|
|
63
|
+
agent,
|
|
64
|
+
canisterId,
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export function checkConfigFile() {
|
|
69
|
+
let configFile = path.join(process.cwd(), 'mops.toml');
|
|
70
|
+
if (!fs.existsSync(configFile)) {
|
|
71
|
+
console.log(chalk.red('Error: ') + `Config file not found ${configFile}`);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function progressBar(step, total) {
|
|
78
|
+
let done = Math.round(step / total * 10);
|
|
79
|
+
return `[${':'.repeat(done)}${' '.repeat(10 - done)}]`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function getLastVersion(pkgName) {
|
|
83
|
+
let actor = await mainActor();
|
|
84
|
+
return actor.getLastVersion(pkgName);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function readConfig(configFile = path.join(process.cwd(), 'mops.toml')) {
|
|
88
|
+
let text = fs.readFileSync(configFile).toString();
|
|
89
|
+
return TOML.parse(text);
|
|
90
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ic-mops",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"mops": "cli.js"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@dfinity/agent": "^0.11.0",
|
|
10
|
+
"@dfinity/candid": "^0.11.0",
|
|
11
|
+
"@dfinity/identity": "^0.11.0",
|
|
12
|
+
"@dfinity/principal": "^0.11.1",
|
|
13
|
+
"@iarna/toml": "^2.2.5",
|
|
14
|
+
"chalk": "^4.1.2",
|
|
15
|
+
"commander": "^9.2.0",
|
|
16
|
+
"del": "^6.0.0",
|
|
17
|
+
"eslint": "^8.15.0",
|
|
18
|
+
"globby": "^13.1.1",
|
|
19
|
+
"log-update": "^5.0.1",
|
|
20
|
+
"minimatch": "^5.0.1",
|
|
21
|
+
"node-fetch": "^2.6.7",
|
|
22
|
+
"pem-file": "^1.0.1",
|
|
23
|
+
"prompts": "^2.4.2"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/parallel.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export async function parallel(threads, items, fn) {
|
|
2
|
+
return new Promise((resolve) => {
|
|
3
|
+
let busyThreads = 0;
|
|
4
|
+
items = items.slice();
|
|
5
|
+
|
|
6
|
+
let loop = () => {
|
|
7
|
+
if (!items.length) {
|
|
8
|
+
if (busyThreads === 0) {
|
|
9
|
+
resolve();
|
|
10
|
+
}
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (busyThreads >= threads) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
busyThreads++;
|
|
17
|
+
fn(items.shift()).then(() => {
|
|
18
|
+
busyThreads--;
|
|
19
|
+
loop();
|
|
20
|
+
});
|
|
21
|
+
loop();
|
|
22
|
+
};
|
|
23
|
+
loop();
|
|
24
|
+
});
|
|
25
|
+
}
|
package/pem.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import {Ed25519KeyIdentity} from '@dfinity/identity';
|
|
3
|
+
import pemfile from 'pem-file';
|
|
4
|
+
|
|
5
|
+
export function decodeFile(file) {
|
|
6
|
+
const rawKey = fs.readFileSync(file).toString();
|
|
7
|
+
return decode(rawKey);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function decode(rawKey) {
|
|
11
|
+
var buf = pemfile.decode(rawKey);
|
|
12
|
+
if (buf.length != 85) {
|
|
13
|
+
throw 'expecting byte length 85 but got ' + buf.length;
|
|
14
|
+
}
|
|
15
|
+
let secretKey = Buffer.concat([buf.slice(16, 48), buf.slice(53, 85)]);
|
|
16
|
+
return Ed25519KeyIdentity.fromSecretKey(secretKey);
|
|
17
|
+
}
|