@statezero/core 0.2.3 → 0.2.5
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/adaptors/vue/composables.js +0 -12
- package/dist/cli/commands/syncModels.js +9 -0
- package/dist/core/eventReceivers.js +0 -15
- package/dist/flavours/django/model.d.ts +2 -1
- package/dist/flavours/django/model.js +9 -1
- package/dist/flavours/django/querySet.js +1 -0
- package/dist/models/backend1/django_app/comprehensivemodel.js +8 -0
- package/dist/models/backend1/django_app/custompkmodel.js +8 -0
- package/dist/models/backend1/django_app/dailyrate.d.ts +47 -0
- package/dist/models/backend1/django_app/dailyrate.js +71 -0
- package/dist/models/backend1/django_app/deepmodellevel1.js +8 -0
- package/dist/models/backend1/django_app/deepmodellevel2.js +8 -0
- package/dist/models/backend1/django_app/deepmodellevel3.js +8 -0
- package/dist/models/backend1/django_app/dummymodel.js +8 -0
- package/dist/models/backend1/django_app/dummyrelatedmodel.js +8 -0
- package/dist/models/backend1/django_app/filetest.js +8 -0
- package/dist/models/backend1/django_app/index.d.ts +2 -0
- package/dist/models/backend1/django_app/index.js +2 -0
- package/dist/models/backend1/django_app/modelwithcustompkrelation.js +8 -0
- package/dist/models/backend1/django_app/namefiltercustompkmodel.js +8 -0
- package/dist/models/backend1/django_app/order.js +8 -0
- package/dist/models/backend1/django_app/orderitem.js +8 -0
- package/dist/models/backend1/django_app/product.js +8 -0
- package/dist/models/backend1/django_app/productcategory.js +8 -0
- package/dist/models/backend1/django_app/rateplan.d.ts +44 -0
- package/dist/models/backend1/django_app/rateplan.js +69 -0
- package/dist/models/default/django_app/comprehensivemodel.js +8 -0
- package/dist/models/default/django_app/custompkmodel.js +8 -0
- package/dist/models/default/django_app/dailyrate.d.ts +47 -0
- package/dist/models/default/django_app/dailyrate.js +71 -0
- package/dist/models/default/django_app/deepmodellevel1.js +8 -0
- package/dist/models/default/django_app/deepmodellevel2.js +8 -0
- package/dist/models/default/django_app/deepmodellevel3.js +8 -0
- package/dist/models/default/django_app/dummymodel.js +8 -0
- package/dist/models/default/django_app/dummyrelatedmodel.js +8 -0
- package/dist/models/default/django_app/filetest.js +8 -0
- package/dist/models/default/django_app/index.d.ts +2 -0
- package/dist/models/default/django_app/index.js +2 -0
- package/dist/models/default/django_app/modelwithcustompkrelation.js +8 -0
- package/dist/models/default/django_app/namefiltercustompkmodel.js +8 -0
- package/dist/models/default/django_app/order.js +8 -0
- package/dist/models/default/django_app/orderitem.js +8 -0
- package/dist/models/default/django_app/product.js +8 -0
- package/dist/models/default/django_app/productcategory.js +8 -0
- package/dist/models/default/django_app/rateplan.d.ts +44 -0
- package/dist/models/default/django_app/rateplan.js +69 -0
- package/dist/syncEngine/stores/modelStore.js +2 -1
- package/dist/syncEngine/stores/querysetStore.d.ts +1 -1
- package/dist/syncEngine/stores/querysetStore.js +3 -10
- package/dist/syncEngine/sync.d.ts +0 -7
- package/dist/syncEngine/sync.js +2 -119
- package/package.json +1 -2
- package/dist/syncEngine/namespaceUtils.d.ts +0 -16
- package/dist/syncEngine/namespaceUtils.js +0 -32
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file was auto-generated. Do not make direct changes to the file.
|
|
3
|
+
*/
|
|
4
|
+
import { Model, Manager, QuerySet, getModelClass } from '../../../../src';
|
|
5
|
+
import { wrapReactiveModel } from '../../../../src';
|
|
6
|
+
import schemaData from './dailyrate.schema.json';
|
|
7
|
+
/**
|
|
8
|
+
* Model-specific QuerySet implementation
|
|
9
|
+
*/
|
|
10
|
+
export class DailyRateQuerySet extends QuerySet {
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Model-specific Manager implementation
|
|
14
|
+
*/
|
|
15
|
+
export class DailyRateManager extends Manager {
|
|
16
|
+
constructor(ModelClass) {
|
|
17
|
+
super(ModelClass, DailyRateQuerySet);
|
|
18
|
+
}
|
|
19
|
+
newQuerySet() {
|
|
20
|
+
return new DailyRateQuerySet(this.ModelClass);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Implementation of the DailyRate model
|
|
25
|
+
*/
|
|
26
|
+
export class DailyRate extends Model {
|
|
27
|
+
constructor(data) {
|
|
28
|
+
DailyRate.validateFields(data);
|
|
29
|
+
super(data);
|
|
30
|
+
// Define getters and setters for all fields
|
|
31
|
+
this._defineProperties();
|
|
32
|
+
return wrapReactiveModel(this);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Define property getters and setters for all model fields
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
_defineProperties() {
|
|
39
|
+
// For each field, define a property that gets/sets from internal storage
|
|
40
|
+
DailyRate.fields.forEach(field => {
|
|
41
|
+
Object.defineProperty(this, field, {
|
|
42
|
+
get: function () {
|
|
43
|
+
return this.getField(field);
|
|
44
|
+
},
|
|
45
|
+
set: function (value) {
|
|
46
|
+
this.setField(field, value);
|
|
47
|
+
},
|
|
48
|
+
enumerable: true, // Make sure fields are enumerable for serialization
|
|
49
|
+
configurable: true
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Bind this model to its backend
|
|
63
|
+
DailyRate.configKey = 'default';
|
|
64
|
+
DailyRate.modelName = 'django_app.dailyrate';
|
|
65
|
+
DailyRate.primaryKeyField = 'id';
|
|
66
|
+
DailyRate.objects = new DailyRateManager(DailyRate);
|
|
67
|
+
DailyRate.fields = ['id', 'rate_plan', 'date', 'price', 'min_stay_arrival', 'min_stay_through', 'max_stay', 'closed_to_arrival', 'closed_to_departure', 'stop_sell'];
|
|
68
|
+
DailyRate.schema = schemaData;
|
|
69
|
+
DailyRate.relationshipFields = new Map([
|
|
70
|
+
['rate_plan', { 'ModelClass': () => getModelClass('django_app.rateplan', 'default'), 'relationshipType': 'foreign-key' }]
|
|
71
|
+
]);
|
|
@@ -49,6 +49,14 @@ export class DeepModelLevel1 extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class DeepModelLevel2 extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class DeepModelLevel3 extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class DummyModel extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class DummyRelatedModel extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class FileTest extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class ModelWithCustomPKRelation extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class NameFilterCustomPKModel extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class Order extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class OrderItem extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class Product extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -49,6 +49,14 @@ export class ProductCategory extends Model {
|
|
|
49
49
|
configurable: true
|
|
50
50
|
});
|
|
51
51
|
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
// Bind this model to its backend
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-specific QuerySet implementation
|
|
3
|
+
*/
|
|
4
|
+
export class RatePlanQuerySet extends QuerySet<any> {
|
|
5
|
+
constructor(ModelClass: ModelConstructor, config?: {
|
|
6
|
+
nodes?: QueryNode[] | undefined;
|
|
7
|
+
orderBy?: {
|
|
8
|
+
field: string;
|
|
9
|
+
direction: "asc" | "desc";
|
|
10
|
+
}[] | undefined;
|
|
11
|
+
fields?: Set<string> | undefined;
|
|
12
|
+
aggregations?: Aggregation[] | undefined;
|
|
13
|
+
initialQueryset?: string | undefined;
|
|
14
|
+
serializerOptions?: SerializerOptions;
|
|
15
|
+
materialized?: boolean | undefined;
|
|
16
|
+
} | undefined, parent?: null);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Model-specific Manager implementation
|
|
20
|
+
*/
|
|
21
|
+
export class RatePlanManager extends Manager {
|
|
22
|
+
constructor(ModelClass: any);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Implementation of the RatePlan model
|
|
26
|
+
*/
|
|
27
|
+
export class RatePlan extends Model {
|
|
28
|
+
static configKey: string;
|
|
29
|
+
static modelName: string;
|
|
30
|
+
static primaryKeyField: string;
|
|
31
|
+
static objects: RatePlanManager;
|
|
32
|
+
static fields: string[];
|
|
33
|
+
static schema: any;
|
|
34
|
+
static relationshipFields: Map<any, any>;
|
|
35
|
+
constructor(data: any);
|
|
36
|
+
/**
|
|
37
|
+
* Define property getters and setters for all model fields
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
private _defineProperties;
|
|
41
|
+
}
|
|
42
|
+
import { QuerySet } from '../../../../src';
|
|
43
|
+
import { Manager } from '../../../../src';
|
|
44
|
+
import { Model } from '../../../../src';
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file was auto-generated. Do not make direct changes to the file.
|
|
3
|
+
*/
|
|
4
|
+
import { Model, Manager, QuerySet, getModelClass } from '../../../../src';
|
|
5
|
+
import { wrapReactiveModel } from '../../../../src';
|
|
6
|
+
import schemaData from './rateplan.schema.json';
|
|
7
|
+
/**
|
|
8
|
+
* Model-specific QuerySet implementation
|
|
9
|
+
*/
|
|
10
|
+
export class RatePlanQuerySet extends QuerySet {
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Model-specific Manager implementation
|
|
14
|
+
*/
|
|
15
|
+
export class RatePlanManager extends Manager {
|
|
16
|
+
constructor(ModelClass) {
|
|
17
|
+
super(ModelClass, RatePlanQuerySet);
|
|
18
|
+
}
|
|
19
|
+
newQuerySet() {
|
|
20
|
+
return new RatePlanQuerySet(this.ModelClass);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Implementation of the RatePlan model
|
|
25
|
+
*/
|
|
26
|
+
export class RatePlan extends Model {
|
|
27
|
+
constructor(data) {
|
|
28
|
+
RatePlan.validateFields(data);
|
|
29
|
+
super(data);
|
|
30
|
+
// Define getters and setters for all fields
|
|
31
|
+
this._defineProperties();
|
|
32
|
+
return wrapReactiveModel(this);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Define property getters and setters for all model fields
|
|
36
|
+
* @private
|
|
37
|
+
*/
|
|
38
|
+
_defineProperties() {
|
|
39
|
+
// For each field, define a property that gets/sets from internal storage
|
|
40
|
+
RatePlan.fields.forEach(field => {
|
|
41
|
+
Object.defineProperty(this, field, {
|
|
42
|
+
get: function () {
|
|
43
|
+
return this.getField(field);
|
|
44
|
+
},
|
|
45
|
+
set: function (value) {
|
|
46
|
+
this.setField(field, value);
|
|
47
|
+
},
|
|
48
|
+
enumerable: true, // Make sure fields are enumerable for serialization
|
|
49
|
+
configurable: true
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
// Add a special read-only getter for the repr field
|
|
53
|
+
Object.defineProperty(this, 'repr', {
|
|
54
|
+
get: function () {
|
|
55
|
+
return this.getField('repr');
|
|
56
|
+
},
|
|
57
|
+
enumerable: true, // Make sure repr is enumerable
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Bind this model to its backend
|
|
63
|
+
RatePlan.configKey = 'default';
|
|
64
|
+
RatePlan.modelName = 'django_app.rateplan';
|
|
65
|
+
RatePlan.primaryKeyField = 'id';
|
|
66
|
+
RatePlan.objects = new RatePlanManager(RatePlan);
|
|
67
|
+
RatePlan.fields = ['id', 'name'];
|
|
68
|
+
RatePlan.schema = schemaData;
|
|
69
|
+
RatePlan.relationshipFields = new Map([]);
|
|
@@ -133,7 +133,8 @@ export class ModelStore {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
if (item && typeof item.serialize === "function") {
|
|
136
|
-
|
|
136
|
+
// Pass includeRepr=true to preserve repr field in cache
|
|
137
|
+
const serializedItem = item.serialize(true);
|
|
137
138
|
serializedItem[pkField] = pk;
|
|
138
139
|
nonTempPkItems.push(serializedItem);
|
|
139
140
|
}
|
|
@@ -46,6 +46,6 @@ export class QuerysetStore {
|
|
|
46
46
|
renderFromRoot(optimistic: boolean | undefined, rootStore: any): any[];
|
|
47
47
|
renderFromData(optimistic?: boolean): any[];
|
|
48
48
|
applyOperation(operation: any, currentPks: any): any;
|
|
49
|
-
sync(
|
|
49
|
+
sync(forceFromDb?: boolean): Promise<void>;
|
|
50
50
|
}
|
|
51
51
|
import { Cache } from '../cache/cache.js';
|
|
@@ -269,8 +269,7 @@ export class QuerysetStore {
|
|
|
269
269
|
}
|
|
270
270
|
return currentPks;
|
|
271
271
|
}
|
|
272
|
-
async sync(
|
|
273
|
-
const { canonical_id, forceFromDb = false } = typeof options === 'boolean' ? { forceFromDb: options } : options;
|
|
272
|
+
async sync(forceFromDb = false) {
|
|
274
273
|
const id = this.modelClass.modelName;
|
|
275
274
|
if (this.isSyncing) {
|
|
276
275
|
console.warn(`[QuerysetStore ${id}] Already syncing, request ignored.`);
|
|
@@ -293,16 +292,10 @@ export class QuerysetStore {
|
|
|
293
292
|
this.isSyncing = true;
|
|
294
293
|
console.log(`[${id}] Starting sync...`);
|
|
295
294
|
try {
|
|
296
|
-
|
|
297
|
-
const requestBody = {
|
|
295
|
+
const response = await this.fetchFn({
|
|
298
296
|
ast: this.queryset.build(),
|
|
299
297
|
modelClass: this.modelClass,
|
|
300
|
-
};
|
|
301
|
-
// Include canonical_id if provided (for cache sharing)
|
|
302
|
-
if (canonical_id) {
|
|
303
|
-
requestBody.canonical_id = canonical_id;
|
|
304
|
-
}
|
|
305
|
-
const response = await this.fetchFn(requestBody);
|
|
298
|
+
});
|
|
306
299
|
const { data, included } = response;
|
|
307
300
|
if (isNil(data)) {
|
|
308
301
|
return;
|
|
@@ -5,7 +5,6 @@ export class EventPayload {
|
|
|
5
5
|
operation_id: any;
|
|
6
6
|
pk_field_name: any;
|
|
7
7
|
configKey: any;
|
|
8
|
-
canonical_id: any;
|
|
9
8
|
instances: any;
|
|
10
9
|
_cachedInstances: any;
|
|
11
10
|
get modelClass(): Function | null;
|
|
@@ -24,22 +23,16 @@ export class SyncManager {
|
|
|
24
23
|
maxWaitMs: number;
|
|
25
24
|
batchStartTime: number | null;
|
|
26
25
|
syncQueue: PQueue<import("p-queue/dist/priority-queue").default, import("p-queue").QueueAddOptions>;
|
|
27
|
-
activeSubscriptions: Map<any, any>;
|
|
28
|
-
currentCanonicalId: any;
|
|
29
26
|
withTimeout(promise: any, ms: any): Promise<any>;
|
|
30
27
|
/**
|
|
31
28
|
* Initialize event handlers for all event receivers
|
|
32
29
|
*/
|
|
33
30
|
initialize(): void;
|
|
34
|
-
handleDisconnect(): void;
|
|
35
|
-
handleReconnect(): void;
|
|
36
31
|
startPeriodicSync(): void;
|
|
37
32
|
syncStaleQuerysets(): void;
|
|
38
33
|
pruneUnreferencedModels(): void;
|
|
39
34
|
isStoreFollowed(registry: any, semanticKey: any): boolean;
|
|
40
35
|
cleanup(): void;
|
|
41
|
-
subscribeToNamespace(queryset: any): Promise<void>;
|
|
42
|
-
unsubscribeFromNamespace(queryset: any): Promise<void>;
|
|
43
36
|
followModel(registry: any, modelClass: any): void;
|
|
44
37
|
unfollowModel(registry: any, modelClass: any): void;
|
|
45
38
|
manageRegistry(registry: any): void;
|
package/dist/syncEngine/sync.js
CHANGED
|
@@ -16,7 +16,6 @@ export class EventPayload {
|
|
|
16
16
|
this.operation_id = data.operation_id;
|
|
17
17
|
this.pk_field_name = data.pk_field_name;
|
|
18
18
|
this.configKey = data.configKey;
|
|
19
|
-
this.canonical_id = data.canonical_id;
|
|
20
19
|
// Parse PK fields to numbers in instances
|
|
21
20
|
this.instances = data.instances?.map(instance => {
|
|
22
21
|
if (instance && this.pk_field_name && instance[this.pk_field_name] != null) {
|
|
@@ -51,10 +50,6 @@ export class SyncManager {
|
|
|
51
50
|
this.handleEvent = (event) => {
|
|
52
51
|
let payload = new EventPayload(event);
|
|
53
52
|
let isLocalOperation = operationRegistry.has(payload.operation_id);
|
|
54
|
-
// Store canonical_id for upcoming refetches
|
|
55
|
-
if (event.canonical_id) {
|
|
56
|
-
this.currentCanonicalId = event.canonical_id;
|
|
57
|
-
}
|
|
58
53
|
// Always process metrics immediately (they're lightweight)
|
|
59
54
|
if (this.registries.has(MetricRegistry)) {
|
|
60
55
|
this.processMetrics(payload);
|
|
@@ -102,9 +97,6 @@ export class SyncManager {
|
|
|
102
97
|
this.batchStartTime = null;
|
|
103
98
|
// SyncQueue
|
|
104
99
|
this.syncQueue = new PQueue({ concurrency: 1 });
|
|
105
|
-
// Namespace subscription tracking
|
|
106
|
-
this.activeSubscriptions = new Map(); // semanticKey -> {queryset, subscribedAt}
|
|
107
|
-
this.currentCanonicalId = null; // Store canonical_id from events
|
|
108
100
|
}
|
|
109
101
|
withTimeout(promise, ms) {
|
|
110
102
|
// If no timeout specified, use 2x the periodic sync interval, or 30s as fallback
|
|
@@ -131,31 +123,15 @@ export class SyncManager {
|
|
|
131
123
|
initializeAllEventReceivers();
|
|
132
124
|
// Get all registered event receivers
|
|
133
125
|
const eventReceivers = getAllEventReceivers();
|
|
134
|
-
// Create event handler with connection lifecycle methods
|
|
135
|
-
const eventHandlerWithLifecycle = this.handleEvent.bind(this);
|
|
136
|
-
eventHandlerWithLifecycle.onReconnected = this.handleReconnect.bind(this);
|
|
137
|
-
eventHandlerWithLifecycle.onDisconnected = this.handleDisconnect.bind(this);
|
|
138
126
|
// Register the event handlers with each receiver
|
|
139
127
|
eventReceivers.forEach((receiver, configKey) => {
|
|
140
128
|
if (receiver) {
|
|
141
129
|
// Model events go to handleEvent
|
|
142
|
-
receiver.addModelEventHandler(
|
|
130
|
+
receiver.addModelEventHandler(this.handleEvent.bind(this));
|
|
143
131
|
}
|
|
144
132
|
});
|
|
145
133
|
this.startPeriodicSync();
|
|
146
134
|
}
|
|
147
|
-
handleDisconnect() {
|
|
148
|
-
// Clear local subscription state on disconnect
|
|
149
|
-
this.activeSubscriptions.clear();
|
|
150
|
-
console.log('[SyncManager] Cleared subscriptions on disconnect');
|
|
151
|
-
}
|
|
152
|
-
handleReconnect() {
|
|
153
|
-
// Resubscribe to all active querysets after reconnect
|
|
154
|
-
console.log('[SyncManager] Resubscribing to active querysets after reconnect');
|
|
155
|
-
for (const queryset of this.followedQuerysets) {
|
|
156
|
-
this.subscribeToNamespace(queryset);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
135
|
startPeriodicSync() {
|
|
160
136
|
if (this.periodicSyncTimer)
|
|
161
137
|
return;
|
|
@@ -231,97 +207,6 @@ export class SyncManager {
|
|
|
231
207
|
this.maxWaitTimer = null;
|
|
232
208
|
}
|
|
233
209
|
}
|
|
234
|
-
async subscribeToNamespace(queryset) {
|
|
235
|
-
const key = queryset.semanticKey;
|
|
236
|
-
// Skip if already subscribed
|
|
237
|
-
if (this.activeSubscriptions.has(key))
|
|
238
|
-
return;
|
|
239
|
-
try {
|
|
240
|
-
const config = getConfig();
|
|
241
|
-
const backendConfig = config.backendConfigs[queryset.modelClass.configKey];
|
|
242
|
-
if (!backendConfig) {
|
|
243
|
-
console.error(`[SyncManager] Backend config not found for: ${queryset.modelClass.configKey}`);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
const apiUrl = backendConfig.API_URL;
|
|
247
|
-
// Get Pusher socket ID
|
|
248
|
-
const eventReceiver = getEventReceiver(queryset.modelClass.configKey);
|
|
249
|
-
const socketId = eventReceiver?.pusherClient?.connection?.socket_id;
|
|
250
|
-
if (!socketId) {
|
|
251
|
-
console.warn('[SyncManager] No socket_id available for subscription');
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
// Send subscription request to backend
|
|
255
|
-
const response = await fetch(`${apiUrl}/namespaces/subscribe/`, {
|
|
256
|
-
method: 'POST',
|
|
257
|
-
headers: {
|
|
258
|
-
'Content-Type': 'application/json',
|
|
259
|
-
},
|
|
260
|
-
body: JSON.stringify({
|
|
261
|
-
socket_id: socketId,
|
|
262
|
-
model_name: queryset.modelClass.modelName,
|
|
263
|
-
filter: queryset._filters // Backend extracts namespace from this
|
|
264
|
-
})
|
|
265
|
-
});
|
|
266
|
-
const result = await response.json();
|
|
267
|
-
if (!result.success) {
|
|
268
|
-
throw new Error('Subscription failed');
|
|
269
|
-
}
|
|
270
|
-
// Subscribe to the namespace-specific Pusher channel
|
|
271
|
-
const namespaceChannel = result.channel; // e.g., "django_app.Message:abc123hash"
|
|
272
|
-
eventReceiver?.subscribe(namespaceChannel);
|
|
273
|
-
this.activeSubscriptions.set(key, {
|
|
274
|
-
queryset,
|
|
275
|
-
subscribedAt: Date.now(),
|
|
276
|
-
channel: namespaceChannel,
|
|
277
|
-
namespace_hash: result.namespace_hash
|
|
278
|
-
});
|
|
279
|
-
console.log(`[SyncManager] Subscribed to namespace channel: ${namespaceChannel}`);
|
|
280
|
-
}
|
|
281
|
-
catch (error) {
|
|
282
|
-
console.error('[SyncManager] Namespace subscription failed:', error);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
async unsubscribeFromNamespace(queryset) {
|
|
286
|
-
const key = queryset.semanticKey;
|
|
287
|
-
if (!this.activeSubscriptions.has(key))
|
|
288
|
-
return;
|
|
289
|
-
const subscription = this.activeSubscriptions.get(key);
|
|
290
|
-
try {
|
|
291
|
-
const config = getConfig();
|
|
292
|
-
const backendConfig = config.backendConfigs[queryset.modelClass.configKey];
|
|
293
|
-
if (!backendConfig) {
|
|
294
|
-
console.error(`[SyncManager] Backend config not found for: ${queryset.modelClass.configKey}`);
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
const apiUrl = backendConfig.API_URL;
|
|
298
|
-
const eventReceiver = getEventReceiver(queryset.modelClass.configKey);
|
|
299
|
-
const socketId = eventReceiver?.pusherClient?.connection?.socket_id;
|
|
300
|
-
if (!socketId)
|
|
301
|
-
return;
|
|
302
|
-
// Unsubscribe from the Pusher channel
|
|
303
|
-
if (subscription.channel) {
|
|
304
|
-
eventReceiver?.unsubscribe(subscription.channel);
|
|
305
|
-
}
|
|
306
|
-
// Notify backend to remove subscription
|
|
307
|
-
await fetch(`${apiUrl}/namespaces/unsubscribe/`, {
|
|
308
|
-
method: 'POST',
|
|
309
|
-
headers: {
|
|
310
|
-
'Content-Type': 'application/json',
|
|
311
|
-
},
|
|
312
|
-
body: JSON.stringify({
|
|
313
|
-
socket_id: socketId,
|
|
314
|
-
model_name: queryset.modelClass.modelName,
|
|
315
|
-
filter: queryset._filters
|
|
316
|
-
})
|
|
317
|
-
});
|
|
318
|
-
this.activeSubscriptions.delete(key);
|
|
319
|
-
console.log(`[SyncManager] Unsubscribed from namespace channel: ${subscription.channel}`);
|
|
320
|
-
}
|
|
321
|
-
catch (error) {
|
|
322
|
-
console.error('[SyncManager] Namespace unsubscription failed:', error);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
210
|
followModel(registry, modelClass) {
|
|
326
211
|
const models = this.followedModels.get(registry) || new Set();
|
|
327
212
|
this.followedModels.set(registry, models);
|
|
@@ -423,9 +308,7 @@ export class SyncManager {
|
|
|
423
308
|
// Sync all relevant stores for this model
|
|
424
309
|
console.log(`[SyncManager] Syncing ${storesToSync.length} queryset stores for ${representativeEvent.model}`);
|
|
425
310
|
storesToSync.forEach((store) => {
|
|
426
|
-
this.syncQueue.add(() => this.withTimeout(store.sync(
|
|
427
|
-
canonical_id: representativeEvent.canonical_id // Pass canonical_id
|
|
428
|
-
})));
|
|
311
|
+
this.syncQueue.add(() => this.withTimeout(store.sync()));
|
|
429
312
|
});
|
|
430
313
|
}
|
|
431
314
|
processMetrics(event) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statezero/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"module": "ESNext",
|
|
6
6
|
"description": "The type-safe frontend client for StateZero - connect directly to your backend models with zero boilerplate",
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
"test:e2e": "vitest run --config=vitest.sequential.config.ts tests/e2e",
|
|
33
33
|
"generate:test-apps": "ts-node scripts/generate-test-apps.js",
|
|
34
34
|
"test:adaptors": "playwright test tests/adaptors",
|
|
35
|
-
"test:integration": "playwright test --config=playwright.integration.config.ts",
|
|
36
35
|
"test:coverage": "vitest run --coverage",
|
|
37
36
|
"build": "tsc",
|
|
38
37
|
"parse-queries": "node scripts/perfect-query-parser.js",
|