@basictech/react 0.2.0-beta.8 → 0.2.0-beta.9

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/changelog.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # 1.3.4
2
2
 
3
+ ## 0.2.0-beta.9
4
+
5
+ ### Minor Changes
6
+
7
+ - add schema validation
8
+
3
9
  ## 0.2.0-beta.8
4
10
 
5
11
  ### Minor Changes
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
+ import { ErrorObject } from 'ajv';
3
4
 
4
5
  declare enum DBStatus {
5
6
  LOADING = "LOADING",
@@ -37,6 +38,97 @@ declare function useBasic(): {
37
38
  dbStatus: DBStatus;
38
39
  };
39
40
 
41
+ declare const basicJsonSchema: {
42
+ $schema: string;
43
+ type: string;
44
+ properties: {
45
+ project_id: {
46
+ type: string;
47
+ };
48
+ namespace: {
49
+ type: string;
50
+ };
51
+ version: {
52
+ type: string;
53
+ minimum: number;
54
+ };
55
+ tables: {
56
+ type: string;
57
+ patternProperties: {
58
+ "^[a-zA-Z0-9_]+$": {
59
+ type: string;
60
+ properties: {
61
+ name: {
62
+ type: string;
63
+ };
64
+ type: {
65
+ type: string;
66
+ enum: string[];
67
+ };
68
+ fields: {
69
+ type: string;
70
+ patternProperties: {
71
+ "^[a-zA-Z0-9_]+$": {
72
+ type: string;
73
+ properties: {
74
+ type: {
75
+ type: string;
76
+ enum: string[];
77
+ };
78
+ indexed: {
79
+ type: string;
80
+ };
81
+ required: {
82
+ type: string;
83
+ };
84
+ };
85
+ required: string[];
86
+ };
87
+ };
88
+ additionalProperties: boolean;
89
+ };
90
+ };
91
+ required: string[];
92
+ };
93
+ };
94
+ additionalProperties: boolean;
95
+ };
96
+ };
97
+ required: string[];
98
+ };
99
+ type Schema = typeof basicJsonSchema;
100
+ declare function generateEmptySchema(): void;
101
+ /**
102
+ * Validate a schema
103
+ * only checks if the schema is formatted correctly, not if can be published
104
+ * @param schema - The schema to validate
105
+ * @returns {valid: boolean, errors: any[]} - The validation result
106
+ */
107
+ declare function validateSchema(schema: Schema): {
108
+ valid: boolean;
109
+ errors: ErrorObject[];
110
+ };
111
+ declare function validateData(schema: any, table: string, data: Record<string, any>, checkRequired?: boolean): {
112
+ valid: boolean;
113
+ errors: ErrorObject<string, Record<string, any>, unknown>[];
114
+ message: string;
115
+ } | {
116
+ valid: boolean;
117
+ errors: {
118
+ message: string;
119
+ }[];
120
+ message: string;
121
+ } | {
122
+ valid: boolean;
123
+ errors: never[];
124
+ message?: undefined;
125
+ };
126
+
40
127
  declare function useQuery(queryable: any): any;
128
+ declare const sc: {
129
+ validateSchema: typeof validateSchema;
130
+ validateData: typeof validateData;
131
+ generateEmptySchema: typeof generateEmptySchema;
132
+ };
41
133
 
42
- export { BasicProvider, useBasic, useQuery };
134
+ export { BasicProvider, sc, useBasic, useQuery };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
+ import { ErrorObject } from 'ajv';
3
4
 
4
5
  declare enum DBStatus {
5
6
  LOADING = "LOADING",
@@ -37,6 +38,97 @@ declare function useBasic(): {
37
38
  dbStatus: DBStatus;
38
39
  };
39
40
 
41
+ declare const basicJsonSchema: {
42
+ $schema: string;
43
+ type: string;
44
+ properties: {
45
+ project_id: {
46
+ type: string;
47
+ };
48
+ namespace: {
49
+ type: string;
50
+ };
51
+ version: {
52
+ type: string;
53
+ minimum: number;
54
+ };
55
+ tables: {
56
+ type: string;
57
+ patternProperties: {
58
+ "^[a-zA-Z0-9_]+$": {
59
+ type: string;
60
+ properties: {
61
+ name: {
62
+ type: string;
63
+ };
64
+ type: {
65
+ type: string;
66
+ enum: string[];
67
+ };
68
+ fields: {
69
+ type: string;
70
+ patternProperties: {
71
+ "^[a-zA-Z0-9_]+$": {
72
+ type: string;
73
+ properties: {
74
+ type: {
75
+ type: string;
76
+ enum: string[];
77
+ };
78
+ indexed: {
79
+ type: string;
80
+ };
81
+ required: {
82
+ type: string;
83
+ };
84
+ };
85
+ required: string[];
86
+ };
87
+ };
88
+ additionalProperties: boolean;
89
+ };
90
+ };
91
+ required: string[];
92
+ };
93
+ };
94
+ additionalProperties: boolean;
95
+ };
96
+ };
97
+ required: string[];
98
+ };
99
+ type Schema = typeof basicJsonSchema;
100
+ declare function generateEmptySchema(): void;
101
+ /**
102
+ * Validate a schema
103
+ * only checks if the schema is formatted correctly, not if can be published
104
+ * @param schema - The schema to validate
105
+ * @returns {valid: boolean, errors: any[]} - The validation result
106
+ */
107
+ declare function validateSchema(schema: Schema): {
108
+ valid: boolean;
109
+ errors: ErrorObject[];
110
+ };
111
+ declare function validateData(schema: any, table: string, data: Record<string, any>, checkRequired?: boolean): {
112
+ valid: boolean;
113
+ errors: ErrorObject<string, Record<string, any>, unknown>[];
114
+ message: string;
115
+ } | {
116
+ valid: boolean;
117
+ errors: {
118
+ message: string;
119
+ }[];
120
+ message: string;
121
+ } | {
122
+ valid: boolean;
123
+ errors: never[];
124
+ message?: undefined;
125
+ };
126
+
40
127
  declare function useQuery(queryable: any): any;
128
+ declare const sc: {
129
+ validateSchema: typeof validateSchema;
130
+ validateData: typeof validateData;
131
+ generateEmptySchema: typeof generateEmptySchema;
132
+ };
41
133
 
42
- export { BasicProvider, useBasic, useQuery };
134
+ export { BasicProvider, sc, useBasic, useQuery };
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  BasicProvider: () => BasicProvider,
34
+ sc: () => sc,
34
35
  useBasic: () => useBasic,
35
36
  useQuery: () => useQuery
36
37
  });
