@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 +16 -0
- package/dist/index.js +0 -0
- package/package.json +45 -39
- package/src/elements.test.ts +16 -0
- package/src/index.test.ts +101 -71
- package/src/index.ts +0 -0
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.
|
|
4
|
-
"description": "Shared Zod validation schemas for the NFCard product family.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./
|
|
7
|
-
"types": "./
|
|
8
|
-
"exports": {
|
|
9
|
-
".":
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
},
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
+
}
|
package/src/elements.test.ts
CHANGED
|
@@ -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
|