@learncard/cli 3.3.176 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/README.md +39 -1
- package/dist/index.js +138 -31
- package/package.json +16 -12
- package/project.json +9 -1
- package/src/index.tsx +119 -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,85 @@
|
|
|
1
1
|
# @learncard/cli
|
|
2
2
|
|
|
3
|
+
## 3.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#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
|
|
8
|
+
|
|
9
|
+
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.
|
|
10
|
+
|
|
11
|
+
Updates `@learncard/cli` to consume the new package and expose REPL helpers for export, import, and restore.
|
|
12
|
+
|
|
13
|
+
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.
|
|
14
|
+
|
|
15
|
+
Adds bounded status-list fetching, optional verify-before-import support, bundle size guards, and capped holder metadata pagination.
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 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)]:
|
|
20
|
+
- @learncard/types@5.17.0
|
|
21
|
+
- @learncard/holder-continuity@0.2.0
|
|
22
|
+
- @learncard/didkit-plugin@1.9.0
|
|
23
|
+
- @learncard/core@9.4.20
|
|
24
|
+
- @learncard/init@2.3.20
|
|
25
|
+
- @learncard/render-method-plugin@3.0.0
|
|
26
|
+
- @learncard/learn-cloud-plugin@2.3.25
|
|
27
|
+
- @learncard/ler-rs-plugin@0.1.11
|
|
28
|
+
- @learncard/linked-claims-plugin@0.2.20
|
|
29
|
+
- @learncard/open-badge-v2-plugin@1.1.21
|
|
30
|
+
- @learncard/simple-signing-plugin@1.1.24
|
|
31
|
+
|
|
32
|
+
## 3.3.177
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- [#1240](https://github.com/learningeconomy/LearnCard/pull/1240) [`3a05603c72d76020b43ec6bbd5e31b2b31c0fd2b`](https://github.com/learningeconomy/LearnCard/commit/3a05603c72d76020b43ec6bbd5e31b2b31c0fd2b) Thanks [@gerardopar](https://github.com/gerardopar)! - feat: [LC-1812][LC-1855] - Add Render Method Plugin + Render Method Toggle
|
|
37
|
+
|
|
38
|
+
Adds `@learncard/render-method-plugin` for attaching and reading W3C `renderMethod` entries on Verifiable Credentials. The plugin is registered as part of the default LearnCard wallet stack.
|
|
39
|
+
|
|
40
|
+
**Write side** (`wallet.invoke`): `attachRenderMethod`, `buildTemplateRenderMethod`.
|
|
41
|
+
|
|
42
|
+
**Read side** (`wallet.invoke` and direct imports):
|
|
43
|
+
|
|
44
|
+
- String-based sugar (most common case): `findTemplateRenderMethod(vc, suite | suites[])`, `findTemplateRenderMethods(vc, suite | suites[])`.
|
|
45
|
+
- Backward-compatible alias: `getSvgMustacheRenderMethod`.
|
|
46
|
+
- Predicate-based escape hatch: `findRenderMethod`, `findRenderMethods`.
|
|
47
|
+
- Raw access: `getRenderMethods` (unwraps `CertifiedBoostCredential`, normalizes object↔array).
|
|
48
|
+
- Data shaping: `buildRenderData(vc, renderProperty?)` (Mustache context with `vc` / `credential` / `credentialSubjects` aliases, RFC 6901 overlay).
|
|
49
|
+
- Exported type guards: `isTemplateRenderMethod`, `isSvgMustacheRenderMethod`.
|
|
50
|
+
|
|
51
|
+
The pure data-shaping helpers (Mustache context, JSON Pointer overlay, boost unwrapping) moved out of `apps/learn-card-app/src/helpers/renderMethod.helpers.ts` into the plugin; the app now only owns the SVG-specific render pipeline (Mustache hydration + DOMPurify sanitization + React display).
|
|
52
|
+
|
|
53
|
+
**`@learncard/types`**: `TemplateRenderMethodValidator` widened — `renderSuite` and `outputPreference.mediaType` are now `z.string()` (were `z.literal('svg-mustache')` and `z.literal('image/svg+xml')`). The literals couldn't express the W3C spec's openness to other suites/types and made the plugin's "future-extensible" read API contradictory. Backward-compatible: all existing literal values still validate.
|
|
54
|
+
|
|
55
|
+
Behavior:
|
|
56
|
+
|
|
57
|
+
- `attachRenderMethod` is **opt-in**: calling it without a config returns the VC unchanged. Pass `{ templateId: DEFAULT_TEMPLATE_ID }` or a custom `{ templateId | templateValue }` to actually attach a render method. This avoids polluting every issued credential's `@context` with the render-method JSON-LD context URL.
|
|
58
|
+
- `templateId` must be an `http://` or `https://` URL. Empty values, `javascript:`, `file:`, `data:` and other schemes are rejected at the plugin boundary.
|
|
59
|
+
- `templateValue` is URL-encoded into a `data:image/svg+xml,` URI. Empty or whitespace-only values are rejected.
|
|
60
|
+
- The `useRenderMethodEnabled` LaunchDarkly flag gates display only (the `RenderMethodDisplay` component, the `BoostDisplayStyleSelector`, the `getSvgMustacheRenderMethod` lookup). It does not gate the write path.
|
|
61
|
+
|
|
62
|
+
Known risk:
|
|
63
|
+
|
|
64
|
+
- The JSON-LD context URL (`https://digitalbazaar.github.io/vc-render-method-context/contexts/v2rc2.jsonld`) is a community-group draft, not a finalized W3C TR. VCs issued with this context depend on the URL remaining stable. Follow-up work will bundle the context locally and migrate to the W3C TR URL when published.
|
|
65
|
+
|
|
66
|
+
Types:
|
|
67
|
+
|
|
68
|
+
- `@learncard/types` adds `TemplateRenderMethod`, `RenderMethod`, and a top-level `renderMethod` field on `UnsignedVC`.
|
|
69
|
+
- `learn-card-base` extends `BespokeLearnCard` to include `RenderMethodPlugin`, making `wallet.invoke.attachRenderMethod` and `wallet.invoke.buildTemplateRenderMethod` type-safe across the codebase.
|
|
70
|
+
|
|
71
|
+
- Updated dependencies [[`3a05603c72d76020b43ec6bbd5e31b2b31c0fd2b`](https://github.com/learningeconomy/LearnCard/commit/3a05603c72d76020b43ec6bbd5e31b2b31c0fd2b), [`37439411ac68618fc27898ac4c0f48dbef4e424b`](https://github.com/learningeconomy/LearnCard/commit/37439411ac68618fc27898ac4c0f48dbef4e424b), [`37439411ac68618fc27898ac4c0f48dbef4e424b`](https://github.com/learningeconomy/LearnCard/commit/37439411ac68618fc27898ac4c0f48dbef4e424b)]:
|
|
72
|
+
- @learncard/types@5.16.0
|
|
73
|
+
- @learncard/render-method-plugin@2.0.0
|
|
74
|
+
- @learncard/init@2.3.19
|
|
75
|
+
- @learncard/core@9.4.19
|
|
76
|
+
- @learncard/didkit-plugin@1.8.10
|
|
77
|
+
- @learncard/learn-cloud-plugin@2.3.24
|
|
78
|
+
- @learncard/ler-rs-plugin@0.1.10
|
|
79
|
+
- @learncard/linked-claims-plugin@0.2.19
|
|
80
|
+
- @learncard/open-badge-v2-plugin@1.1.20
|
|
81
|
+
- @learncard/simple-signing-plugin@1.1.23
|
|
82
|
+
|
|
3
83
|
## 3.3.176
|
|
4
84
|
|
|
5
85
|
### 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');
|
|
@@ -15,7 +17,9 @@ var figlet = require('figlet');
|
|
|
15
17
|
var commander = require('commander');
|
|
16
18
|
var clipboard = require('clipboardy');
|
|
17
19
|
var lerRsPlugin = require('@learncard/ler-rs-plugin');
|
|
20
|
+
var renderMethodPlugin = require('@learncard/render-method-plugin');
|
|
18
21
|
var crypto = require('crypto');
|
|
22
|
+
var holderContinuity = require('@learncard/holder-continuity');
|
|
19
23
|
|
|
20
24
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
21
25
|
|
|
@@ -30,14 +34,49 @@ var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto);
|
|
|
30
34
|
|
|
31
35
|
const generateRandomSeed = () => crypto__default["default"].randomBytes(32).toString("hex");
|
|
32
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
|
+
|
|
33
71
|
var name = "@learncard/cli";
|
|
34
|
-
var version = "3.
|
|
72
|
+
var version = "3.4.0";
|
|
35
73
|
var description = "Command Line Interface for LearnCard";
|
|
36
74
|
var main = "dist/index.js";
|
|
37
75
|
var bin = "dist/index.js";
|
|
38
76
|
var scripts = {
|
|
39
77
|
start: "rollup -c && node --enable-source-maps dist/index.js",
|
|
40
|
-
build: "rollup -c"
|
|
78
|
+
build: "rollup -c",
|
|
79
|
+
test: "vitest run"
|
|
41
80
|
};
|
|
42
81
|
var author = "Learning Economy Foundation (www.learningeconomy.io)";
|
|
43
82
|
var license = "MIT";
|
|
@@ -49,7 +88,9 @@ var dependencies = {
|
|
|
49
88
|
"@learncard/ler-rs-plugin": "workspace:*",
|
|
50
89
|
"@learncard/linked-claims-plugin": "workspace:*",
|
|
51
90
|
"@learncard/open-badge-v2-plugin": "workspace:*",
|
|
91
|
+
"@learncard/render-method-plugin": "workspace:*",
|
|
52
92
|
"@learncard/simple-signing-plugin": "workspace:*",
|
|
93
|
+
"@learncard/holder-continuity": "workspace:*",
|
|
53
94
|
"@learncard/types": "workspace:*",
|
|
54
95
|
"@rollup/plugin-json": "^4.1.0",
|
|
55
96
|
clipboardy: "^4.0.0",
|
|
@@ -65,7 +106,8 @@ var devDependencies = {
|
|
|
65
106
|
"@types/figlet": "^1.5.4",
|
|
66
107
|
"@types/node": "^18.0.0",
|
|
67
108
|
nodemon: "^2.0.16",
|
|
68
|
-
"ts-node": "^10.8.1"
|
|
109
|
+
"ts-node": "^10.8.1",
|
|
110
|
+
vitest: "^1.6.0"
|
|
69
111
|
};
|
|
70
112
|
var repository = {
|
|
71
113
|
type: "git",
|
|
@@ -100,7 +142,13 @@ const g = {
|
|
|
100
142
|
seed: gradient__default["default"](["cyan", "green"])("seed"),
|
|
101
143
|
generateRandomSeed: gradient__default["default"](["cyan", "green"])("generateRandomSeed"),
|
|
102
144
|
types: gradient__default["default"](["cyan", "green"])("types"),
|
|
103
|
-
|
|
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")
|
|
104
152
|
};
|
|
105
153
|
const copyFunction = (text) => {
|
|
106
154
|
if (typeof text === "object") {
|
|
@@ -113,7 +161,25 @@ const copyFunction = (text) => {
|
|
|
113
161
|
clipboard__default["default"].writeSync(text);
|
|
114
162
|
console.log("Copied to clipboard!");
|
|
115
163
|
} catch (error) {
|
|
116
|
-
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");
|
|
117
183
|
}
|
|
118
184
|
};
|
|
119
185
|
commander.program.version(packageJson.version).argument("[seed]").action(async (_seed = generateRandomSeed()) => {
|
|
@@ -130,13 +196,14 @@ commander.program.version(packageJson.version).argument("[seed]").action(async (
|
|
|
130
196
|
globalThis.emptyLearnCard = init.emptyLearnCard;
|
|
131
197
|
globalThis.learnCardFromSeed = init.learnCardFromSeed;
|
|
132
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
|
+
);
|
|
133
202
|
const _learnCard = await init.initLearnCard({
|
|
134
203
|
seed,
|
|
135
204
|
network: true,
|
|
136
205
|
allowRemoteContexts: true,
|
|
137
|
-
didkit
|
|
138
|
-
require.resolve("@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm")
|
|
139
|
-
)
|
|
206
|
+
didkit
|
|
140
207
|
});
|
|
141
208
|
const simpleSigningLc = await _learnCard.addPlugin(
|
|
142
209
|
await simpleSigningPlugin.getSimpleSigningPlugin(_learnCard, "https://api.learncard.app/trpc")
|
|
@@ -148,56 +215,96 @@ commander.program.version(packageJson.version).argument("[seed]").action(async (
|
|
|
148
215
|
globalThis.learnCard = await globalThis.learnCard.addPlugin(
|
|
149
216
|
openBadgeV2Plugin.openBadgeV2Plugin(globalThis.learnCard)
|
|
150
217
|
);
|
|
218
|
+
globalThis.learnCard = await globalThis.learnCard.addPlugin(
|
|
219
|
+
renderMethodPlugin.getRenderMethodPlugin(globalThis.learnCard)
|
|
220
|
+
);
|
|
151
221
|
globalThis.types = types__default["default"];
|
|
152
222
|
globalThis.getTestCache = core.getTestCache;
|
|
153
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;
|
|
154
240
|
(_b = (_a = process.stdout).moveCursor) == null ? void 0 : _b.call(_a, 0, -1);
|
|
155
241
|
(_d = (_c = process.stdout).clearLine) == null ? void 0 : _d.call(_c, 1);
|
|
156
242
|
console.log("Wallet created!\n");
|
|
157
|
-
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");
|
|
158
|
-
console.log("\u2502
|
|
159
|
-
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");
|
|
160
|
-
console.log("\u2502 Variable
|
|
161
|
-
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");
|
|
162
|
-
console.log(`\u2502
|
|
163
|
-
console.log(`\u2502
|
|
164
|
-
console.log(`\u2502
|
|
165
|
-
console.log(`\u2502
|
|
166
|
-
console.log(`\u2502
|
|
167
|
-
console.log(`\u2502
|
|
168
|
-
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");
|
|
169
259
|
console.log("");
|
|
170
260
|
console.log(
|
|
171
261
|
"For help/documentation regarding your wallet, please read the documentation at\n"
|
|
172
262
|
);
|
|
173
263
|
console.log("https://docs.learncard.com/sdks/learncard-core/construction\n");
|
|
174
264
|
console.log("To get a feel for what's possible, try some of the following commands\n");
|
|
175
|
-
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");
|
|
176
|
-
console.log("\u2502 Description \u2502 Command \u2502");
|
|
177
|
-
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");
|
|
178
265
|
console.log(
|
|
179
|
-
|
|
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`
|
|
180
288
|
);
|
|
181
289
|
console.log(
|
|
182
|
-
`\u2502
|
|
290
|
+
`\u2502 Verify a signed VP \u2502 await ${g.learnCard}.invoke.verifyPresentation(vp); \u2502`
|
|
183
291
|
);
|
|
184
292
|
console.log(
|
|
185
|
-
`\u2502
|
|
293
|
+
`\u2502 Prompt bundle password \u2502 const password = await ${g.getLearnCardBundlePassword}(); \u2502`
|
|
186
294
|
);
|
|
187
295
|
console.log(
|
|
188
|
-
`\u2502
|
|
296
|
+
`\u2502 Export wallet ZIP \u2502 await ${g.exportLearnCardBundle}(${g.learnCard}, { out: './export.zip', password }); \u2502`
|
|
189
297
|
);
|
|
190
298
|
console.log(
|
|
191
|
-
`\u2502
|
|
299
|
+
`\u2502 Restore original wallet \u2502 await ${g.restoreLearnCardFromBundle}('./export.zip', { password }); \u2502`
|
|
192
300
|
);
|
|
193
301
|
console.log(
|
|
194
|
-
|
|
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"
|
|
195
303
|
);
|
|
196
|
-
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");
|
|
197
304
|
console.log("");
|
|
198
305
|
repl__default["default"].start({
|
|
199
306
|
colorize: (input) => {
|
|
200
|
-
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);
|
|
201
308
|
}
|
|
202
309
|
});
|
|
203
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.0",
|
|
4
4
|
"description": "Command Line Interface for LearnCard",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": "dist/index.js",
|
|
@@ -15,22 +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/
|
|
19
|
-
"@learncard/
|
|
20
|
-
"@learncard/
|
|
21
|
-
"@learncard/
|
|
22
|
-
"@learncard/
|
|
23
|
-
"@learncard/
|
|
24
|
-
"@learncard/
|
|
25
|
-
"@learncard/
|
|
26
|
-
"@learncard/
|
|
18
|
+
"@learncard/core": "9.4.20",
|
|
19
|
+
"@learncard/didkit-plugin": "^1.9.0",
|
|
20
|
+
"@learncard/init": "^2.3.20",
|
|
21
|
+
"@learncard/learn-cloud-plugin": "2.3.25",
|
|
22
|
+
"@learncard/ler-rs-plugin": "0.1.11",
|
|
23
|
+
"@learncard/linked-claims-plugin": "0.2.20",
|
|
24
|
+
"@learncard/open-badge-v2-plugin": "1.1.21",
|
|
25
|
+
"@learncard/render-method-plugin": "3.0.0",
|
|
26
|
+
"@learncard/holder-continuity": "0.2.0",
|
|
27
|
+
"@learncard/types": "5.17.0",
|
|
28
|
+
"@learncard/simple-signing-plugin": "1.1.24"
|
|
27
29
|
},
|
|
28
30
|
"devDependencies": {
|
|
29
31
|
"@types/cors": "^2.8.12",
|
|
30
32
|
"@types/figlet": "^1.5.4",
|
|
31
33
|
"@types/node": "^18.0.0",
|
|
32
34
|
"nodemon": "^2.0.16",
|
|
33
|
-
"ts-node": "^10.8.1"
|
|
35
|
+
"ts-node": "^10.8.1",
|
|
36
|
+
"vitest": "^1.6.0"
|
|
34
37
|
},
|
|
35
38
|
"repository": {
|
|
36
39
|
"type": "git",
|
|
@@ -42,6 +45,7 @@
|
|
|
42
45
|
},
|
|
43
46
|
"scripts": {
|
|
44
47
|
"start": "rollup -c && node --enable-source-maps dist/index.js",
|
|
45
|
-
"build": "rollup -c"
|
|
48
|
+
"build": "rollup -c",
|
|
49
|
+
"test": "vitest run"
|
|
46
50
|
}
|
|
47
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';
|
|
@@ -14,8 +16,20 @@ import { program } from 'commander';
|
|
|
14
16
|
import clipboard from 'clipboardy';
|
|
15
17
|
|
|
16
18
|
import { getLerRsPlugin } from '@learncard/ler-rs-plugin';
|
|
19
|
+
import { getRenderMethodPlugin } from '@learncard/render-method-plugin';
|
|
17
20
|
|
|
18
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';
|
|
19
33
|
|
|
20
34
|
import packageJson from '../package.json';
|
|
21
35
|
|
|
@@ -29,7 +43,13 @@ const g = {
|
|
|
29
43
|
seed: gradient(['cyan', 'green'])('seed'),
|
|
30
44
|
generateRandomSeed: gradient(['cyan', 'green'])('generateRandomSeed'),
|
|
31
45
|
types: gradient(['cyan', 'green'])('types'),
|
|
46
|
+
getLearnCardBundlePassword: gradient(['cyan', 'green'])('getLearnCardBundlePassword'),
|
|
32
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'),
|
|
33
53
|
};
|
|
34
54
|
|
|
35
55
|
const copyFunction = (text: string | object | number) => {
|
|
@@ -43,7 +63,28 @@ const copyFunction = (text: string | object | number) => {
|
|
|
43
63
|
clipboard.writeSync(text);
|
|
44
64
|
console.log('Copied to clipboard!');
|
|
45
65
|
} catch (error) {
|
|
46
|
-
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');
|
|
47
88
|
}
|
|
48
89
|
};
|
|
49
90
|
|
|
@@ -68,13 +109,15 @@ program
|
|
|
68
109
|
globalThis.learnCardFromSeed = learnCardFromSeed;
|
|
69
110
|
globalThis.initLearnCard = initLearnCard;
|
|
70
111
|
|
|
112
|
+
const didkit = fs.readFile(
|
|
113
|
+
require.resolve('@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm')
|
|
114
|
+
);
|
|
115
|
+
|
|
71
116
|
const _learnCard = await initLearnCard({
|
|
72
117
|
seed,
|
|
73
118
|
network: true,
|
|
74
119
|
allowRemoteContexts: true,
|
|
75
|
-
didkit
|
|
76
|
-
require.resolve('@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm')
|
|
77
|
-
),
|
|
120
|
+
didkit,
|
|
78
121
|
});
|
|
79
122
|
|
|
80
123
|
const simpleSigningLc = await _learnCard.addPlugin(
|
|
@@ -92,10 +135,32 @@ program
|
|
|
92
135
|
openBadgeV2Plugin(globalThis.learnCard)
|
|
93
136
|
);
|
|
94
137
|
|
|
138
|
+
// Add Render Method plugin for attaching W3C renderMethod to VCs
|
|
139
|
+
globalThis.learnCard = await globalThis.learnCard.addPlugin(
|
|
140
|
+
getRenderMethodPlugin(globalThis.learnCard)
|
|
141
|
+
);
|
|
142
|
+
|
|
95
143
|
globalThis.types = types;
|
|
96
144
|
globalThis.getTestCache = getTestCache;
|
|
97
145
|
|
|
98
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;
|
|
99
164
|
|
|
100
165
|
// delete 'Creating wallet...' message
|
|
101
166
|
process.stdout.moveCursor?.(0, -1);
|
|
@@ -103,18 +168,22 @@ program
|
|
|
103
168
|
|
|
104
169
|
console.log('Wallet created!\n');
|
|
105
170
|
|
|
106
|
-
console.log('
|
|
107
|
-
console.log('│
|
|
108
|
-
console.log('
|
|
109
|
-
console.log('│ Variable
|
|
110
|
-
console.log('
|
|
111
|
-
console.log(`│
|
|
112
|
-
console.log(`│
|
|
113
|
-
console.log(`│
|
|
114
|
-
console.log(`│
|
|
115
|
-
console.log(`│
|
|
116
|
-
console.log(`│
|
|
117
|
-
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('└────────────────────────────┴──────────────────────────────────┘');
|
|
118
187
|
|
|
119
188
|
console.log('');
|
|
120
189
|
|
|
@@ -126,28 +195,45 @@ program
|
|
|
126
195
|
|
|
127
196
|
console.log("To get a feel for what's possible, try some of the following commands\n");
|
|
128
197
|
|
|
129
|
-
console.log('┌─────────────────────────┬────────────────────────────────────────────────┐');
|
|
130
|
-
console.log('│ Description │ Command │');
|
|
131
|
-
console.log('├─────────────────────────┼────────────────────────────────────────────────┤');
|
|
132
198
|
console.log(
|
|
133
|
-
|
|
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); │`
|
|
134
221
|
);
|
|
135
222
|
console.log(
|
|
136
|
-
`│
|
|
223
|
+
`│ Verify a signed VP │ await ${g.learnCard}.invoke.verifyPresentation(vp); │`
|
|
137
224
|
);
|
|
138
225
|
console.log(
|
|
139
|
-
`│
|
|
226
|
+
`│ Prompt bundle password │ const password = await ${g.getLearnCardBundlePassword}(); │`
|
|
140
227
|
);
|
|
141
228
|
console.log(
|
|
142
|
-
`│
|
|
229
|
+
`│ Export wallet ZIP │ await ${g.exportLearnCardBundle}(${g.learnCard}, { out: './export.zip', password }); │`
|
|
143
230
|
);
|
|
144
231
|
console.log(
|
|
145
|
-
`│
|
|
232
|
+
`│ Restore original wallet │ await ${g.restoreLearnCardFromBundle}('./export.zip', { password }); │`
|
|
146
233
|
);
|
|
147
234
|
console.log(
|
|
148
|
-
|
|
235
|
+
'└─────────────────────────┴───────────────────────────────────────────────────────────────────────────────────┘'
|
|
149
236
|
);
|
|
150
|
-
console.log('└─────────────────────────┴────────────────────────────────────────────────┘');
|
|
151
237
|
|
|
152
238
|
console.log('');
|
|
153
239
|
|
|
@@ -160,7 +246,13 @@ program
|
|
|
160
246
|
.replace('learnCard', g.learnCard)
|
|
161
247
|
.replace('seed', g.seed)
|
|
162
248
|
.replace('generateRandomSeed', g.generateRandomSeed)
|
|
163
|
-
.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);
|
|
164
256
|
},
|
|
165
257
|
});
|
|
166
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
|
+
};
|