@learncard/cli 3.3.177 → 3.4.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/CHANGELOG.md +46 -0
- package/README.md +39 -1
- package/dist/index.js +134 -32
- package/package.json +16 -13
- package/project.json +9 -1
- package/src/index.tsx +113 -27
- package/src/replHelpers.test.ts +80 -0
- package/src/replHelpers.ts +43 -0
- package/vitest.config.ts +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# @learncard/cli
|
|
2
2
|
|
|
3
|
+
## 3.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`1706490abb9a8c1b099882c84d144ccabf92ffe2`](https://github.com/learningeconomy/LearnCard/commit/1706490abb9a8c1b099882c84d144ccabf92ffe2), [`1706490abb9a8c1b099882c84d144ccabf92ffe2`](https://github.com/learningeconomy/LearnCard/commit/1706490abb9a8c1b099882c84d144ccabf92ffe2)]:
|
|
8
|
+
- @learncard/init@2.3.21
|
|
9
|
+
- @learncard/didkit-plugin@1.9.1
|
|
10
|
+
- @learncard/learn-cloud-plugin@2.3.26
|
|
11
|
+
- @learncard/ler-rs-plugin@0.1.12
|
|
12
|
+
- @learncard/linked-claims-plugin@0.2.21
|
|
13
|
+
- @learncard/open-badge-v2-plugin@1.1.22
|
|
14
|
+
- @learncard/types@5.17.1
|
|
15
|
+
- @learncard/holder-continuity@0.2.1
|
|
16
|
+
- @learncard/core@9.4.21
|
|
17
|
+
- @learncard/render-method-plugin@3.0.1
|
|
18
|
+
- @learncard/simple-signing-plugin@1.1.25
|
|
19
|
+
|
|
20
|
+
## 3.4.0
|
|
21
|
+
|
|
22
|
+
### Minor Changes
|
|
23
|
+
|
|
24
|
+
- [#1269](https://github.com/learningeconomy/LearnCard/pull/1269) [`406f5f64ff49aaecbf8cb499a7f6b294c7105cc3`](https://github.com/learningeconomy/LearnCard/commit/406f5f64ff49aaecbf8cb499a7f6b294c7105cc3) Thanks [@TaylorBeeston](https://github.com/TaylorBeeston)! - feat: [LC-1798] Holder continuity export, restore, and metadata
|
|
25
|
+
|
|
26
|
+
Adds a new `@learncard/holder-continuity` package for creating encrypted holder continuity bundles, reading them back, importing credentials into a fresh wallet, and restoring the original wallet directly from the exported private-key seed.
|
|
27
|
+
|
|
28
|
+
Updates `@learncard/cli` to consume the new package and expose REPL helpers for export, import, and restore.
|
|
29
|
+
|
|
30
|
+
Adds holder export metadata types, an authenticated brain-service route, and a network plugin method for exporting consent records and transaction history without exposing credential payloads or key material from the service.
|
|
31
|
+
|
|
32
|
+
Adds bounded status-list fetching, optional verify-before-import support, bundle size guards, and capped holder metadata pagination.
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- Updated dependencies [[`7e90089f517908562becf72eb3831e9208232278`](https://github.com/learningeconomy/LearnCard/commit/7e90089f517908562becf72eb3831e9208232278), [`406f5f64ff49aaecbf8cb499a7f6b294c7105cc3`](https://github.com/learningeconomy/LearnCard/commit/406f5f64ff49aaecbf8cb499a7f6b294c7105cc3), [`7c5fea147f7c9876dd8d7cbe2ece082eb0e5a42b`](https://github.com/learningeconomy/LearnCard/commit/7c5fea147f7c9876dd8d7cbe2ece082eb0e5a42b)]:
|
|
37
|
+
- @learncard/types@5.17.0
|
|
38
|
+
- @learncard/holder-continuity@0.2.0
|
|
39
|
+
- @learncard/didkit-plugin@1.9.0
|
|
40
|
+
- @learncard/core@9.4.20
|
|
41
|
+
- @learncard/init@2.3.20
|
|
42
|
+
- @learncard/render-method-plugin@3.0.0
|
|
43
|
+
- @learncard/learn-cloud-plugin@2.3.25
|
|
44
|
+
- @learncard/ler-rs-plugin@0.1.11
|
|
45
|
+
- @learncard/linked-claims-plugin@0.2.20
|
|
46
|
+
- @learncard/open-badge-v2-plugin@1.1.21
|
|
47
|
+
- @learncard/simple-signing-plugin@1.1.24
|
|
48
|
+
|
|
3
49
|
## 3.3.177
|
|
4
50
|
|
|
5
51
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ you all the tools you need to easily play around with the Learn Card SDK!
|
|
|
12
12
|

|
|
13
13
|
|
|
14
14
|
## Documentation
|
|
15
|
+
|
|
15
16
|
All LearnCard documentation can be found at:
|
|
16
17
|
https://docs.learncard.com
|
|
17
18
|
|
|
@@ -24,7 +25,45 @@ npx @learncard/cli
|
|
|
24
25
|
npx @learncard/cli 1b498556081a298261313657c32d5d0a9ce8285dc4d659e6787392207e4a7ac2
|
|
25
26
|
```
|
|
26
27
|
|
|
28
|
+
## Holder continuity export
|
|
29
|
+
|
|
30
|
+
The CLI exposes REPL helpers from `@learncard/holder-continuity` for holder-controlled export, restore, and self-import:
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
const password = await getLearnCardBundlePassword();
|
|
34
|
+
|
|
35
|
+
await exportLearnCardBundle(learnCard, {
|
|
36
|
+
out: './learncard-export.zip',
|
|
37
|
+
password,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const freshWallet = await initLearnCard({ seed: '0'.repeat(64), network: true });
|
|
41
|
+
await importLearnCardBundle('./learncard-export.zip', {
|
|
42
|
+
password,
|
|
43
|
+
wallet: freshWallet,
|
|
44
|
+
verifyBeforeImport: true,
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
const restoredWallet = await restoreLearnCardFromBundle('./learncard-export.zip', { password });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`getLearnCardBundlePassword()` prompts without echoing the password into the REPL, which avoids saving it in REPL history. You can still pass a password string directly for local scripts.
|
|
53
|
+
|
|
54
|
+
`restoreLearnCardFromBundle(...)` decrypts the exported seed and returns a wallet with the original DID. It does not upload bundle payloads or recreate index records; use `importLearnCardBundle(...)` when copying credentials into another wallet.
|
|
55
|
+
|
|
56
|
+
If you omit the first argument, the CLI exports the default `learnCard` wallet it created at startup:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
const password = await getLearnCardBundlePassword();
|
|
60
|
+
await exportLearnCardBundle({ out: './learncard-export.zip', password });
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
See `@learncard/holder-continuity` `BUNDLE_SPEC.md` for the ZIP layout and manifest hashing rules.
|
|
64
|
+
|
|
27
65
|
## Contributing
|
|
66
|
+
|
|
28
67
|
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
|
|
29
68
|
|
|
30
69
|
Please make sure to update tests as appropriate.
|
|
@@ -33,7 +72,6 @@ Please make sure to update tests as appropriate.
|
|
|
33
72
|
|
|
34
73
|
**[Learning Economy Foundation (LEF)](https://www.learningeconomy.io)** is a 501(c)(3) non-profit organization leveraging global standards and web3 protocols to bring quality skills and equal opportunity to every human on earth, and address the persistent inequities that exist around the globe in education and employment. We help you build the future of education and work with:
|
|
35
74
|
|
|
36
|
-
|
|
37
75
|
## License
|
|
38
76
|
|
|
39
77
|
MIT © [Learning Economy Foundation](https://github.com/Learning-Economy-Foundation)
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
var fs = require('fs/promises');
|
|
5
5
|
var dns = require('node:dns');
|
|
6
|
+
var promises = require('node:readline/promises');
|
|
7
|
+
var node_stream = require('node:stream');
|
|
6
8
|
var repl = require('pretty-repl');
|
|
7
9
|
var core = require('@learncard/core');
|
|
8
10
|
var init = require('@learncard/init');
|
|
@@ -17,6 +19,7 @@ var clipboard = require('clipboardy');
|
|
|
17
19
|
var lerRsPlugin = require('@learncard/ler-rs-plugin');
|
|
18
20
|
var renderMethodPlugin = require('@learncard/render-method-plugin');
|
|
19
21
|
var crypto = require('crypto');
|
|
22
|
+
var holderContinuity = require('@learncard/holder-continuity');
|
|
20
23
|
|
|
21
24
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
22
25
|
|
|
@@ -31,14 +34,49 @@ var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
|
|
|
31
34
|
|
|
32
35
|
const generateRandomSeed = () => crypto__default["default"].randomBytes(32).toString("hex");
|
|
33
36
|
|
|
37
|
+
var __defProp = Object.defineProperty;
|
|
38
|
+
var __defProps = Object.defineProperties;
|
|
39
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
40
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
41
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
42
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
43
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
44
|
+
var __spreadValues = (a, b) => {
|
|
45
|
+
for (var prop in b || (b = {}))
|
|
46
|
+
if (__hasOwnProp.call(b, prop))
|
|
47
|
+
__defNormalProp(a, prop, b[prop]);
|
|
48
|
+
if (__getOwnPropSymbols)
|
|
49
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
50
|
+
if (__propIsEnum.call(b, prop))
|
|
51
|
+
__defNormalProp(a, prop, b[prop]);
|
|
52
|
+
}
|
|
53
|
+
return a;
|
|
54
|
+
};
|
|
55
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
56
|
+
const createExportLearnCardBundleHelper = (exportBundle, defaultWallet) => {
|
|
57
|
+
return (walletOrOptions, maybeOptions) => {
|
|
58
|
+
if (maybeOptions) return exportBundle(walletOrOptions, maybeOptions);
|
|
59
|
+
return exportBundle(defaultWallet, walletOrOptions);
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
const createRestoreLearnCardFromBundleHelper = (restoreBundle, defaultInit) => {
|
|
63
|
+
return (path, options = {}) => {
|
|
64
|
+
var _a;
|
|
65
|
+
return restoreBundle(path, __spreadProps(__spreadValues({}, options), {
|
|
66
|
+
init: __spreadValues(__spreadValues({}, defaultInit), (_a = options.init) != null ? _a : {})
|
|
67
|
+
}));
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
34
71
|
var name = "@learncard/cli";
|
|
35
|
-
var version = "3.
|
|
72
|
+
var version = "3.4.1";
|
|
36
73
|
var description = "Command Line Interface for LearnCard";
|
|
37
74
|
var main = "dist/index.js";
|
|
38
75
|
var bin = "dist/index.js";
|
|
39
76
|
var scripts = {
|
|
40
77
|
start: "rollup -c && node --enable-source-maps dist/index.js",
|
|
41
|
-
build: "rollup -c"
|
|
78
|
+
build: "rollup -c",
|
|
79
|
+
test: "vitest run"
|
|
42
80
|
};
|
|
43
81
|
var author = "Learning Economy Foundation (www.learningeconomy.io)";
|
|
44
82
|
var license = "MIT";
|
|
@@ -49,9 +87,10 @@ var dependencies = {
|
|
|
49
87
|
"@learncard/learn-cloud-plugin": "workspace:*",
|
|
50
88
|
"@learncard/ler-rs-plugin": "workspace:*",
|
|
51
89
|
"@learncard/linked-claims-plugin": "workspace:*",
|
|
52
|
-
"@learncard/render-method-plugin": "workspace:*",
|
|
53
90
|
"@learncard/open-badge-v2-plugin": "workspace:*",
|
|
91
|
+
"@learncard/render-method-plugin": "workspace:*",
|
|
54
92
|
"@learncard/simple-signing-plugin": "workspace:*",
|
|
93
|
+
"@learncard/holder-continuity": "workspace:*",
|
|
55
94
|
"@learncard/types": "workspace:*",
|
|
56
95
|
"@rollup/plugin-json": "^4.1.0",
|
|
57
96
|
clipboardy: "^4.0.0",
|
|
@@ -67,7 +106,8 @@ var devDependencies = {
|
|
|
67
106
|
"@types/figlet": "^1.5.4",
|
|
68
107
|
"@types/node": "^18.0.0",
|
|
69
108
|
nodemon: "^2.0.16",
|
|
70
|
-
"ts-node": "^10.8.1"
|
|
109
|
+
"ts-node": "^10.8.1",
|
|
110
|
+
vitest: "^1.6.0"
|
|
71
111
|
};
|
|
72
112
|
var repository = {
|
|
73
113
|
type: "git",
|
|
@@ -102,7 +142,13 @@ const g = {
|
|
|
102
142
|
seed: gradient__default["default"](["cyan", "green"])("seed"),
|
|
103
143
|
generateRandomSeed: gradient__default["default"](["cyan", "green"])("generateRandomSeed"),
|
|
104
144
|
types: gradient__default["default"](["cyan", "green"])("types"),
|
|
105
|
-
|
|
145
|
+
getLearnCardBundlePassword: gradient__default["default"](["cyan", "green"])("getLearnCardBundlePassword"),
|
|
146
|
+
copy: gradient__default["default"](["cyan", "green"])("copy"),
|
|
147
|
+
exportLearnCardBundle: gradient__default["default"](["cyan", "green"])("exportLearnCardBundle"),
|
|
148
|
+
importLearnCardBundle: gradient__default["default"](["cyan", "green"])("importLearnCardBundle"),
|
|
149
|
+
createLearnCardBundle: gradient__default["default"](["cyan", "green"])("createLearnCardBundle"),
|
|
150
|
+
readLearnCardBundle: gradient__default["default"](["cyan", "green"])("readLearnCardBundle"),
|
|
151
|
+
restoreLearnCardFromBundle: gradient__default["default"](["cyan", "green"])("restoreLearnCardFromBundle")
|
|
106
152
|
};
|
|
107
153
|
const copyFunction = (text) => {
|
|
108
154
|
if (typeof text === "object") {
|
|
@@ -115,7 +161,25 @@ const copyFunction = (text) => {
|
|
|
115
161
|
clipboard__default["default"].writeSync(text);
|
|
116
162
|
console.log("Copied to clipboard!");
|
|
117
163
|
} catch (error) {
|
|
118
|
-
console.error(
|
|
164
|
+
console.error(
|
|
165
|
+
"Failed to copy to clipboard:",
|
|
166
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const getLearnCardBundlePassword = async (prompt = "Bundle password: ") => {
|
|
171
|
+
process.stdout.write(prompt);
|
|
172
|
+
const mutedOutput = new node_stream.Writable({
|
|
173
|
+
write(_chunk, _encoding, callback) {
|
|
174
|
+
callback();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
const rl = promises.createInterface({ input: process.stdin, output: mutedOutput, terminal: true });
|
|
178
|
+
try {
|
|
179
|
+
return await rl.question("");
|
|
180
|
+
} finally {
|
|
181
|
+
rl.close();
|
|
182
|
+
process.stdout.write("\n");
|
|
119
183
|
}
|
|
120
184
|
};
|
|
121
185
|
commander.program.version(packageJson.version).argument("[seed]").action(async (_seed = generateRandomSeed()) => {
|
|
@@ -132,13 +196,14 @@ commander.program.version(packageJson.version).argument("[seed]").action(async (
|
|
|
132
196
|
globalThis.emptyLearnCard = init.emptyLearnCard;
|
|
133
197
|
globalThis.learnCardFromSeed = init.learnCardFromSeed;
|
|
134
198
|
globalThis.initLearnCard = init.initLearnCard;
|
|
199
|
+
const didkit = fs__default["default"].readFile(
|
|
200
|
+
require.resolve("@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm")
|
|
201
|
+
);
|
|
135
202
|
const _learnCard = await init.initLearnCard({
|
|
136
203
|
seed,
|
|
137
204
|
network: true,
|
|
138
205
|
allowRemoteContexts: true,
|
|
139
|
-
didkit
|
|
140
|
-
require.resolve("@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm")
|
|
141
|
-
)
|
|
206
|
+
didkit
|
|
142
207
|
});
|
|
143
208
|
const simpleSigningLc = await _learnCard.addPlugin(
|
|
144
209
|
await simpleSigningPlugin.getSimpleSigningPlugin(_learnCard, "https://api.learncard.app/trpc")
|
|
@@ -156,53 +221,90 @@ commander.program.version(packageJson.version).argument("[seed]").action(async (
|
|
|
156
221
|
globalThis.types = types__default["default"];
|
|
157
222
|
globalThis.getTestCache = core.getTestCache;
|
|
158
223
|
globalThis.copy = copyFunction;
|
|
224
|
+
globalThis.getLearnCardBundlePassword = getLearnCardBundlePassword;
|
|
225
|
+
globalThis.exportLearnCardBundle = createExportLearnCardBundleHelper(
|
|
226
|
+
holderContinuity.exportLearnCardBundle,
|
|
227
|
+
globalThis.learnCard
|
|
228
|
+
);
|
|
229
|
+
globalThis.restoreLearnCardFromBundle = createRestoreLearnCardFromBundleHelper(
|
|
230
|
+
holderContinuity.restoreLearnCardFromBundle,
|
|
231
|
+
{
|
|
232
|
+
network: true,
|
|
233
|
+
allowRemoteContexts: true,
|
|
234
|
+
didkit
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
globalThis.importLearnCardBundle = holderContinuity.importLearnCardBundle;
|
|
238
|
+
globalThis.createLearnCardBundle = holderContinuity.createLearnCardBundle;
|
|
239
|
+
globalThis.readLearnCardBundle = holderContinuity.readLearnCardBundle;
|
|
159
240
|
(_b = (_a = process.stdout).moveCursor) == null ? void 0 : _b.call(_a, 0, -1);
|
|
160
241
|
(_d = (_c = process.stdout).clearLine) == null ? void 0 : _d.call(_c, 1);
|
|
161
242
|
console.log("Wallet created!\n");
|
|
162
|
-
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
163
|
-
console.log("\u2502
|
|
164
|
-
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
165
|
-
console.log("\u2502 Variable
|
|
166
|
-
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
167
|
-
console.log(`\u2502
|
|
168
|
-
console.log(`\u2502
|
|
169
|
-
console.log(`\u2502
|
|
170
|
-
console.log(`\u2502
|
|
171
|
-
console.log(`\u2502
|
|
172
|
-
console.log(`\u2502
|
|
173
|
-
console.log(
|
|
243
|
+
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
244
|
+
console.log("\u2502 Variables Available \u2502");
|
|
245
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
246
|
+
console.log("\u2502 Variable \u2502 Description \u2502");
|
|
247
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
248
|
+
console.log(`\u2502 ${g.learnCard} \u2502 Learn Card Wallet \u2502`);
|
|
249
|
+
console.log(`\u2502 ${g.initLearnCard} \u2502 Wallet Instantiation Function \u2502`);
|
|
250
|
+
console.log(`\u2502 ${g.seed} \u2502 Seed used to generate wallet \u2502`);
|
|
251
|
+
console.log(`\u2502 ${g.generateRandomSeed} \u2502 Generates a random seed \u2502`);
|
|
252
|
+
console.log(`\u2502 ${g.types} \u2502 Helpful zod validators \u2502`);
|
|
253
|
+
console.log(`\u2502 ${g.copy} \u2502 Copy text to clipboard \u2502`);
|
|
254
|
+
console.log(`\u2502 ${g.getLearnCardBundlePassword} \u2502 Prompt for bundle password \u2502`);
|
|
255
|
+
console.log(`\u2502 ${g.exportLearnCardBundle} \u2502 Export wallet continuity ZIP \u2502`);
|
|
256
|
+
console.log(`\u2502 ${g.importLearnCardBundle} \u2502 Import continuity ZIP \u2502`);
|
|
257
|
+
console.log(`\u2502 ${g.restoreLearnCardFromBundle} \u2502 Restore original wallet from ZIP \u2502`);
|
|
258
|
+
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
174
259
|
console.log("");
|
|
175
260
|
console.log(
|
|
176
261
|
"For help/documentation regarding your wallet, please read the documentation at\n"
|
|
177
262
|
);
|
|
178
263
|
console.log("https://docs.learncard.com/sdks/learncard-core/construction\n");
|
|
179
264
|
console.log("To get a feel for what's possible, try some of the following commands\n");
|
|
180
|
-
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
181
|
-
console.log("\u2502 Description \u2502 Command \u2502");
|
|
182
|
-
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
183
265
|
console.log(
|
|
184
|
-
|
|
266
|
+
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"
|
|
267
|
+
);
|
|
268
|
+
console.log(
|
|
269
|
+
"\u2502 Description \u2502 Command \u2502"
|
|
270
|
+
);
|
|
271
|
+
console.log(
|
|
272
|
+
"\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"
|
|
273
|
+
);
|
|
274
|
+
console.log(
|
|
275
|
+
`\u2502 View your did \u2502 ${g.learnCard}.id.did(); \u2502`
|
|
276
|
+
);
|
|
277
|
+
console.log(
|
|
278
|
+
`\u2502 Generate an unsigned VC \u2502 ${g.learnCard}.invoke.getTestVc(); \u2502`
|
|
279
|
+
);
|
|
280
|
+
console.log(
|
|
281
|
+
`\u2502 Issue a signed VC \u2502 await ${g.learnCard}.invoke.issueCredential(uvc); \u2502`
|
|
282
|
+
);
|
|
283
|
+
console.log(
|
|
284
|
+
`\u2502 Verify a signed VC \u2502 await ${g.learnCard}.invoke.verifyCredential(vc); \u2502`
|
|
285
|
+
);
|
|
286
|
+
console.log(
|
|
287
|
+
`\u2502 Issue a signed VP \u2502 await ${g.learnCard}.invoke.issuePresentation(vc); \u2502`
|
|
185
288
|
);
|
|
186
289
|
console.log(
|
|
187
|
-
`\u2502
|
|
290
|
+
`\u2502 Verify a signed VP \u2502 await ${g.learnCard}.invoke.verifyPresentation(vp); \u2502`
|
|
188
291
|
);
|
|
189
292
|
console.log(
|
|
190
|
-
`\u2502
|
|
293
|
+
`\u2502 Prompt bundle password \u2502 const password = await ${g.getLearnCardBundlePassword}(); \u2502`
|
|
191
294
|
);
|
|
192
295
|
console.log(
|
|
193
|
-
`\u2502
|
|
296
|
+
`\u2502 Export wallet ZIP \u2502 await ${g.exportLearnCardBundle}(${g.learnCard}, { out: './export.zip', password }); \u2502`
|
|
194
297
|
);
|
|
195
298
|
console.log(
|
|
196
|
-
`\u2502
|
|
299
|
+
`\u2502 Restore original wallet \u2502 await ${g.restoreLearnCardFromBundle}('./export.zip', { password }); \u2502`
|
|
197
300
|
);
|
|
198
301
|
console.log(
|
|
199
|
-
|
|
302
|
+
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"
|
|
200
303
|
);
|
|
201
|
-
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
202
304
|
console.log("");
|
|
203
305
|
repl__default["default"].start({
|
|
204
306
|
colorize: (input) => {
|
|
205
|
-
return input.replace("emptyLearnCard", g.emptyLearnCard).replace("learnCardFromKey", g.learnCardFromKey).replace("initLearnCard", g.initLearnCard).replace("learnCard", g.learnCard).replace("seed", g.seed).replace("generateRandomSeed", g.generateRandomSeed).replace("copy", g.copy);
|
|
307
|
+
return input.replace("emptyLearnCard", g.emptyLearnCard).replace("learnCardFromKey", g.learnCardFromKey).replace("initLearnCard", g.initLearnCard).replace("learnCard", g.learnCard).replace("seed", g.seed).replace("generateRandomSeed", g.generateRandomSeed).replace("copy", g.copy).replace("getLearnCardBundlePassword", g.getLearnCardBundlePassword).replace("exportLearnCardBundle", g.exportLearnCardBundle).replace("importLearnCardBundle", g.importLearnCardBundle).replace("createLearnCardBundle", g.createLearnCardBundle).replace("readLearnCardBundle", g.readLearnCardBundle).replace("restoreLearnCardFromBundle", g.restoreLearnCardFromBundle);
|
|
206
308
|
}
|
|
207
309
|
});
|
|
208
310
|
}).parse(process.argv);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@learncard/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.1",
|
|
4
4
|
"description": "Command Line Interface for LearnCard",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": "dist/index.js",
|
|
@@ -15,23 +15,25 @@
|
|
|
15
15
|
"pretty-repl": "^3.1.1",
|
|
16
16
|
"rollup": "^2.80.0",
|
|
17
17
|
"rollup-plugin-esbuild": "^4.9.1",
|
|
18
|
-
"@learncard/core": "9.4.
|
|
19
|
-
"@learncard/
|
|
20
|
-
"@learncard/
|
|
21
|
-
"@learncard/
|
|
22
|
-
"@learncard/
|
|
23
|
-
"@learncard/ler-rs-plugin": "0.1.
|
|
24
|
-
"@learncard/
|
|
25
|
-
"@learncard/
|
|
26
|
-
"@learncard/simple-signing-plugin": "1.1.
|
|
27
|
-
"@learncard/types": "5.
|
|
18
|
+
"@learncard/core": "9.4.21",
|
|
19
|
+
"@learncard/learn-cloud-plugin": "2.3.26",
|
|
20
|
+
"@learncard/didkit-plugin": "^1.9.1",
|
|
21
|
+
"@learncard/linked-claims-plugin": "0.2.21",
|
|
22
|
+
"@learncard/open-badge-v2-plugin": "1.1.22",
|
|
23
|
+
"@learncard/ler-rs-plugin": "0.1.12",
|
|
24
|
+
"@learncard/init": "^2.3.21",
|
|
25
|
+
"@learncard/render-method-plugin": "3.0.1",
|
|
26
|
+
"@learncard/simple-signing-plugin": "1.1.25",
|
|
27
|
+
"@learncard/types": "5.17.1",
|
|
28
|
+
"@learncard/holder-continuity": "0.2.1"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@types/cors": "^2.8.12",
|
|
31
32
|
"@types/figlet": "^1.5.4",
|
|
32
33
|
"@types/node": "^18.0.0",
|
|
33
34
|
"nodemon": "^2.0.16",
|
|
34
|
-
"ts-node": "^10.8.1"
|
|
35
|
+
"ts-node": "^10.8.1",
|
|
36
|
+
"vitest": "^1.6.0"
|
|
35
37
|
},
|
|
36
38
|
"repository": {
|
|
37
39
|
"type": "git",
|
|
@@ -43,6 +45,7 @@
|
|
|
43
45
|
},
|
|
44
46
|
"scripts": {
|
|
45
47
|
"start": "rollup -c && node --enable-source-maps dist/index.js",
|
|
46
|
-
"build": "rollup -c"
|
|
48
|
+
"build": "rollup -c",
|
|
49
|
+
"test": "vitest run"
|
|
47
50
|
}
|
|
48
51
|
}
|
package/project.json
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"nx-run-command",
|
|
10
10
|
"types",
|
|
11
11
|
"init",
|
|
12
|
-
"open-badge-v2-plugin"
|
|
12
|
+
"open-badge-v2-plugin",
|
|
13
|
+
"holder-continuity"
|
|
13
14
|
],
|
|
14
15
|
"namedInputs": {
|
|
15
16
|
"source": ["{projectRoot}/src/**/*"],
|
|
@@ -23,6 +24,13 @@
|
|
|
23
24
|
"script": "build"
|
|
24
25
|
}
|
|
25
26
|
},
|
|
27
|
+
"test": {
|
|
28
|
+
"executor": "nx:run-script",
|
|
29
|
+
"inputs": ["source"],
|
|
30
|
+
"options": {
|
|
31
|
+
"script": "test"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
26
34
|
"start": {
|
|
27
35
|
"executor": "./tools/executors/workspace:run-command",
|
|
28
36
|
"dependsOn": ["^build"],
|
package/src/index.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import dns from 'node:dns';
|
|
3
|
+
import { createInterface } from 'node:readline/promises';
|
|
4
|
+
import { Writable } from 'node:stream';
|
|
3
5
|
|
|
4
6
|
import repl from 'pretty-repl';
|
|
5
7
|
import { getTestCache } from '@learncard/core';
|
|
@@ -17,6 +19,17 @@ import { getLerRsPlugin } from '@learncard/ler-rs-plugin';
|
|
|
17
19
|
import { getRenderMethodPlugin } from '@learncard/render-method-plugin';
|
|
18
20
|
|
|
19
21
|
import { generateRandomSeed } from './random';
|
|
22
|
+
import {
|
|
23
|
+
createLearnCardBundle,
|
|
24
|
+
exportLearnCardBundle as writeLearnCardBundle,
|
|
25
|
+
importLearnCardBundle,
|
|
26
|
+
readLearnCardBundle,
|
|
27
|
+
restoreLearnCardFromBundle as restoreBundle,
|
|
28
|
+
} from '@learncard/holder-continuity';
|
|
29
|
+
import {
|
|
30
|
+
createExportLearnCardBundleHelper,
|
|
31
|
+
createRestoreLearnCardFromBundleHelper,
|
|
32
|
+
} from './replHelpers';
|
|
20
33
|
|
|
21
34
|
import packageJson from '../package.json';
|
|
22
35
|
|
|
@@ -30,7 +43,13 @@ const g = {
|
|
|
30
43
|
seed: gradient(['cyan', 'green'])('seed'),
|
|
31
44
|
generateRandomSeed: gradient(['cyan', 'green'])('generateRandomSeed'),
|
|
32
45
|
types: gradient(['cyan', 'green'])('types'),
|
|
46
|
+
getLearnCardBundlePassword: gradient(['cyan', 'green'])('getLearnCardBundlePassword'),
|
|
33
47
|
copy: gradient(['cyan', 'green'])('copy'),
|
|
48
|
+
exportLearnCardBundle: gradient(['cyan', 'green'])('exportLearnCardBundle'),
|
|
49
|
+
importLearnCardBundle: gradient(['cyan', 'green'])('importLearnCardBundle'),
|
|
50
|
+
createLearnCardBundle: gradient(['cyan', 'green'])('createLearnCardBundle'),
|
|
51
|
+
readLearnCardBundle: gradient(['cyan', 'green'])('readLearnCardBundle'),
|
|
52
|
+
restoreLearnCardFromBundle: gradient(['cyan', 'green'])('restoreLearnCardFromBundle'),
|
|
34
53
|
};
|
|
35
54
|
|
|
36
55
|
const copyFunction = (text: string | object | number) => {
|
|
@@ -44,7 +63,28 @@ const copyFunction = (text: string | object | number) => {
|
|
|
44
63
|
clipboard.writeSync(text);
|
|
45
64
|
console.log('Copied to clipboard!');
|
|
46
65
|
} catch (error) {
|
|
47
|
-
console.error(
|
|
66
|
+
console.error(
|
|
67
|
+
'Failed to copy to clipboard:',
|
|
68
|
+
error instanceof Error ? error.message : 'Unknown error'
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const getLearnCardBundlePassword = async (prompt = 'Bundle password: '): Promise<string> => {
|
|
74
|
+
process.stdout.write(prompt);
|
|
75
|
+
|
|
76
|
+
const mutedOutput = new Writable({
|
|
77
|
+
write(_chunk, _encoding, callback) {
|
|
78
|
+
callback();
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
const rl = createInterface({ input: process.stdin, output: mutedOutput, terminal: true });
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
return await rl.question('');
|
|
85
|
+
} finally {
|
|
86
|
+
rl.close();
|
|
87
|
+
process.stdout.write('\n');
|
|
48
88
|
}
|
|
49
89
|
};
|
|
50
90
|
|
|
@@ -69,13 +109,15 @@ program
|
|
|
69
109
|
globalThis.learnCardFromSeed = learnCardFromSeed;
|
|
70
110
|
globalThis.initLearnCard = initLearnCard;
|
|
71
111
|
|
|
112
|
+
const didkit = fs.readFile(
|
|
113
|
+
require.resolve('@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm')
|
|
114
|
+
);
|
|
115
|
+
|
|
72
116
|
const _learnCard = await initLearnCard({
|
|
73
117
|
seed,
|
|
74
118
|
network: true,
|
|
75
119
|
allowRemoteContexts: true,
|
|
76
|
-
didkit
|
|
77
|
-
require.resolve('@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm')
|
|
78
|
-
),
|
|
120
|
+
didkit,
|
|
79
121
|
});
|
|
80
122
|
|
|
81
123
|
const simpleSigningLc = await _learnCard.addPlugin(
|
|
@@ -102,6 +144,23 @@ program
|
|
|
102
144
|
globalThis.getTestCache = getTestCache;
|
|
103
145
|
|
|
104
146
|
globalThis.copy = copyFunction;
|
|
147
|
+
globalThis.getLearnCardBundlePassword = getLearnCardBundlePassword;
|
|
148
|
+
globalThis.exportLearnCardBundle = createExportLearnCardBundleHelper(
|
|
149
|
+
writeLearnCardBundle,
|
|
150
|
+
globalThis.learnCard
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
globalThis.restoreLearnCardFromBundle = createRestoreLearnCardFromBundleHelper(
|
|
154
|
+
restoreBundle,
|
|
155
|
+
{
|
|
156
|
+
network: true,
|
|
157
|
+
allowRemoteContexts: true,
|
|
158
|
+
didkit,
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
globalThis.importLearnCardBundle = importLearnCardBundle;
|
|
162
|
+
globalThis.createLearnCardBundle = createLearnCardBundle;
|
|
163
|
+
globalThis.readLearnCardBundle = readLearnCardBundle;
|
|
105
164
|
|
|
106
165
|
// delete 'Creating wallet...' message
|
|
107
166
|
process.stdout.moveCursor?.(0, -1);
|
|
@@ -109,18 +168,22 @@ program
|
|
|
109
168
|
|
|
110
169
|
console.log('Wallet created!\n');
|
|
111
170
|
|
|
112
|
-
console.log('
|
|
113
|
-
console.log('│
|
|
114
|
-
console.log('
|
|
115
|
-
console.log('│ Variable
|
|
116
|
-
console.log('
|
|
117
|
-
console.log(`│
|
|
118
|
-
console.log(`│
|
|
119
|
-
console.log(`│
|
|
120
|
-
console.log(`│
|
|
121
|
-
console.log(`│
|
|
122
|
-
console.log(`│
|
|
123
|
-
console.log(
|
|
171
|
+
console.log('┌───────────────────────────────────────────────────────────────┐');
|
|
172
|
+
console.log('│ Variables Available │');
|
|
173
|
+
console.log('├────────────────────────────┬──────────────────────────────────┤');
|
|
174
|
+
console.log('│ Variable │ Description │');
|
|
175
|
+
console.log('├────────────────────────────┼──────────────────────────────────┤');
|
|
176
|
+
console.log(`│ ${g.learnCard} │ Learn Card Wallet │`);
|
|
177
|
+
console.log(`│ ${g.initLearnCard} │ Wallet Instantiation Function │`);
|
|
178
|
+
console.log(`│ ${g.seed} │ Seed used to generate wallet │`);
|
|
179
|
+
console.log(`│ ${g.generateRandomSeed} │ Generates a random seed │`);
|
|
180
|
+
console.log(`│ ${g.types} │ Helpful zod validators │`);
|
|
181
|
+
console.log(`│ ${g.copy} │ Copy text to clipboard │`);
|
|
182
|
+
console.log(`│ ${g.getLearnCardBundlePassword} │ Prompt for bundle password │`);
|
|
183
|
+
console.log(`│ ${g.exportLearnCardBundle} │ Export wallet continuity ZIP │`);
|
|
184
|
+
console.log(`│ ${g.importLearnCardBundle} │ Import continuity ZIP │`);
|
|
185
|
+
console.log(`│ ${g.restoreLearnCardFromBundle} │ Restore original wallet from ZIP │`);
|
|
186
|
+
console.log('└────────────────────────────┴──────────────────────────────────┘');
|
|
124
187
|
|
|
125
188
|
console.log('');
|
|
126
189
|
|
|
@@ -132,28 +195,45 @@ program
|
|
|
132
195
|
|
|
133
196
|
console.log("To get a feel for what's possible, try some of the following commands\n");
|
|
134
197
|
|
|
135
|
-
console.log('┌─────────────────────────┬────────────────────────────────────────────────┐');
|
|
136
|
-
console.log('│ Description │ Command │');
|
|
137
|
-
console.log('├─────────────────────────┼────────────────────────────────────────────────┤');
|
|
138
198
|
console.log(
|
|
139
|
-
|
|
199
|
+
'┌─────────────────────────┬───────────────────────────────────────────────────────────────────────────────────┐'
|
|
200
|
+
);
|
|
201
|
+
console.log(
|
|
202
|
+
'│ Description │ Command │'
|
|
203
|
+
);
|
|
204
|
+
console.log(
|
|
205
|
+
'├─────────────────────────┼───────────────────────────────────────────────────────────────────────────────────┤'
|
|
206
|
+
);
|
|
207
|
+
console.log(
|
|
208
|
+
`│ View your did │ ${g.learnCard}.id.did(); │`
|
|
209
|
+
);
|
|
210
|
+
console.log(
|
|
211
|
+
`│ Generate an unsigned VC │ ${g.learnCard}.invoke.getTestVc(); │`
|
|
212
|
+
);
|
|
213
|
+
console.log(
|
|
214
|
+
`│ Issue a signed VC │ await ${g.learnCard}.invoke.issueCredential(uvc); │`
|
|
215
|
+
);
|
|
216
|
+
console.log(
|
|
217
|
+
`│ Verify a signed VC │ await ${g.learnCard}.invoke.verifyCredential(vc); │`
|
|
218
|
+
);
|
|
219
|
+
console.log(
|
|
220
|
+
`│ Issue a signed VP │ await ${g.learnCard}.invoke.issuePresentation(vc); │`
|
|
140
221
|
);
|
|
141
222
|
console.log(
|
|
142
|
-
`│
|
|
223
|
+
`│ Verify a signed VP │ await ${g.learnCard}.invoke.verifyPresentation(vp); │`
|
|
143
224
|
);
|
|
144
225
|
console.log(
|
|
145
|
-
`│
|
|
226
|
+
`│ Prompt bundle password │ const password = await ${g.getLearnCardBundlePassword}(); │`
|
|
146
227
|
);
|
|
147
228
|
console.log(
|
|
148
|
-
`│
|
|
229
|
+
`│ Export wallet ZIP │ await ${g.exportLearnCardBundle}(${g.learnCard}, { out: './export.zip', password }); │`
|
|
149
230
|
);
|
|
150
231
|
console.log(
|
|
151
|
-
`│
|
|
232
|
+
`│ Restore original wallet │ await ${g.restoreLearnCardFromBundle}('./export.zip', { password }); │`
|
|
152
233
|
);
|
|
153
234
|
console.log(
|
|
154
|
-
|
|
235
|
+
'└─────────────────────────┴───────────────────────────────────────────────────────────────────────────────────┘'
|
|
155
236
|
);
|
|
156
|
-
console.log('└─────────────────────────┴────────────────────────────────────────────────┘');
|
|
157
237
|
|
|
158
238
|
console.log('');
|
|
159
239
|
|
|
@@ -166,7 +246,13 @@ program
|
|
|
166
246
|
.replace('learnCard', g.learnCard)
|
|
167
247
|
.replace('seed', g.seed)
|
|
168
248
|
.replace('generateRandomSeed', g.generateRandomSeed)
|
|
169
|
-
.replace('copy', g.copy)
|
|
249
|
+
.replace('copy', g.copy)
|
|
250
|
+
.replace('getLearnCardBundlePassword', g.getLearnCardBundlePassword)
|
|
251
|
+
.replace('exportLearnCardBundle', g.exportLearnCardBundle)
|
|
252
|
+
.replace('importLearnCardBundle', g.importLearnCardBundle)
|
|
253
|
+
.replace('createLearnCardBundle', g.createLearnCardBundle)
|
|
254
|
+
.replace('readLearnCardBundle', g.readLearnCardBundle)
|
|
255
|
+
.replace('restoreLearnCardFromBundle', g.restoreLearnCardFromBundle);
|
|
170
256
|
},
|
|
171
257
|
});
|
|
172
258
|
})
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
ExportLearnCardBundleOptions,
|
|
5
|
+
LearnCardBundleWallet,
|
|
6
|
+
RestoreLearnCardFromBundleOptions,
|
|
7
|
+
} from '@learncard/holder-continuity';
|
|
8
|
+
import {
|
|
9
|
+
createExportLearnCardBundleHelper,
|
|
10
|
+
createRestoreLearnCardFromBundleHelper,
|
|
11
|
+
} from './replHelpers';
|
|
12
|
+
|
|
13
|
+
const createWallet = (did: string): LearnCardBundleWallet => ({
|
|
14
|
+
id: { did: () => did },
|
|
15
|
+
invoke: {},
|
|
16
|
+
index: { LearnCloud: { get: async () => [], add: async () => true } },
|
|
17
|
+
read: { get: async () => undefined },
|
|
18
|
+
store: { LearnCloud: {} },
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('createExportLearnCardBundleHelper', () => {
|
|
22
|
+
it('uses the default wallet when only options are provided', async () => {
|
|
23
|
+
const defaultWallet = createWallet('did:key:default');
|
|
24
|
+
const exportBundle = vi.fn(async () => ({
|
|
25
|
+
data: Buffer.from(''),
|
|
26
|
+
manifest: {} as never,
|
|
27
|
+
warnings: [],
|
|
28
|
+
}));
|
|
29
|
+
const helper = createExportLearnCardBundleHelper(exportBundle, defaultWallet);
|
|
30
|
+
const options: ExportLearnCardBundleOptions = { out: './bundle.zip', password: 'secret' };
|
|
31
|
+
|
|
32
|
+
await helper(options);
|
|
33
|
+
|
|
34
|
+
expect(exportBundle).toHaveBeenCalledWith(defaultWallet, options);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('uses the provided wallet when wallet and options are both provided', async () => {
|
|
38
|
+
const defaultWallet = createWallet('did:key:default');
|
|
39
|
+
const otherWallet = createWallet('did:key:other');
|
|
40
|
+
const exportBundle = vi.fn(async () => ({
|
|
41
|
+
data: Buffer.from(''),
|
|
42
|
+
manifest: {} as never,
|
|
43
|
+
warnings: [],
|
|
44
|
+
}));
|
|
45
|
+
const helper = createExportLearnCardBundleHelper(exportBundle, defaultWallet);
|
|
46
|
+
const options: ExportLearnCardBundleOptions = { out: './bundle.zip', password: 'secret' };
|
|
47
|
+
|
|
48
|
+
await helper(otherWallet, options);
|
|
49
|
+
|
|
50
|
+
expect(exportBundle).toHaveBeenCalledWith(otherWallet, options);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('createRestoreLearnCardFromBundleHelper', () => {
|
|
55
|
+
it('merges default init config with per-call overrides', async () => {
|
|
56
|
+
const restoreBundle = vi.fn(async () => ({ restored: true }));
|
|
57
|
+
const helper = createRestoreLearnCardFromBundleHelper(restoreBundle, {
|
|
58
|
+
network: true,
|
|
59
|
+
allowRemoteContexts: true,
|
|
60
|
+
didkit: 'node',
|
|
61
|
+
});
|
|
62
|
+
const options: Omit<RestoreLearnCardFromBundleOptions, 'init'> & {
|
|
63
|
+
init?: Partial<RestoreLearnCardFromBundleOptions['init']>;
|
|
64
|
+
} = {
|
|
65
|
+
password: 'secret',
|
|
66
|
+
init: { network: 'http://localhost:4000/trpc' },
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
await helper('./bundle.zip', options);
|
|
70
|
+
|
|
71
|
+
expect(restoreBundle).toHaveBeenCalledWith('./bundle.zip', {
|
|
72
|
+
password: 'secret',
|
|
73
|
+
init: {
|
|
74
|
+
network: 'http://localhost:4000/trpc',
|
|
75
|
+
allowRemoteContexts: true,
|
|
76
|
+
didkit: 'node',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExportLearnCardBundleOptions,
|
|
3
|
+
LearnCardBundleWallet,
|
|
4
|
+
RestoreLearnCardFromBundleOptions,
|
|
5
|
+
RestoreLearnCardInit,
|
|
6
|
+
} from '@learncard/holder-continuity';
|
|
7
|
+
|
|
8
|
+
type ExportLearnCardBundleFn = typeof import('@learncard/holder-continuity').exportLearnCardBundle;
|
|
9
|
+
type RestoreLearnCardFromBundleFn = typeof import('@learncard/holder-continuity').restoreLearnCardFromBundle;
|
|
10
|
+
|
|
11
|
+
export const createExportLearnCardBundleHelper = (
|
|
12
|
+
exportBundle: ExportLearnCardBundleFn,
|
|
13
|
+
defaultWallet: LearnCardBundleWallet
|
|
14
|
+
) => {
|
|
15
|
+
return (
|
|
16
|
+
walletOrOptions: LearnCardBundleWallet | ExportLearnCardBundleOptions,
|
|
17
|
+
maybeOptions?: ExportLearnCardBundleOptions
|
|
18
|
+
) => {
|
|
19
|
+
if (maybeOptions) return exportBundle(walletOrOptions as LearnCardBundleWallet, maybeOptions);
|
|
20
|
+
|
|
21
|
+
return exportBundle(defaultWallet, walletOrOptions as ExportLearnCardBundleOptions);
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const createRestoreLearnCardFromBundleHelper = (
|
|
26
|
+
restoreBundle: RestoreLearnCardFromBundleFn,
|
|
27
|
+
defaultInit: RestoreLearnCardInit
|
|
28
|
+
) => {
|
|
29
|
+
return (
|
|
30
|
+
path: string,
|
|
31
|
+
options: (Omit<RestoreLearnCardFromBundleOptions, 'init'> & {
|
|
32
|
+
init?: Partial<RestoreLearnCardInit>;
|
|
33
|
+
}) = {}
|
|
34
|
+
) => {
|
|
35
|
+
return restoreBundle(path, {
|
|
36
|
+
...options,
|
|
37
|
+
init: {
|
|
38
|
+
...defaultInit,
|
|
39
|
+
...(options.init ?? {}),
|
|
40
|
+
} as RestoreLearnCardInit,
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
};
|