@sundaeswap/sprinkles 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sundaeswap/sprinkles",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "A TypeScript library for building interactive CLI menus and TUI applications with TypeBox schema validation",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -178,4 +178,112 @@ describe("Settings Persistence", () => {
178
178
  expect(sprinkle.defaults).toEqual({ string: "old" });
179
179
  expect(sprinkle.profileMeta.name).toBe("Default");
180
180
  });
181
+
182
+ describe("currentProfile", () => {
183
+ test("returns null when no profile loaded", () => {
184
+ const schema = Type.Object({ name: Type.String() });
185
+ const sprinkle = new Sprinkle(schema, tmpDir);
186
+
187
+ expect(sprinkle.currentProfile).toBeNull();
188
+ });
189
+
190
+ test("returns profile info when loaded", () => {
191
+ const schema = Type.Object({ name: Type.String() });
192
+ const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
193
+
194
+ const profile = sprinkle.currentProfile;
195
+ expect(profile).not.toBeNull();
196
+ expect(profile!.id).toBe("test");
197
+ expect(profile!.name).toBe("Test");
198
+ expect(profile!.createdAt).toBeDefined();
199
+ expect(profile!.updatedAt).toBeDefined();
200
+ });
201
+
202
+ test("includes description when present", () => {
203
+ const schema = Type.Object({ name: Type.String() });
204
+ const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
205
+ sprinkle.profileMeta.description = "Test profile description";
206
+
207
+ const profile = sprinkle.currentProfile;
208
+ expect(profile!.description).toBe("Test profile description");
209
+ });
210
+
211
+ test("has undefined description when not set", () => {
212
+ const schema = Type.Object({ name: Type.String() });
213
+ const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
214
+ delete sprinkle.profileMeta.description;
215
+
216
+ const profile = sprinkle.currentProfile;
217
+ expect(profile!.description).toBeUndefined();
218
+ });
219
+ });
220
+
221
+ describe("getDisplaySettings", () => {
222
+ test("masks sensitive fields", () => {
223
+ const schema = Type.Object({
224
+ name: Type.String(),
225
+ secret: Type.String({ sensitive: true }),
226
+ });
227
+ const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
228
+ sprinkle.settings = { name: "visible", secret: "hidden" } as any;
229
+
230
+ const display = sprinkle.getDisplaySettings();
231
+ expect(display.name).toBe("visible");
232
+ expect(display.secret).toBe("********");
233
+ });
234
+
235
+ test("preserves non-sensitive fields", () => {
236
+ const schema = Type.Object({
237
+ name: Type.String(),
238
+ count: Type.Number(),
239
+ });
240
+ const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
241
+ sprinkle.settings = { name: "test", count: 42 } as any;
242
+
243
+ const display = sprinkle.getDisplaySettings();
244
+ expect(display.name).toBe("test");
245
+ expect(display.count).toBe(42);
246
+ });
247
+
248
+ test("preserves BigInt values", () => {
249
+ const schema = Type.Object({
250
+ amount: Type.BigInt(),
251
+ secret: Type.String({ sensitive: true }),
252
+ });
253
+ const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
254
+ sprinkle.settings = { amount: 42n, secret: "hidden" } as any;
255
+
256
+ const display = sprinkle.getDisplaySettings();
257
+ expect(display.amount).toBe(42n);
258
+ expect(display.secret).toBe("********");
259
+ });
260
+
261
+ test("masks nested sensitive fields", () => {
262
+ const schema = Type.Object({
263
+ wallet: Type.Object({
264
+ key: Type.String({ sensitive: true }),
265
+ address: Type.String(),
266
+ }),
267
+ });
268
+ const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
269
+ sprinkle.settings = {
270
+ wallet: { key: "secret", address: "addr1..." },
271
+ } as any;
272
+
273
+ const display = sprinkle.getDisplaySettings();
274
+ expect(display.wallet.key).toBe("********");
275
+ expect(display.wallet.address).toBe("addr1...");
276
+ });
277
+
278
+ test("does not mask empty sensitive fields", () => {
279
+ const schema = Type.Object({
280
+ secret: Type.String({ sensitive: true }),
281
+ });
282
+ const sprinkle = withProfile(new Sprinkle(schema, tmpDir));
283
+ sprinkle.settings = { secret: "" } as any;
284
+
285
+ const display = sprinkle.getDisplaySettings();
286
+ expect(display.secret).toBe("");
287
+ });
288
+ });
181
289
  });
@@ -74,6 +74,10 @@ export interface IProfileMeta {
74
74
  updatedAt: string;
75
75
  }
76
76
 
77
+ export interface ICurrentProfile extends IProfileMeta {
78
+ id: string;
79
+ }
80
+
77
81
  export interface IProfileEntry {
78
82
  id: string;
79
83
  meta: IProfileMeta;
@@ -211,6 +215,16 @@ export class Sprinkle<S extends TSchema> {
211
215
  this.options = options ?? {};
212
216
  }
213
217
 
218
+ // --- Current Profile Accessor ---
219
+
220
+ get currentProfile(): ICurrentProfile | null {
221
+ if (!this.profileId) return null;
222
+ return {
223
+ id: this.profileId,
224
+ ...this.profileMeta,
225
+ };
226
+ }
227
+
214
228
  // --- Profile path helpers ---
215
229
 
216
230
  static sanitizeProfileId(name: string): string {
@@ -865,6 +879,21 @@ export class Sprinkle<S extends TSchema> {
865
879
  this.saveProfile();
866
880
  }
867
881
 
882
+ getDisplaySettings(): TExact<S> {
883
+ const clone = JSON.parse(
884
+ JSON.stringify(this.settings, Sprinkle.bigIntReplacer),
885
+ Sprinkle.bigIntReviver,
886
+ );
887
+ const sensitivePaths = Sprinkle.collectSensitivePaths(this.type);
888
+ for (const p of sensitivePaths) {
889
+ const value = Sprinkle.getNestedValue(clone, p);
890
+ if (typeof value === "string" && value.length > 0) {
891
+ Sprinkle.setNestedValue(clone, p, "********");
892
+ }
893
+ }
894
+ return clone;
895
+ }
896
+
868
897
  // --- TxDialog Helpers ---
869
898
 
870
899
  /**