@sundaeswap/sprinkles 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +260 -0
  3. package/dist/cjs/Sprinkle/__tests__/bigint-reviver.test.js +40 -0
  4. package/dist/cjs/Sprinkle/__tests__/bigint-reviver.test.js.map +1 -0
  5. package/dist/cjs/Sprinkle/__tests__/encryption.test.js +267 -0
  6. package/dist/cjs/Sprinkle/__tests__/encryption.test.js.map +1 -0
  7. package/dist/cjs/Sprinkle/__tests__/enhancements.test.js +147 -0
  8. package/dist/cjs/Sprinkle/__tests__/enhancements.test.js.map +1 -0
  9. package/dist/cjs/Sprinkle/__tests__/extract-message.test.js +60 -0
  10. package/dist/cjs/Sprinkle/__tests__/extract-message.test.js.map +1 -0
  11. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +131 -0
  12. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -0
  13. package/dist/cjs/Sprinkle/__tests__/schemas.test.js +184 -0
  14. package/dist/cjs/Sprinkle/__tests__/schemas.test.js.map +1 -0
  15. package/dist/cjs/Sprinkle/__tests__/settings-persistence.test.js +199 -0
  16. package/dist/cjs/Sprinkle/__tests__/settings-persistence.test.js.map +1 -0
  17. package/dist/cjs/Sprinkle/__tests__/show-menu.test.js +108 -0
  18. package/dist/cjs/Sprinkle/__tests__/show-menu.test.js.map +1 -0
  19. package/dist/cjs/Sprinkle/__tests__/test-helpers.js +16 -0
  20. package/dist/cjs/Sprinkle/__tests__/test-helpers.js.map +1 -0
  21. package/dist/cjs/Sprinkle/__tests__/tx-dialog.test.js +271 -0
  22. package/dist/cjs/Sprinkle/__tests__/tx-dialog.test.js.map +1 -0
  23. package/dist/cjs/Sprinkle/index.js +954 -0
  24. package/dist/cjs/Sprinkle/index.js.map +1 -0
  25. package/dist/cjs/index.js +17 -0
  26. package/dist/cjs/index.js.map +1 -0
  27. package/dist/cjs/package.json +1 -0
  28. package/dist/esm/Sprinkle/__tests__/bigint-reviver.test.js +38 -0
  29. package/dist/esm/Sprinkle/__tests__/bigint-reviver.test.js.map +1 -0
  30. package/dist/esm/Sprinkle/__tests__/encryption.test.js +264 -0
  31. package/dist/esm/Sprinkle/__tests__/encryption.test.js.map +1 -0
  32. package/dist/esm/Sprinkle/__tests__/enhancements.test.js +145 -0
  33. package/dist/esm/Sprinkle/__tests__/enhancements.test.js.map +1 -0
  34. package/dist/esm/Sprinkle/__tests__/extract-message.test.js +58 -0
  35. package/dist/esm/Sprinkle/__tests__/extract-message.test.js.map +1 -0
  36. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +130 -0
  37. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -0
  38. package/dist/esm/Sprinkle/__tests__/schemas.test.js +182 -0
  39. package/dist/esm/Sprinkle/__tests__/schemas.test.js.map +1 -0
  40. package/dist/esm/Sprinkle/__tests__/settings-persistence.test.js +196 -0
  41. package/dist/esm/Sprinkle/__tests__/settings-persistence.test.js.map +1 -0
  42. package/dist/esm/Sprinkle/__tests__/show-menu.test.js +106 -0
  43. package/dist/esm/Sprinkle/__tests__/show-menu.test.js.map +1 -0
  44. package/dist/esm/Sprinkle/__tests__/test-helpers.js +10 -0
  45. package/dist/esm/Sprinkle/__tests__/test-helpers.js.map +1 -0
  46. package/dist/esm/Sprinkle/__tests__/tx-dialog.test.js +269 -0
  47. package/dist/esm/Sprinkle/__tests__/tx-dialog.test.js.map +1 -0
  48. package/dist/esm/Sprinkle/index.js +928 -0
  49. package/dist/esm/Sprinkle/index.js.map +1 -0
  50. package/dist/esm/index.js +2 -0
  51. package/dist/esm/index.js.map +1 -0
  52. package/dist/types/Sprinkle/index.d.ts +205 -0
  53. package/dist/types/Sprinkle/index.d.ts.map +1 -0
  54. package/dist/types/index.d.ts +2 -0
  55. package/dist/types/index.d.ts.map +1 -0
  56. package/dist/types/tsconfig.build.tsbuildinfo +1 -0
  57. package/package.json +85 -0
  58. package/src/Sprinkle/__tests__/bigint-reviver.test.ts +49 -0
  59. package/src/Sprinkle/__tests__/encryption.test.ts +266 -0
  60. package/src/Sprinkle/__tests__/enhancements.test.ts +154 -0
  61. package/src/Sprinkle/__tests__/extract-message.test.ts +60 -0
  62. package/src/Sprinkle/__tests__/fill-in-struct.test.ts +159 -0
  63. package/src/Sprinkle/__tests__/schemas.test.ts +215 -0
  64. package/src/Sprinkle/__tests__/settings-persistence.test.ts +181 -0
  65. package/src/Sprinkle/__tests__/show-menu.test.ts +123 -0
  66. package/src/Sprinkle/__tests__/test-helpers.ts +14 -0
  67. package/src/Sprinkle/__tests__/tx-dialog.test.ts +293 -0
  68. package/src/Sprinkle/index.ts +1215 -0
  69. package/src/index.ts +1 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SundaeSwap Finance
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,260 @@
1
+ # Sprinkles
2
+
3
+ > **Note:** This is an early release (v0.x). The API may change between minor versions as we refine the library based on community feedback.
4
+
5
+ A TypeScript library for building interactive CLI menus and TUI applications with TypeBox schema validation. Sprinkles provides a declarative way to create nested menus, handle user input, and manage persistent settings with type safety.
6
+
7
+ ## Features
8
+
9
+ - **Schema-driven UI**: Define your data structures using TypeBox schemas, and Sprinkles automatically generates interactive prompts
10
+ - **Nested menu support**: Create hierarchical menu structures with submenus
11
+ - **Persistent settings**: Automatic JSON-based settings storage with BigInt support
12
+ - **Type-safe**: Full TypeScript support with type inference from schemas
13
+ - **Cardano integration**: Built-in helpers for Blaze SDK wallet and provider management
14
+ - **Transaction dialogs**: Ready-to-use transaction signing and submission flows
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @sundaeswap/sprinkles
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import { Sprinkle, Type } from "sprinkles";
26
+
27
+ // Define your settings schema
28
+ const AppSettingsSchema = Type.Object({
29
+ username: Type.String({ title: "Username" }),
30
+ theme: Type.Union([
31
+ Type.Literal("dark"),
32
+ Type.Literal("light")
33
+ ])
34
+ });
35
+
36
+ // Create a Sprinkle instance
37
+ const app = await Sprinkle.New(AppSettingsSchema, "./config");
38
+
39
+ // Define your menu
40
+ const mainMenu = {
41
+ title: "Main Menu",
42
+ items: [
43
+ {
44
+ title: "Say Hello",
45
+ action: async (sprinkle) => {
46
+ console.log(`Hello, ${sprinkle.settings.username}!`);
47
+ }
48
+ }
49
+ ]
50
+ };
51
+
52
+ // Show the menu
53
+ await app.showMenu(mainMenu);
54
+ ```
55
+
56
+ ## API Reference
57
+
58
+ ### Core Classes
59
+
60
+ #### `Sprinkle<S extends TSchema>`
61
+
62
+ The main class for managing your CLI application.
63
+
64
+ ##### Constructor
65
+
66
+ ```typescript
67
+ constructor(type: S, storagePath: string)
68
+ ```
69
+
70
+ ##### Static Methods
71
+
72
+ - `Sprinkle.New<S>(type: S, storagePath: string): Promise<Sprinkle<S>>` - Create and initialize a new Sprinkle instance
73
+ - `Sprinkle.GetProvider(network, settings): Provider` - Create a Cardano provider instance
74
+ - `Sprinkle.GetWallet(settings, provider): Promise<Wallet>` - Create a Cardano wallet instance
75
+ - `Sprinkle.GetBlaze(network, providerSettings, walletSettings): Promise<Blaze>` - Create a Blaze SDK instance
76
+ - `Sprinkle.SettingsPath(storagePath: string): string` - Get the settings file path
77
+
78
+ ##### Instance Methods
79
+
80
+ - `showMenu(menu: IMenu<S>): Promise<void>` - Display a menu and handle user interactions
81
+ - `EditStruct<U>(type: U, current: TExact<U>): Promise<TExact<U>>` - Interactive editor for schema-based structures
82
+ - `FillInStruct<U>(type: U, def?: TExact<U>): Promise<TExact<U>>` - Interactive form to fill in a structure
83
+ - `TxDialog(blaze, tx): Promise<void>` - Display transaction dialog with sign/submit options
84
+ - `saveSettings(): void` - Persist current settings to disk
85
+ - `LoadSettings(type, storagePath): Promise<void>` - Load settings from disk
86
+
87
+ ### Types
88
+
89
+ #### `IMenu<S>`
90
+
91
+ Defines a menu structure:
92
+
93
+ ```typescript
94
+ interface IMenu<S extends TSchema> {
95
+ title: string;
96
+ items: TMenuItem<S>[];
97
+ }
98
+ ```
99
+
100
+ #### `IMenuAction<S>`
101
+
102
+ Defines a menu action:
103
+
104
+ ```typescript
105
+ interface IMenuAction<S extends TSchema> {
106
+ title: string;
107
+ action: (sprinkle: Sprinkle<S>) => Promise<Sprinkle<S> | void>;
108
+ }
109
+ ```
110
+
111
+ #### `TMenuItem<S>`
112
+
113
+ A menu item can be either an action or a submenu:
114
+
115
+ ```typescript
116
+ type TMenuItem<S extends TSchema> = IMenuAction<S> | IMenu<S>;
117
+ ```
118
+
119
+ ### Built-in Schemas
120
+
121
+ #### `NetworkSchema`
122
+
123
+ Cardano network selection:
124
+
125
+ ```typescript
126
+ Type.Union([
127
+ Type.Literal("mainnet"),
128
+ Type.Literal("preview"),
129
+ Type.Literal("preprod")
130
+ ])
131
+ ```
132
+
133
+ #### `ProviderSettingsSchema`
134
+
135
+ Cardano provider configuration:
136
+
137
+ ```typescript
138
+ Type.Union([
139
+ Type.Object({
140
+ type: Type.Literal("blockfrost"),
141
+ projectId: Type.String({ minLength: 1, title: "Blockfrost Project ID" })
142
+ }),
143
+ Type.Object({
144
+ type: Type.Literal("maestro"),
145
+ apiKey: Type.String({ minLength: 1, title: "Maestro API Key" })
146
+ })
147
+ ])
148
+ ```
149
+
150
+ #### `WalletSettingsSchema`
151
+
152
+ Cardano wallet configuration:
153
+
154
+ ```typescript
155
+ Type.Union([
156
+ Type.Object({
157
+ type: Type.Literal("hot"),
158
+ privateKey: Type.String({ minLength: 1, title: "Hot Wallet Private Key" })
159
+ }),
160
+ Type.Object({
161
+ type: Type.Literal("cold"),
162
+ address: Type.String({ minLength: 1, title: "Cold Wallet Address" })
163
+ })
164
+ ])
165
+ ```
166
+
167
+ #### `MultisigScript`
168
+
169
+ Cardano multisig script schema with support for:
170
+ - Signature verification
171
+ - AllOf (all signatures required)
172
+ - AnyOf (any signature works)
173
+ - AtLeast (m-of-n threshold)
174
+ - Before/After (time-based conditions)
175
+ - Script hash references
176
+
177
+ ## Advanced Usage
178
+
179
+ ### Creating Nested Menus
180
+
181
+ ```typescript
182
+ const menu = {
183
+ title: "Main Menu",
184
+ items: [
185
+ {
186
+ title: "User Management",
187
+ items: [
188
+ {
189
+ title: "Add User",
190
+ action: async (sprinkle) => {
191
+ // Add user logic
192
+ }
193
+ },
194
+ {
195
+ title: "Remove User",
196
+ action: async (sprinkle) => {
197
+ // Remove user logic
198
+ }
199
+ }
200
+ ]
201
+ }
202
+ ]
203
+ };
204
+ ```
205
+
206
+ ### Modifying Settings from Actions
207
+
208
+ ```typescript
209
+ {
210
+ title: "Change Username",
211
+ action: async (sprinkle) => {
212
+ const newSettings = await sprinkle.EditStruct(
213
+ Type.Object({ username: Type.String() }),
214
+ { username: sprinkle.settings.username }
215
+ );
216
+ return new Sprinkle(sprinkle.type, sprinkle.storagePath);
217
+ }
218
+ }
219
+ ```
220
+
221
+ ### Working with Cardano Transactions
222
+
223
+ ```typescript
224
+ const blaze = await Sprinkle.GetBlaze(
225
+ "preprod",
226
+ providerSettings,
227
+ walletSettings
228
+ );
229
+
230
+ // Build your transaction
231
+ const tx = await blaze
232
+ .newTransaction()
233
+ .payLovelace(recipientAddress, 5_000_000n)
234
+ .complete();
235
+
236
+ // Show transaction dialog
237
+ await app.TxDialog(blaze, tx);
238
+ ```
239
+
240
+ ## Settings Persistence
241
+
242
+ Settings are automatically saved to `{storagePath}/settings.json`. The file format includes:
243
+
244
+ ```json
245
+ {
246
+ "settings": {
247
+ "username": "alice",
248
+ "count": "42n"
249
+ },
250
+ "defaults": {
251
+ "string": "last_entered_value"
252
+ }
253
+ }
254
+ ```
255
+
256
+ Note: BigInt values are serialized with an 'n' suffix and automatically parsed on load.
257
+
258
+ ## License
259
+
260
+ MIT
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ var _bunTest = require("bun:test");
4
+ var _index = require("../index.js");
5
+ (0, _bunTest.describe)("bigIntReviver", () => {
6
+ (0, _bunTest.test)("converts string ending with n to BigInt", () => {
7
+ (0, _bunTest.expect)(_index.Sprinkle.bigIntReviver("key", "42n")).toBe(42n);
8
+ });
9
+ (0, _bunTest.test)("converts zero bigint string", () => {
10
+ (0, _bunTest.expect)(_index.Sprinkle.bigIntReviver("key", "0n")).toBe(0n);
11
+ });
12
+ (0, _bunTest.test)("converts large bigint string", () => {
13
+ (0, _bunTest.expect)(_index.Sprinkle.bigIntReviver("key", "99999999999999999999n")).toBe(99999999999999999999n);
14
+ });
15
+ (0, _bunTest.test)("does not convert regular strings", () => {
16
+ (0, _bunTest.expect)(_index.Sprinkle.bigIntReviver("key", "hello")).toBe("hello");
17
+ });
18
+ (0, _bunTest.test)("does not convert strings with n in the middle", () => {
19
+ (0, _bunTest.expect)(_index.Sprinkle.bigIntReviver("key", "12n34")).toBe("12n34");
20
+ });
21
+ (0, _bunTest.test)("does not convert non-numeric n-suffixed strings", () => {
22
+ (0, _bunTest.expect)(_index.Sprinkle.bigIntReviver("key", "abcn")).toBe("abcn");
23
+ });
24
+ (0, _bunTest.test)("passes through numbers unchanged", () => {
25
+ (0, _bunTest.expect)(_index.Sprinkle.bigIntReviver("key", 42)).toBe(42);
26
+ });
27
+ (0, _bunTest.test)("passes through booleans unchanged", () => {
28
+ (0, _bunTest.expect)(_index.Sprinkle.bigIntReviver("key", true)).toBe(true);
29
+ });
30
+ (0, _bunTest.test)("passes through null unchanged", () => {
31
+ (0, _bunTest.expect)(_index.Sprinkle.bigIntReviver("key", null)).toBe(null);
32
+ });
33
+ (0, _bunTest.test)("works with JSON.parse", () => {
34
+ const json = '{"amount": "100n", "name": "test"}';
35
+ const parsed = JSON.parse(json, _index.Sprinkle.bigIntReviver);
36
+ (0, _bunTest.expect)(parsed.amount).toBe(100n);
37
+ (0, _bunTest.expect)(parsed.name).toBe("test");
38
+ });
39
+ });
40
+ //# sourceMappingURL=bigint-reviver.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bigint-reviver.test.js","names":["_bunTest","require","_index","describe","test","expect","Sprinkle","bigIntReviver","toBe","json","parsed","JSON","parse","amount","name"],"sources":["../../../../src/Sprinkle/__tests__/bigint-reviver.test.ts"],"sourcesContent":["import { describe, expect, test } from \"bun:test\";\nimport { Sprinkle } from \"../index.js\";\n\ndescribe(\"bigIntReviver\", () => {\n test(\"converts string ending with n to BigInt\", () => {\n expect(Sprinkle.bigIntReviver(\"key\", \"42n\")).toBe(42n);\n });\n\n test(\"converts zero bigint string\", () => {\n expect(Sprinkle.bigIntReviver(\"key\", \"0n\")).toBe(0n);\n });\n\n test(\"converts large bigint string\", () => {\n expect(Sprinkle.bigIntReviver(\"key\", \"99999999999999999999n\")).toBe(\n 99999999999999999999n,\n );\n });\n\n test(\"does not convert regular strings\", () => {\n expect(Sprinkle.bigIntReviver(\"key\", \"hello\")).toBe(\"hello\");\n });\n\n test(\"does not convert strings with n in the middle\", () => {\n expect(Sprinkle.bigIntReviver(\"key\", \"12n34\")).toBe(\"12n34\");\n });\n\n test(\"does not convert non-numeric n-suffixed strings\", () => {\n expect(Sprinkle.bigIntReviver(\"key\", \"abcn\")).toBe(\"abcn\");\n });\n\n test(\"passes through numbers unchanged\", () => {\n expect(Sprinkle.bigIntReviver(\"key\", 42)).toBe(42);\n });\n\n test(\"passes through booleans unchanged\", () => {\n expect(Sprinkle.bigIntReviver(\"key\", true)).toBe(true);\n });\n\n test(\"passes through null unchanged\", () => {\n expect(Sprinkle.bigIntReviver(\"key\", null)).toBe(null);\n });\n\n test(\"works with JSON.parse\", () => {\n const json = '{\"amount\": \"100n\", \"name\": \"test\"}';\n const parsed = JSON.parse(json, Sprinkle.bigIntReviver);\n expect(parsed.amount).toBe(100n);\n expect(parsed.name).toBe(\"test\");\n });\n});\n"],"mappings":";;AAAA,IAAAA,QAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AAEA,IAAAE,iBAAQ,EAAC,eAAe,EAAE,MAAM;EAC9B,IAAAC,aAAI,EAAC,yCAAyC,EAAE,MAAM;IACpD,IAAAC,eAAM,EAACC,eAAQ,CAACC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAACC,IAAI,CAAC,GAAG,CAAC;EACxD,CAAC,CAAC;EAEF,IAAAJ,aAAI,EAAC,6BAA6B,EAAE,MAAM;IACxC,IAAAC,eAAM,EAACC,eAAQ,CAACC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAACC,IAAI,CAAC,EAAE,CAAC;EACtD,CAAC,CAAC;EAEF,IAAAJ,aAAI,EAAC,8BAA8B,EAAE,MAAM;IACzC,IAAAC,eAAM,EAACC,eAAQ,CAACC,aAAa,CAAC,KAAK,EAAE,uBAAuB,CAAC,CAAC,CAACC,IAAI,CACjE,qBACF,CAAC;EACH,CAAC,CAAC;EAEF,IAAAJ,aAAI,EAAC,kCAAkC,EAAE,MAAM;IAC7C,IAAAC,eAAM,EAACC,eAAQ,CAACC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAACC,IAAI,CAAC,OAAO,CAAC;EAC9D,CAAC,CAAC;EAEF,IAAAJ,aAAI,EAAC,+CAA+C,EAAE,MAAM;IAC1D,IAAAC,eAAM,EAACC,eAAQ,CAACC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAACC,IAAI,CAAC,OAAO,CAAC;EAC9D,CAAC,CAAC;EAEF,IAAAJ,aAAI,EAAC,iDAAiD,EAAE,MAAM;IAC5D,IAAAC,eAAM,EAACC,eAAQ,CAACC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAACC,IAAI,CAAC,MAAM,CAAC;EAC5D,CAAC,CAAC;EAEF,IAAAJ,aAAI,EAAC,kCAAkC,EAAE,MAAM;IAC7C,IAAAC,eAAM,EAACC,eAAQ,CAACC,aAAa,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAACC,IAAI,CAAC,EAAE,CAAC;EACpD,CAAC,CAAC;EAEF,IAAAJ,aAAI,EAAC,mCAAmC,EAAE,MAAM;IAC9C,IAAAC,eAAM,EAACC,eAAQ,CAACC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAACC,IAAI,CAAC,IAAI,CAAC;EACxD,CAAC,CAAC;EAEF,IAAAJ,aAAI,EAAC,+BAA+B,EAAE,MAAM;IAC1C,IAAAC,eAAM,EAACC,eAAQ,CAACC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAACC,IAAI,CAAC,IAAI,CAAC;EACxD,CAAC,CAAC;EAEF,IAAAJ,aAAI,EAAC,uBAAuB,EAAE,MAAM;IAClC,MAAMK,IAAI,GAAG,oCAAoC;IACjD,MAAMC,MAAM,GAAGC,IAAI,CAACC,KAAK,CAACH,IAAI,EAAEH,eAAQ,CAACC,aAAa,CAAC;IACvD,IAAAF,eAAM,EAACK,MAAM,CAACG,MAAM,CAAC,CAACL,IAAI,CAAC,IAAI,CAAC;IAChC,IAAAH,eAAM,EAACK,MAAM,CAACI,IAAI,CAAC,CAACN,IAAI,CAAC,MAAM,CAAC;EAClC,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+
3
+ var _bunTest = require("bun:test");
4
+ var _index = require("../index.js");
5
+ var fs = _interopRequireWildcard(require("fs"));
6
+ var path = _interopRequireWildcard(require("path"));
7
+ var os = _interopRequireWildcard(require("os"));
8
+ var _testHelpers = require("./test-helpers.js");
9
+ 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); }
10
+ const mockSelect = (0, _bunTest.mock)();
11
+ const mockInput = (0, _bunTest.mock)();
12
+ const mockPassword = (0, _bunTest.mock)();
13
+ _bunTest.mock.module("@inquirer/prompts", () => ({
14
+ select: mockSelect,
15
+ input: mockInput,
16
+ password: mockPassword
17
+ }));
18
+ (0, _bunTest.describe)("Encryption & Sensitive Fields", () => {
19
+ let tmpDir;
20
+ (0, _bunTest.beforeEach)(() => {
21
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-enc-test-"));
22
+ mockSelect.mockClear();
23
+ mockInput.mockClear();
24
+ mockPassword.mockClear();
25
+ });
26
+ (0, _bunTest.afterEach)(() => {
27
+ fs.rmSync(tmpDir, {
28
+ recursive: true,
29
+ force: true
30
+ });
31
+ });
32
+ (0, _bunTest.describe)("sensitive field prompts", () => {
33
+ (0, _bunTest.test)("uses password() for sensitive string fields", async () => {
34
+ const schema = _index.Type.Object({
35
+ secret: _index.Type.String({
36
+ sensitive: true,
37
+ title: "Enter secret"
38
+ })
39
+ });
40
+ const sprinkle = new _index.Sprinkle(schema, tmpDir);
41
+ mockPassword.mockResolvedValueOnce("my-secret");
42
+ const result = await sprinkle.FillInStruct(schema);
43
+ (0, _bunTest.expect)(result).toEqual({
44
+ secret: "my-secret"
45
+ });
46
+ (0, _bunTest.expect)(mockPassword).toHaveBeenCalledTimes(1);
47
+ (0, _bunTest.expect)(mockPassword.mock.calls[0][0].message).toBe("Enter secret");
48
+ (0, _bunTest.expect)(mockInput).not.toHaveBeenCalled();
49
+ });
50
+ (0, _bunTest.test)("uses input() for non-sensitive string fields", async () => {
51
+ const schema = _index.Type.Object({
52
+ name: _index.Type.String({
53
+ title: "Enter name"
54
+ })
55
+ });
56
+ const sprinkle = new _index.Sprinkle(schema, tmpDir);
57
+ mockInput.mockResolvedValueOnce("visible");
58
+ const result = await sprinkle.FillInStruct(schema);
59
+ (0, _bunTest.expect)(result).toEqual({
60
+ name: "visible"
61
+ });
62
+ (0, _bunTest.expect)(mockInput).toHaveBeenCalledTimes(1);
63
+ (0, _bunTest.expect)(mockPassword).not.toHaveBeenCalled();
64
+ });
65
+ (0, _bunTest.test)("does not remember sensitive field as default", async () => {
66
+ const schema = _index.Type.String({
67
+ sensitive: true
68
+ });
69
+ const sprinkle = new _index.Sprinkle(_index.Type.Object({
70
+ p: _index.Type.String()
71
+ }), tmpDir);
72
+ mockPassword.mockResolvedValueOnce("secret-val");
73
+ await sprinkle.FillInStruct(schema);
74
+ (0, _bunTest.expect)(sprinkle.defaults["string"]).toBeUndefined();
75
+ });
76
+ });
77
+ (0, _bunTest.describe)("encryption on save/load", () => {
78
+ (0, _bunTest.test)("encrypts sensitive fields when saving with encryption configured", () => {
79
+ const schema = _index.Type.Object({
80
+ name: _index.Type.String(),
81
+ secret: _index.Type.String({
82
+ sensitive: true
83
+ })
84
+ });
85
+ const sprinkle = (0, _testHelpers.withProfile)(new _index.Sprinkle(schema, tmpDir, {
86
+ encryption: {
87
+ encrypt: plain => `ENC:${plain}`,
88
+ decrypt: async cipher => cipher.replace("ENC:", "")
89
+ }
90
+ }));
91
+ sprinkle.settings = {
92
+ name: "visible",
93
+ secret: "hidden"
94
+ };
95
+ sprinkle.saveSettings();
96
+ const content = fs.readFileSync(path.join(tmpDir, "profiles", "test.json"), "utf-8");
97
+ const parsed = JSON.parse(content);
98
+ (0, _bunTest.expect)(parsed.settings.name).toBe("visible");
99
+ (0, _bunTest.expect)(parsed.settings.secret).toBe("ENC:hidden");
100
+ });
101
+ (0, _bunTest.test)("decrypts sensitive fields when loading with encryption configured", async () => {
102
+ const schema = _index.Type.Object({
103
+ name: _index.Type.String(),
104
+ secret: _index.Type.String({
105
+ sensitive: true
106
+ })
107
+ });
108
+
109
+ // First save with encryption
110
+ const sprinkle1 = (0, _testHelpers.withProfile)(new _index.Sprinkle(schema, tmpDir, {
111
+ encryption: {
112
+ encrypt: plain => `ENC:${plain}`,
113
+ decrypt: async cipher => cipher.replace("ENC:", "")
114
+ }
115
+ }));
116
+ sprinkle1.settings = {
117
+ name: "visible",
118
+ secret: "hidden"
119
+ };
120
+ sprinkle1.saveSettings();
121
+
122
+ // Then load with same encryption
123
+ const sprinkle2 = new _index.Sprinkle(schema, tmpDir, {
124
+ encryption: {
125
+ encrypt: plain => `ENC:${plain}`,
126
+ decrypt: async cipher => cipher.replace("ENC:", "")
127
+ }
128
+ });
129
+ await sprinkle2.loadProfile("test");
130
+ (0, _bunTest.expect)(sprinkle2.settings).toEqual({
131
+ name: "visible",
132
+ secret: "hidden"
133
+ });
134
+ });
135
+ (0, _bunTest.test)("does not encrypt when no encryption configured", () => {
136
+ const schema = _index.Type.Object({
137
+ secret: _index.Type.String({
138
+ sensitive: true
139
+ })
140
+ });
141
+ const sprinkle = (0, _testHelpers.withProfile)(new _index.Sprinkle(schema, tmpDir));
142
+ sprinkle.settings = {
143
+ secret: "plain-value"
144
+ };
145
+ sprinkle.saveSettings();
146
+ const content = fs.readFileSync(path.join(tmpDir, "profiles", "test.json"), "utf-8");
147
+ const parsed = JSON.parse(content);
148
+ (0, _bunTest.expect)(parsed.settings.secret).toBe("plain-value");
149
+ });
150
+ (0, _bunTest.test)("encrypts nested sensitive fields", () => {
151
+ const schema = _index.Type.Object({
152
+ wallet: _index.Type.Object({
153
+ key: _index.Type.String({
154
+ sensitive: true
155
+ }),
156
+ address: _index.Type.String()
157
+ })
158
+ });
159
+ const sprinkle = (0, _testHelpers.withProfile)(new _index.Sprinkle(schema, tmpDir, {
160
+ encryption: {
161
+ encrypt: plain => `ENC:${plain}`,
162
+ decrypt: async cipher => cipher.replace("ENC:", "")
163
+ }
164
+ }));
165
+ sprinkle.settings = {
166
+ wallet: {
167
+ key: "secret-key",
168
+ address: "addr1..."
169
+ }
170
+ };
171
+ sprinkle.saveSettings();
172
+ const content = fs.readFileSync(path.join(tmpDir, "profiles", "test.json"), "utf-8");
173
+ const parsed = JSON.parse(content);
174
+ (0, _bunTest.expect)(parsed.settings.wallet.key).toBe("ENC:secret-key");
175
+ (0, _bunTest.expect)(parsed.settings.wallet.address).toBe("addr1...");
176
+ });
177
+ (0, _bunTest.test)("handles sensitive fields in union variants", () => {
178
+ const schema = _index.Type.Union([_index.Type.Object({
179
+ type: _index.Type.Literal("hot"),
180
+ privateKey: _index.Type.String({
181
+ sensitive: true
182
+ })
183
+ }), _index.Type.Object({
184
+ type: _index.Type.Literal("cold"),
185
+ address: _index.Type.String()
186
+ })]);
187
+ const outerSchema = _index.Type.Object({
188
+ wallet: schema
189
+ });
190
+ const sprinkle = (0, _testHelpers.withProfile)(new _index.Sprinkle(outerSchema, tmpDir, {
191
+ encryption: {
192
+ encrypt: plain => `ENC:${plain}`,
193
+ decrypt: async cipher => cipher.replace("ENC:", "")
194
+ }
195
+ }));
196
+ sprinkle.settings = {
197
+ wallet: {
198
+ type: "hot",
199
+ privateKey: "my-key"
200
+ }
201
+ };
202
+ sprinkle.saveSettings();
203
+ const content = fs.readFileSync(path.join(tmpDir, "profiles", "test.json"), "utf-8");
204
+ const parsed = JSON.parse(content);
205
+ (0, _bunTest.expect)(parsed.settings.wallet.privateKey).toBe("ENC:my-key");
206
+ });
207
+ (0, _bunTest.test)("round-trip with encryption preserves all data", async () => {
208
+ const schema = _index.Type.Object({
209
+ network: _index.Type.String(),
210
+ secret: _index.Type.String({
211
+ sensitive: true
212
+ }),
213
+ count: _index.Type.BigInt()
214
+ });
215
+ const opts = {
216
+ encryption: {
217
+ encrypt: plain => Buffer.from(plain).toString("base64"),
218
+ decrypt: async cipher => Buffer.from(cipher, "base64").toString()
219
+ }
220
+ };
221
+ const s1 = (0, _testHelpers.withProfile)(new _index.Sprinkle(schema, tmpDir, opts));
222
+ s1.settings = {
223
+ network: "mainnet",
224
+ secret: "top-secret",
225
+ count: 42n
226
+ };
227
+ s1.saveSettings();
228
+ const s2 = new _index.Sprinkle(schema, tmpDir, opts);
229
+ await s2.loadProfile("test");
230
+ (0, _bunTest.expect)(s2.settings).toEqual({
231
+ network: "mainnet",
232
+ secret: "top-secret",
233
+ count: 42n
234
+ });
235
+ });
236
+ });
237
+ (0, _bunTest.describe)("Sprinkle.New with options", () => {
238
+ (0, _bunTest.test)("passes options through to instance and migrates legacy", async () => {
239
+ const schema = _index.Type.Object({
240
+ name: _index.Type.String()
241
+ });
242
+
243
+ // Write legacy settings file so New triggers migration
244
+ fs.mkdirSync(tmpDir, {
245
+ recursive: true
246
+ });
247
+ fs.writeFileSync(path.join(tmpDir, "settings.json"), JSON.stringify({
248
+ settings: {
249
+ name: "test"
250
+ },
251
+ defaults: {}
252
+ }));
253
+ const sprinkle = await _index.Sprinkle.New(schema, tmpDir, {
254
+ encryption: {
255
+ encrypt: p => p,
256
+ decrypt: async c => c
257
+ }
258
+ });
259
+ (0, _bunTest.expect)(sprinkle.options.encryption).toBeDefined();
260
+ (0, _bunTest.expect)(sprinkle.profileId).toBe("default");
261
+ (0, _bunTest.expect)(sprinkle.settings).toEqual({
262
+ name: "test"
263
+ });
264
+ });
265
+ });
266
+ });
267
+ //# sourceMappingURL=encryption.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.test.js","names":["_bunTest","require","_index","fs","_interopRequireWildcard","path","os","_testHelpers","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","mockSelect","mock","mockInput","mockPassword","module","select","input","password","describe","tmpDir","beforeEach","mkdtempSync","join","tmpdir","mockClear","afterEach","rmSync","recursive","force","test","schema","Type","secret","String","sensitive","title","sprinkle","Sprinkle","mockResolvedValueOnce","result","FillInStruct","expect","toEqual","toHaveBeenCalledTimes","calls","message","toBe","not","toHaveBeenCalled","name","p","defaults","toBeUndefined","withProfile","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":[]}