@memizy/oqse 0.1.2 → 0.1.4

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.
@@ -2,7 +2,7 @@
2
2
  * OQSEP v0.1 Type Definitions
3
3
  * (Open Quiz & Study Exchange - Progress)
4
4
  *
5
- * @see /SPECIFICATION.md#25-user-progress-portability-oqsep
5
+ * @see ../oqse-progress.md#data-model
6
6
  */
7
7
  /** Aggregate performance statistics for a single item. */
8
8
  export interface StatsObject {
@@ -16,7 +16,7 @@ export interface LastAnswerObject {
16
16
  confidence?: 1 | 2 | 3 | 4;
17
17
  answeredAt: string;
18
18
  timeSpent?: number;
19
- hintsUsed?: number;
19
+ hintsUsed: number;
20
20
  isSkipped?: boolean;
21
21
  }
22
22
  /** Progress state for one item from the linked OQSE set. */
@@ -34,7 +34,7 @@ export interface ProgressMeta {
34
34
  algorithm?: string;
35
35
  }
36
36
  /** Root OQSEP payload for one user and one study set. */
37
- export interface OQSEPFile {
37
+ export interface OQSEProgress {
38
38
  $schema?: string;
39
39
  version: string;
40
40
  meta: ProgressMeta;
@@ -1,9 +1,9 @@
1
1
  import { z } from 'zod';
2
- import { LastAnswerObject, OQSEPFile, ProgressMeta, ProgressRecord, StatsObject } from './progress';
2
+ import { LastAnswerObject, OQSEProgress, ProgressMeta, ProgressRecord, StatsObject } from './progress';
3
3
  export declare const StatsObjectSchema: z.ZodType<StatsObject>;
4
4
  export declare const LastAnswerObjectSchema: z.ZodType<LastAnswerObject>;
5
5
  export declare const ProgressRecordSchema: z.ZodType<ProgressRecord>;
6
6
  export declare const ProgressMetaSchema: z.ZodType<ProgressMeta>;
7
- export declare const OQSEPFileSchema: z.ZodType<OQSEPFile>;
8
- export declare function validateOQSEPFile(data: unknown): OQSEPFile;
9
- export declare function safeValidateOQSEPFile(data: unknown): ReturnType<typeof OQSEPFileSchema.safeParse>;
7
+ export declare const OQSEProgressSchema: z.ZodType<OQSEProgress>;
8
+ export declare function validateOQSEProgress(data: unknown): OQSEProgress;
9
+ export declare function safeValidateOQSEProgress(data: unknown): ReturnType<typeof OQSEProgressSchema.safeParse>;
@@ -1,3 +1,4 @@
1
+ import { ZodError } from 'zod';
1
2
  export type UUID = string;
2
3
  /**
3
4
  * Validates if the given string is a syntactically valid UUID (any version).
@@ -10,3 +11,13 @@ export declare function isValidUUID(id: string): boolean;
10
11
  * because it is time-sortable and optimized for database indexing.
11
12
  */
12
13
  export declare function generateUUID(): UUID;
14
+ /**
15
+ * Checks if an object exceeds the maximum allowed nesting depth.
16
+ * OQSE specification requires a limit of 10 levels for customData and appSpecific.
17
+ */
18
+ export declare function validateJsonDepth(data: unknown, maxDepth?: number, currentDepth?: number): void;
19
+ /**
20
+ * Formats a ZodError into a flat array of human-readable string messages.
21
+ * Useful for displaying validation issues in UI lists or console logs.
22
+ */
23
+ export declare function formatOQSEErrors(error: ZodError): string[];
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memizy/oqse",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "TypeScript SDK and Zod validators for the OQSE specification.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -29,6 +29,7 @@
29
29
  "prepublishOnly": "npm run build"
30
30
  },
31
31
  "devDependencies": {
32
+ "@types/node": "^25.6.0",
32
33
  "@types/uuid": "^10.0.0",
33
34
  "tsx": "^4.21.0",
34
35
  "typescript": "~6.0.2",
@@ -0,0 +1,120 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "id": {
6
+ "type": "string",
7
+ "format": "uuid",
8
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
9
+ },
10
+ "title": {
11
+ "type": "string",
12
+ "minLength": 1,
13
+ "maxLength": 500
14
+ },
15
+ "language": {
16
+ "type": "string",
17
+ "minLength": 2,
18
+ "pattern": "^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2})?$"
19
+ },
20
+ "updatedAt": {
21
+ "type": "string",
22
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?(Z|[+-]\\d{2}:\\d{2})?)?$"
23
+ },
24
+ "description": {
25
+ "type": "string",
26
+ "minLength": 1,
27
+ "maxLength": 5000
28
+ },
29
+ "author": {
30
+ "type": "object",
31
+ "properties": {
32
+ "name": {
33
+ "type": "string",
34
+ "minLength": 1
35
+ },
36
+ "role": {
37
+ "type": "string"
38
+ },
39
+ "email": {
40
+ "type": "string",
41
+ "format": "email",
42
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
43
+ },
44
+ "url": {
45
+ "type": "string",
46
+ "format": "uri"
47
+ }
48
+ },
49
+ "required": [
50
+ "name"
51
+ ],
52
+ "additionalProperties": false
53
+ },
54
+ "subject": {
55
+ "type": "string"
56
+ },
57
+ "tags": {
58
+ "type": "array",
59
+ "items": {
60
+ "type": "string",
61
+ "minLength": 1
62
+ }
63
+ },
64
+ "createdAt": {
65
+ "type": "string",
66
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?(Z|[+-]\\d{2}:\\d{2})?)?$"
67
+ },
68
+ "estimatedTime": {
69
+ "type": "number",
70
+ "exclusiveMinimum": 0
71
+ },
72
+ "requirements": {
73
+ "type": "object",
74
+ "properties": {
75
+ "features": {
76
+ "type": "array",
77
+ "items": {
78
+ "type": "string"
79
+ }
80
+ },
81
+ "latexPackages": {
82
+ "type": "array",
83
+ "items": {
84
+ "type": "string",
85
+ "minLength": 1
86
+ }
87
+ },
88
+ "itemProperties": {
89
+ "type": "array",
90
+ "items": {
91
+ "type": "string"
92
+ }
93
+ },
94
+ "metaProperties": {
95
+ "type": "array",
96
+ "items": {
97
+ "type": "string"
98
+ }
99
+ }
100
+ },
101
+ "additionalProperties": false
102
+ },
103
+ "url": {
104
+ "type": "string",
105
+ "format": "uri"
106
+ },
107
+ "$schema": {
108
+ "type": "string",
109
+ "format": "uri"
110
+ }
111
+ },
112
+ "required": [
113
+ "id",
114
+ "title",
115
+ "language",
116
+ "updatedAt",
117
+ "url"
118
+ ],
119
+ "additionalProperties": false
120
+ }
@@ -7,22 +7,28 @@
7
7
  "format": "uri"
