@statezero/core 0.1.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.
Files changed (89) hide show
  1. package/dist/adaptors/react/composables.d.ts +1 -0
  2. package/dist/adaptors/react/composables.js +4 -0
  3. package/dist/adaptors/react/index.d.ts +1 -0
  4. package/dist/adaptors/react/index.js +1 -0
  5. package/dist/adaptors/vue/composables.d.ts +2 -0
  6. package/dist/adaptors/vue/composables.js +36 -0
  7. package/dist/adaptors/vue/index.d.ts +2 -0
  8. package/dist/adaptors/vue/index.js +2 -0
  9. package/dist/adaptors/vue/reactivity.d.ts +18 -0
  10. package/dist/adaptors/vue/reactivity.js +125 -0
  11. package/dist/cli/commands/syncModels.d.ts +132 -0
  12. package/dist/cli/commands/syncModels.js +1040 -0
  13. package/dist/cli/configFileLoader.d.ts +10 -0
  14. package/dist/cli/configFileLoader.js +85 -0
  15. package/dist/cli/index.d.ts +2 -0
  16. package/dist/cli/index.js +14 -0
  17. package/dist/config.d.ts +52 -0
  18. package/dist/config.js +242 -0
  19. package/dist/core/eventReceivers.d.ts +179 -0
  20. package/dist/core/eventReceivers.js +210 -0
  21. package/dist/core/utils.d.ts +8 -0
  22. package/dist/core/utils.js +62 -0
  23. package/dist/filtering/localFiltering.d.ts +116 -0
  24. package/dist/filtering/localFiltering.js +834 -0
  25. package/dist/flavours/django/dates.d.ts +33 -0
  26. package/dist/flavours/django/dates.js +99 -0
  27. package/dist/flavours/django/errors.d.ts +138 -0
  28. package/dist/flavours/django/errors.js +187 -0
  29. package/dist/flavours/django/f.d.ts +6 -0
  30. package/dist/flavours/django/f.js +91 -0
  31. package/dist/flavours/django/files.d.ts +76 -0
  32. package/dist/flavours/django/files.js +338 -0
  33. package/dist/flavours/django/makeApiCall.d.ts +20 -0
  34. package/dist/flavours/django/makeApiCall.js +169 -0
  35. package/dist/flavours/django/manager.d.ts +197 -0
  36. package/dist/flavours/django/manager.js +222 -0
  37. package/dist/flavours/django/model.d.ts +112 -0
  38. package/dist/flavours/django/model.js +253 -0
  39. package/dist/flavours/django/operationFactory.d.ts +65 -0
  40. package/dist/flavours/django/operationFactory.js +216 -0
  41. package/dist/flavours/django/q.d.ts +70 -0
  42. package/dist/flavours/django/q.js +43 -0
  43. package/dist/flavours/django/queryExecutor.d.ts +131 -0
  44. package/dist/flavours/django/queryExecutor.js +468 -0
  45. package/dist/flavours/django/querySet.d.ts +412 -0
  46. package/dist/flavours/django/querySet.js +601 -0
  47. package/dist/flavours/django/tempPk.d.ts +19 -0
  48. package/dist/flavours/django/tempPk.js +48 -0
  49. package/dist/flavours/django/utils.d.ts +19 -0
  50. package/dist/flavours/django/utils.js +29 -0
  51. package/dist/index.d.ts +38 -0
  52. package/dist/index.js +38 -0
  53. package/dist/react-entry.d.ts +2 -0
  54. package/dist/react-entry.js +2 -0
  55. package/dist/reactiveAdaptor.d.ts +24 -0
  56. package/dist/reactiveAdaptor.js +38 -0
  57. package/dist/setup.d.ts +15 -0
  58. package/dist/setup.js +22 -0
  59. package/dist/syncEngine/cache/cache.d.ts +75 -0
  60. package/dist/syncEngine/cache/cache.js +341 -0
  61. package/dist/syncEngine/metrics/metricOptCalcs.d.ts +79 -0
  62. package/dist/syncEngine/metrics/metricOptCalcs.js +284 -0
  63. package/dist/syncEngine/registries/metricRegistry.d.ts +53 -0
  64. package/dist/syncEngine/registries/metricRegistry.js +162 -0
  65. package/dist/syncEngine/registries/modelStoreRegistry.d.ts +11 -0
  66. package/dist/syncEngine/registries/modelStoreRegistry.js +56 -0
  67. package/dist/syncEngine/registries/querysetStoreRegistry.d.ts +55 -0
  68. package/dist/syncEngine/registries/querysetStoreRegistry.js +244 -0
  69. package/dist/syncEngine/stores/metricStore.d.ts +55 -0
  70. package/dist/syncEngine/stores/metricStore.js +222 -0
  71. package/dist/syncEngine/stores/modelStore.d.ts +40 -0
  72. package/dist/syncEngine/stores/modelStore.js +405 -0
  73. package/dist/syncEngine/stores/operation.d.ts +99 -0
  74. package/dist/syncEngine/stores/operation.js +224 -0
  75. package/dist/syncEngine/stores/operationEventHandlers.d.ts +8 -0
  76. package/dist/syncEngine/stores/operationEventHandlers.js +239 -0
  77. package/dist/syncEngine/stores/querysetStore.d.ts +32 -0
  78. package/dist/syncEngine/stores/querysetStore.js +200 -0
  79. package/dist/syncEngine/stores/reactivity.d.ts +3 -0
  80. package/dist/syncEngine/stores/reactivity.js +4 -0
  81. package/dist/syncEngine/stores/utils.d.ts +14 -0
  82. package/dist/syncEngine/stores/utils.js +32 -0
  83. package/dist/syncEngine/sync.d.ts +32 -0
  84. package/dist/syncEngine/sync.js +169 -0
  85. package/dist/vue-entry.d.ts +6 -0
  86. package/dist/vue-entry.js +2 -0
  87. package/license.md +116 -0
  88. package/package.json +123 -0
  89. package/readme.md +222 -0
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Date parsing utilities for handling Django style date formats
3
+ */
4
+ export class DateParsingHelpers {
5
+ static SUPPORTED_FORMATS: {
6
+ 'iso-8601': null;
7
+ '%Y-%m-%d': string;
8
+ '%Y-%m-%d %H:%M:%S': string;
9
+ '%d/%m/%Y': string;
10
+ '%m/%d/%Y': string;
11
+ '%Y/%m/%d': string;
12
+ '%d-%m-%Y': string;
13
+ '%m-%d-%Y': string;
14
+ '%B %d, %Y': string;
15
+ '%d %B %Y': string;
16
+ };
17
+ /**
18
+ * Parse a date value using Django's format settings
19
+ * @param {string|Date} value - The date value to parse
20
+ * @param {string} fieldName - Name of the field (for schema lookup)
21
+ * @param {Object} schema - The model schema containing format info
22
+ * @returns {Date|null} - Parsed Date object or null if invalid
23
+ */
24
+ static parseDate(value: string | Date, fieldName: string, schema: Object): Date | null;
25
+ /**
26
+ * Serialize a date using the field's configured format
27
+ * @param {Date} date - The date to serialize
28
+ * @param {string} fieldName - Name of the field (for schema lookup)
29
+ * @param {Object} schema - The model schema containing format info
30
+ * @returns {string|null} - Formatted date string or null if invalid
31
+ */
32
+ static serializeDate(date: Date, fieldName: string, schema: Object): string | null;
33
+ }
@@ -0,0 +1,99 @@
1
+ import { format, parse, parseISO } from 'date-fns';
2
+ /**
3
+ * Date parsing utilities for handling Django style date formats
4
+ */
5
+ export class DateParsingHelpers {
6
+ /**
7
+ * Parse a date value using Django's format settings
8
+ * @param {string|Date} value - The date value to parse
9
+ * @param {string} fieldName - Name of the field (for schema lookup)
10
+ * @param {Object} schema - The model schema containing format info
11
+ * @returns {Date|null} - Parsed Date object or null if invalid
12
+ */
13
+ static parseDate(value, fieldName, schema) {
14
+ if (!value)
15
+ return null;
16
+ // If already a Date object, return as-is
17
+ if (value instanceof Date)
18
+ return value;
19
+ const fieldFormat = schema.properties[fieldName].format;
20
+ if (!["date", "date-time"].includes(fieldFormat)) {
21
+ throw new Error(`Only date and date-time fields can be processed to JS date objects. ${fieldName} has format ${fieldFormat}`);
22
+ }
23
+ // Get field-specific format from schema
24
+ const formatStrings = {
25
+ 'date': schema.date_format,
26
+ 'datetime': schema.datetime_format
27
+ };
28
+ const dateFormat = formatStrings[fieldFormat];
29
+ // Check if format is supported
30
+ if (dateFormat && !this.SUPPORTED_FORMATS.hasOwnProperty(dateFormat)) {
31
+ throw new Error(`Unsupported date format "${dateFormat}" for field ${fieldName}. Supported formats: ${Object.keys(this.SUPPORTED_FORMATS).join(', ')}`);
32
+ }
33
+ try {
34
+ // Handle ISO format (Django's default)
35
+ if (!dateFormat || dateFormat === 'iso-8601') {
36
+ return parseISO(value);
37
+ }
38
+ // Handle supported Django formats
39
+ const dateFnsFormat = this.SUPPORTED_FORMATS[dateFormat];
40
+ return parse(value, dateFnsFormat, new Date());
41
+ }
42
+ catch (error) {
43
+ console.error(`Failed to parse date "${value}" with format "${dateFormat}"`, error);
44
+ return null;
45
+ }
46
+ }
47
+ /**
48
+ * Serialize a date using the field's configured format
49
+ * @param {Date} date - The date to serialize
50
+ * @param {string} fieldName - Name of the field (for schema lookup)
51
+ * @param {Object} schema - The model schema containing format info
52
+ * @returns {string|null} - Formatted date string or null if invalid
53
+ */
54
+ static serializeDate(date, fieldName, schema) {
55
+ if (!date || !(date instanceof Date) || isNaN(date.getTime())) {
56
+ return date;
57
+ }
58
+ const fieldFormat = schema.properties[fieldName].format;
59
+ if (!["date", "datetime"].includes(fieldFormat)) {
60
+ throw new Error(`Only date and date-time fields can be processed to JS date objects. ${fieldName} has format ${fieldFormat}`);
61
+ }
62
+ // Get field-specific format from schema
63
+ const formatStrings = {
64
+ 'date': schema.date_format,
65
+ 'datetime': schema.datetime_format
66
+ };
67
+ const dateFormat = formatStrings[fieldFormat];
68
+ // Check if format is supported
69
+ if (dateFormat && !this.SUPPORTED_FORMATS.hasOwnProperty(dateFormat)) {
70
+ throw new Error(`Unsupported date format "${dateFormat}" for field ${fieldName}. Supported formats: ${Object.keys(this.SUPPORTED_FORMATS).join(', ')}`);
71
+ }
72
+ try {
73
+ // Handle ISO format (Django's default)
74
+ if (!dateFormat || dateFormat === 'iso-8601') {
75
+ return date.toISOString();
76
+ }
77
+ // Handle supported Django formats
78
+ const dateFnsFormat = this.SUPPORTED_FORMATS[dateFormat];
79
+ return format(date, dateFnsFormat);
80
+ }
81
+ catch (error) {
82
+ console.error(`Failed to format date with format "${dateFormat}"`, error);
83
+ return date.toISOString(); // Fallback to ISO format
84
+ }
85
+ }
86
+ }
87
+ // Supported Django strftime formats and their date-fns equivalents
88
+ DateParsingHelpers.SUPPORTED_FORMATS = {
89
+ 'iso-8601': null, // Special case - use parseISO/toISOString
90
+ '%Y-%m-%d': 'yyyy-MM-dd', // 2024-12-31
91
+ '%Y-%m-%d %H:%M:%S': 'yyyy-MM-dd HH:mm:ss', // 2024-12-31 14:30:45
92
+ '%d/%m/%Y': 'dd/MM/yyyy', // 31/12/2024
93
+ '%m/%d/%Y': 'MM/dd/yyyy', // 12/31/2024
94
+ '%Y/%m/%d': 'yyyy/MM/dd', // 2024/12/31
95
+ '%d-%m-%Y': 'dd-MM-yyyy', // 31-12-2024
96
+ '%m-%d-%Y': 'MM-dd-yyyy', // 12-31-2024
97
+ '%B %d, %Y': 'MMMM dd, yyyy', // December 31, 2024
98
+ '%d %B %Y': 'dd MMMM yyyy', // 31 December 2024
99
+ };
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Parses a JSON error response from the backend and returns an instance
3
+ * of the corresponding custom error.
4
+ *
5
+ * @param {IErrorResponse} errorResponse - The error response JSON.
6
+ * @returns {StateZeroError} An instance of a StateZeroError subclass.
7
+ */
8
+ export function parseStateZeroError(errorResponse: IErrorResponse): StateZeroError;
9
+ /**
10
+ * @typedef {Object} IErrorResponse
11
+ * @property {number} status - The HTTP status code.
12
+ * @property {string} type - The error type.
13
+ * @property {*} detail - The error details.
14
+ */
15
+ /**
16
+ * @typedef {Object} IErrorDetail
17
+ * @property {string} message - The error message.
18
+ * @property {string} code - The error code.
19
+ */
20
+ /**
21
+ * Base error class for StateZero errors.
22
+ */
23
+ export class StateZeroError extends Error {
24
+ /**
25
+ * Creates a new StateZeroError.
26
+ *
27
+ * @param {string} message - The error message.
28
+ * @param {string} code - The error code.
29
+ * @param {IErrorDetail|Object|string} detail - The error details.
30
+ * @param {number} status - The HTTP status code.
31
+ */
32
+ constructor(message: string, code: string, detail: IErrorDetail | Object | string, status: number);
33
+ code: string;
34
+ detail: string | Object | IErrorDetail;
35
+ status: number;
36
+ /**
37
+ * Returns a full error message including the detail.
38
+ *
39
+ * @returns {string} The full error message with details
40
+ */
41
+ getFullMessage(): string;
42
+ }
43
+ /**
44
+ * Error class for validation errors.
45
+ */
46
+ export class ValidationError extends StateZeroError {
47
+ /**
48
+ * Creates a new ValidationError.
49
+ *
50
+ * @param {IErrorDetail|Object|string} detail - The error details.
51
+ * @param {number} [status=400] - The HTTP status code.
52
+ */
53
+ constructor(detail: IErrorDetail | Object | string, status?: number);
54
+ }
55
+ /**
56
+ * Error class for "Does Not Exist" errors (renamed from NotFound).
57
+ */
58
+ export class DoesNotExist extends StateZeroError {
59
+ /**
60
+ * Creates a new DoesNotExist error.
61
+ *
62
+ * @param {IErrorDetail|Object|string} [detail="Does not exist"] - The error details.
63
+ * @param {number} [status=404] - The HTTP status code.
64
+ */
65
+ constructor(detail?: IErrorDetail | Object | string, status?: number);
66
+ }
67
+ /**
68
+ * Error class for permission denied errors.
69
+ */
70
+ export class PermissionDenied extends StateZeroError {
71
+ /**
72
+ * Creates a new PermissionDenied error.
73
+ *
74
+ * @param {IErrorDetail|Object|string} [detail="Permission denied"] - The error details.
75
+ * @param {number} [status=403] - The HTTP status code.
76
+ */
77
+ constructor(detail?: IErrorDetail | Object | string, status?: number);
78
+ }
79
+ /**
80
+ * Error class for multiple objects returned errors.
81
+ */
82
+ export class MultipleObjectsReturned extends StateZeroError {
83
+ /**
84
+ * Creates a new MultipleObjectsReturned error.
85
+ *
86
+ * @param {IErrorDetail|Object|string} [detail="Multiple objects returned"] - The error details.
87
+ * @param {number} [status=500] - The HTTP status code.
88
+ */
89
+ constructor(detail?: IErrorDetail | Object | string, status?: number);
90
+ }
91
+ /**
92
+ * Error class for AST validation errors.
93
+ */
94
+ export class ASTValidationError extends StateZeroError {
95
+ /**
96
+ * Creates a new ASTValidationError.
97
+ *
98
+ * @param {IErrorDetail|Object|string} detail - The error details.
99
+ * @param {number} [status=400] - The HTTP status code.
100
+ */
101
+ constructor(detail: IErrorDetail | Object | string, status?: number);
102
+ }
103
+ /**
104
+ * Error class for configuration errors.
105
+ */
106
+ export class ConfigError extends StateZeroError {
107
+ /**
108
+ * Creates a new ConfigError.
109
+ *
110
+ * @param {IErrorDetail|Object|string} detail - The error details.
111
+ * @param {number} [status=500] - The HTTP status code.
112
+ */
113
+ constructor(detail: IErrorDetail | Object | string, status?: number);
114
+ }
115
+ export type IErrorResponse = {
116
+ /**
117
+ * - The HTTP status code.
118
+ */
119
+ status: number;
120
+ /**
121
+ * - The error type.
122
+ */
123
+ type: string;
124
+ /**
125
+ * - The error details.
126
+ */
127
+ detail: any;
128
+ };
129
+ export type IErrorDetail = {
130
+ /**
131
+ * - The error message.
132
+ */
133
+ message: string;
134
+ /**
135
+ * - The error code.
136
+ */
137
+ code: string;
138
+ };
@@ -0,0 +1,187 @@
1
+ /**
2
+ * @typedef {Object} IErrorResponse
3
+ * @property {number} status - The HTTP status code.
4
+ * @property {string} type - The error type.
5
+ * @property {*} detail - The error details.
6
+ */
7
+ /**
8
+ * @typedef {Object} IErrorDetail
9
+ * @property {string} message - The error message.
10
+ * @property {string} code - The error code.
11
+ */
12
+ /**
13
+ * Base error class for StateZero errors.
14
+ */
15
+ export class StateZeroError extends Error {
16
+ /**
17
+ * Creates a new StateZeroError.
18
+ *
19
+ * @param {string} message - The error message.
20
+ * @param {string} code - The error code.
21
+ * @param {IErrorDetail|Object|string} detail - The error details.
22
+ * @param {number} status - The HTTP status code.
23
+ */
24
+ constructor(message, code, detail, status) {
25
+ super(message);
26
+ this.name = this.constructor.name;
27
+ this.code = code;
28
+ this.detail = detail;
29
+ this.status = status;
30
+ Object.setPrototypeOf(this, new.target.prototype);
31
+ }
32
+ /**
33
+ * Returns a full error message including the detail.
34
+ *
35
+ * @returns {string} The full error message with details
36
+ */
37
+ getFullMessage() {
38
+ if (typeof this.detail === 'string') {
39
+ return `${this.message}: ${this.detail}`;
40
+ }
41
+ else if (this.detail && typeof this.detail === 'object') {
42
+ if (this.detail.message) {
43
+ return `${this.message}: ${this.detail.message}`;
44
+ }
45
+ else {
46
+ try {
47
+ return `${this.message}: ${JSON.stringify(this.detail)}`;
48
+ }
49
+ catch (e) {
50
+ return `${this.message}: [Complex detail object]`;
51
+ }
52
+ }
53
+ }
54
+ return this.message;
55
+ }
56
+ }
57
+ /**
58
+ * Error class for validation errors.
59
+ */
60
+ export class ValidationError extends StateZeroError {
61
+ /**
62
+ * Creates a new ValidationError.
63
+ *
64
+ * @param {IErrorDetail|Object|string} detail - The error details.
65
+ * @param {number} [status=400] - The HTTP status code.
66
+ */
67
+ constructor(detail, status = 400) {
68
+ super("Validation error", "validation_error", detail, status);
69
+ }
70
+ }
71
+ /**
72
+ * Error class for "Does Not Exist" errors (renamed from NotFound).
73
+ */
74
+ export class DoesNotExist extends StateZeroError {
75
+ /**
76
+ * Creates a new DoesNotExist error.
77
+ *
78
+ * @param {IErrorDetail|Object|string} [detail="Does not exist"] - The error details.
79
+ * @param {number} [status=404] - The HTTP status code.
80
+ */
81
+ constructor(detail = "Does not exist", status = 404) {
82
+ super("DoesNotExist", "does_not_exist", detail, status);
83
+ }
84
+ }
85
+ /**
86
+ * Error class for permission denied errors.
87
+ */
88
+ export class PermissionDenied extends StateZeroError {
89
+ /**
90
+ * Creates a new PermissionDenied error.
91
+ *
92
+ * @param {IErrorDetail|Object|string} [detail="Permission denied"] - The error details.
93
+ * @param {number} [status=403] - The HTTP status code.
94
+ */
95
+ constructor(detail = "Permission denied", status = 403) {
96
+ super("Permission denied", "permission_denied", detail, status);
97
+ }
98
+ }
99
+ /**
100
+ * Error class for multiple objects returned errors.
101
+ */
102
+ export class MultipleObjectsReturned extends StateZeroError {
103
+ /**
104
+ * Creates a new MultipleObjectsReturned error.
105
+ *
106
+ * @param {IErrorDetail|Object|string} [detail="Multiple objects returned"] - The error details.
107
+ * @param {number} [status=500] - The HTTP status code.
108
+ */
109
+ constructor(detail = "Multiple objects returned", status = 500) {
110
+ super("Multiple objects returned", "multiple_objects_returned", detail, status);
111
+ }
112
+ }
113
+ /**
114
+ * Error class for AST validation errors.
115
+ */
116
+ export class ASTValidationError extends StateZeroError {
117
+ /**
118
+ * Creates a new ASTValidationError.
119
+ *
120
+ * @param {IErrorDetail|Object|string} detail - The error details.
121
+ * @param {number} [status=400] - The HTTP status code.
122
+ */
123
+ constructor(detail, status = 400) {
124
+ super("Query syntax error", "ast_validation_error", detail, status);
125
+ }
126
+ }
127
+ /**
128
+ * Error class for configuration errors.
129
+ */
130
+ export class ConfigError extends StateZeroError {
131
+ /**
132
+ * Creates a new ConfigError.
133
+ *
134
+ * @param {IErrorDetail|Object|string} detail - The error details.
135
+ * @param {number} [status=500] - The HTTP status code.
136
+ */
137
+ constructor(detail, status = 500) {
138
+ super("Configuration error", "config_error", detail, status);
139
+ }
140
+ }
141
+ /**
142
+ * Parses a JSON error response from the backend and returns an instance
143
+ * of the corresponding custom error.
144
+ *
145
+ * @param {IErrorResponse} errorResponse - The error response JSON.
146
+ * @returns {StateZeroError} An instance of a StateZeroError subclass.
147
+ */
148
+ export function parseStateZeroError(errorResponse) {
149
+ console.log(JSON.stringify(errorResponse));
150
+ const { status, type, detail } = errorResponse;
151
+ // Handle undefined type/status case (like in permission denied)
152
+ if (type === undefined && detail === 'Invalid token.') {
153
+ return new PermissionDenied(detail, 403);
154
+ }
155
+ switch (type) {
156
+ // Direct mappings
157
+ case "ValidationError":
158
+ return new ValidationError(detail, status);
159
+ case "NotFound":
160
+ return new DoesNotExist(detail, status);
161
+ case "MultipleObjectsReturned":
162
+ return new MultipleObjectsReturned(detail, status);
163
+ case "PermissionDenied":
164
+ return new PermissionDenied(detail, status);
165
+ case "ASTValidationError":
166
+ return new ASTValidationError(detail, status);
167
+ case "ConfigError":
168
+ return new ConfigError(detail, status);
169
+ // Django error types that map to our error classes
170
+ case "FieldError":
171
+ return new ValidationError(detail, status);
172
+ case "ValueError":
173
+ return new ValidationError(detail, status);
174
+ default:
175
+ // Fallback to status code based mapping
176
+ if (status === 400) {
177
+ return new ValidationError(detail, status);
178
+ }
179
+ else if (status === 403) {
180
+ return new PermissionDenied(detail, status);
181
+ }
182
+ else if (status === 404) {
183
+ return new DoesNotExist(detail, status);
184
+ }
185
+ return new StateZeroError("Unknown error", "unknown", detail, status);
186
+ }
187
+ }
@@ -0,0 +1,6 @@
1
+ export function F(expression: any): {
2
+ __f_expr: boolean;
3
+ original_expr: string;
4
+ ast: any;
5
+ };
6
+ export function evaluateExpression(expr: any, data: any): any;
@@ -0,0 +1,91 @@
1
+ import { ValidationError } from './errors';
2
+ import * as math from 'mathjs';
3
+ // Create a math instance
4
+ const mathInstance = math.create();
5
+ // Define the allowed functions that we want to keep
6
+ const allowedFunctions = ['abs', 'round', 'floor', 'ceil', 'min', 'max'];
7
+ // Define allowed operators
8
+ const ALLOWED_OPERATORS = ['+', '-', '*', '/', '%', '^'];
9
+ export function F(expression) {
10
+ if (typeof expression !== 'string' || !expression) {
11
+ throw new ValidationError('F expression requires a non-empty string');
12
+ }
13
+ try {
14
+ const node = math.parse(expression);
15
+ validateExpression(node);
16
+ return {
17
+ __f_expr: true,
18
+ original_expr: expression,
19
+ ast: node.toJSON()
20
+ };
21
+ }
22
+ catch (err) {
23
+ throw new ValidationError(`Invalid F expression: ${err.message}`);
24
+ }
25
+ }
26
+ function validateExpression(node) {
27
+ if (!node)
28
+ return;
29
+ if (node.type === 'OperatorNode') {
30
+ if (!ALLOWED_OPERATORS.includes(node.op)) {
31
+ throw new ValidationError(`Unsupported operator: ${node.op}`);
32
+ }
33
+ node.args.forEach(validateExpression);
34
+ }
35
+ else if (node.type === 'FunctionNode') {
36
+ if (!allowedFunctions.includes(node.name)) {
37
+ throw new ValidationError(`Function not allowed: ${node.name}`);
38
+ }
39
+ node.args.forEach(validateExpression);
40
+ }
41
+ else if (node.type === 'SymbolNode') {
42
+ if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(node.name)) {
43
+ throw new ValidationError(`Invalid field name: ${node.name}`);
44
+ }
45
+ }
46
+ else if (node.type === 'ConstantNode') {
47
+ // Constants are fine
48
+ }
49
+ else if (node.type === 'ParenthesisNode') {
50
+ validateExpression(node.content);
51
+ }
52
+ else if (node.type === 'ConditionalNode') {
53
+ throw new ValidationError('Conditional expressions are not supported in F expressions');
54
+ }
55
+ else if (node.type === 'AssignmentNode') {
56
+ throw new ValidationError('Assignment expressions are not supported in F expressions');
57
+ }
58
+ else if (node.type === 'BlockNode') {
59
+ throw new ValidationError('Block expressions are not supported in F expressions');
60
+ }
61
+ else if (node.type === 'AccessorNode') {
62
+ throw new ValidationError('Accessor expressions are not supported in F expressions');
63
+ }
64
+ else if (node.type === 'IndexNode') {
65
+ throw new ValidationError('Index expressions are not supported in F expressions');
66
+ }
67
+ else if (node.type === 'RangeNode') {
68
+ throw new ValidationError('Range expressions are not supported in F expressions');
69
+ }
70
+ else if (node.type === 'ArrayNode') {
71
+ throw new ValidationError('Array expressions are not supported in F expressions');
72
+ }
73
+ else if (node.type === 'ObjectNode') {
74
+ throw new ValidationError('Object expressions are not supported in F expressions');
75
+ }
76
+ else {
77
+ throw new ValidationError(`Unsupported node type: ${node.type}`);
78
+ }
79
+ }
80
+ export function evaluateExpression(expr, data) {
81
+ if (!expr || !expr.__f_expr) {
82
+ return expr;
83
+ }
84
+ try {
85
+ return math.evaluate(expr.original_expr, data);
86
+ }
87
+ catch (err) {
88
+ console.warn(`Error evaluating F expression: ${err.message}`);
89
+ return null;
90
+ }
91
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * FileObject - A file wrapper that handles uploads to StateZero backend
3
+ */
4
+ export class FileObject {
5
+ static configKey: string;
6
+ static MIN_CHUNK_SIZE: number;
7
+ constructor(file: any, options?: {});
8
+ name: string;
9
+ size: number;
10
+ type: string;
11
+ lastModified: number;
12
+ uploaded: boolean;
13
+ uploading: boolean;
14
+ uploadResult: any;
15
+ uploadError: any;
16
+ fileData: any;
17
+ uploadType: string | null;
18
+ uploadId: any;
19
+ totalChunks: number;
20
+ completedChunks: number;
21
+ chunkSize: any;
22
+ maxConcurrency: any;
23
+ uploadPromise: any;
24
+ get status(): "failed" | "uploading" | "uploaded" | "pending";
25
+ get filePath(): any;
26
+ get fileUrl(): any;
27
+ _initializeAndStartUpload(file: any, options: any): any;
28
+ /**
29
+ * Fast upload using S3 presigned URLs with multipart support
30
+ */
31
+ _fastUpload(file: any, options?: {}): any;
32
+ /**
33
+ * Handle single file upload
34
+ */
35
+ _singleUpload(file: any, uploadData: any, options: any): Promise<any>;
36
+ /**
37
+ * Handle multipart upload with concurrency using p-queue
38
+ */
39
+ _multipartUpload(file: any, uploadData: any, options: any): Promise<any>;
40
+ /**
41
+ * Create file chunks for multipart upload
42
+ */
43
+ _createFileChunks(file: any): any[];
44
+ /**
45
+ * Complete the upload (both single and multipart)
46
+ */
47
+ _completeUpload(filePath: any, originalName: any, uploadId?: null, parts?: null): Promise<any>;
48
+ /**
49
+ * Direct upload to Django backend (original method)
50
+ */
51
+ _directUpload(options?: {}): Promise<any>;
52
+ /**
53
+ * Reads the file content into an ArrayBuffer (for direct uploads only)
54
+ */
55
+ _readFileData(file: any): Promise<void>;
56
+ /**
57
+ * Gets the file data as a Blob (for direct uploads only)
58
+ */
59
+ getBlob(): Blob;
60
+ waitForUpload(): Promise<any>;
61
+ toJSON(): {
62
+ name: string;
63
+ size: number;
64
+ type: string;
65
+ status: string;
66
+ uploaded: boolean;
67
+ filePath: any;
68
+ fileUrl: any;
69
+ uploadResult: any;
70
+ uploadError: string | null;
71
+ uploadType: string | null;
72
+ uploadId: any;
73
+ totalChunks: number;
74
+ completedChunks: number;
75
+ };
76
+ }