@sundaeswap/sprinkles 0.4.0 → 0.6.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/dist/cjs/Sprinkle/__tests__/encryption.test.js +22 -8
- package/dist/cjs/Sprinkle/__tests__/encryption.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/enhancements.test.js +37 -46
- package/dist/cjs/Sprinkle/__tests__/enhancements.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/field-utils.test.js +170 -0
- package/dist/cjs/Sprinkle/__tests__/field-utils.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +283 -81
- package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/formatting.test.js +97 -0
- package/dist/cjs/Sprinkle/__tests__/formatting.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/show-menu.test.js +97 -7
- package/dist/cjs/Sprinkle/__tests__/show-menu.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/tx-dialog.test.js +30 -0
- package/dist/cjs/Sprinkle/__tests__/tx-dialog.test.js.map +1 -1
- package/dist/cjs/Sprinkle/encryption.js +131 -0
- package/dist/cjs/Sprinkle/encryption.js.map +1 -0
- package/dist/cjs/Sprinkle/index.js +427 -438
- package/dist/cjs/Sprinkle/index.js.map +1 -1
- package/dist/cjs/Sprinkle/menus/array-menu.js +195 -0
- package/dist/cjs/Sprinkle/menus/array-menu.js.map +1 -0
- package/dist/cjs/Sprinkle/menus/field-menu.js +161 -0
- package/dist/cjs/Sprinkle/menus/field-menu.js.map +1 -0
- package/dist/cjs/Sprinkle/menus/index.js +33 -0
- package/dist/cjs/Sprinkle/menus/index.js.map +1 -0
- package/dist/cjs/Sprinkle/menus/object-menu.js +324 -0
- package/dist/cjs/Sprinkle/menus/object-menu.js.map +1 -0
- package/dist/cjs/Sprinkle/prompts.js +459 -0
- package/dist/cjs/Sprinkle/prompts.js.map +1 -0
- package/dist/cjs/Sprinkle/schemas.js +97 -0
- package/dist/cjs/Sprinkle/schemas.js.map +1 -0
- package/dist/cjs/Sprinkle/tx-dialog.js +101 -0
- package/dist/cjs/Sprinkle/tx-dialog.js.map +1 -0
- package/dist/cjs/Sprinkle/type-guards.js +89 -0
- package/dist/cjs/Sprinkle/type-guards.js.map +1 -0
- package/dist/cjs/Sprinkle/types.js +73 -0
- package/dist/cjs/Sprinkle/types.js.map +1 -0
- package/dist/cjs/Sprinkle/utils/field-utils.js +154 -0
- package/dist/cjs/Sprinkle/utils/field-utils.js.map +1 -0
- package/dist/cjs/Sprinkle/utils/formatting.js +126 -0
- package/dist/cjs/Sprinkle/utils/formatting.js.map +1 -0
- package/dist/cjs/Sprinkle/utils/index.js +56 -0
- package/dist/cjs/Sprinkle/utils/index.js.map +1 -0
- package/dist/cjs/Sprinkle/wallet.js +98 -0
- package/dist/cjs/Sprinkle/wallet.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/encryption.test.js +22 -8
- package/dist/esm/Sprinkle/__tests__/encryption.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/enhancements.test.js +37 -46
- package/dist/esm/Sprinkle/__tests__/enhancements.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/field-utils.test.js +168 -0
- package/dist/esm/Sprinkle/__tests__/field-utils.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +284 -82
- package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/formatting.test.js +95 -0
- package/dist/esm/Sprinkle/__tests__/formatting.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/show-menu.test.js +98 -8
- package/dist/esm/Sprinkle/__tests__/show-menu.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/tx-dialog.test.js +30 -0
- package/dist/esm/Sprinkle/__tests__/tx-dialog.test.js.map +1 -1
- package/dist/esm/Sprinkle/encryption.js +117 -0
- package/dist/esm/Sprinkle/encryption.js.map +1 -0
- package/dist/esm/Sprinkle/index.js +248 -425
- package/dist/esm/Sprinkle/index.js.map +1 -1
- package/dist/esm/Sprinkle/menus/array-menu.js +190 -0
- package/dist/esm/Sprinkle/menus/array-menu.js.map +1 -0
- package/dist/esm/Sprinkle/menus/field-menu.js +155 -0
- package/dist/esm/Sprinkle/menus/field-menu.js.map +1 -0
- package/dist/esm/Sprinkle/menus/index.js +8 -0
- package/dist/esm/Sprinkle/menus/index.js.map +1 -0
- package/dist/esm/Sprinkle/menus/object-menu.js +318 -0
- package/dist/esm/Sprinkle/menus/object-menu.js.map +1 -0
- package/dist/esm/Sprinkle/prompts.js +443 -0
- package/dist/esm/Sprinkle/prompts.js.map +1 -0
- package/dist/esm/Sprinkle/schemas.js +91 -0
- package/dist/esm/Sprinkle/schemas.js.map +1 -0
- package/dist/esm/Sprinkle/tx-dialog.js +90 -0
- package/dist/esm/Sprinkle/tx-dialog.js.map +1 -0
- package/dist/esm/Sprinkle/type-guards.js +66 -0
- package/dist/esm/Sprinkle/type-guards.js.map +1 -0
- package/dist/esm/Sprinkle/types.js +66 -0
- package/dist/esm/Sprinkle/types.js.map +1 -0
- package/dist/esm/Sprinkle/utils/field-utils.js +145 -0
- package/dist/esm/Sprinkle/utils/field-utils.js.map +1 -0
- package/dist/esm/Sprinkle/utils/formatting.js +118 -0
- package/dist/esm/Sprinkle/utils/formatting.js.map +1 -0
- package/dist/esm/Sprinkle/utils/index.js +7 -0
- package/dist/esm/Sprinkle/utils/index.js.map +1 -0
- package/dist/esm/Sprinkle/wallet.js +90 -0
- package/dist/esm/Sprinkle/wallet.js.map +1 -0
- package/dist/types/Sprinkle/encryption.d.ts +43 -0
- package/dist/types/Sprinkle/encryption.d.ts.map +1 -0
- package/dist/types/Sprinkle/index.d.ts +17 -177
- package/dist/types/Sprinkle/index.d.ts.map +1 -1
- package/dist/types/Sprinkle/menus/array-menu.d.ts +31 -0
- package/dist/types/Sprinkle/menus/array-menu.d.ts.map +1 -0
- package/dist/types/Sprinkle/menus/field-menu.d.ts +34 -0
- package/dist/types/Sprinkle/menus/field-menu.d.ts.map +1 -0
- package/dist/types/Sprinkle/menus/index.d.ts +10 -0
- package/dist/types/Sprinkle/menus/index.d.ts.map +1 -0
- package/dist/types/Sprinkle/menus/object-menu.d.ts +34 -0
- package/dist/types/Sprinkle/menus/object-menu.d.ts.map +1 -0
- package/dist/types/Sprinkle/prompts.d.ts +119 -0
- package/dist/types/Sprinkle/prompts.d.ts.map +1 -0
- package/dist/types/Sprinkle/schemas.d.ts +125 -0
- package/dist/types/Sprinkle/schemas.d.ts.map +1 -0
- package/dist/types/Sprinkle/tx-dialog.d.ts +37 -0
- package/dist/types/Sprinkle/tx-dialog.d.ts.map +1 -0
- package/dist/types/Sprinkle/type-guards.d.ts +45 -0
- package/dist/types/Sprinkle/type-guards.d.ts.map +1 -0
- package/dist/types/Sprinkle/types.d.ts +115 -0
- package/dist/types/Sprinkle/types.d.ts.map +1 -0
- package/dist/types/Sprinkle/utils/field-utils.d.ts +47 -0
- package/dist/types/Sprinkle/utils/field-utils.d.ts.map +1 -0
- package/dist/types/Sprinkle/utils/formatting.d.ts +30 -0
- package/dist/types/Sprinkle/utils/formatting.d.ts.map +1 -0
- package/dist/types/Sprinkle/wallet.d.ts +27 -0
- package/dist/types/Sprinkle/wallet.d.ts.map +1 -0
- package/dist/types/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/Sprinkle/__tests__/encryption.test.ts +23 -8
- package/src/Sprinkle/__tests__/enhancements.test.ts +34 -47
- package/src/Sprinkle/__tests__/field-utils.test.ts +191 -0
- package/src/Sprinkle/__tests__/fill-in-struct.test.ts +301 -86
- package/src/Sprinkle/__tests__/formatting.test.ts +115 -0
- package/src/Sprinkle/__tests__/show-menu.test.ts +102 -8
- package/src/Sprinkle/__tests__/tx-dialog.test.ts +30 -0
- package/src/Sprinkle/encryption.ts +130 -0
- package/src/Sprinkle/index.ts +368 -598
- package/src/Sprinkle/menus/array-menu.ts +191 -0
- package/src/Sprinkle/menus/field-menu.ts +145 -0
- package/src/Sprinkle/menus/index.ts +12 -0
- package/src/Sprinkle/menus/object-menu.ts +336 -0
- package/src/Sprinkle/prompts.ts +551 -0
- package/src/Sprinkle/schemas.ts +111 -0
- package/src/Sprinkle/tx-dialog.ts +100 -0
- package/src/Sprinkle/type-guards.ts +93 -0
- package/src/Sprinkle/types.ts +116 -0
- package/src/Sprinkle/utils/field-utils.ts +158 -0
- package/src/Sprinkle/utils/formatting.ts +127 -0
- package/src/Sprinkle/utils/index.ts +17 -0
- package/src/Sprinkle/wallet.ts +133 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["_formatting","require","_fieldUtils"],"sources":["../../../../src/Sprinkle/utils/index.ts"],"sourcesContent":["/**\n * Utility functions for menu-based struct editing.\n */\n\nexport {\n formatValuePreview,\n formatPath,\n formatBreadcrumb,\n} from \"./formatting.js\";\n\nexport {\n countRequiredFields,\n isFieldRequired,\n buildFieldLabel,\n getInitialFieldState,\n allRequiredFieldsFilled,\n} from \"./field-utils.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,IAAAA,WAAA,GAAAC,OAAA;AAMA,IAAAC,WAAA,GAAAD,OAAA","ignoreList":[]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.GetBlaze = GetBlaze;
|
|
7
|
+
exports.GetProvider = GetProvider;
|
|
8
|
+
exports.GetWallet = GetWallet;
|
|
9
|
+
exports.generateWalletFromMnemonic = generateWalletFromMnemonic;
|
|
10
|
+
var _query = require("@blaze-cardano/query");
|
|
11
|
+
var _sdk = require("@blaze-cardano/sdk");
|
|
12
|
+
var _core = require("@blaze-cardano/core");
|
|
13
|
+
var _prompts = require("./prompts.js");
|
|
14
|
+
var _types = require("./types.js");
|
|
15
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } /**
|
|
16
|
+
* Wallet and provider setup utilities.
|
|
17
|
+
* Functions for creating providers, wallets, and Blaze instances.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Creates a blockchain data provider based on settings.
|
|
21
|
+
*/
|
|
22
|
+
async function GetProvider(network, settings) {
|
|
23
|
+
switch (settings.type) {
|
|
24
|
+
case "blockfrost":
|
|
25
|
+
return new _query.Blockfrost({
|
|
26
|
+
network: `cardano-${network}`,
|
|
27
|
+
projectId: settings.projectId
|
|
28
|
+
});
|
|
29
|
+
case "maestro":
|
|
30
|
+
// Dynamic import - Maestro may or may not be exported depending on @blaze-cardano/query version
|
|
31
|
+
const queryModule = await Promise.resolve().then(() => _interopRequireWildcard(require("@blaze-cardano/query")));
|
|
32
|
+
if (!queryModule.Maestro) {
|
|
33
|
+
throw new Error("Maestro is not available in the installed version of @blaze-cardano/query. Please install a version that includes Maestro support.");
|
|
34
|
+
}
|
|
35
|
+
return new queryModule.Maestro({
|
|
36
|
+
network: network,
|
|
37
|
+
apiKey: settings.apiKey
|
|
38
|
+
});
|
|
39
|
+
default:
|
|
40
|
+
throw new Error("Invalid provider type");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Creates a wallet instance based on settings.
|
|
46
|
+
*/
|
|
47
|
+
async function GetWallet(settings, provider) {
|
|
48
|
+
switch (settings.type) {
|
|
49
|
+
case "hot":
|
|
50
|
+
return _sdk.HotWallet.fromMasterkey(_sdk.Core.Bip32PrivateKeyHex(settings.privateKey), provider, provider.network);
|
|
51
|
+
case "cold":
|
|
52
|
+
return new _sdk.ColdWallet(_sdk.Core.Address.fromBech32(settings.address), provider.network, provider);
|
|
53
|
+
default:
|
|
54
|
+
throw new Error("Invalid wallet type");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates a Blaze instance with provider and wallet.
|
|
60
|
+
*/
|
|
61
|
+
async function GetBlaze(network, providerSettings, walletSettings) {
|
|
62
|
+
const provider = await GetProvider(network, providerSettings);
|
|
63
|
+
const wallet = await GetWallet(walletSettings, provider);
|
|
64
|
+
return _sdk.Blaze.from(provider, wallet);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Generates a new wallet from a BIP39 mnemonic phrase.
|
|
69
|
+
* Displays the 24-word recovery phrase and requires user confirmation.
|
|
70
|
+
* @returns The Bip32PrivateKey hex string for storage
|
|
71
|
+
*/
|
|
72
|
+
async function generateWalletFromMnemonic() {
|
|
73
|
+
const mnemonic = _sdk.Core.generateMnemonic(_core.wordlist, 256); // 24 words
|
|
74
|
+
const words = mnemonic.split(" ");
|
|
75
|
+
console.log("\n=== NEW WALLET GENERATED ===\n");
|
|
76
|
+
console.log("IMPORTANT: Save these 24 words in a secure location.");
|
|
77
|
+
console.log("This is the ONLY way to recover your wallet.\n");
|
|
78
|
+
|
|
79
|
+
// Display in 4 columns
|
|
80
|
+
for (let i = 0; i < 6; i++) {
|
|
81
|
+
console.log(`${(i + 1).toString().padStart(2)}. ${words[i].padEnd(12)} ` + `${(i + 7).toString().padStart(2)}. ${words[i + 6].padEnd(12)} ` + `${(i + 13).toString().padStart(2)}. ${words[i + 12].padEnd(12)} ` + `${(i + 19).toString().padStart(2)}. ${words[i + 18]}`);
|
|
82
|
+
}
|
|
83
|
+
console.log("");
|
|
84
|
+
const confirmed = await (0, _prompts.confirmCancellable)({
|
|
85
|
+
message: "Have you saved your recovery phrase?",
|
|
86
|
+
default: false
|
|
87
|
+
});
|
|
88
|
+
if (confirmed === null) {
|
|
89
|
+
throw new _types.UserCancelledError("Wallet generation cancelled");
|
|
90
|
+
}
|
|
91
|
+
if (!confirmed) {
|
|
92
|
+
throw new Error("Wallet generation cancelled - recovery phrase not saved");
|
|
93
|
+
}
|
|
94
|
+
const entropy = _sdk.Core.mnemonicToEntropy(mnemonic, _core.wordlist);
|
|
95
|
+
const masterKey = _sdk.Core.Bip32PrivateKey.fromBip39Entropy(Buffer.from(entropy), "");
|
|
96
|
+
return masterKey.hex();
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=wallet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wallet.js","names":["_query","require","_sdk","_core","_prompts","_types","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","GetProvider","network","settings","type","Blockfrost","projectId","queryModule","Promise","resolve","then","Maestro","Error","apiKey","GetWallet","provider","HotWallet","fromMasterkey","Core","Bip32PrivateKeyHex","privateKey","ColdWallet","Address","fromBech32","address","GetBlaze","providerSettings","walletSettings","wallet","Blaze","from","generateWalletFromMnemonic","mnemonic","generateMnemonic","wordlist","words","split","console","log","toString","padStart","padEnd","confirmed","confirmCancellable","message","UserCancelledError","entropy","mnemonicToEntropy","masterKey","Bip32PrivateKey","fromBip39Entropy","Buffer","hex"],"sources":["../../../src/Sprinkle/wallet.ts"],"sourcesContent":["/**\n * Wallet and provider setup utilities.\n * Functions for creating providers, wallets, and Blaze instances.\n */\n\nimport { Blockfrost, type Provider } from \"@blaze-cardano/query\";\nimport {\n Blaze,\n ColdWallet,\n Core,\n HotWallet,\n type Wallet,\n} from \"@blaze-cardano/sdk\";\nimport { wordlist } from \"@blaze-cardano/core\";\nimport { confirmCancellable } from \"./prompts.js\";\nimport { UserCancelledError, type TExact } from \"./types.js\";\nimport {\n NetworkSchema,\n ProviderSettingsSchema,\n WalletSettingsSchema,\n} from \"./schemas.js\";\n\n/**\n * Creates a blockchain data provider based on settings.\n */\nexport async function GetProvider(\n network: TExact<typeof NetworkSchema>,\n settings: TExact<typeof ProviderSettingsSchema>,\n): Promise<Provider> {\n switch (settings.type) {\n case \"blockfrost\":\n return new Blockfrost({\n network: `cardano-${network}`,\n projectId: settings.projectId,\n });\n case \"maestro\":\n // Dynamic import - Maestro may or may not be exported depending on @blaze-cardano/query version\n const queryModule = (await import(\"@blaze-cardano/query\")) as any;\n if (!queryModule.Maestro) {\n throw new Error(\n \"Maestro is not available in the installed version of @blaze-cardano/query. Please install a version that includes Maestro support.\",\n );\n }\n return new queryModule.Maestro({\n network: network as \"mainnet\" | \"preview\" | \"preprod\",\n apiKey: settings.apiKey,\n });\n default:\n throw new Error(\"Invalid provider type\");\n }\n}\n\n/**\n * Creates a wallet instance based on settings.\n */\nexport async function GetWallet(\n settings: TExact<typeof WalletSettingsSchema>,\n provider: Provider,\n): Promise<Wallet> {\n switch (settings.type) {\n case \"hot\":\n return HotWallet.fromMasterkey(\n Core.Bip32PrivateKeyHex(settings.privateKey),\n provider,\n provider.network,\n );\n case \"cold\":\n return new ColdWallet(\n Core.Address.fromBech32(settings.address),\n provider.network,\n provider,\n );\n default:\n throw new Error(\"Invalid wallet type\");\n }\n}\n\n/**\n * Creates a Blaze instance with provider and wallet.\n */\nexport async function GetBlaze(\n network: TExact<typeof NetworkSchema>,\n providerSettings: TExact<typeof ProviderSettingsSchema>,\n walletSettings: TExact<typeof WalletSettingsSchema>,\n): Promise<Blaze<Provider, Wallet>> {\n const provider = await GetProvider(network, providerSettings);\n const wallet = await GetWallet(walletSettings, provider);\n return Blaze.from(provider, wallet);\n}\n\n/**\n * Generates a new wallet from a BIP39 mnemonic phrase.\n * Displays the 24-word recovery phrase and requires user confirmation.\n * @returns The Bip32PrivateKey hex string for storage\n */\nexport async function generateWalletFromMnemonic(): Promise<string> {\n const mnemonic = Core.generateMnemonic(wordlist, 256); // 24 words\n const words = mnemonic.split(\" \");\n\n console.log(\"\\n=== NEW WALLET GENERATED ===\\n\");\n console.log(\"IMPORTANT: Save these 24 words in a secure location.\");\n console.log(\"This is the ONLY way to recover your wallet.\\n\");\n\n // Display in 4 columns\n for (let i = 0; i < 6; i++) {\n console.log(\n `${(i + 1).toString().padStart(2)}. ${words[i]!.padEnd(12)} ` +\n `${(i + 7).toString().padStart(2)}. ${words[i + 6]!.padEnd(12)} ` +\n `${(i + 13).toString().padStart(2)}. ${words[i + 12]!.padEnd(12)} ` +\n `${(i + 19).toString().padStart(2)}. ${words[i + 18]}`,\n );\n }\n console.log(\"\");\n\n const confirmed = await confirmCancellable({\n message: \"Have you saved your recovery phrase?\",\n default: false,\n });\n\n if (confirmed === null) {\n throw new UserCancelledError(\"Wallet generation cancelled\");\n }\n if (!confirmed) {\n throw new Error(\"Wallet generation cancelled - recovery phrase not saved\");\n }\n\n const entropy = Core.mnemonicToEntropy(mnemonic, wordlist);\n const masterKey = Core.Bip32PrivateKey.fromBip39Entropy(\n Buffer.from(entropy),\n \"\",\n );\n return masterKey.hex();\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -7,11 +7,22 @@ import { withProfile } from "./test-helpers.js";
|
|
|
7
7
|
const mockSelect = mock();
|
|
8
8
|
const mockInput = mock();
|
|
9
9
|
const mockPassword = mock();
|
|
10
|
+
const mockSelectCancellable = mock();
|
|
11
|
+
const mockInputCancellable = mock();
|
|
12
|
+
const mockPasswordCancellable = mock();
|
|
10
13
|
mock.module("@inquirer/prompts", () => ({
|
|
11
14
|
select: mockSelect,
|
|
12
15
|
input: mockInput,
|
|
13
16
|
password: mockPassword
|
|
14
17
|
}));
|
|
18
|
+
mock.module("../prompts.js", () => ({
|
|
19
|
+
selectCancellable: mockSelectCancellable,
|
|
20
|
+
inputCancellable: mockInputCancellable,
|
|
21
|
+
passwordCancellable: mockPasswordCancellable,
|
|
22
|
+
confirmCancellable: mock(),
|
|
23
|
+
searchCancellable: mock(),
|
|
24
|
+
select: mockSelectCancellable
|
|
25
|
+
}));
|
|
15
26
|
describe("Encryption & Sensitive Fields", () => {
|
|
16
27
|
let tmpDir;
|
|
17
28
|
beforeEach(() => {
|
|
@@ -19,6 +30,9 @@ describe("Encryption & Sensitive Fields", () => {
|
|
|
19
30
|
mockSelect.mockClear();
|
|
20
31
|
mockInput.mockClear();
|
|
21
32
|
mockPassword.mockClear();
|
|
33
|
+
mockSelectCancellable.mockClear();
|
|
34
|
+
mockInputCancellable.mockClear();
|
|
35
|
+
mockPasswordCancellable.mockClear();
|
|
22
36
|
});
|
|
23
37
|
afterEach(() => {
|
|
24
38
|
fs.rmSync(tmpDir, {
|
|
@@ -35,14 +49,14 @@ describe("Encryption & Sensitive Fields", () => {
|
|
|
35
49
|
})
|
|
36
50
|
});
|
|
37
51
|
const sprinkle = new Sprinkle(schema, tmpDir);
|
|
38
|
-
|
|
52
|
+
mockPasswordCancellable.mockResolvedValueOnce("my-secret");
|
|
39
53
|
const result = await sprinkle.FillInStruct(schema);
|
|
40
54
|
expect(result).toEqual({
|
|
41
55
|
secret: "my-secret"
|
|
42
56
|
});
|
|
43
|
-
expect(
|
|
44
|
-
expect(
|
|
45
|
-
expect(
|
|
57
|
+
expect(mockPasswordCancellable).toHaveBeenCalledTimes(1);
|
|
58
|
+
expect(mockPasswordCancellable.mock.calls[0][0].message).toBe("Enter secret");
|
|
59
|
+
expect(mockInputCancellable).not.toHaveBeenCalled();
|
|
46
60
|
});
|
|
47
61
|
test("uses input() for non-sensitive string fields", async () => {
|
|
48
62
|
const schema = Type.Object({
|
|
@@ -51,13 +65,13 @@ describe("Encryption & Sensitive Fields", () => {
|
|
|
51
65
|
})
|
|
52
66
|
});
|
|
53
67
|
const sprinkle = new Sprinkle(schema, tmpDir);
|
|
54
|
-
|
|
68
|
+
mockInputCancellable.mockResolvedValueOnce("visible");
|
|
55
69
|
const result = await sprinkle.FillInStruct(schema);
|
|
56
70
|
expect(result).toEqual({
|
|
57
71
|
name: "visible"
|
|
58
72
|
});
|
|
59
|
-
expect(
|
|
60
|
-
expect(
|
|
73
|
+
expect(mockInputCancellable).toHaveBeenCalledTimes(1);
|
|
74
|
+
expect(mockPasswordCancellable).not.toHaveBeenCalled();
|
|
61
75
|
});
|
|
62
76
|
test("does not remember sensitive field as default", async () => {
|
|
63
77
|
const schema = Type.String({
|
|
@@ -66,7 +80,7 @@ describe("Encryption & Sensitive Fields", () => {
|
|
|
66
80
|
const sprinkle = new Sprinkle(Type.Object({
|
|
67
81
|
p: Type.String()
|
|
68
82
|
}), tmpDir);
|
|
69
|
-
|
|
83
|
+
mockPasswordCancellable.mockResolvedValueOnce("secret-val");
|
|
70
84
|
await sprinkle.FillInStruct(schema);
|
|
71
85
|
expect(sprinkle.defaults["string"]).toBeUndefined();
|
|
72
86
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.test.js","names":["describe","expect","test","mock","beforeEach","afterEach","Sprinkle","Type","fs","path","os","withProfile","mockSelect","mockInput","mockPassword","module","select","input","password","tmpDir","mkdtempSync","join","tmpdir","mockClear","rmSync","recursive","force","schema","Object","secret","String","sensitive","title","sprinkle","mockResolvedValueOnce","result","FillInStruct","toEqual","toHaveBeenCalledTimes","calls","message","toBe","not","toHaveBeenCalled","name","p","defaults","toBeUndefined","encryption","encrypt","plain","decrypt","cipher","replace","settings","saveSettings","content","readFileSync","parsed","JSON","parse","sprinkle1","sprinkle2","loadProfile","wallet","key","address","Union","type","Literal","privateKey","outerSchema","network","count","BigInt","opts","Buffer","from","toString","s1","s2","mkdirSync","writeFileSync","stringify","New","c","options","toBeDefined","profileId"],"sources":["../../../../src/Sprinkle/__tests__/encryption.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach, afterEach } from \"bun:test\";\nimport { Sprinkle, Type } from \"../index.js\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { withProfile } from \"./test-helpers.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockPassword = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n password: mockPassword,\n}));\n\ndescribe(\"Encryption & Sensitive Fields\", () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"sprinkles-enc-test-\"));\n mockSelect.mockClear();\n mockInput.mockClear();\n mockPassword.mockClear();\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe(\"sensitive field prompts\", () => {\n test(\"uses password() for sensitive string fields\", async () => {\n const schema = Type.Object({\n secret: Type.String({ sensitive: true, title: \"Enter secret\" }),\n });\n const sprinkle = new Sprinkle(schema, tmpDir);\n\n mockPassword.mockResolvedValueOnce(\"my-secret\");\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result).toEqual({ secret: \"my-secret\" });\n expect(mockPassword).toHaveBeenCalledTimes(1);\n expect(mockPassword.mock.calls[0][0].message).toBe(\"Enter secret\");\n expect(mockInput).not.toHaveBeenCalled();\n });\n\n test(\"uses input() for non-sensitive string fields\", async () => {\n const schema = Type.Object({\n name: Type.String({ title: \"Enter name\" }),\n });\n const sprinkle = new Sprinkle(schema, tmpDir);\n\n mockInput.mockResolvedValueOnce(\"visible\");\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result).toEqual({ name: \"visible\" });\n expect(mockInput).toHaveBeenCalledTimes(1);\n expect(mockPassword).not.toHaveBeenCalled();\n });\n\n test(\"does not remember sensitive field as default\", async () => {\n const schema = Type.String({ sensitive: true });\n const sprinkle = new Sprinkle(Type.Object({ p: Type.String() }), tmpDir);\n\n mockPassword.mockResolvedValueOnce(\"secret-val\");\n\n await sprinkle.FillInStruct(schema);\n expect(sprinkle.defaults[\"string\"]).toBeUndefined();\n });\n });\n\n describe(\"encryption on save/load\", () => {\n test(\"encrypts sensitive fields when saving with encryption configured\", () => {\n const schema = Type.Object({\n name: Type.String(),\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = { name: \"visible\", secret: \"hidden\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.name).toBe(\"visible\");\n expect(parsed.settings.secret).toBe(\"ENC:hidden\");\n });\n\n test(\"decrypts sensitive fields when loading with encryption configured\", async () => {\n const schema = Type.Object({\n name: Type.String(),\n secret: Type.String({ sensitive: true }),\n });\n\n // First save with encryption\n const sprinkle1 = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle1.settings = { name: \"visible\", secret: \"hidden\" } as any;\n sprinkle1.saveSettings();\n\n // Then load with same encryption\n const sprinkle2 = new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n });\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.settings).toEqual({ name: \"visible\", secret: \"hidden\" });\n });\n\n test(\"does not encrypt when no encryption configured\", () => {\n const schema = Type.Object({\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { secret: \"plain-value\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.secret).toBe(\"plain-value\");\n });\n\n test(\"encrypts nested sensitive fields\", () => {\n const schema = Type.Object({\n wallet: Type.Object({\n key: Type.String({ sensitive: true }),\n address: Type.String(),\n }),\n });\n const sprinkle = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = {\n wallet: { key: \"secret-key\", address: \"addr1...\" },\n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.wallet.key).toBe(\"ENC:secret-key\");\n expect(parsed.settings.wallet.address).toBe(\"addr1...\");\n });\n\n test(\"handles sensitive fields in union variants\", () => {\n const schema = Type.Union([\n Type.Object({\n type: Type.Literal(\"hot\"),\n privateKey: Type.String({ sensitive: true }),\n }),\n Type.Object({\n type: Type.Literal(\"cold\"),\n address: Type.String(),\n }),\n ]);\n const outerSchema = Type.Object({ wallet: schema });\n const sprinkle = withProfile(\n new Sprinkle(outerSchema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = {\n wallet: { type: \"hot\", privateKey: \"my-key\" },\n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.wallet.privateKey).toBe(\"ENC:my-key\");\n });\n\n test(\"round-trip with encryption preserves all data\", async () => {\n const schema = Type.Object({\n network: Type.String(),\n secret: Type.String({ sensitive: true }),\n count: Type.BigInt(),\n });\n const opts = {\n encryption: {\n encrypt: (plain: string) => Buffer.from(plain).toString(\"base64\"),\n decrypt: async (cipher: string) =>\n Buffer.from(cipher, \"base64\").toString(),\n },\n };\n const s1 = withProfile(new Sprinkle(schema, tmpDir, opts));\n s1.settings = {\n network: \"mainnet\",\n secret: \"top-secret\",\n count: 42n,\n } as any;\n s1.saveSettings();\n\n const s2 = new Sprinkle(schema, tmpDir, opts);\n await s2.loadProfile(\"test\");\n\n expect(s2.settings).toEqual({\n network: \"mainnet\",\n secret: \"top-secret\",\n count: 42n,\n });\n });\n });\n\n describe(\"Sprinkle.New with options\", () => {\n test(\"passes options through to instance and migrates legacy\", async () => {\n const schema = Type.Object({ name: Type.String() });\n\n // Write legacy settings file so New triggers migration\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(\n path.join(tmpDir, \"settings.json\"),\n JSON.stringify({ settings: { name: \"test\" }, defaults: {} }),\n );\n\n const sprinkle = await Sprinkle.New(schema, tmpDir, {\n encryption: {\n encrypt: (p) => p,\n decrypt: async (c) => c,\n },\n });\n\n expect(sprinkle.options.encryption).toBeDefined();\n expect(sprinkle.profileId).toBe(\"default\");\n expect(sprinkle.settings).toEqual({ name: \"test\" });\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"encryption.test.js","names":["describe","expect","test","mock","beforeEach","afterEach","Sprinkle","Type","fs","path","os","withProfile","mockSelect","mockInput","mockPassword","mockSelectCancellable","mockInputCancellable","mockPasswordCancellable","module","select","input","password","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","searchCancellable","tmpDir","mkdtempSync","join","tmpdir","mockClear","rmSync","recursive","force","schema","Object","secret","String","sensitive","title","sprinkle","mockResolvedValueOnce","result","FillInStruct","toEqual","toHaveBeenCalledTimes","calls","message","toBe","not","toHaveBeenCalled","name","p","defaults","toBeUndefined","encryption","encrypt","plain","decrypt","cipher","replace","settings","saveSettings","content","readFileSync","parsed","JSON","parse","sprinkle1","sprinkle2","loadProfile","wallet","key","address","Union","type","Literal","privateKey","outerSchema","network","count","BigInt","opts","Buffer","from","toString","s1","s2","mkdirSync","writeFileSync","stringify","New","c","options","toBeDefined","profileId"],"sources":["../../../../src/Sprinkle/__tests__/encryption.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach, afterEach } from \"bun:test\";\nimport { Sprinkle, Type } from \"../index.js\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { withProfile } from \"./test-helpers.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockPassword = mock();\nconst mockSelectCancellable = mock();\nconst mockInputCancellable = mock();\nconst mockPasswordCancellable = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n password: mockPassword,\n}));\n\nmock.module(\"../prompts.js\", () => ({\n selectCancellable: mockSelectCancellable,\n inputCancellable: mockInputCancellable,\n passwordCancellable: mockPasswordCancellable,\n confirmCancellable: mock(),\n searchCancellable: mock(),\n select: mockSelectCancellable,\n}));\n\ndescribe(\"Encryption & Sensitive Fields\", () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"sprinkles-enc-test-\"));\n mockSelect.mockClear();\n mockInput.mockClear();\n mockPassword.mockClear();\n mockSelectCancellable.mockClear();\n mockInputCancellable.mockClear();\n mockPasswordCancellable.mockClear();\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe(\"sensitive field prompts\", () => {\n test(\"uses password() for sensitive string fields\", async () => {\n const schema = Type.Object({\n secret: Type.String({ sensitive: true, title: \"Enter secret\" }),\n });\n const sprinkle = new Sprinkle(schema, tmpDir);\n\n mockPasswordCancellable.mockResolvedValueOnce(\"my-secret\");\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result).toEqual({ secret: \"my-secret\" });\n expect(mockPasswordCancellable).toHaveBeenCalledTimes(1);\n expect(mockPasswordCancellable.mock.calls[0][0].message).toBe(\"Enter secret\");\n expect(mockInputCancellable).not.toHaveBeenCalled();\n });\n\n test(\"uses input() for non-sensitive string fields\", async () => {\n const schema = Type.Object({\n name: Type.String({ title: \"Enter name\" }),\n });\n const sprinkle = new Sprinkle(schema, tmpDir);\n\n mockInputCancellable.mockResolvedValueOnce(\"visible\");\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result).toEqual({ name: \"visible\" });\n expect(mockInputCancellable).toHaveBeenCalledTimes(1);\n expect(mockPasswordCancellable).not.toHaveBeenCalled();\n });\n\n test(\"does not remember sensitive field as default\", async () => {\n const schema = Type.String({ sensitive: true });\n const sprinkle = new Sprinkle(Type.Object({ p: Type.String() }), tmpDir);\n\n mockPasswordCancellable.mockResolvedValueOnce(\"secret-val\");\n\n await sprinkle.FillInStruct(schema);\n expect(sprinkle.defaults[\"string\"]).toBeUndefined();\n });\n });\n\n describe(\"encryption on save/load\", () => {\n test(\"encrypts sensitive fields when saving with encryption configured\", () => {\n const schema = Type.Object({\n name: Type.String(),\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = { name: \"visible\", secret: \"hidden\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.name).toBe(\"visible\");\n expect(parsed.settings.secret).toBe(\"ENC:hidden\");\n });\n\n test(\"decrypts sensitive fields when loading with encryption configured\", async () => {\n const schema = Type.Object({\n name: Type.String(),\n secret: Type.String({ sensitive: true }),\n });\n\n // First save with encryption\n const sprinkle1 = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle1.settings = { name: \"visible\", secret: \"hidden\" } as any;\n sprinkle1.saveSettings();\n\n // Then load with same encryption\n const sprinkle2 = new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n });\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.settings).toEqual({ name: \"visible\", secret: \"hidden\" });\n });\n\n test(\"does not encrypt when no encryption configured\", () => {\n const schema = Type.Object({\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { secret: \"plain-value\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.secret).toBe(\"plain-value\");\n });\n\n test(\"encrypts nested sensitive fields\", () => {\n const schema = Type.Object({\n wallet: Type.Object({\n key: Type.String({ sensitive: true }),\n address: Type.String(),\n }),\n });\n const sprinkle = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = {\n wallet: { key: \"secret-key\", address: \"addr1...\" },\n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.wallet.key).toBe(\"ENC:secret-key\");\n expect(parsed.settings.wallet.address).toBe(\"addr1...\");\n });\n\n test(\"handles sensitive fields in union variants\", () => {\n const schema = Type.Union([\n Type.Object({\n type: Type.Literal(\"hot\"),\n privateKey: Type.String({ sensitive: true }),\n }),\n Type.Object({\n type: Type.Literal(\"cold\"),\n address: Type.String(),\n }),\n ]);\n const outerSchema = Type.Object({ wallet: schema });\n const sprinkle = withProfile(\n new Sprinkle(outerSchema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = {\n wallet: { type: \"hot\", privateKey: \"my-key\" },\n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.wallet.privateKey).toBe(\"ENC:my-key\");\n });\n\n test(\"round-trip with encryption preserves all data\", async () => {\n const schema = Type.Object({\n network: Type.String(),\n secret: Type.String({ sensitive: true }),\n count: Type.BigInt(),\n });\n const opts = {\n encryption: {\n encrypt: (plain: string) => Buffer.from(plain).toString(\"base64\"),\n decrypt: async (cipher: string) =>\n Buffer.from(cipher, \"base64\").toString(),\n },\n };\n const s1 = withProfile(new Sprinkle(schema, tmpDir, opts));\n s1.settings = {\n network: \"mainnet\",\n secret: \"top-secret\",\n count: 42n,\n } as any;\n s1.saveSettings();\n\n const s2 = new Sprinkle(schema, tmpDir, opts);\n await s2.loadProfile(\"test\");\n\n expect(s2.settings).toEqual({\n network: \"mainnet\",\n secret: \"top-secret\",\n count: 42n,\n });\n });\n });\n\n describe(\"Sprinkle.New with options\", () => {\n test(\"passes options through to instance and migrates legacy\", async () => {\n const schema = Type.Object({ name: Type.String() });\n\n // Write legacy settings file so New triggers migration\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(\n path.join(tmpDir, \"settings.json\"),\n JSON.stringify({ settings: { name: \"test\" }, defaults: {} }),\n );\n\n const sprinkle = await Sprinkle.New(schema, tmpDir, {\n encryption: {\n encrypt: (p) => p,\n decrypt: async (c) => c,\n },\n });\n\n expect(sprinkle.options.encryption).toBeDefined();\n expect(sprinkle.profileId).toBe(\"default\");\n expect(sprinkle.settings).toEqual({ name: \"test\" });\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -3,12 +3,23 @@ import { Sprinkle, Type } from "../index.js";
|
|
|
3
3
|
const mockSelect = mock();
|
|
4
4
|
const mockInput = mock();
|
|
5
5
|
const mockPassword = mock();
|
|
6
|
-
const
|
|
6
|
+
const mockSelectCancellable = mock();
|
|
7
|
+
const mockInputCancellable = mock();
|
|
8
|
+
const mockPasswordCancellable = mock();
|
|
9
|
+
const mockConfirmCancellable = mock();
|
|
10
|
+
const mockSearchCancellable = mock();
|
|
7
11
|
mock.module("@inquirer/prompts", () => ({
|
|
8
12
|
select: mockSelect,
|
|
9
13
|
input: mockInput,
|
|
10
|
-
password: mockPassword
|
|
11
|
-
|
|
14
|
+
password: mockPassword
|
|
15
|
+
}));
|
|
16
|
+
mock.module("../prompts.js", () => ({
|
|
17
|
+
selectCancellable: mockSelectCancellable,
|
|
18
|
+
inputCancellable: mockInputCancellable,
|
|
19
|
+
passwordCancellable: mockPasswordCancellable,
|
|
20
|
+
confirmCancellable: mockConfirmCancellable,
|
|
21
|
+
searchCancellable: mockSearchCancellable,
|
|
22
|
+
select: mockSelectCancellable
|
|
12
23
|
}));
|
|
13
24
|
describe("beforeShow hook (2.2)", () => {
|
|
14
25
|
let sprinkle;
|
|
@@ -21,13 +32,14 @@ describe("beforeShow hook (2.2)", () => {
|
|
|
21
32
|
name: "test"
|
|
22
33
|
};
|
|
23
34
|
mockSelect.mockClear();
|
|
35
|
+
mockSelectCancellable.mockClear();
|
|
24
36
|
});
|
|
25
37
|
test("calls beforeShow before rendering menu", async () => {
|
|
26
38
|
const callOrder = [];
|
|
27
39
|
const beforeShowFn = mock(async () => {
|
|
28
40
|
callOrder.push("beforeShow");
|
|
29
41
|
});
|
|
30
|
-
|
|
42
|
+
mockSelectCancellable.mockImplementation(async () => {
|
|
31
43
|
callOrder.push("select");
|
|
32
44
|
return -1; // exit
|
|
33
45
|
});
|
|
@@ -46,7 +58,7 @@ describe("beforeShow hook (2.2)", () => {
|
|
|
46
58
|
});
|
|
47
59
|
test("passes sprinkle instance to beforeShow", async () => {
|
|
48
60
|
let receivedSprinkle;
|
|
49
|
-
|
|
61
|
+
mockSelectCancellable.mockResolvedValueOnce(-1);
|
|
50
62
|
const menu = {
|
|
51
63
|
title: "Test",
|
|
52
64
|
beforeShow: async s => {
|
|
@@ -61,7 +73,7 @@ describe("beforeShow hook (2.2)", () => {
|
|
|
61
73
|
expect(receivedSprinkle).toBe(sprinkle);
|
|
62
74
|
});
|
|
63
75
|
test("menu works without beforeShow", async () => {
|
|
64
|
-
|
|
76
|
+
mockSelectCancellable.mockResolvedValueOnce(-1);
|
|
65
77
|
const menu = {
|
|
66
78
|
title: "Test",
|
|
67
79
|
items: [{
|
|
@@ -75,10 +87,10 @@ describe("beforeShow hook (2.2)", () => {
|
|
|
75
87
|
});
|
|
76
88
|
describe("SearchSelect (2.3)", () => {
|
|
77
89
|
beforeEach(() => {
|
|
78
|
-
|
|
90
|
+
mockSearchCancellable.mockClear();
|
|
79
91
|
});
|
|
80
92
|
test("delegates to search prompt", async () => {
|
|
81
|
-
|
|
93
|
+
mockSearchCancellable.mockResolvedValueOnce("selected-value");
|
|
82
94
|
const result = await Sprinkle.SearchSelect({
|
|
83
95
|
message: "Pick one",
|
|
84
96
|
source: () => [{
|
|
@@ -90,56 +102,35 @@ describe("SearchSelect (2.3)", () => {
|
|
|
90
102
|
}]
|
|
91
103
|
});
|
|
92
104
|
expect(result).toBe("selected-value");
|
|
93
|
-
expect(
|
|
94
|
-
expect(
|
|
105
|
+
expect(mockSearchCancellable).toHaveBeenCalledTimes(1);
|
|
106
|
+
expect(mockSearchCancellable.mock.calls[0][0].message).toBe("Pick one");
|
|
95
107
|
});
|
|
96
108
|
test("passes source function through", async () => {
|
|
97
109
|
const sourceFn = mock(() => [{
|
|
98
110
|
name: "X",
|
|
99
111
|
value: "x"
|
|
100
112
|
}]);
|
|
101
|
-
|
|
113
|
+
mockSearchCancellable.mockResolvedValueOnce("x");
|
|
102
114
|
await Sprinkle.SearchSelect({
|
|
103
115
|
message: "Search",
|
|
104
116
|
source: sourceFn
|
|
105
117
|
});
|
|
106
|
-
expect(
|
|
118
|
+
expect(mockSearchCancellable.mock.calls[0][0].source).toBe(sourceFn);
|
|
107
119
|
});
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
mockSelect.mockClear();
|
|
117
|
-
mockInput.mockClear();
|
|
118
|
-
});
|
|
119
|
-
test("skips optional field when user selects Skip", async () => {
|
|
120
|
-
const schema = Type.Object({
|
|
121
|
-
name: Type.String(),
|
|
122
|
-
nickname: Type.Optional(Type.String())
|
|
123
|
-
});
|
|
124
|
-
mockInput.mockResolvedValueOnce("Alice"); // name
|
|
125
|
-
mockSelect.mockResolvedValueOnce(false); // skip nickname
|
|
126
|
-
|
|
127
|
-
const result = await sprinkle.FillInStruct(schema);
|
|
128
|
-
expect(result.name).toBe("Alice");
|
|
129
|
-
expect(result.nickname).toBeUndefined();
|
|
130
|
-
});
|
|
131
|
-
test("fills optional field when user selects Yes", async () => {
|
|
132
|
-
const schema = Type.Object({
|
|
133
|
-
name: Type.String(),
|
|
134
|
-
nickname: Type.Optional(Type.String())
|
|
120
|
+
test("returns null when cancelled", async () => {
|
|
121
|
+
mockSearchCancellable.mockResolvedValueOnce(null);
|
|
122
|
+
const result = await Sprinkle.SearchSelect({
|
|
123
|
+
message: "Pick one",
|
|
124
|
+
source: () => [{
|
|
125
|
+
name: "A",
|
|
126
|
+
value: "a"
|
|
127
|
+
}]
|
|
135
128
|
});
|
|
136
|
-
|
|
137
|
-
.mockResolvedValueOnce("Ali"); // nickname
|
|
138
|
-
mockSelect.mockResolvedValueOnce(true); // fill nickname
|
|
139
|
-
|
|
140
|
-
const result = await sprinkle.FillInStruct(schema);
|
|
141
|
-
expect(result.name).toBe("Alice");
|
|
142
|
-
expect(result.nickname).toBe("Ali");
|
|
129
|
+
expect(result).toBeNull();
|
|
143
130
|
});
|
|
144
131
|
});
|
|
132
|
+
|
|
133
|
+
// Note: "Optional type support (2.4)" tests removed - they tested the old sequential
|
|
134
|
+
// FillInStruct behavior. The new menu-based FillInStruct handles optional fields
|
|
135
|
+
// differently (via menu selection). See fill-in-struct.test.ts for comprehensive tests.
|
|
145
136
|
//# sourceMappingURL=enhancements.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enhancements.test.js","names":["describe","expect","test","mock","beforeEach","Sprinkle","Type","mockSelect","mockInput","mockPassword","
|
|
1
|
+
{"version":3,"file":"enhancements.test.js","names":["describe","expect","test","mock","beforeEach","Sprinkle","Type","mockSelect","mockInput","mockPassword","mockSelectCancellable","mockInputCancellable","mockPasswordCancellable","mockConfirmCancellable","mockSearchCancellable","module","select","input","password","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","searchCancellable","sprinkle","schema","Object","name","String","settings","mockClear","callOrder","beforeShowFn","push","mockImplementation","menu","title","beforeShow","items","action","showMenu","toHaveBeenCalledTimes","toBe","receivedSprinkle","mockResolvedValueOnce","s","result","SearchSelect","message","source","value","calls","sourceFn","toBeNull"],"sources":["../../../../src/Sprinkle/__tests__/enhancements.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach } from \"bun:test\";\nimport { Sprinkle, Type, type IMenu } from \"../index.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockPassword = mock();\nconst mockSelectCancellable = mock();\nconst mockInputCancellable = mock();\nconst mockPasswordCancellable = mock();\nconst mockConfirmCancellable = mock();\nconst mockSearchCancellable = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n password: mockPassword,\n}));\n\nmock.module(\"../prompts.js\", () => ({\n selectCancellable: mockSelectCancellable,\n inputCancellable: mockInputCancellable,\n passwordCancellable: mockPasswordCancellable,\n confirmCancellable: mockConfirmCancellable,\n searchCancellable: mockSearchCancellable,\n select: mockSelectCancellable,\n}));\n\ndescribe(\"beforeShow hook (2.2)\", () => {\n let sprinkle: Sprinkle<any>;\n\n beforeEach(() => {\n const schema = Type.Object({ name: Type.String() });\n sprinkle = new Sprinkle(schema, \"/tmp/test\");\n sprinkle.settings = { name: \"test\" } as any;\n mockSelect.mockClear();\n mockSelectCancellable.mockClear();\n });\n\n test(\"calls beforeShow before rendering menu\", async () => {\n const callOrder: string[] = [];\n\n const beforeShowFn = mock(async () => {\n callOrder.push(\"beforeShow\");\n });\n\n mockSelectCancellable.mockImplementation(async () => {\n callOrder.push(\"select\");\n return -1; // exit\n });\n\n const menu: IMenu<any> = {\n title: \"Test\",\n beforeShow: beforeShowFn,\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n expect(beforeShowFn).toHaveBeenCalledTimes(1);\n expect(callOrder[0]).toBe(\"beforeShow\");\n expect(callOrder[1]).toBe(\"select\");\n });\n\n test(\"passes sprinkle instance to beforeShow\", async () => {\n let receivedSprinkle: any;\n\n mockSelectCancellable.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n beforeShow: async (s) => {\n receivedSprinkle = s;\n },\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n expect(receivedSprinkle).toBe(sprinkle);\n });\n\n test(\"menu works without beforeShow\", async () => {\n mockSelectCancellable.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n // Should complete without error\n });\n});\n\ndescribe(\"SearchSelect (2.3)\", () => {\n beforeEach(() => {\n mockSearchCancellable.mockClear();\n });\n\n test(\"delegates to search prompt\", async () => {\n mockSearchCancellable.mockResolvedValueOnce(\"selected-value\");\n\n const result = await Sprinkle.SearchSelect({\n message: \"Pick one\",\n source: () => [\n { name: \"Option A\", value: \"a\" },\n { name: \"Option B\", value: \"b\" },\n ],\n });\n\n expect(result).toBe(\"selected-value\");\n expect(mockSearchCancellable).toHaveBeenCalledTimes(1);\n expect(mockSearchCancellable.mock.calls[0][0].message).toBe(\"Pick one\");\n });\n\n test(\"passes source function through\", async () => {\n const sourceFn = mock(() => [{ name: \"X\", value: \"x\" }]);\n mockSearchCancellable.mockResolvedValueOnce(\"x\");\n\n await Sprinkle.SearchSelect({\n message: \"Search\",\n source: sourceFn,\n });\n\n expect(mockSearchCancellable.mock.calls[0][0].source).toBe(sourceFn);\n });\n\n test(\"returns null when cancelled\", async () => {\n mockSearchCancellable.mockResolvedValueOnce(null);\n\n const result = await Sprinkle.SearchSelect({\n message: \"Pick one\",\n source: () => [{ name: \"A\", value: \"a\" }],\n });\n\n expect(result).toBeNull();\n });\n});\n\n// Note: \"Optional type support (2.4)\" tests removed - they tested the old sequential\n// FillInStruct behavior. The new menu-based FillInStruct handles optional fields\n// differently (via menu selection). See fill-in-struct.test.ts for comprehensive tests.\n"],"mappings":"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","ignoreList":[]}
|