@nfcard/validation 0.8.0 → 0.9.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/index.js CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nfcard/validation",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Shared Zod validation schemas for the NFCard product family.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "dependencies": {
19
19
  "zod": "^3.24.0",
20
- "@nfcard/types": "0.7.0"
20
+ "@nfcard/types": "0.8.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "tsup": "^8.0.0"
package/src/index.test.ts CHANGED
@@ -6,11 +6,9 @@ import {
6
6
  configurationCreateSchema,
7
7
  contactExchangeSchema,
8
8
  createOrderSchema,
9
- ctaButtonsSchema,
10
9
  digitalConfigSchema,
11
10
  hubConfigSchema,
12
11
  materialSchema,
13
- MAX_CTA_BUTTONS,
14
12
  physicalConfigSchema,
15
13
  profileCreateSchema,
16
14
  profileVisibilitySchema,
@@ -270,93 +268,6 @@ describe('socialOverridesSchema (FOXHOLE-595 input side)', () => {
270
268
  });
271
269
  });
272
270
 
273
- // ── ctaButtonsSchema (NFCARD-211 — Pro CTA buttons) ─────────────
274
-
275
- describe('ctaButtonsSchema (NFCARD-211 — Pro CTA buttons)', () => {
276
- it('keeps a valid button and upgrades http → https', () => {
277
- const out = ctaButtonsSchema.parse([
278
- { label: 'Book a call', url: 'http://calendly.com/foxhome' },
279
- ]);
280
- expect(out).toEqual([
281
- { label: 'Book a call', url: 'https://calendly.com/foxhome' },
282
- ]);
283
- });
284
-
285
- it('prefixes https onto a bare-host url', () => {
286
- const [btn] = ctaButtonsSchema.parse([
287
- { label: 'Shop', url: 'foxhome.hu/shop' },
288
- ]);
289
- expect(btn.url).toBe('https://foxhome.hu/shop');
290
- });
291
-
292
- it.each([
293
- 'javascript:alert(1)',
294
- 'JaVaScRiPt:alert(1)',
295
- 'data:text/html,<script>alert(1)</script>',
296
- 'vbscript:msgbox(1)',
297
- 'file:///etc/passwd',
298
- 'mailto:a@b.c',
299
- ])('drops a button whose url is a dangerous/non-http scheme: %s', (bad) => {
300
- // url sanitizes to '' → the button is incomplete → filtered out.
301
- expect(ctaButtonsSchema.parse([{ label: 'Click me', url: bad }])).toEqual([]);
302
- });
303
-
304
- it('strips HTML tags from the label and caps its length at 40', () => {
305
- const [btn] = ctaButtonsSchema.parse([
306
- { label: '<b>Pay now</b>', url: 'https://pay.example.com' },
307
- ]);
308
- expect(btn.label).toBe('Pay now');
309
- const long = ctaButtonsSchema.parse([
310
- { label: 'x'.repeat(200), url: 'https://e.com' },
311
- ]);
312
- expect(long[0].label.length).toBe(40);
313
- });
314
-
315
- it('drops incomplete buttons (missing label or url)', () => {
316
- const out = ctaButtonsSchema.parse([
317
- { label: '', url: 'https://valid.example.com' },
318
- { label: 'No link', url: '' },
319
- { label: 'Good', url: 'https://ok.example.com' },
320
- ]);
321
- // URL.href normalises a bare origin with a trailing slash.
322
- expect(out).toEqual([{ label: 'Good', url: 'https://ok.example.com/' }]);
323
- });
324
-
325
- it(`caps the list at MAX_CTA_BUTTONS (${MAX_CTA_BUTTONS})`, () => {
326
- const many = Array.from({ length: MAX_CTA_BUTTONS + 4 }, (_, i) => ({
327
- label: `Btn ${i}`,
328
- url: `https://e${i}.example.com`,
329
- }));
330
- expect(ctaButtonsSchema.parse(many)).toHaveLength(MAX_CTA_BUTTONS);
331
- });
332
-
333
- it('rejects an abusive payload over the hard array cap', () => {
334
- const huge = Array.from({ length: 51 }, () => ({
335
- label: 'x',
336
- url: 'https://e.example.com',
337
- }));
338
- expect(ctaButtonsSchema.safeParse(huge).success).toBe(false);
339
- });
340
-
341
- it('flows through digitalConfigSchema — unsafe buttons dropped on save', () => {
342
- const r = digitalConfigSchema.safeParse({
343
- templateId: 'card',
344
- accentColor: '#1A6B52',
345
- fontKey: 'inter',
346
- showAvatar: true,
347
- ctaButtons: [
348
- { label: 'Evil', url: 'javascript:alert(1)' },
349
- { label: 'Book', url: 'calendly.com/x' },
350
- ],
351
- });
352
- expect(r.success).toBe(true);
353
- if (r.success)
354
- expect(r.data.ctaButtons).toEqual([
355
- { label: 'Book', url: 'https://calendly.com/x' },
356
- ]);
357
- });
358
- });
359
-
360
271
  // ── userDataSchema ──────────────────────────────────────────────
361
272
 
362
273
  describe('userDataSchema / validateUserData', () => {
package/src/index.ts CHANGED
Binary file