@statezero/core 0.1.1 → 0.1.3-9.1
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/LICENSE +3 -2
- package/dist/cli/commands/sync.d.ts +6 -0
- package/dist/cli/commands/sync.js +30 -0
- package/dist/cli/commands/syncActions.d.ts +46 -0
- package/dist/cli/commands/syncActions.js +623 -0
- package/dist/cli/commands/syncModels.js +61 -29
- package/dist/cli/index.js +18 -10
- package/dist/config.d.ts +5 -0
- package/dist/config.js +40 -10
- package/dist/flavours/django/dates.js +3 -3
- package/dist/flavours/django/files.d.ts +8 -7
- package/dist/flavours/django/files.js +36 -2
- package/dist/flavours/django/model.d.ts +15 -0
- package/dist/flavours/django/model.js +143 -24
- package/dist/setup.js +11 -0
- package/dist/syncEngine/registries/metricRegistry.d.ts +5 -0
- package/dist/syncEngine/registries/metricRegistry.js +8 -0
- package/dist/syncEngine/registries/querysetStoreGraph.d.ts +21 -0
- package/dist/syncEngine/registries/querysetStoreGraph.js +95 -0
- package/dist/syncEngine/registries/querysetStoreRegistry.d.ts +14 -0
- package/dist/syncEngine/registries/querysetStoreRegistry.js +64 -16
- package/dist/syncEngine/stores/modelStore.d.ts +1 -0
- package/dist/syncEngine/stores/modelStore.js +23 -12
- package/dist/syncEngine/stores/querysetStore.d.ts +18 -0
- package/dist/syncEngine/stores/querysetStore.js +129 -18
- package/dist/syncEngine/sync.d.ts +5 -0
- package/dist/syncEngine/sync.js +61 -5
- package/package.json +126 -123
- package/readme.md +1 -1
|
@@ -94,6 +94,59 @@ import { loadConfigFromFile } from "../configFileLoader.js";
|
|
|
94
94
|
* @property {string} model
|
|
95
95
|
*/
|
|
96
96
|
// --------------------
|
|
97
|
+
// Fallback Selection for Inquirer Errors
|
|
98
|
+
// --------------------
|
|
99
|
+
/**
|
|
100
|
+
* Simple fallback that generates all models when inquirer fails
|
|
101
|
+
* @param {Array} choices - Array of choice objects with {name, value, checked} properties
|
|
102
|
+
* @param {string} message - Selection message
|
|
103
|
+
* @returns {Promise<Array>} - All model values
|
|
104
|
+
*/
|
|
105
|
+
async function fallbackSelectAll(choices, message) {
|
|
106
|
+
console.log(`\n${message}`);
|
|
107
|
+
console.log("Interactive selection not available - generating ALL models:");
|
|
108
|
+
const allModels = [];
|
|
109
|
+
for (const choice of choices) {
|
|
110
|
+
// Skip separators (they don't have a 'value' property)
|
|
111
|
+
if (!choice.value) {
|
|
112
|
+
console.log(choice.name); // Print separator text
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// Add ALL models, regardless of checked status
|
|
116
|
+
allModels.push(choice.value);
|
|
117
|
+
console.log(` ✓ ${choice.name}`);
|
|
118
|
+
}
|
|
119
|
+
console.log(`\nGenerating ALL ${allModels.length} models.`);
|
|
120
|
+
return allModels;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Model selection with inquirer fallback
|
|
124
|
+
* @param {Array} choices - Array of choice objects
|
|
125
|
+
* @param {string} message - Selection message
|
|
126
|
+
* @returns {Promise<Array>} - Selected model objects
|
|
127
|
+
*/
|
|
128
|
+
async function selectModels(choices, message) {
|
|
129
|
+
try {
|
|
130
|
+
// Try to use inquirer first
|
|
131
|
+
const inquirer = (await import("inquirer")).default;
|
|
132
|
+
const { selectedModels } = await inquirer.prompt([
|
|
133
|
+
{
|
|
134
|
+
type: "checkbox",
|
|
135
|
+
name: "selectedModels",
|
|
136
|
+
message,
|
|
137
|
+
choices,
|
|
138
|
+
pageSize: 20,
|
|
139
|
+
},
|
|
140
|
+
]);
|
|
141
|
+
return selectedModels;
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
// Fall back to generating all models if inquirer fails for any reason
|
|
145
|
+
console.warn("Interactive selection failed, generating all models:", error.message);
|
|
146
|
+
return await fallbackSelectAll(choices, message);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// --------------------
|
|
97
150
|
// Handlebars Templates & Helpers
|
|
98
151
|
// --------------------
|
|
99
152
|
// Updated JS_MODEL_TEMPLATE with getters and setters
|
|
@@ -106,7 +159,7 @@ const JS_MODEL_TEMPLATE = `/**
|
|
|
106
159
|
|
|
107
160
|
import { Model, Manager, QuerySet, getModelClass } from '{{modulePath}}';
|
|
108
161
|
import { wrapReactiveModel } from '{{modulePath}}';
|
|
109
|
-
import schemaData from './{{className}}.schema.json';
|
|
162
|
+
import schemaData from './{{toLowerCase className}}.schema.json';
|
|
110
163
|
|
|
111
164
|
/**
|
|
112
165
|
* Model-specific QuerySet implementation
|
|
@@ -174,22 +227,6 @@ export class {{className}} extends Model {
|
|
|
174
227
|
});
|
|
175
228
|
});
|
|
176
229
|
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Serialize the model's data.
|
|
180
|
-
* Returns a plain object containing the current values of all fields,
|
|
181
|
-
* including raw IDs for relationship fields.
|
|
182
|
-
* @returns {Object}
|
|
183
|
-
*/
|
|
184
|
-
serialize() {
|
|
185
|
-
const data = {};
|
|
186
|
-
// Simply assign the current value of each field.
|
|
187
|
-
// No special handling or PK extraction for relationships here.
|
|
188
|
-
{{#each properties}}
|
|
189
|
-
data.{{name}} = this.{{name}};
|
|
190
|
-
{{/each}}
|
|
191
|
-
return data;
|
|
192
|
-
}
|
|
193
230
|
}
|
|
194
231
|
`;
|
|
195
232
|
// Updated TS_DECLARATION_TEMPLATE with improved relationship handling
|
|
@@ -446,6 +483,9 @@ Handlebars.registerHelper("ifDefaultProvided", function (defaultValue, options)
|
|
|
446
483
|
Handlebars.registerHelper("isRequired", function (required) {
|
|
447
484
|
return required ? "" : "?";
|
|
448
485
|
});
|
|
486
|
+
Handlebars.registerHelper("toLowerCase", function (str) {
|
|
487
|
+
return str.toLowerCase();
|
|
488
|
+
});
|
|
449
489
|
const jsTemplate = Handlebars.compile(JS_MODEL_TEMPLATE);
|
|
450
490
|
const dtsTemplate = Handlebars.compile(TS_DECLARATION_TEMPLATE);
|
|
451
491
|
// --------------------
|
|
@@ -944,14 +984,12 @@ export declare const FileObject: typeof ${backend.NAME}FileObject;
|
|
|
944
984
|
// --------------------
|
|
945
985
|
// Main Runner: Fetch models and prompt selection
|
|
946
986
|
// --------------------
|
|
947
|
-
// Update main function to use this new approach
|
|
948
987
|
async function main() {
|
|
949
988
|
// Load configuration from file (CLI-only or tests) before any other operations.
|
|
950
989
|
loadConfigFromFile();
|
|
951
990
|
// Retrieve the validated configuration from the global config singleton.
|
|
952
991
|
const configData = configInstance.getConfig();
|
|
953
992
|
const backendConfigs = configData.backendConfigs;
|
|
954
|
-
const inquirer = (await import("inquirer")).default;
|
|
955
993
|
const fetchPromises = Object.keys(backendConfigs).map(async (key) => {
|
|
956
994
|
const backend = backendConfigs[key];
|
|
957
995
|
backend.NAME = key;
|
|
@@ -966,8 +1004,10 @@ async function main() {
|
|
|
966
1004
|
});
|
|
967
1005
|
const backendModels = await Promise.all(fetchPromises);
|
|
968
1006
|
const choices = [];
|
|
1007
|
+
// Create a simple separator object for environments where inquirer.Separator isn't available
|
|
1008
|
+
const createSeparator = (text) => ({ name: text, value: null });
|
|
969
1009
|
for (const { backend, models } of backendModels) {
|
|
970
|
-
choices.push(
|
|
1010
|
+
choices.push(createSeparator(`\n=== ${backend.NAME} ===\n`));
|
|
971
1011
|
for (const model of models) {
|
|
972
1012
|
choices.push({
|
|
973
1013
|
name: model,
|
|
@@ -980,15 +1020,7 @@ async function main() {
|
|
|
980
1020
|
console.log("No models to synchronise");
|
|
981
1021
|
process.exit(0);
|
|
982
1022
|
}
|
|
983
|
-
const
|
|
984
|
-
{
|
|
985
|
-
type: "checkbox",
|
|
986
|
-
name: "selectedModels",
|
|
987
|
-
message: "Select models to synchronise:",
|
|
988
|
-
choices,
|
|
989
|
-
pageSize: 20,
|
|
990
|
-
},
|
|
991
|
-
]);
|
|
1023
|
+
const selectedModels = await selectModels(choices, "Select models to synchronise:");
|
|
992
1024
|
if (!selectedModels || selectedModels.length === 0) {
|
|
993
1025
|
console.log("No models selected. Exiting.");
|
|
994
1026
|
process.exit(0);
|
package/dist/cli/index.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import dotenv from
|
|
2
|
+
import dotenv from "dotenv";
|
|
3
3
|
dotenv.config();
|
|
4
|
-
import yargs from
|
|
5
|
-
import { hideBin } from
|
|
6
|
-
import { generateSchema } from
|
|
4
|
+
import yargs from "yargs";
|
|
5
|
+
import { hideBin } from "yargs/helpers";
|
|
6
|
+
import { generateSchema } from "./commands/syncModels.js";
|
|
7
|
+
import { generateActions } from "./commands/syncActions.js";
|
|
8
|
+
import { sync } from "./commands/sync.js"; // Import the new combined sync function
|
|
7
9
|
yargs(hideBin(process.argv))
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
await
|
|
10
|
+
// The new 'sync' command
|
|
11
|
+
.command("sync", "Synchronize both models and actions from the backend", {}, // Builder for command-specific options (if any)
|
|
12
|
+
async (argv) => {
|
|
13
|
+
await sync(argv);
|
|
12
14
|
})
|
|
13
|
-
.
|
|
14
|
-
|
|
15
|
+
.command("sync-models", "Generate model classes from the backend schema", {}, async (argv) => {
|
|
16
|
+
await generateSchema(argv);
|
|
17
|
+
})
|
|
18
|
+
.command("sync-actions", "Generate action functions from the backend schema", {}, async (argv) => {
|
|
19
|
+
await generateActions(); // This function does not take arguments
|
|
20
|
+
})
|
|
21
|
+
.demandCommand(1, "You must provide a command to run. Use --help to see available commands.")
|
|
22
|
+
.help().argv;
|
package/dist/config.d.ts
CHANGED
|
@@ -29,6 +29,10 @@ export function initializeAllEventReceivers(): Object;
|
|
|
29
29
|
* @param {Function} getterFn - The getModelClass function imported from model-registry.js
|
|
30
30
|
*/
|
|
31
31
|
export function registerModelGetter(getterFn: Function): void;
|
|
32
|
+
/**
|
|
33
|
+
* Helper function to build file URLs
|
|
34
|
+
*/
|
|
35
|
+
export function buildFileUrl(fileUrl: any, backendKey?: string): any;
|
|
32
36
|
/**
|
|
33
37
|
* Get a model class by name using the registered getter.
|
|
34
38
|
*
|
|
@@ -47,6 +51,7 @@ export namespace configInstance {
|
|
|
47
51
|
export { initializeEventReceiver };
|
|
48
52
|
export { registerModelGetter };
|
|
49
53
|
export { getModelClass };
|
|
54
|
+
export { buildFileUrl };
|
|
50
55
|
}
|
|
51
56
|
export default configInstance;
|
|
52
57
|
import { PusherEventReceiver } from './core/eventReceivers.js';
|
package/dist/config.js
CHANGED
|
@@ -44,15 +44,23 @@ const eventConfigSchema = z.object({
|
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
46
|
const backendSchema = z.object({
|
|
47
|
-
API_URL: z.string().url(
|
|
48
|
-
GENERATED_TYPES_DIR: z.string({
|
|
47
|
+
API_URL: z.string().url("API_URL must be a valid URL"),
|
|
48
|
+
GENERATED_TYPES_DIR: z.string({
|
|
49
|
+
required_error: "GENERATED_TYPES_DIR is required",
|
|
50
|
+
}),
|
|
51
|
+
GENERATED_ACTIONS_DIR: z.string().optional(),
|
|
49
52
|
BACKEND_TZ: z.string().optional(),
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.
|
|
55
|
-
|
|
53
|
+
fileRootURL: z.string().url("fileRootURL must be a valid URL").optional(),
|
|
54
|
+
fileUploadMode: z.enum(["server", "s3"]).default("server"),
|
|
55
|
+
getAuthHeaders: z
|
|
56
|
+
.function()
|
|
57
|
+
.optional()
|
|
58
|
+
.refine((fn) => fn === undefined || typeof fn === "function", "getAuthHeaders must be a function if provided"),
|
|
59
|
+
eventInterceptor: z
|
|
60
|
+
.function()
|
|
61
|
+
.optional()
|
|
62
|
+
.refine((fn) => fn === undefined || typeof fn === "function", "eventInterceptor must be a function if provided"),
|
|
63
|
+
events: z.lazy(() => eventConfigSchema.optional()),
|
|
56
64
|
});
|
|
57
65
|
const configSchema = z.object({
|
|
58
66
|
backendConfigs: z.record(z.string(), backendSchema)
|
|
@@ -76,7 +84,8 @@ const configSchema = z.object({
|
|
|
76
84
|
}
|
|
77
85
|
}
|
|
78
86
|
return { message: errors.join('; ') };
|
|
79
|
-
})
|
|
87
|
+
}),
|
|
88
|
+
periodicSyncIntervalSeconds: z.number().min(5).nullable().optional().default(null),
|
|
80
89
|
});
|
|
81
90
|
// Internal variable to hold the validated configuration.
|
|
82
91
|
let config = null;
|
|
@@ -212,6 +221,26 @@ export function registerModelGetter(getterFn) {
|
|
|
212
221
|
}
|
|
213
222
|
modelGetter = getterFn;
|
|
214
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Helper function to build file URLs
|
|
226
|
+
*/
|
|
227
|
+
export function buildFileUrl(fileUrl, backendKey = 'default') {
|
|
228
|
+
// If URL is already absolute (cloud storage), use it as-is
|
|
229
|
+
if (fileUrl && fileUrl.startsWith('http')) {
|
|
230
|
+
return fileUrl;
|
|
231
|
+
}
|
|
232
|
+
const cfg = getConfig();
|
|
233
|
+
const backend = cfg.backendConfigs[backendKey];
|
|
234
|
+
if (!backend) {
|
|
235
|
+
throw new ConfigError(`Backend "${backendKey}" not found in configuration.`);
|
|
236
|
+
}
|
|
237
|
+
// If no fileRootURL provided, return relative URL as-is
|
|
238
|
+
if (!backend.fileRootURL) {
|
|
239
|
+
return fileUrl;
|
|
240
|
+
}
|
|
241
|
+
// Construct full URL
|
|
242
|
+
return backend.fileRootURL.replace(/\/$/, '') + fileUrl;
|
|
243
|
+
}
|
|
215
244
|
/**
|
|
216
245
|
* Get a model class by name using the registered getter.
|
|
217
246
|
*
|
|
@@ -237,6 +266,7 @@ export const configInstance = {
|
|
|
237
266
|
setBackendConfig,
|
|
238
267
|
initializeEventReceiver,
|
|
239
268
|
registerModelGetter,
|
|
240
|
-
getModelClass
|
|
269
|
+
getModelClass,
|
|
270
|
+
buildFileUrl
|
|
241
271
|
};
|
|
242
272
|
export default configInstance;
|
|
@@ -23,7 +23,7 @@ export class DateParsingHelpers {
|
|
|
23
23
|
// Get field-specific format from schema
|
|
24
24
|
const formatStrings = {
|
|
25
25
|
'date': schema.date_format,
|
|
26
|
-
'
|
|
26
|
+
'date-time': schema.datetime_format
|
|
27
27
|
};
|
|
28
28
|
const dateFormat = formatStrings[fieldFormat];
|
|
29
29
|
// Check if format is supported
|
|
@@ -56,13 +56,13 @@ export class DateParsingHelpers {
|
|
|
56
56
|
return date;
|
|
57
57
|
}
|
|
58
58
|
const fieldFormat = schema.properties[fieldName].format;
|
|
59
|
-
if (!["date", "
|
|
59
|
+
if (!["date", "date-time"].includes(fieldFormat)) {
|
|
60
60
|
throw new Error(`Only date and date-time fields can be processed to JS date objects. ${fieldName} has format ${fieldFormat}`);
|
|
61
61
|
}
|
|
62
62
|
// Get field-specific format from schema
|
|
63
63
|
const formatStrings = {
|
|
64
64
|
'date': schema.date_format,
|
|
65
|
-
'
|
|
65
|
+
'date-time': schema.datetime_format
|
|
66
66
|
};
|
|
67
67
|
const dateFormat = formatStrings[fieldFormat];
|
|
68
68
|
// Check if format is supported
|
|
@@ -5,10 +5,10 @@ export class FileObject {
|
|
|
5
5
|
static configKey: string;
|
|
6
6
|
static MIN_CHUNK_SIZE: number;
|
|
7
7
|
constructor(file: any, options?: {});
|
|
8
|
-
name:
|
|
9
|
-
size:
|
|
10
|
-
type:
|
|
11
|
-
lastModified: number;
|
|
8
|
+
name: any;
|
|
9
|
+
size: any;
|
|
10
|
+
type: any;
|
|
11
|
+
lastModified: number | null;
|
|
12
12
|
uploaded: boolean;
|
|
13
13
|
uploading: boolean;
|
|
14
14
|
uploadResult: any;
|
|
@@ -21,6 +21,7 @@ export class FileObject {
|
|
|
21
21
|
chunkSize: any;
|
|
22
22
|
maxConcurrency: any;
|
|
23
23
|
uploadPromise: any;
|
|
24
|
+
get isStoredFile(): any;
|
|
24
25
|
get status(): "failed" | "uploading" | "uploaded" | "pending";
|
|
25
26
|
get filePath(): any;
|
|
26
27
|
get fileUrl(): any;
|
|
@@ -59,9 +60,9 @@ export class FileObject {
|
|
|
59
60
|
getBlob(): Blob;
|
|
60
61
|
waitForUpload(): Promise<any>;
|
|
61
62
|
toJSON(): {
|
|
62
|
-
name:
|
|
63
|
-
size:
|
|
64
|
-
type:
|
|
63
|
+
name: any;
|
|
64
|
+
size: any;
|
|
65
|
+
type: any;
|
|
65
66
|
status: string;
|
|
66
67
|
uploaded: boolean;
|
|
67
68
|
filePath: any;
|
|
@@ -5,9 +5,37 @@ import PQueue from "p-queue";
|
|
|
5
5
|
* FileObject - A file wrapper that handles uploads to StateZero backend
|
|
6
6
|
*/
|
|
7
7
|
export class FileObject {
|
|
8
|
+
// Simple changes to FileObject constructor
|
|
8
9
|
constructor(file, options = {}) {
|
|
10
|
+
// Handle stored file data (from API)
|
|
11
|
+
if (file &&
|
|
12
|
+
typeof file === "object" &&
|
|
13
|
+
file.file_path &&
|
|
14
|
+
!(file instanceof File)) {
|
|
15
|
+
// This is stored file data from the backend
|
|
16
|
+
this.name = file.file_name;
|
|
17
|
+
this.size = file.size;
|
|
18
|
+
this.type = file.mime_type; // Now coming from backend
|
|
19
|
+
this.lastModified = null;
|
|
20
|
+
// Mark as already uploaded
|
|
21
|
+
this.uploaded = true;
|
|
22
|
+
this.uploading = false;
|
|
23
|
+
this.uploadResult = file; // Store the entire response
|
|
24
|
+
this.uploadError = null;
|
|
25
|
+
this.fileData = null;
|
|
26
|
+
// No upload properties needed
|
|
27
|
+
this.uploadType = null;
|
|
28
|
+
this.uploadId = null;
|
|
29
|
+
this.totalChunks = 0;
|
|
30
|
+
this.completedChunks = 0;
|
|
31
|
+
this.chunkSize = null;
|
|
32
|
+
this.maxConcurrency = null;
|
|
33
|
+
this.uploadPromise = Promise.resolve(this.uploadResult);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// Handle File objects (for upload) - existing code
|
|
9
37
|
if (!file || !(file instanceof File)) {
|
|
10
|
-
throw new Error("FileObject requires a File object");
|
|
38
|
+
throw new Error("FileObject requires a File object or stored file data");
|
|
11
39
|
}
|
|
12
40
|
// Store file metadata directly
|
|
13
41
|
this.name = file.name;
|
|
@@ -33,6 +61,9 @@ export class FileObject {
|
|
|
33
61
|
this.maxConcurrency = options.maxConcurrency || 3;
|
|
34
62
|
this.uploadPromise = this._initializeAndStartUpload(file, options);
|
|
35
63
|
}
|
|
64
|
+
get isStoredFile() {
|
|
65
|
+
return this.uploaded && !this.fileData && this.uploadResult?.file_path;
|
|
66
|
+
}
|
|
36
67
|
get status() {
|
|
37
68
|
if (this.uploadError)
|
|
38
69
|
return "failed";
|
|
@@ -46,7 +77,10 @@ export class FileObject {
|
|
|
46
77
|
return this.uploadResult?.file_path;
|
|
47
78
|
}
|
|
48
79
|
get fileUrl() {
|
|
49
|
-
|
|
80
|
+
if (!this.uploadResult?.file_url) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return configInstance.buildFileUrl(this.uploadResult.file_url, this.constructor.configKey);
|
|
50
84
|
}
|
|
51
85
|
async _initializeAndStartUpload(file, options) {
|
|
52
86
|
const config = configInstance.getConfig();
|
|
@@ -35,6 +35,14 @@ export class Model {
|
|
|
35
35
|
* @throws {ValidationError} If an unknown key is found.
|
|
36
36
|
*/
|
|
37
37
|
static validateFields(data: Object): void;
|
|
38
|
+
/**
|
|
39
|
+
* Static method to validate data without creating an instance
|
|
40
|
+
* @param {Object} data - Data to validate
|
|
41
|
+
* @param {string} validateType - 'create' or 'update'
|
|
42
|
+
* @param {boolean} partial - Whether to allow partial validation
|
|
43
|
+
* @returns {Promise<boolean>} Promise that resolves to true if valid, throws error if invalid
|
|
44
|
+
*/
|
|
45
|
+
static validate(data: Object, validateType?: string, partial?: boolean): Promise<boolean>;
|
|
38
46
|
constructor(data?: {});
|
|
39
47
|
_data: {};
|
|
40
48
|
_pk: any;
|
|
@@ -105,6 +113,13 @@ export class Model {
|
|
|
105
113
|
* @throws {Error} If the instance has not been saved (no primary key).
|
|
106
114
|
*/
|
|
107
115
|
refreshFromDb(): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Validates the model instance using the same serialize behavior as save()
|
|
118
|
+
* @param {string} validateType - 'create' or 'update' (defaults to auto-detect)
|
|
119
|
+
* @param {boolean} partial - Whether to allow partial validation
|
|
120
|
+
* @returns {Promise<boolean>} Promise that resolves to true if valid, throws error if invalid
|
|
121
|
+
*/
|
|
122
|
+
validate(validateType?: string, partial?: boolean): Promise<boolean>;
|
|
108
123
|
}
|
|
109
124
|
/**
|
|
110
125
|
* A constructor for a Model.
|