@@ -50,8 +51,7 @@ var import_dexie_observable = require("dexie-observable");
50
51
  var import_dexie = require("dexie");
51
52
 
52
53
  // src/config.ts
53
- var import_ajv = __toESM(require("ajv"));
54
- var SERVER_URL = "http://localhost:3000";
54
+ var SERVER_URL = "https://api.basic.tech";
55
55
  var log = (...args) => {
56
56
  try {
57
57
  if (localStorage.getItem("basic_debug") === "true") {
@@ -60,65 +60,6 @@ var log = (...args) => {
60
60
  } catch (e) {
61
61
  }
62
62
  };
63
- var basicJsonSchema = {
64
- "$schema": "http://json-schema.org/draft-07/schema#",
65
- "type": "object",
66
- "properties": {
67
- "project_id": {
68
- "type": "string"
69
- },
70
- "namespace": {
71
- "type": "string"
72
- },
73
- "version": {
74
- "type": "integer",
75
- "minimum": 0
76
- },
77
- "tables": {
78
- "type": "object",
79
- "patternProperties": {
80
- "^[a-zA-Z0-9_]+$": {
81
- "type": "object",
82
- "properties": {
83
- "name": {
84
- "type": "string"
85
- },
86
- "type": {
87
- "type": "string",
88
- "enum": ["collection"]
89
- },
90
- "fields": {
91
- "type": "object",
92
- "patternProperties": {
93
- "^[a-zA-Z0-9_]+$": {
94
- "type": "object",
95
- "properties": {
96
- "type": {
97
- "type": "string"
98
- },
99
- "primary": {
100
- "type": "boolean"
101
- },
102
- "indexed": {
103
- "type": "boolean"
104
- }
105
- },
106
- "required": ["type"]
107
- }
108
- },
109
- "additionalProperties": true
110
- }
111
- },
112
- "required": ["fields"]
113
- }
114
- },
115
- "additionalProperties": true
116
- }
117
- },
118
- "required": ["project_id", "version", "tables"]
119
- };
120
- var ajv = new import_ajv.default();
121
- var validator = ajv.compile(basicJsonSchema);
122
63
 
123
64
  // src/sync/syncProtocol.js
124
65
  var syncProtocol = function() {
@@ -223,6 +164,117 @@ var syncProtocol = function() {
223
164
  });
224
165
  };
225
166
 
167
+ // src/schema.ts
168
+ var import_ajv = __toESM(require("ajv"));
169
+ var basicJsonSchema = {
170
+ "$schema": "http://json-schema.org/draft-07/schema#",
171
+ "type": "object",
172
+ "properties": {
173
+ "project_id": {
174
+ "type": "string"
175
+ },
176
+ "namespace": {
177
+ "type": "string"
178
+ },
179
+ "version": {
180
+ "type": "integer",
181
+ "minimum": 0
182
+ },
183
+ "tables": {
184
+ "type": "object",
185
+ "patternProperties": {
186
+ "^[a-zA-Z0-9_]+$": {
187
+ "type": "object",
188
+ "properties": {
189
+ "name": {
190
+ "type": "string"
191
+ },
192
+ "type": {
193
+ "type": "string",
194
+ "enum": ["collection"]
195
+ },
196
+ "fields": {
197
+ "type": "object",
198
+ "patternProperties": {
199
+ "^[a-zA-Z0-9_]+$": {
200
+ "type": "object",
201
+ "properties": {
202
+ "type": {
203
+ "type": "string",
204
+ "enum": ["string", "boolean", "number", "json"]
205
+ },
206
+ "indexed": {
207
+ "type": "boolean"
208
+ },
209
+ "required": {
210
+ "type": "boolean"
211
+ }
212
+ },
213
+ "required": ["type"]
214
+ }
215
+ },
216
+ "additionalProperties": true
217
+ }
218
+ },
219
+ "required": ["fields"]
220
+ }
221
+ },
222
+ "additionalProperties": true
223
+ }
224
+ },
225
+ "required": ["project_id", "version", "tables"]
226
+ };
227
+ var ajv = new import_ajv.default();
228
+ var validator = ajv.compile(basicJsonSchema);
229
+ function generateEmptySchema() {
230
+ }
231
+ function validateSchema(schema) {
232
+ const v = validator(schema);
233
+ return {
234
+ valid: v,
235
+ errors: validator.errors || []
236
+ };
237
+ }
238
+ function validateData(schema, table, data, checkRequired = true) {
239
+ const valid = validateSchema(schema);
240
+ if (!valid.valid) {
241
+ return { valid: false, errors: valid.errors, message: "Schema is invalid" };
242
+ }
243
+ const tableSchema = schema.tables[table];
244
+ if (!tableSchema) {
245
+ return { valid: false, errors: [{ message: `Table ${table} not found in schema` }], message: "Table not found" };
246
+ }
247
+ for (const [fieldName, fieldValue] of Object.entries(data)) {
248
+ const fieldSchema = tableSchema.fields[fieldName];
249
+ if (!fieldSchema) {
250
+ return {
251
+ valid: false,
252
+ errors: [{ message: `Field ${fieldName} not found in schema` }],
253
+ message: "Invalid field"
254
+ };
255
+ }
256
+ const schemaType = fieldSchema.type;
257
+ const valueType = typeof fieldValue;
258
+ if (schemaType === "string" && valueType !== "string" || schemaType === "number" && valueType !== "number" || schemaType === "boolean" && valueType !== "boolean" || schemaType === "json" && valueType !== "object") {
259
+ return {
260
+ valid: false,
261
+ errors: [{
262
+ message: `Field ${fieldName} should be type ${schemaType}, got ${valueType}`
263
+ }],
264
+ message: "invalid type"
265
+ };
266
+ }
267
+ }
268
+ if (checkRequired) {
269
+ for (const [fieldName, fieldSchema] of Object.entries(tableSchema.fields)) {
270
+ if (fieldSchema.required && !data[fieldName]) {
271
+ return { valid: false, errors: [{ message: `Field ${fieldName} is required` }], message: "Required field missing" };
272
+ }
273
+ }
274
+ }
275
+ return { valid: true, errors: [] };
276
+ }
277
+
226
278
  // src/sync/index.ts
227
279
  syncProtocol();
228
280
  var BasicSync = class extends import_dexie2.Dexie {
@@ -290,19 +342,33 @@ var BasicSync = class extends import_dexie2.Dexie {
290
342
  ref: this.table(name),
291
343
  // --- WRITE ---- //
292
344
  add: (data) => {
293
- log("Adding data to", name, data);
345
+ const valid = validateData(this.basic_schema, name, data);
346
+ if (!valid.valid) {
347
+ log("Invalid data", valid);
348
+ return Promise.reject({ ...valid });
349
+ }
294
350
  return this.table(name).add({
295
351
  id: (0, import_uuid.v7)(),
296
352
  ...data
297
353
  });
298
354
  },
299
355
  put: (data) => {
356
+ const valid = validateData(this.basic_schema, name, data);
357
+ if (!valid.valid) {
358
+ log("Invalid data", valid);
359
+ return Promise.reject({ ...valid });
360
+ }
300
361
  return this.table(name).put({
301
362
  id: (0, import_uuid.v7)(),
302
363
  ...data
303
364
  });
304
365
  },
305
366
  update: (id, data) => {
367
+ const valid = validateData(this.basic_schema, name, data, false);
368
+ if (!valid.valid) {
369
+ log("Invalid data", valid);
370
+ return Promise.reject({ ...valid });
371
+ }
306
372
  return this.table(name).update(id, data);
307
373
  },
308
374
  delete: (id) => {
@@ -414,11 +480,12 @@ function BasicProvider({ children, project_id, schema, debug = false }) {
414
480
  const syncRef = (0, import_react.useRef)(null);
415
481
  (0, import_react.useEffect)(() => {
416
482
  function initDb() {
417
- if (!validator(schema)) {
418
- log("Basic Schema is invalid!", validator.errors);
483
+ const valid = validateSchema(schema);
484
+ if (!valid.valid) {
485
+ log("Basic Schema is invalid!", valid.errors);
419
486
  console.group("Schema Errors");
420
487
  let errorMessage = "";
421
- validator.errors.forEach((error2, index) => {
488
+ valid.errors.forEach((error2, index) => {
422
489
  log(`${index + 1}:`, error2.message, ` - at ${error2.instancePath}`);
423
490
  errorMessage += `${index + 1}: ${error2.message} - at ${error2.instancePath}
424
491
  `;
@@ -686,9 +753,15 @@ function useQuery(queryable) {
686
753
  return queryable;
687
754
  }, [queryable], []);
688
755
  }
756
+ var sc = {
757
+ validateSchema,
758
+ validateData,
759
+ generateEmptySchema
760
+ };
689
761
  // Annotate the CommonJS export names for ESM import in node:
690
762
  0 && (module.exports = {
691
763
  BasicProvider,
764
+ sc,
692
765
  useBasic,
693
766
  useQuery
694
767
  });