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 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
@@ -0,0 +1,16 @@
1
+ # MOPS
2
+ CLI tool for [MOPS](http://mops.one)
3
+
4
+ ## Usage
5
+
6
+ **Install cli**
7
+ ```
8
+ npm i -g ic-mops
9
+ ```
10
+
11
+ **Install specific Motoko package**
12
+ ```
13
+ mops i <package_name>
14
+ ```
15
+
16
+ For more docs visit http://mops.one
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
+ // }
@@ -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
+ }