@learncard/cli 3.4.7 → 3.4.8

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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # @learncard/cli
2
2
 
3
+ ## 3.4.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1359](https://github.com/learningeconomy/LearnCard/pull/1359) [`ca6760392066c4ca5daf0061e740523a63b6cf52`](https://github.com/learningeconomy/LearnCard/commit/ca6760392066c4ca5daf0061e740523a63b6cf52) Thanks [@smurflo2](https://github.com/smurflo2)! - Fix CLI
8
+
9
+ - Updated dependencies [[`c0b5edb671ba3704b44547f9d0ef99f6f0e090ba`](https://github.com/learningeconomy/LearnCard/commit/c0b5edb671ba3704b44547f9d0ef99f6f0e090ba)]:
10
+ - @learncard/types@5.17.6
11
+ - @learncard/holder-continuity@0.2.8
12
+ - @learncard/core@9.4.27
13
+ - @learncard/init@2.4.6
14
+ - @learncard/didkit-plugin@1.9.7
15
+ - @learncard/learn-cloud-plugin@2.3.32
16
+ - @learncard/ler-rs-plugin@0.1.18
17
+ - @learncard/linked-claims-plugin@0.2.27
18
+ - @learncard/open-badge-v2-plugin@1.1.28
19
+ - @learncard/render-method-plugin@3.0.7
20
+ - @learncard/simple-signing-plugin@1.1.31
21
+
3
22
  ## 3.4.7
4
23
 
5
24
  ### Patch Changes
package/dist/index.js CHANGED
@@ -3,9 +3,9 @@
3
3
 
4
4
  var fs = require('fs/promises');
5
5
  var dns = require('node:dns');
6
- var node_readline = require('node:readline');
7
6
  var promises = require('node:readline/promises');
8
7
  var node_stream = require('node:stream');
8
+ var node_util = require('node:util');
9
9
  var core = require('@learncard/core');
10
10
  var init = require('@learncard/init');
11
11
  var simpleSigningPlugin = require('@learncard/simple-signing-plugin');
@@ -87,7 +87,7 @@ const createRestoreLearnCardFromBundleHelper = (restoreBundle, defaultInit) => {
87
87
  };
88
88
 
89
89
  var name = "@learncard/cli";
90
- var version = "3.4.7";
90
+ var version = "3.4.8";
91
91
  var description = "Command Line Interface for LearnCard";
92
92
  var main = "dist/index.js";
93
93
  var bin = "dist/index.js";
@@ -156,6 +156,7 @@ var packageJson = {
156
156
  var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
157
157
  var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")]) ? it.call(obj) : (obj = obj[__knownSymbol("iterator")](), it = {}, method = (key, fn) => (fn = obj[key]) && (it[key] = (arg) => new Promise((yes, no, done) => (arg = fn.call(obj, arg), done = arg.done, Promise.resolve(arg.value).then((value) => yes({ value, done }), no)))), method("next"), method("return"), it);
158
158
  dns__default["default"].setDefaultResultOrder("ipv4first");
159
+ const cliGlobals = globalThis;
159
160
  const replGlobals = [
160
161
  "learnCard",
161
162
  "emptyLearnCard",
@@ -240,7 +241,9 @@ const globalAssignmentPattern = /^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(
240
241
  const parseGlobalAssignment = (source) => {
241
242
  const match = source.match(globalAssignmentPattern);
242
243
  if (!match) return;
243
- const [, name, initializer] = match;
244
+ const name = match[1];
245
+ const initializer = match[2];
246
+ if (!name || !initializer) return;
244
247
  return { name, initializer };
245
248
  };
246
249
  const getCurrentToken = (line) => {
@@ -287,10 +290,22 @@ const completeBunReplInput = (line) => {
287
290
  }
288
291
  };
289
292
  const evaluateBunReplInput = async (source) => {
293
+ const trimmedSource = source.trim();
294
+ const expressionSource = trimmedSource.replace(/;+\s*$/, "");
295
+ const statements = trimmedSource.split(";").map((statement) => statement.trim()).filter(Boolean);
290
296
  try {
291
- return await globalThis.eval(`(async () => (${source}))()`);
297
+ return await globalThis.eval(`(async () => (${expressionSource}))()`);
292
298
  } catch (e) {
293
- const globalAssignment = parseGlobalAssignment(source);
299
+ if (statements.length > 1) {
300
+ const lastStatement = statements[statements.length - 1];
301
+ if (lastStatement && !/^(?:const|let|var)\b/.test(lastStatement)) {
302
+ const body = statements.slice(0, -1).join(";\n");
303
+ const wrappedSource = `${body ? `${body};
304
+ ` : ""}return (${lastStatement});`;
305
+ return await globalThis.eval(`(async () => { ${wrappedSource} })()`);
306
+ }
307
+ }
308
+ const globalAssignment = parseGlobalAssignment(trimmedSource);
294
309
  if (globalAssignment) {
295
310
  const value = await globalThis.eval(
296
311
  `(async () => (${globalAssignment.initializer}))()`
@@ -298,29 +313,15 @@ const evaluateBunReplInput = async (source) => {
298
313
  globalThis[globalAssignment.name] = value;
299
314
  return value;
300
315
  }
301
- return await globalThis.eval(`(async () => { ${source} })()`);
316
+ return await globalThis.eval(`(async () => { ${trimmedSource} })()`);
302
317
  }
303
318
  };
304
- const getSharedCompletion = (matches) => {
305
- if (!matches.length) return;
306
- return matches.reduce((prefix, match) => {
307
- let index = 0;
308
- while (index < prefix.length && prefix[index] === match[index]) index += 1;
309
- return prefix.slice(0, index);
310
- });
311
- };
312
- const renderBunReplLine = (prompt, line, cursor, colorize) => {
313
- process.stdout.clearLine(0);
314
- process.stdout.cursorTo(0);
315
- process.stdout.write(prompt + colorize(line));
316
- const trailingLength = line.length - cursor;
317
- if (trailingLength > 0) process.stdout.write(`\x1B[${trailingLength}D`);
318
- };
319
319
  const startReadlineRepl = async (colorize) => {
320
+ var _a;
320
321
  const rl = promises.createInterface({
321
322
  input: process.stdin,
322
323
  output: process.stdout,
323
- prompt: "> ",
324
+ prompt: colorize ? colorize("> ") : "> ",
324
325
  completer: completeBunReplInput
325
326
  });
326
327
  rl.prompt();
@@ -335,11 +336,16 @@ const startReadlineRepl = async (colorize) => {
335
336
  }
336
337
  try {
337
338
  const result = await evaluateBunReplInput(source);
338
- if (result !== void 0) console.dir(result, { depth: 6 });
339
+ process.stdout.write(
340
+ `${node_util.inspect(result, { depth: 6, colors: process.stdout.isTTY })}
341
+ `
342
+ );
339
343
  } catch (error2) {
340
- console.error(error2);
344
+ process.stdout.write(
345
+ `${error2 instanceof Error ? (_a = error2.stack) != null ? _a : error2.message : String(error2)}
346
+ `
347
+ );
341
348
  }
342
- if (colorize) process.stdout.write(colorize(""));
343
349
  rl.prompt();
344
350
  }
345
351
  } catch (temp) {
@@ -355,172 +361,37 @@ const startReadlineRepl = async (colorize) => {
355
361
  rl.close();
356
362
  };
357
363
  const startBunRepl = async (colorize) => {
358
- if (!process.stdin.isTTY || !process.stdin.setRawMode) {
359
- await startReadlineRepl(colorize);
360
- return;
361
- }
362
- const prompt = "> ";
363
- const history = [];
364
- let line = "";
365
- let cursor = 0;
366
- let historyIndex = 0;
367
- let draft = "";
368
- let pending = Promise.resolve();
369
- const resetHistory = () => {
370
- historyIndex = history.length;
371
- draft = "";
372
- };
373
- const setLine = (nextLine) => {
374
- line = nextLine;
375
- cursor = line.length;
376
- renderBunReplLine(prompt, line, cursor, colorize);
377
- };
378
- const insertText = (text) => {
379
- line = line.slice(0, cursor) + text + line.slice(cursor);
380
- cursor += text.length;
381
- renderBunReplLine(prompt, line, cursor, colorize);
382
- };
383
- const applyCompletion = () => {
384
- const linePrefix = line.slice(0, cursor);
385
- const [matches, token] = completeBunReplInput(linePrefix);
386
- const completion = matches.length === 1 ? matches[0] : getSharedCompletion(matches);
387
- if (completion && completion !== token) {
388
- line = line.slice(0, cursor - token.length) + completion + line.slice(cursor);
389
- cursor += completion.length - token.length;
390
- renderBunReplLine(prompt, line, cursor, colorize);
391
- return;
392
- }
393
- if (matches.length > 1) {
394
- process.stdout.write(`
395
- ${matches.join(" ")}
396
- `);
397
- renderBunReplLine(prompt, line, cursor, colorize);
398
- }
399
- };
400
- const evaluateLine = async () => {
401
- process.stdout.write("\n");
402
- const source = line.trim();
403
- if (source === ".exit") return false;
404
- if (source) {
405
- history.push(source);
406
- try {
407
- const result = await evaluateBunReplInput(source);
408
- if (result !== void 0) console.dir(result, { depth: 6 });
409
- } catch (error) {
410
- console.error(error);
411
- }
412
- }
413
- line = "";
414
- cursor = 0;
415
- resetHistory();
416
- renderBunReplLine(prompt, line, cursor, colorize);
417
- return true;
418
- };
419
- const handleKey = async (input, key) => {
420
- var _a, _b;
421
- if (key.ctrl && key.name === "c") return false;
422
- if (key.name === "return" || key.name === "enter") return await evaluateLine();
423
- if (key.ctrl && key.name === "d" && !line) return false;
424
- if (key.name === "tab") {
425
- applyCompletion();
426
- return true;
427
- }
428
- if (key.name === "backspace") {
429
- if (cursor === 0) return true;
430
- line = line.slice(0, cursor - 1) + line.slice(cursor);
431
- cursor -= 1;
432
- renderBunReplLine(prompt, line, cursor, colorize);
433
- return true;
434
- }
435
- if (key.name === "delete") {
436
- if (cursor >= line.length) return true;
437
- line = line.slice(0, cursor) + line.slice(cursor + 1);
438
- renderBunReplLine(prompt, line, cursor, colorize);
439
- return true;
440
- }
441
- if (key.name === "left") {
442
- if (cursor > 0) cursor -= 1;
443
- renderBunReplLine(prompt, line, cursor, colorize);
444
- return true;
445
- }
446
- if (key.name === "right") {
447
- if (cursor < line.length) cursor += 1;
448
- renderBunReplLine(prompt, line, cursor, colorize);
449
- return true;
450
- }
451
- if (key.name === "home") {
452
- cursor = 0;
453
- renderBunReplLine(prompt, line, cursor, colorize);
454
- return true;
455
- }
456
- if (key.name === "end") {
457
- cursor = line.length;
458
- renderBunReplLine(prompt, line, cursor, colorize);
459
- return true;
460
- }
461
- if (key.name === "up") {
462
- if (historyIndex === history.length) draft = line;
463
- if (historyIndex > 0) historyIndex -= 1;
464
- setLine((_a = history[historyIndex]) != null ? _a : draft);
465
- return true;
466
- }
467
- if (key.name === "down") {
468
- if (historyIndex < history.length) historyIndex += 1;
469
- setLine(historyIndex === history.length ? draft : (_b = history[historyIndex]) != null ? _b : "");
470
- return true;
471
- }
472
- if (input && !key.ctrl && input >= " ") {
473
- insertText(input);
474
- resetHistory();
475
- }
476
- return true;
477
- };
478
- await new Promise((resolve) => {
479
- var _a, _b;
480
- const onKeypress = (input, key) => {
481
- pending = pending.then(async () => {
482
- const keepRunning = await handleKey(input, key);
483
- if (!keepRunning) cleanup();
484
- });
485
- };
486
- const cleanup = () => {
487
- var _a2, _b2;
488
- process.stdin.off("keypress", onKeypress);
489
- (_b2 = (_a2 = process.stdin).setRawMode) == null ? void 0 : _b2.call(_a2, false);
490
- process.stdin.pause();
491
- process.stdout.write("\n");
492
- resolve();
493
- };
494
- node_readline.emitKeypressEvents(process.stdin);
495
- (_b = (_a = process.stdin).setRawMode) == null ? void 0 : _b.call(_a, true);
496
- process.stdin.resume();
497
- console.log("Bun dev REPL ready. Tab completes globals/properties. Type .exit to quit.");
498
- renderBunReplLine(prompt, line, cursor, colorize);
499
- process.stdin.on("keypress", onKeypress);
500
- });
364
+ await startReadlineRepl(colorize);
501
365
  };
502
366
  const startCliRepl = async (colorize) => {
503
367
  if (!("Bun" in globalThis)) {
504
368
  const repl = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('pretty-repl')); });
505
- repl.default.start({ colorize });
369
+ repl.default.start();
506
370
  return;
507
371
  }
508
372
  await startBunRepl(colorize);
509
373
  };
510
374
  commander.program.version(packageJson.version).argument("[seed]").action(async (_seed = generateRandomSeed()) => {
511
- var _a, _b, _c, _d;
375
+ var _a, _b, _c, _d, _e;
512
376
  console.clear();
513
- const seed = _seed.padStart(64, "0");
514
- console.log(gradient__default["default"](["cyan", "green"])(figlet__default["default"].textSync("Learn Card", "Big Money-ne")));
377
+ const envSeed = (_a = process.env.LEARNCARD_CLI_SEED) != null ? _a : process.env.SEED;
378
+ const seedInput = envSeed != null ? envSeed : _seed;
379
+ const seed = seedInput.padStart(64, "0");
380
+ console.log(
381
+ gradient__default["default"](["cyan", "green"])(figlet__default["default"].textSync("Learn Card", "Big Money-ne"))
382
+ );
515
383
  console.log("Welcome to the Learn Card CLI!\n");
516
384
  console.log(`Your seed is ${seed}
517
385
  `);
386
+ if (envSeed) {
387
+ console.log("Using seed from LEARNCARD_CLI_SEED / SEED.\n");
388
+ }
518
389
  console.log("Creating wallet...");
519
- globalThis.seed = seed;
520
- globalThis.generateRandomSeed = generateRandomSeed;
521
- globalThis.emptyLearnCard = init.emptyLearnCard;
522
- globalThis.learnCardFromSeed = init.learnCardFromSeed;
523
- globalThis.initLearnCard = init.initLearnCard;
390
+ cliGlobals.seed = seed;
391
+ cliGlobals.generateRandomSeed = generateRandomSeed;
392
+ cliGlobals.emptyLearnCard = init.emptyLearnCard;
393
+ cliGlobals.learnCardFromSeed = init.learnCardFromSeed;
394
+ cliGlobals.initLearnCard = init.initLearnCard;
524
395
  const didkit = fs__default["default"].readFile(
525
396
  require.resolve("@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm")
526
397
  );
@@ -533,25 +404,25 @@ commander.program.version(packageJson.version).argument("[seed]").action(async (
533
404
  const simpleSigningLc = await _learnCard.addPlugin(
534
405
  await simpleSigningPlugin.getSimpleSigningPlugin(_learnCard, "https://api.learncard.app/trpc")
535
406
  );
536
- globalThis.learnCard = await simpleSigningLc.addPlugin(lerRsPlugin.getLerRsPlugin(simpleSigningLc));
537
- globalThis.learnCard = await globalThis.learnCard.addPlugin(
538
- linkedClaimsPlugin.getLinkedClaimsPlugin(globalThis.learnCard)
407
+ cliGlobals.learnCard = await simpleSigningLc.addPlugin(lerRsPlugin.getLerRsPlugin(simpleSigningLc));
408
+ cliGlobals.learnCard = await cliGlobals.learnCard.addPlugin(
409
+ linkedClaimsPlugin.getLinkedClaimsPlugin(cliGlobals.learnCard)
539
410
  );
540
- globalThis.learnCard = await globalThis.learnCard.addPlugin(
541
- openBadgeV2Plugin.openBadgeV2Plugin(globalThis.learnCard)
411
+ cliGlobals.learnCard = await cliGlobals.learnCard.addPlugin(
412
+ openBadgeV2Plugin.openBadgeV2Plugin(cliGlobals.learnCard)
542
413
  );
543
- globalThis.learnCard = await globalThis.learnCard.addPlugin(
544
- renderMethodPlugin.getRenderMethodPlugin(globalThis.learnCard)
414
+ cliGlobals.learnCard = await cliGlobals.learnCard.addPlugin(
415
+ renderMethodPlugin.getRenderMethodPlugin(cliGlobals.learnCard)
545
416
  );
546
- globalThis.types = types__namespace;
547
- globalThis.getTestCache = core.getTestCache;
548
- globalThis.copy = copyFunction;
549
- globalThis.getLearnCardBundlePassword = getLearnCardBundlePassword;
550
- globalThis.exportLearnCardBundle = createExportLearnCardBundleHelper(
417
+ cliGlobals.types = types__namespace;
418
+ cliGlobals.getTestCache = core.getTestCache;
419
+ cliGlobals.copy = copyFunction;
420
+ cliGlobals.getLearnCardBundlePassword = getLearnCardBundlePassword;
421
+ cliGlobals.exportLearnCardBundle = createExportLearnCardBundleHelper(
551
422
  holderContinuity.exportLearnCardBundle,
552
- globalThis.learnCard
423
+ cliGlobals.learnCard
553
424
  );
554
- globalThis.restoreLearnCardFromBundle = createRestoreLearnCardFromBundleHelper(
425
+ cliGlobals.restoreLearnCardFromBundle = createRestoreLearnCardFromBundleHelper(
555
426
  holderContinuity.restoreLearnCardFromBundle,
556
427
  {
557
428
  network: true,
@@ -559,11 +430,11 @@ commander.program.version(packageJson.version).argument("[seed]").action(async (
559
430
  didkit
560
431
  }
561
432
  );
562
- globalThis.importLearnCardBundle = holderContinuity.importLearnCardBundle;
563
- globalThis.createLearnCardBundle = holderContinuity.createLearnCardBundle;
564
- globalThis.readLearnCardBundle = holderContinuity.readLearnCardBundle;
565
- (_b = (_a = process.stdout).moveCursor) == null ? void 0 : _b.call(_a, 0, -1);
566
- (_d = (_c = process.stdout).clearLine) == null ? void 0 : _d.call(_c, 1);
433
+ cliGlobals.importLearnCardBundle = holderContinuity.importLearnCardBundle;
434
+ cliGlobals.createLearnCardBundle = holderContinuity.createLearnCardBundle;
435
+ cliGlobals.readLearnCardBundle = holderContinuity.readLearnCardBundle;
436
+ (_c = (_b = process.stdout).moveCursor) == null ? void 0 : _c.call(_b, 0, -1);
437
+ (_e = (_d = process.stdout).clearLine) == null ? void 0 : _e.call(_d, 1);
567
438
  console.log("Wallet created!\n");
568
439
  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");
569
440
  console.log("\u2502 Variables Available \u2502");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@learncard/cli",
3
- "version": "3.4.7",
3
+ "version": "3.4.8",
4
4
  "description": "Command Line Interface for LearnCard",
5
5
  "main": "dist/index.js",
6
6
  "bin": "dist/index.js",
@@ -14,17 +14,17 @@
14
14
  "author": "Learning Economy Foundation (www.learningeconomy.io)",
15
15
  "license": "MIT",
16
16
  "dependencies": {
17
- "@learncard/core": "9.4.26",
18
- "@learncard/didkit-plugin": "^1.9.6",
19
- "@learncard/init": "^2.4.5",
20
- "@learncard/learn-cloud-plugin": "2.3.31",
21
- "@learncard/ler-rs-plugin": "0.1.17",
22
- "@learncard/linked-claims-plugin": "0.2.26",
23
- "@learncard/open-badge-v2-plugin": "1.1.27",
24
- "@learncard/render-method-plugin": "3.0.6",
25
- "@learncard/simple-signing-plugin": "1.1.30",
26
- "@learncard/holder-continuity": "0.2.7",
27
- "@learncard/types": "5.17.5",
17
+ "@learncard/core": "9.4.27",
18
+ "@learncard/didkit-plugin": "^1.9.7",
19
+ "@learncard/init": "^2.4.6",
20
+ "@learncard/learn-cloud-plugin": "2.3.32",
21
+ "@learncard/ler-rs-plugin": "0.1.18",
22
+ "@learncard/linked-claims-plugin": "0.2.27",
23
+ "@learncard/open-badge-v2-plugin": "1.1.28",
24
+ "@learncard/render-method-plugin": "3.0.7",
25
+ "@learncard/simple-signing-plugin": "1.1.31",
26
+ "@learncard/holder-continuity": "0.2.8",
27
+ "@learncard/types": "5.17.6",
28
28
  "@rollup/plugin-json": "^4.1.0",
29
29
  "clipboardy": "^4.0.0",
30
30
  "commander": "^9.3.0",
package/project.json CHANGED
@@ -32,11 +32,11 @@
32
32
  }
33
33
  },
34
34
  "start": {
35
- "executor": "./tools/executors/workspace:run-command",
35
+ "executor": "nx:run-commands",
36
36
  "dependsOn": ["^build"],
37
37
  "options": {
38
- "command": "bun run start",
39
- "cwd": "{root}/packages/learn-card-cli"
38
+ "command": "bun run start --",
39
+ "cwd": "{projectRoot}"
40
40
  }
41
41
  }
42
42
  }
package/src/index.tsx CHANGED
@@ -1,8 +1,8 @@
1
1
  import fs from 'fs/promises';
2
2
  import dns from 'node:dns';
3
- import { emitKeypressEvents } from 'node:readline';
4
3
  import { createInterface } from 'node:readline/promises';
5
4
  import { Writable } from 'node:stream';
5
+ import { inspect } from 'node:util';
6
6
 
7
7
  import { getTestCache } from '@learncard/core';
8
8
  import { initLearnCard, emptyLearnCard, learnCardFromSeed } from '@learncard/init';
@@ -35,13 +35,28 @@ import packageJson from '../package.json';
35
35
 
36
36
  dns.setDefaultResultOrder('ipv4first');
37
37
 
38
- type ReplCompletion = [string[], string];
39
- type ReplKey = {
40
- ctrl?: boolean;
41
- name?: string;
42
- sequence?: string;
38
+ type CliGlobals = {
39
+ seed: string;
40
+ generateRandomSeed: typeof generateRandomSeed;
41
+ emptyLearnCard: typeof emptyLearnCard;
42
+ learnCardFromSeed: typeof learnCardFromSeed;
43
+ initLearnCard: typeof initLearnCard;
44
+ learnCard: any;
45
+ types: typeof types;
46
+ getTestCache: typeof getTestCache;
47
+ copy: typeof copyFunction;
48
+ getLearnCardBundlePassword: typeof getLearnCardBundlePassword;
49
+ exportLearnCardBundle: ReturnType<typeof createExportLearnCardBundleHelper>;
50
+ importLearnCardBundle: typeof importLearnCardBundle;
51
+ createLearnCardBundle: typeof createLearnCardBundle;
52
+ readLearnCardBundle: typeof readLearnCardBundle;
53
+ restoreLearnCardFromBundle: ReturnType<typeof createRestoreLearnCardFromBundleHelper>;
43
54
  };
44
55
 
56
+ const cliGlobals = globalThis as typeof globalThis & CliGlobals;
57
+
58
+ type ReplCompletion = [string[], string];
59
+
45
60
  const replGlobals = [
46
61
  'learnCard',
47
62
  'emptyLearnCard',
@@ -147,7 +162,10 @@ const parseGlobalAssignment = (
147
162
 
148
163
  if (!match) return;
149
164
 
150
- const [, name, initializer] = match;
165
+ const name = match[1];
166
+ const initializer = match[2];
167
+
168
+ if (!name || !initializer) return;
151
169
 
152
170
  return { name, initializer };
153
171
  };
@@ -218,10 +236,28 @@ const completeBunReplInput = (line: string): ReplCompletion => {
218
236
  };
219
237
 
220
238
  const evaluateBunReplInput = async (source: string): Promise<unknown> => {
239
+ const trimmedSource = source.trim();
240
+ const expressionSource = trimmedSource.replace(/;+\s*$/, '');
241
+ const statements = trimmedSource
242
+ .split(';')
243
+ .map(statement => statement.trim())
244
+ .filter(Boolean);
245
+
221
246
  try {
222
- return await globalThis.eval(`(async () => (${source}))()`);
247
+ return await globalThis.eval(`(async () => (${expressionSource}))()`);
223
248
  } catch {
224
- const globalAssignment = parseGlobalAssignment(source);
249
+ if (statements.length > 1) {
250
+ const lastStatement = statements[statements.length - 1];
251
+
252
+ if (lastStatement && !/^(?:const|let|var)\b/.test(lastStatement)) {
253
+ const body = statements.slice(0, -1).join(';\n');
254
+ const wrappedSource = `${body ? `${body};\n` : ''}return (${lastStatement});`;
255
+
256
+ return await globalThis.eval(`(async () => { ${wrappedSource} })()`);
257
+ }
258
+ }
259
+
260
+ const globalAssignment = parseGlobalAssignment(trimmedSource);
225
261
 
226
262
  if (globalAssignment) {
227
263
  const value = await globalThis.eval(
@@ -231,42 +267,15 @@ const evaluateBunReplInput = async (source: string): Promise<unknown> => {
231
267
  return value;
232
268
  }
233
269
 
234
- return await globalThis.eval(`(async () => { ${source} })()`);
270
+ return await globalThis.eval(`(async () => { ${trimmedSource} })()`);
235
271
  }
236
272
  };
237
273
 
238
- const getSharedCompletion = (matches: string[]): string | undefined => {
239
- if (!matches.length) return;
240
-
241
- return matches.reduce((prefix, match) => {
242
- let index = 0;
243
-
244
- while (index < prefix.length && prefix[index] === match[index]) index += 1;
245
-
246
- return prefix.slice(0, index);
247
- });
248
- };
249
-
250
- const renderBunReplLine = (
251
- prompt: string,
252
- line: string,
253
- cursor: number,
254
- colorize: (input: string) => string
255
- ): void => {
256
- process.stdout.clearLine(0);
257
- process.stdout.cursorTo(0);
258
- process.stdout.write(prompt + colorize(line));
259
-
260
- const trailingLength = line.length - cursor;
261
-
262
- if (trailingLength > 0) process.stdout.write(`\x1b[${trailingLength}D`);
263
- };
264
-
265
274
  const startReadlineRepl = async (colorize?: (input: string) => string): Promise<void> => {
266
275
  const rl = createInterface({
267
276
  input: process.stdin,
268
277
  output: process.stdout,
269
- prompt: '> ',
278
+ prompt: colorize ? colorize('> ') : '> ',
270
279
  completer: completeBunReplInput,
271
280
  });
272
281
 
@@ -286,13 +295,15 @@ const startReadlineRepl = async (colorize?: (input: string) => string): Promise<
286
295
  try {
287
296
  const result = await evaluateBunReplInput(source);
288
297
 
289
- if (result !== undefined) console.dir(result, { depth: 6 });
298
+ process.stdout.write(
299
+ `${inspect(result, { depth: 6, colors: process.stdout.isTTY })}\n`
300
+ );
290
301
  } catch (error) {
291
- console.error(error);
302
+ process.stdout.write(
303
+ `${error instanceof Error ? error.stack ?? error.message : String(error)}\n`
304
+ );
292
305
  }
293
306
 
294
- if (colorize) process.stdout.write(colorize(''));
295
-
296
307
  rl.prompt();
297
308
  }
298
309
 
@@ -300,203 +311,14 @@ const startReadlineRepl = async (colorize?: (input: string) => string): Promise<
300
311
  };
301
312
 
302
313
  const startBunRepl = async (colorize: (input: string) => string): Promise<void> => {
303
- if (!process.stdin.isTTY || !process.stdin.setRawMode) {
304
- await startReadlineRepl(colorize);
305
-
306
- return;
307
- }
308
-
309
- const prompt = '> ';
310
- const history: string[] = [];
311
-
312
- let line = '';
313
- let cursor = 0;
314
- let historyIndex = 0;
315
- let draft = '';
316
- let pending = Promise.resolve();
317
-
318
- const resetHistory = (): void => {
319
- historyIndex = history.length;
320
- draft = '';
321
- };
322
-
323
- const setLine = (nextLine: string): void => {
324
- line = nextLine;
325
- cursor = line.length;
326
- renderBunReplLine(prompt, line, cursor, colorize);
327
- };
328
-
329
- const insertText = (text: string): void => {
330
- line = line.slice(0, cursor) + text + line.slice(cursor);
331
- cursor += text.length;
332
- renderBunReplLine(prompt, line, cursor, colorize);
333
- };
334
-
335
- const applyCompletion = (): void => {
336
- const linePrefix = line.slice(0, cursor);
337
- const [matches, token] = completeBunReplInput(linePrefix);
338
- const completion = matches.length === 1 ? matches[0] : getSharedCompletion(matches);
339
-
340
- if (completion && completion !== token) {
341
- line = line.slice(0, cursor - token.length) + completion + line.slice(cursor);
342
- cursor += completion.length - token.length;
343
- renderBunReplLine(prompt, line, cursor, colorize);
344
-
345
- return;
346
- }
347
-
348
- if (matches.length > 1) {
349
- process.stdout.write(`\n${matches.join(' ')}\n`);
350
- renderBunReplLine(prompt, line, cursor, colorize);
351
- }
352
- };
353
-
354
- const evaluateLine = async (): Promise<boolean> => {
355
- process.stdout.write('\n');
356
-
357
- const source = line.trim();
358
-
359
- if (source === '.exit') return false;
360
-
361
- if (source) {
362
- history.push(source);
363
-
364
- try {
365
- const result = await evaluateBunReplInput(source);
366
-
367
- if (result !== undefined) console.dir(result, { depth: 6 });
368
- } catch (error) {
369
- console.error(error);
370
- }
371
- }
372
-
373
- line = '';
374
- cursor = 0;
375
- resetHistory();
376
- renderBunReplLine(prompt, line, cursor, colorize);
377
-
378
- return true;
379
- };
380
-
381
- const handleKey = async (input: string, key: ReplKey): Promise<boolean> => {
382
- if (key.ctrl && key.name === 'c') return false;
383
-
384
- if (key.name === 'return' || key.name === 'enter') return await evaluateLine();
385
-
386
- if (key.ctrl && key.name === 'd' && !line) return false;
387
-
388
- if (key.name === 'tab') {
389
- applyCompletion();
390
-
391
- return true;
392
- }
393
-
394
- if (key.name === 'backspace') {
395
- if (cursor === 0) return true;
396
-
397
- line = line.slice(0, cursor - 1) + line.slice(cursor);
398
- cursor -= 1;
399
- renderBunReplLine(prompt, line, cursor, colorize);
400
-
401
- return true;
402
- }
403
-
404
- if (key.name === 'delete') {
405
- if (cursor >= line.length) return true;
406
-
407
- line = line.slice(0, cursor) + line.slice(cursor + 1);
408
- renderBunReplLine(prompt, line, cursor, colorize);
409
-
410
- return true;
411
- }
412
-
413
- if (key.name === 'left') {
414
- if (cursor > 0) cursor -= 1;
415
-
416
- renderBunReplLine(prompt, line, cursor, colorize);
417
-
418
- return true;
419
- }
420
-
421
- if (key.name === 'right') {
422
- if (cursor < line.length) cursor += 1;
423
-
424
- renderBunReplLine(prompt, line, cursor, colorize);
425
-
426
- return true;
427
- }
428
-
429
- if (key.name === 'home') {
430
- cursor = 0;
431
- renderBunReplLine(prompt, line, cursor, colorize);
432
-
433
- return true;
434
- }
435
-
436
- if (key.name === 'end') {
437
- cursor = line.length;
438
- renderBunReplLine(prompt, line, cursor, colorize);
439
-
440
- return true;
441
- }
442
-
443
- if (key.name === 'up') {
444
- if (historyIndex === history.length) draft = line;
445
- if (historyIndex > 0) historyIndex -= 1;
446
-
447
- setLine(history[historyIndex] ?? draft);
448
-
449
- return true;
450
- }
451
-
452
- if (key.name === 'down') {
453
- if (historyIndex < history.length) historyIndex += 1;
454
-
455
- setLine(historyIndex === history.length ? draft : history[historyIndex] ?? '');
456
-
457
- return true;
458
- }
459
-
460
- if (input && !key.ctrl && input >= ' ') {
461
- insertText(input);
462
- resetHistory();
463
- }
464
-
465
- return true;
466
- };
467
-
468
- await new Promise<void>(resolve => {
469
- const onKeypress = (input: string, key: ReplKey): void => {
470
- pending = pending.then(async () => {
471
- const keepRunning = await handleKey(input, key);
472
-
473
- if (!keepRunning) cleanup();
474
- });
475
- };
476
-
477
- const cleanup = (): void => {
478
- process.stdin.off('keypress', onKeypress);
479
- process.stdin.setRawMode?.(false);
480
- process.stdin.pause();
481
- process.stdout.write('\n');
482
- resolve();
483
- };
484
-
485
- emitKeypressEvents(process.stdin);
486
- process.stdin.setRawMode?.(true);
487
- process.stdin.resume();
488
-
489
- console.log('Bun dev REPL ready. Tab completes globals/properties. Type .exit to quit.');
490
- renderBunReplLine(prompt, line, cursor, colorize);
491
- process.stdin.on('keypress', onKeypress);
492
- });
314
+ await startReadlineRepl(colorize);
493
315
  };
494
316
 
495
317
  const startCliRepl = async (colorize: (input: string) => string): Promise<void> => {
496
318
  if (!('Bun' in globalThis)) {
497
319
  const repl = await import('pretty-repl');
498
320
 
499
- repl.default.start({ colorize });
321
+ repl.default.start();
500
322
 
501
323
  return;
502
324
  }
@@ -510,20 +332,28 @@ program
510
332
  .action(async (_seed: string = generateRandomSeed()) => {
511
333
  console.clear();
512
334
 
513
- const seed = _seed.padStart(64, '0');
335
+ const envSeed = process.env.LEARNCARD_CLI_SEED ?? process.env.SEED;
336
+ const seedInput = envSeed ?? _seed;
337
+ const seed = seedInput.padStart(64, '0');
514
338
 
515
- console.log(gradient(['cyan', 'green'])(figlet.textSync('Learn Card', 'Big Money-ne')));
339
+ console.log(
340
+ gradient(['cyan', 'green'])(figlet.textSync('Learn Card', 'Big Money-ne' as any))
341
+ );
516
342
  console.log('Welcome to the Learn Card CLI!\n');
517
343
 
518
344
  console.log(`Your seed is ${seed}\n`);
519
345
 
346
+ if (envSeed) {
347
+ console.log('Using seed from LEARNCARD_CLI_SEED / SEED.\n');
348
+ }
349
+
520
350
  console.log('Creating wallet...');
521
351
 
522
- globalThis.seed = seed;
523
- globalThis.generateRandomSeed = generateRandomSeed;
524
- globalThis.emptyLearnCard = emptyLearnCard;
525
- globalThis.learnCardFromSeed = learnCardFromSeed;
526
- globalThis.initLearnCard = initLearnCard;
352
+ cliGlobals.seed = seed;
353
+ cliGlobals.generateRandomSeed = generateRandomSeed;
354
+ cliGlobals.emptyLearnCard = emptyLearnCard;
355
+ cliGlobals.learnCardFromSeed = learnCardFromSeed;
356
+ cliGlobals.initLearnCard = initLearnCard;
527
357
 
528
358
  const didkit = fs.readFile(
529
359
  require.resolve('@learncard/didkit-plugin/dist/didkit/didkit_wasm_bg.wasm')
@@ -537,36 +367,36 @@ program
537
367
  });
538
368
 
539
369
  const simpleSigningLc = await _learnCard.addPlugin(
540
- await getSimpleSigningPlugin(_learnCard, 'https://api.learncard.app/trpc')
370
+ await getSimpleSigningPlugin(_learnCard as any, 'https://api.learncard.app/trpc')
541
371
  );
542
372
 
543
- globalThis.learnCard = await simpleSigningLc.addPlugin(getLerRsPlugin(simpleSigningLc));
373
+ cliGlobals.learnCard = await simpleSigningLc.addPlugin(getLerRsPlugin(simpleSigningLc));
544
374
  // Add LinkedClaims plugin so endorse/verify/store/getEndorsements are available in the CLI
545
- globalThis.learnCard = await globalThis.learnCard.addPlugin(
546
- getLinkedClaimsPlugin(globalThis.learnCard)
375
+ cliGlobals.learnCard = await cliGlobals.learnCard.addPlugin(
376
+ getLinkedClaimsPlugin(cliGlobals.learnCard)
547
377
  );
548
378
 
549
379
  // Add OpenBadge v2 wrapper plugin for backwards-compatible OBv2 -> VC wrapping
550
- globalThis.learnCard = await globalThis.learnCard.addPlugin(
551
- openBadgeV2Plugin(globalThis.learnCard)
380
+ cliGlobals.learnCard = await cliGlobals.learnCard.addPlugin(
381
+ openBadgeV2Plugin(cliGlobals.learnCard)
552
382
  );
553
383
 
554
384
  // Add Render Method plugin for attaching W3C renderMethod to VCs
555
- globalThis.learnCard = await globalThis.learnCard.addPlugin(
556
- getRenderMethodPlugin(globalThis.learnCard)
385
+ cliGlobals.learnCard = await cliGlobals.learnCard.addPlugin(
386
+ getRenderMethodPlugin(cliGlobals.learnCard)
557
387
  );
558
388
 
559
- globalThis.types = types;
560
- globalThis.getTestCache = getTestCache;
389
+ cliGlobals.types = types;
390
+ cliGlobals.getTestCache = getTestCache;
561
391
 
562
- globalThis.copy = copyFunction;
563
- globalThis.getLearnCardBundlePassword = getLearnCardBundlePassword;
564
- globalThis.exportLearnCardBundle = createExportLearnCardBundleHelper(
392
+ cliGlobals.copy = copyFunction;
393
+ cliGlobals.getLearnCardBundlePassword = getLearnCardBundlePassword;
394
+ cliGlobals.exportLearnCardBundle = createExportLearnCardBundleHelper(
565
395
  writeLearnCardBundle,
566
- globalThis.learnCard
396
+ cliGlobals.learnCard
567
397
  );
568
398
 
569
- globalThis.restoreLearnCardFromBundle = createRestoreLearnCardFromBundleHelper(
399
+ cliGlobals.restoreLearnCardFromBundle = createRestoreLearnCardFromBundleHelper(
570
400
  restoreBundle,
571
401
  {
572
402
  network: true,
@@ -574,9 +404,9 @@ program
574
404
  didkit,
575
405
  }
576
406
  );
577
- globalThis.importLearnCardBundle = importLearnCardBundle;
578
- globalThis.createLearnCardBundle = createLearnCardBundle;
579
- globalThis.readLearnCardBundle = readLearnCardBundle;
407
+ cliGlobals.importLearnCardBundle = importLearnCardBundle;
408
+ cliGlobals.createLearnCardBundle = createLearnCardBundle;
409
+ cliGlobals.readLearnCardBundle = readLearnCardBundle;
580
410
 
581
411
  // delete 'Creating wallet...' message
582
412
  process.stdout.moveCursor?.(0, -1);
package/src/types.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ declare module 'gradient-string' {
2
+ const gradient: (...args: any[]) => any;
3
+ export default gradient;
4
+ }
5
+
6
+ declare module '@learncard/holder-continuity' {
7
+ export type ExportLearnCardBundleOptions = any;
8
+ export type LearnCardBundleWallet = any;
9
+ export type RestoreLearnCardFromBundleOptions = any;
10
+ export type RestoreLearnCardInit = any;
11
+
12
+ export const createLearnCardBundle: any;
13
+ export const exportLearnCardBundle: any;
14
+ export const importLearnCardBundle: any;
15
+ export const readLearnCardBundle: any;
16
+ export const restoreLearnCardFromBundle: any;
17
+ }