@nfcard/validation 0.15.0 → 0.17.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.d.ts CHANGED
@@ -5306,9 +5306,13 @@ declare const entrySourceSchema: z.ZodObject<{
5306
5306
  ref: z.ZodOptional<z.ZodString>;
5307
5307
  path: z.ZodOptional<z.ZodString>;
5308
5308
  referrer: z.ZodOptional<z.ZodString>;
5309
+ material: z.ZodOptional<z.ZodEnum<["plastic", "3dprint_standard", "metal", "bamboo"]>>;
5310
+ template: z.ZodOptional<z.ZodString>;
5309
5311
  utm: z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodString>, Record<string, string>, Record<string, string>>>;
5310
5312
  }, "strict", z.ZodTypeAny, {
5311
5313
  path?: string | undefined;
5314
+ material?: "plastic" | "3dprint_standard" | "metal" | "bamboo" | undefined;
5315
+ template?: string | undefined;
5312
5316
  output?: "with-card" | "digital-only" | undefined;
5313
5317
  entryFlow?: "order" | "try" | undefined;
5314
5318
  ref?: string | undefined;
@@ -5316,6 +5320,8 @@ declare const entrySourceSchema: z.ZodObject<{
5316
5320
  utm?: Record<string, string> | undefined;
5317
5321
  }, {
5318
5322
  path?: string | undefined;
5323
+ material?: "plastic" | "3dprint_standard" | "metal" | "bamboo" | undefined;
5324
+ template?: string | undefined;
5319
5325
  output?: "with-card" | "digital-only" | undefined;
5320
5326
  entryFlow?: "order" | "try" | undefined;
5321
5327
  ref?: string | undefined;
@@ -8866,9 +8872,13 @@ declare const configurationCreateSchema: z.ZodObject<{
8866
8872
  ref: z.ZodOptional<z.ZodString>;
8867
8873
  path: z.ZodOptional<z.ZodString>;
8868
8874
  referrer: z.ZodOptional<z.ZodString>;
8875
+ material: z.ZodOptional<z.ZodEnum<["plastic", "3dprint_standard", "metal", "bamboo"]>>;
8876
+ template: z.ZodOptional<z.ZodString>;
8869
8877
  utm: z.ZodOptional<z.ZodEffects<z.ZodRecord<z.ZodString, z.ZodString>, Record<string, string>, Record<string, string>>>;
8870
8878
  }, "strict", z.ZodTypeAny, {
8871
8879
  path?: string | undefined;
8880
+ material?: "plastic" | "3dprint_standard" | "metal" | "bamboo" | undefined;
8881
+ template?: string | undefined;
8872
8882
  output?: "with-card" | "digital-only" | undefined;
8873
8883
  entryFlow?: "order" | "try" | undefined;
8874
8884
  ref?: string | undefined;
@@ -8876,6 +8886,8 @@ declare const configurationCreateSchema: z.ZodObject<{
8876
8886
  utm?: Record<string, string> | undefined;
8877
8887
  }, {
8878
8888
  path?: string | undefined;
8889
+ material?: "plastic" | "3dprint_standard" | "metal" | "bamboo" | undefined;
8890
+ template?: string | undefined;
8879
8891
  output?: "with-card" | "digital-only" | undefined;
8880
8892
  entryFlow?: "order" | "try" | undefined;
8881
8893
  ref?: string | undefined;
@@ -9240,6 +9252,8 @@ declare const configurationCreateSchema: z.ZodObject<{
9240
9252
  physicalTemplateId?: string | undefined;
9241
9253
  entrySource?: {
9242
9254
  path?: string | undefined;
9255
+ material?: "plastic" | "3dprint_standard" | "metal" | "bamboo" | undefined;
9256
+ template?: string | undefined;
9243
9257
  output?: "with-card" | "digital-only" | undefined;
9244
9258
  entryFlow?: "order" | "try" | undefined;
9245
9259
  ref?: string | undefined;
@@ -9604,6 +9618,8 @@ declare const configurationCreateSchema: z.ZodObject<{
9604
9618
  physicalTemplateId?: string | undefined;
9605
9619
  entrySource?: {
9606
9620
  path?: string | undefined;
9621
+ material?: "plastic" | "3dprint_standard" | "metal" | "bamboo" | undefined;
9622
+ template?: string | undefined;
9607
9623
  output?: "with-card" | "digital-only" | undefined;
9608
9624
  entryFlow?: "order" | "try" | undefined;
9609
9625
  ref?: string | undefined;
package/dist/index.js CHANGED
Binary file
package/package.json CHANGED
@@ -1,39 +1,45 @@
1
- {
2
- "name": "@nfcard/validation",
3
- "version": "0.15.0",
4
- "description": "Shared Zod validation schemas for the NFCard product family.",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
12
- }
13
- },
14
- "files": [
15
- "dist",
16
- "src"
17
- ],
18
- "dependencies": {
19
- "zod": "^3.24.0",
20
- "@nfcard/types": "0.13.0"
21
- },
22
- "devDependencies": {
23
- "tsup": "^8.0.0"
24
- },
25
- "publishConfig": {
26
- "access": "public",
27
- "registry": "https://registry.npmjs.org/"
28
- },
29
- "repository": {
30
- "type": "git",
31
- "url": "https://bitbucket.org/fox-hole/nfcard-shared.git",
32
- "directory": "validation"
33
- },
34
- "scripts": {
35
- "test": "vitest run",
36
- "test:watch": "vitest",
37
- "build": "tsup src/index.ts --format esm --dts --clean"
38
- }
39
- }
1
+ {
2
+ "name": "@nfcard/validation",
3
+ "version": "0.17.0",
4
+ "description": "Shared Zod validation schemas for the NFCard product family.",
5
+ "type": "module",
6
+ "main": "./src/index.ts",
7
+ "types": "./src/index.ts",
8
+ "exports": {
9
+ ".": "./src/index.ts"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "src"
14
+ ],
15
+ "scripts": {
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "build": "tsup src/index.ts --format esm --dts --clean",
19
+ "prepublishOnly": "pnpm build"
20
+ },
21
+ "dependencies": {
22
+ "zod": "^3.24.0",
23
+ "@nfcard/types": "workspace:*"
24
+ },
25
+ "devDependencies": {
26
+ "tsup": "^8.0.0"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public",
30
+ "registry": "https://registry.npmjs.org/",
31
+ "main": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "import": "./dist/index.js",
36
+ "types": "./dist/index.d.ts"
37
+ }
38
+ }
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://bitbucket.org/fox-hole/nfcard-shared.git",
43
+ "directory": "validation"
44
+ }
45
+ }
@@ -81,6 +81,22 @@ describe('cardDesignSchema — free-transform element layer (NFCARD-197/198)', (
81
81
  expect(res.success).toBe(true)
82
82
  })
83
83
 
84
+ it('NFCARD-480: accepts a HIDDEN chip (shape -1) — the order gate must not 400 it', () => {
85
+ const res = cardDesignSchema.safeParse(withElements([chipEl({ shape: -1 }), textEl(), qrEl()]))
86
+ expect(res.success).toBe(true)
87
+ })
88
+
89
+ it('NFCARD-480: a CELL never takes the hidden sentinel (cellShape -1 still rejected)', () => {
90
+ const validPattern = {
91
+ family: 'spiral', variant: 'pulse', density: 0.3, holeMinMm: 0.5, holeMaxMm: 1.8,
92
+ intensity: 0.5, cellShape: 0, cellRotationDeg: 0, chipShape: 0, chipRotationDeg: 0,
93
+ }
94
+ expect(cardDesignSchema.safeParse(withElements([chipEl()], { pattern: validPattern })).success).toBe(true)
95
+ const res = cardDesignSchema.safeParse(withElements([chipEl()], { pattern: { ...validPattern, cellShape: -1 } }))
96
+ expect(res.success).toBe(false)
97
+ expect(codes(res)).toContain('cellSidesRange')
98
+ })
99
+
84
100
  it('rejects a QR below the scannable size floor', () => {
85
101
  const res = cardDesignSchema.safeParse(withElements([chipEl(), qrEl({ sizeMm: 12 })]))
86
102
  expect(res.success).toBe(false)
package/src/index.test.ts CHANGED
@@ -974,74 +974,104 @@ describe('physicalConfig.cardDesign (nested, not stripped)', () => {
974
974
  expect(physicalConfigSchema.safeParse(validPhysicalConfig).success).toBe(true);
975
975
  });
976
976
  });
977
-
978
- // -- entrySourceSchema (NFCARD-392) --------------------------------
979
-
980
- describe('entrySourceSchema on configurationCreateSchema', () => {
981
- const base = {
982
- sessionId: '550e8400-e29b-41d4-a716-446655440000',
983
- userData: validUserData,
984
- physicalConfig: validPhysicalConfig,
985
- digitalConfig: validDigitalConfig,
986
- };
987
-
988
- it('accepts a full entry-attribution blob', () => {
989
- const r = configurationCreateSchema.safeParse({
990
- ...base,
991
- entrySource: {
992
- output: 'with-card',
993
- entryFlow: 'order',
994
- ref: 'PROMO24',
995
- path: '/configurator',
996
- referrer: 'google.com',
997
- utm: { utm_source: 'ads', utm_campaign: 'launch' },
998
- },
999
- });
1000
- expect(r.success).toBe(true);
1001
- if (r.success) expect(r.data.entrySource?.output).toBe('with-card');
1002
- });
1003
-
1004
- it('is optional — older clients omit it entirely', () => {
1005
- const r = configurationCreateSchema.safeParse(base);
1006
- expect(r.success).toBe(true);
1007
- if (r.success) expect(r.data.entrySource).toBeUndefined();
1008
- });
1009
-
1010
- it('rejects unknown keys (strict) and out-of-enum values', () => {
1011
- expect(
1012
- configurationCreateSchema.safeParse({
1013
- ...base,
1014
- entrySource: { output: 'with-card', evil: 'payload' },
1015
- }).success,
1016
- ).toBe(false);
1017
- expect(
1018
- configurationCreateSchema.safeParse({
1019
- ...base,
1020
- entrySource: { output: 'both-please' },
1021
- }).success,
1022
- ).toBe(false);
1023
- });
1024
-
1025
- it('bounds the utm map (max 10 entries, capped value length)', () => {
1026
- const utm: Record<string, string> = {};
1027
- for (let i = 0; i < 11; i++) utm['k' + i] = 'v';
1028
- expect(
1029
- configurationCreateSchema.safeParse({ ...base, entrySource: { utm } }).success,
1030
- ).toBe(false);
1031
- expect(
1032
- configurationCreateSchema.safeParse({
1033
- ...base,
1034
- entrySource: { referrer: 'x'.repeat(300) },
1035
- }).success,
1036
- ).toBe(false);
1037
- });
1038
-
1039
- it('is create-only: the update schema strips/ignores it', () => {
1040
- const r = configurationUpdateSchema.safeParse({
1041
- entrySource: { output: 'with-card' },
1042
- });
1043
- // z.object strips unknown keys by default - the field must not survive.
1044
- expect(r.success).toBe(true);
1045
- if (r.success) expect((r.data as Record<string, unknown>).entrySource).toBeUndefined();
1046
- });
1047
- });
977
+
978
+ // -- entrySourceSchema (NFCARD-392) --------------------------------
979
+
980
+ describe('entrySourceSchema on configurationCreateSchema', () => {
981
+ const base = {
982
+ sessionId: '550e8400-e29b-41d4-a716-446655440000',
983
+ userData: validUserData,
984
+ physicalConfig: validPhysicalConfig,
985
+ digitalConfig: validDigitalConfig,
986
+ };
987
+
988
+ it('accepts a full entry-attribution blob', () => {
989
+ const r = configurationCreateSchema.safeParse({
990
+ ...base,
991
+ entrySource: {
992
+ output: 'with-card',
993
+ entryFlow: 'order',
994
+ ref: 'PROMO24',
995
+ path: '/configurator',
996
+ referrer: 'google.com',
997
+ utm: { utm_source: 'ads', utm_campaign: 'launch' },
998
+ },
999
+ });
1000
+ expect(r.success).toBe(true);
1001
+ if (r.success) expect(r.data.entrySource?.output).toBe('with-card');
1002
+ });
1003
+
1004
+ it('is optional — older clients omit it entirely', () => {
1005
+ const r = configurationCreateSchema.safeParse(base);
1006
+ expect(r.success).toBe(true);
1007
+ if (r.success) expect(r.data.entrySource).toBeUndefined();
1008
+ });
1009
+
1010
+ it('rejects unknown keys (strict) and out-of-enum values', () => {
1011
+ expect(
1012
+ configurationCreateSchema.safeParse({
1013
+ ...base,
1014
+ entrySource: { output: 'with-card', evil: 'payload' },
1015
+ }).success,
1016
+ ).toBe(false);
1017
+ expect(
1018
+ configurationCreateSchema.safeParse({
1019
+ ...base,
1020
+ entrySource: { output: 'both-please' },
1021
+ }).success,
1022
+ ).toBe(false);
1023
+ });
1024
+
1025
+ it('bounds the utm map (max 10 entries, capped value length)', () => {
1026
+ const utm: Record<string, string> = {};
1027
+ for (let i = 0; i < 11; i++) utm['k' + i] = 'v';
1028
+ expect(
1029
+ configurationCreateSchema.safeParse({ ...base, entrySource: { utm } }).success,
1030
+ ).toBe(false);
1031
+ expect(
1032
+ configurationCreateSchema.safeParse({
1033
+ ...base,
1034
+ entrySource: { referrer: 'x'.repeat(300) },
1035
+ }).success,
1036
+ ).toBe(false);
1037
+ });
1038
+
1039
+ it('is create-only: the update schema strips/ignores it', () => {
1040
+ const r = configurationUpdateSchema.safeParse({
1041
+ entrySource: { output: 'with-card' },
1042
+ });
1043
+ // z.object strips unknown keys by default - the field must not survive.
1044
+ expect(r.success).toBe(true);
1045
+ if (r.success) expect((r.data as Record<string, unknown>).entrySource).toBeUndefined();
1046
+ });
1047
+ });
1048
+
1049
+ describe('entrySourceSchema material/template preselects (NFCARD-393)', () => {
1050
+ const base = {
1051
+ sessionId: '550e8400-e29b-41d4-a716-446655440000',
1052
+ userData: validUserData,
1053
+ physicalConfig: validPhysicalConfig,
1054
+ digitalConfig: validDigitalConfig,
1055
+ };
1056
+
1057
+ it('accepts the deep-link preselects', () => {
1058
+ const r = configurationCreateSchema.safeParse({
1059
+ ...base,
1060
+ entrySource: { output: 'with-card', material: '3dprint_standard', template: 'tpl-pvc-white' },
1061
+ });
1062
+ expect(r.success).toBe(true);
1063
+ if (r.success) {
1064
+ expect(r.data.entrySource?.material).toBe('3dprint_standard');
1065
+ expect(r.data.entrySource?.template).toBe('tpl-pvc-white');
1066
+ }
1067
+ });
1068
+
1069
+ it('rejects a non-enum material', () => {
1070
+ expect(
1071
+ configurationCreateSchema.safeParse({
1072
+ ...base,
1073
+ entrySource: { material: 'carbon-fiber' },
1074
+ }).success,
1075
+ ).toBe(false);
1076
+ });
1077
+ });
package/src/index.ts CHANGED
Binary file