8
8
  },
9
9
  "id": {
10
- "type": "string",
11
- "minLength": 1,
12
- "pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)*$"
10
+ "anyOf": [
11
+ {
12
+ "type": "string",
13
+ "format": "uri"
14
+ },
15
+ {
16
+ "type": "string",
17
+ "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
18
+ }
19
+ ]
13
20
  },
14
21
  "appName": {
15
22
  "type": "string",
16
23
  "minLength": 1,
17
- "maxLength": 100
24
+ "maxLength": 200
18
25
  },
19
26
  "version": {
20
27
  "type": "string",
21
28
  "pattern": "^\\d+\\.\\d+$"
22
29
  },
23
30
  "pluginVersion": {
24
- "type": "string",
25
- "pattern": "^\\d+\\.\\d+\\.\\d+$"
31
+ "type": "string"
26
32
  },
27
33
  "minOqseVersion": {
28
34
  "type": "string",
@@ -191,10 +197,63 @@
191
197
  "additionalProperties": false
192
198
  },
193
199
  "author": {
200
+ "type": "object",
201
+ "properties": {
202
+ "name": {
203
+ "type": "string",
204
+ "minLength": 1
205
+ },
206
+ "role": {
207
+ "type": "string"
208
+ },
209
+ "email": {
210
+ "type": "string",
211
+ "format": "email",
212
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
213
+ },
214
+ "url": {
215
+ "type": "string",
216
+ "format": "uri"
217
+ }
218
+ },
219
+ "required": [
220
+ "name"
221
+ ],
222
+ "additionalProperties": false
223
+ },
224
+ "contributors": {
225
+ "type": "array",
226
+ "items": {
227
+ "type": "object",
228
+ "properties": {
229
+ "name": {
230
+ "type": "string",
231
+ "minLength": 1
232
+ },
233
+ "role": {
234
+ "type": "string"
235
+ },
236
+ "email": {
237
+ "type": "string",
238
+ "format": "email",
239
+ "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
240
+ },
241
+ "url": {
242
+ "type": "string",
243
+ "format": "uri"
244
+ }
245
+ },
246
+ "required": [
247
+ "name"
248
+ ],
249
+ "additionalProperties": false
250
+ }
251
+ },
252
+ "license": {
194
253
  "type": "string",
195
254
  "maxLength": 100
196
255
  },
197
- "authorUrl": {
256
+ "licenseUrl": {
198
257
  "type": "string",
199
258
  "format": "uri"
200
259
  },
@@ -202,12 +261,12 @@
202
261
  "type": "array",
203
262
  "items": {
204
263
  "type": "string",
205
- "minLength": 1
264
+ "pattern": "^[a-zA-Z]{2,8}(-[a-zA-Z0-9\\-]+)*$"
206
265
  }
207
266
  },
208
267
  "description": {
209
268
  "type": "string",
210
- "maxLength": 500
269
+ "maxLength": 5000
211
270
  },
212
271
  "emoji": {
213
272
  "type": "string"
@@ -133,6 +133,7 @@
133
133
  "maximum": 9007199254740991
134
134
  },
135
135
  "hintsUsed": {
136
+ "default": 0,
136
137
  "type": "integer",
137
138
  "minimum": 0,
138
139
  "maximum": 9007199254740991
@@ -143,7 +144,8 @@
143
144
  },
144
145
  "required": [
145
146
  "isCorrect",
146
- "answeredAt"
147
+ "answeredAt",
148
+ "hintsUsed"
147
149
  ],
148
150
  "additionalProperties": false
149
151
  },