@statezero/core 0.1.2 → 0.1.3-9.2

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.
@@ -58,6 +58,7 @@ export class SyncManager {
58
58
  // Map of querysets to keep synced
59
59
  this.followAllQuerysets = true;
60
60
  this.followedQuerysets = new Map();
61
+ this.periodicSyncTimer = null;
61
62
  }
62
63
  /**
63
64
  * Initialize event handlers for all event receivers
@@ -74,13 +75,68 @@ export class SyncManager {
74
75
  receiver.addModelEventHandler(this.handleEvent.bind(this));
75
76
  }
76
77
  });
78
+ this.startPeriodicSync();
79
+ }
80
+ startPeriodicSync() {
81
+ if (this.periodicSyncTimer)
82
+ return;
83
+ try {
84
+ const config = getConfig();
85
+ const intervalSeconds = config.periodicSyncIntervalSeconds;
86
+ // If null or undefined, don't start periodic sync
87
+ if (!intervalSeconds) {
88
+ console.log("[SyncManager] Periodic sync disabled (set to null)");
89
+ return;
90
+ }
91
+ const intervalMs = intervalSeconds * 1000;
92
+ this.periodicSyncTimer = setInterval(() => {
93
+ this.syncStaleQuerysets();
94
+ }, intervalMs);
95
+ console.log(`[SyncManager] Periodic sync started: ${intervalSeconds}s intervals`);
96
+ }
97
+ catch (error) {
98
+ // If no config, don't start periodic sync by default
99
+ console.log("[SyncManager] No config found, periodic sync disabled by default");
100
+ }
101
+ }
102
+ syncStaleQuerysets() {
103
+ let syncedCount = 0;
104
+ // Sync all followed querysets - keep it simple
105
+ const querysetRegistry = this.registries.get("QuerysetStoreRegistry");
106
+ if (querysetRegistry) {
107
+ for (const [semanticKey, store] of querysetRegistry._stores.entries()) {
108
+ // Only sync if this store is actually being followed
109
+ const isFollowed = this.isStoreFollowed(querysetRegistry, semanticKey);
110
+ if (this.followAllQuerysets || isFollowed) {
111
+ store.sync();
112
+ syncedCount++;
113
+ }
114
+ }
115
+ }
116
+ if (syncedCount > 0) {
117
+ console.log(`[SyncManager] Periodic sync: ${syncedCount} stores synced`);
118
+ }
119
+ }
120
+ isStoreFollowed(registry, semanticKey) {
121
+ const followingQuerysets = registry.followingQuerysets.get(semanticKey);
122
+ if (!followingQuerysets)
123
+ return false;
124
+ return [...followingQuerysets].some((queryset) => {
125
+ return this.isQuerysetFollowed(queryset);
126
+ });
127
+ }
128
+ cleanup() {
129
+ if (this.periodicSyncTimer) {
130
+ clearInterval(this.periodicSyncTimer);
131
+ this.periodicSyncTimer = null;
132
+ }
77
133
  }
78
134
  followModel(registry, modelClass) {
79
135
  const models = this.followedModels.get(registry) || new Set();
80
136
  this.followedModels.set(registry, models);
81
137
  if (models.has(modelClass))
82
138
  return;
83
- const alreadyFollowed = [...this.followedModels.values()].some(set => set.has(modelClass));
139
+ const alreadyFollowed = [...this.followedModels.values()].some((set) => set.has(modelClass));
84
140
  models.add(modelClass);
85
141
  if (!alreadyFollowed) {
86
142
  getEventReceiver(modelClass.configKey)?.subscribe(modelClass.modelName, this.handleEvent);
@@ -91,7 +147,7 @@ export class SyncManager {
91
147
  if (!models)
92
148
  return;
93
149
  models.delete(modelClass);
94
- const stillFollowed = [...this.followedModels.values()].some(set => set.has(modelClass));
150
+ const stillFollowed = [...this.followedModels.values()].some((set) => set.has(modelClass));
95
151
  if (!stillFollowed) {
96
152
  getEventReceiver(modelClass.configKey)?.unsubscribe(modelClass.modelName, this.handleEvent);
97
153
  }
@@ -104,10 +160,10 @@ export class SyncManager {
104
160
  this.registries.delete(registry.constructor.name);
105
161
  }
106
162
  isQuerysetFollowed(queryset) {
163
+ const activeSemanticKeys = new Set([...this.followedQuerysets].map((qs) => qs.semanticKey));
107
164
  let current = queryset;
108
- // All followed querysets and their descendents get updated
109
165
  while (current) {
110
- if (this.followedQuerysets.has(current)) {
166
+ if (activeSemanticKeys.has(current.semanticKey)) {
111
167
  return true;
112
168
  }
113
169
  current = current.__parent;
@@ -127,7 +183,7 @@ export class SyncManager {
127
183
  const followingQuerysets = registry.followingQuerysets.get(semanticKey);
128
184
  if (followingQuerysets) {
129
185
  // Use some() to break early when we find a match
130
- const shouldSync = [...followingQuerysets].some(queryset => {
186
+ const shouldSync = [...followingQuerysets].some((queryset) => {
131
187
  return this.isQuerysetFollowed(queryset);
132
188
  });
133
189
  if (shouldSync) {
package/package.json CHANGED
@@ -1,123 +1,126 @@
1
- {
2
- "name": "@statezero/core",
3
- "version": "0.1.2",
4
- "type": "module",
5
- "module": "ESNext",
6
- "description": "The type-safe frontend client for StateZero - connect directly to your backend models with zero boilerplate",
7
- "main": "dist/index.js",
8
- "types": "dist/index.d.ts",
9
- "bin": {
10
- "statezero": "dist/cli/index.js"
11
- },
12
- "exports": {
13
- ".": {
14
- "import": "./dist/index.js",
15
- "require": "./dist/index.js"
16
- },
17
- "./cli": {
18
- "import": "./dist/cli/index.js",
19
- "require": "./dist/cli/index.js"
20
- },
21
- "./react": {
22
- "import": "./dist/react-entry.js",
23
- "require": "./dist/react-entry.js"
24
- },
25
- "./vue": {
26
- "import": "./dist/vue-entry.js",
27
- "require": "./dist/vue-entry.js"
28
- }
29
- },
30
- "scripts": {
31
- "test": "vitest run --config=vitest.base.config.ts",
32
- "test:e2e": "vitest run --config=vitest.sequential.config.ts tests/e2e",
33
- "generate:test-apps": "ts-node scripts/generate-test-apps.js",
34
- "test:adaptors": "playwright test tests/adaptors",
35
- "test:coverage": "vitest run --coverage",
36
- "build": "tsc",
37
- "parse-queries": "node scripts/perfect-query-parser.js",
38
- "sync-models": "node src/cli/index.js sync-models",
39
- "sync-models:dev": "npx cross-env NODE_ENV=test npm run sync-models",
40
- "clean": "npx rimraf dist",
41
- "prepare": "npm run clean && npm run build",
42
- "prepublishOnly": "npm run clean && npm run build"
43
- },
44
- "keywords": [
45
- "typescript",
46
- "orm",
47
- "backend",
48
- "frontend",
49
- "database",
50
- "sql",
51
- "django",
52
- "sqlalchemy",
53
- "react",
54
- "vue",
55
- "svelte"
56
- ],
57
- "author": "Robert Herring <robert.herring@resipilot.com>",
58
- "license": "SEE LICENSE IN LICENSE",
59
- "repository": {
60
- "type": "git",
61
- "url": "git+https://github.com/state-zero/statezero-client.git"
62
- },
63
- "files": [
64
- "dist",
65
- "LICENSE",
66
- "README.md"
67
- ],
68
- "homepage": "https://www.statezero.dev",
69
- "dependencies": {
70
- "axios": "^1.7.9",
71
- "cli-progress": "^3.12.0",
72
- "cosmiconfig": "^9.0.0",
73
- "cosmiconfig-typescript-loader": "^6.1.0",
74
- "date-fns": "^4.1.0",
75
- "dotenv": "^16.4.7",
76
- "fs-extra": "^11.3.0",
77
- "handlebars": "^4.7.8",
78
- "idb": "^8.0.2",
79
- "inquirer": "^12.4.2",
80
- "lodash-es": "^4.17.21",
81
- "luxon": "^3.6.1",
82
- "mathjs": "^14.4.0",
83
- "mitt": "^3.0.1",
84
- "mobx": "^6.13.7",
85
- "mobx-utils": "^6.1.0",
86
- "object-hash": "^3.0.0",
87
- "openapi-typescript": "^6.7.1",
88
- "p-queue": "^8.1.0",
89
- "pusher-js": "^8.4.0",
90
- "rfdc": "^1.4.1",
91
- "sift": "^17.1.3",
92
- "superjson": "^2.2.2",
93
- "uuid": "^11.1.0",
94
- "yargs": "^17.7.2",
95
- "zod": "^3.24.2"
96
- },
97
- "devDependencies": {
98
- "@playwright/test": "^1.50.1",
99
- "@types/cli-progress": "^3.11.6",
100
- "@types/lodash-es": "^4.17.12",
101
- "@types/node": "^22.13.1",
102
- "@types/react": "^18.3.18",
103
- "@types/yargs": "^17.0.32",
104
- "@vitest/coverage-v8": "^3.0.5",
105
- "fake-indexeddb": "^6.0.0",
106
- "fast-glob": "^3.3.3",
107
- "react": "^18.2.0",
108
- "rimraf": "^5.0.5",
109
- "ts-node": "^10.9.2",
110
- "typescript": "^5.7.3",
111
- "vitest": "^3.0.5",
112
- "vue": "^3.2.0"
113
- },
114
- "publishConfig": {
115
- "access": "restricted"
116
- },
117
- "bugs": {
118
- "url": "https://github.com/state-zero/statezero-client/issues"
119
- },
120
- "directories": {
121
- "test": "tests"
122
- }
123
- }
1
+ {
2
+ "name": "@statezero/core",
3
+ "version": "0.1.39.2",
4
+ "type": "module",
5
+ "module": "ESNext",
6
+ "description": "The type-safe frontend client for StateZero - connect directly to your backend models with zero boilerplate",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "bin": {
10
+ "statezero": "dist/cli/index.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.js"
16
+ },
17
+ "./cli": {
18
+ "import": "./dist/cli/index.js",
19
+ "require": "./dist/cli/index.js"
20
+ },
21
+ "./react": {
22
+ "import": "./dist/react-entry.js",
23
+ "require": "./dist/react-entry.js"
24
+ },
25
+ "./vue": {
26
+ "import": "./dist/vue-entry.js",
27
+ "require": "./dist/vue-entry.js"
28
+ }
29
+ },
30
+ "scripts": {
31
+ "test": "vitest run --config=vitest.base.config.ts",
32
+ "test:e2e": "vitest run --config=vitest.sequential.config.ts tests/e2e",
33
+ "generate:test-apps": "ts-node scripts/generate-test-apps.js",
34
+ "test:adaptors": "playwright test tests/adaptors",
35
+ "test:coverage": "vitest run --coverage",
36
+ "build": "tsc",
37
+ "parse-queries": "node scripts/perfect-query-parser.js",
38
+ "sync": "node src/cli/index.js sync",
39
+ "sync:dev": "npx cross-env NODE_ENV=test npm run sync",
40
+ "sync-models": "node src/cli/index.js sync-models",
41
+ "sync-models:dev": "npx cross-env NODE_ENV=test npm run sync-models",
42
+ "sync-actions": "node src/cli/index.js sync-actions",
43
+ "sync-actions:dev": "npx cross-env NODE_ENV=test npm run sync-actions",
44
+ "clean": "npx rimraf dist",
45
+ "prepare": "npm run clean && npm run build",
46
+ "prepublishOnly": "npm run clean && npm run build"
47
+ },
48
+ "keywords": [
49
+ "typescript",
50
+ "orm",
51
+ "backend",
52
+ "frontend",
53
+ "database",
54
+ "sql",
55
+ "django",
56
+ "sqlalchemy",
57
+ "react",
58
+ "vue",
59
+ "svelte"
60
+ ],
61
+ "author": "Robert Herring <robert.herring@resipilot.com>",
62
+ "license": "SEE LICENSE IN LICENSE",
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "git+https://github.com/state-zero/statezero-client.git"
66
+ },
67
+ "files": [
68
+ "dist",
69
+ "LICENSE",
70
+ "README.md"
71
+ ],
72
+ "homepage": "https://www.statezero.dev",
73
+ "dependencies": {
74
+ "axios": "^1.7.9",
75
+ "cli-progress": "^3.12.0",
76
+ "cosmiconfig": "^9.0.0",
77
+ "cosmiconfig-typescript-loader": "^6.1.0",
78
+ "date-fns": "^4.1.0",
79
+ "dotenv": "^16.4.7",
80
+ "fs-extra": "^11.3.0",
81
+ "graphlib": "^2.1.8",
82
+ "handlebars": "^4.7.8",
83
+ "idb": "^8.0.2",
84
+ "inquirer": "^12.4.2",
85
+ "lodash-es": "^4.17.21",
86
+ "luxon": "^3.6.1",
87
+ "mathjs": "^14.4.0",
88
+ "mitt": "^3.0.1",
89
+ "object-hash": "^3.0.0",
90
+ "openapi-typescript": "^6.7.1",
91
+ "p-queue": "^8.1.0",
92
+ "pusher-js": "^8.4.0",
93
+ "rfdc": "^1.4.1",
94
+ "sift": "^17.1.3",
95
+ "superjson": "^2.2.2",
96
+ "uuid": "^11.1.0",
97
+ "yargs": "^17.7.2",
98
+ "zod": "^3.24.2"
99
+ },
100
+ "devDependencies": {
101
+ "@playwright/test": "^1.50.1",
102
+ "@types/cli-progress": "^3.11.6",
103
+ "@types/lodash-es": "^4.17.12",
104
+ "@types/node": "^22.13.1",
105
+ "@types/react": "^18.3.18",
106
+ "@types/yargs": "^17.0.32",
107
+ "@vitest/coverage-v8": "^3.0.5",
108
+ "fake-indexeddb": "^6.0.0",
109
+ "fast-glob": "^3.3.3",
110
+ "react": "^18.2.0",
111
+ "rimraf": "^5.0.5",
112
+ "ts-node": "^10.9.2",
113
+ "typescript": "^5.7.3",
114
+ "vitest": "^3.0.5",
115
+ "vue": "^3.2.0"
116
+ },
117
+ "publishConfig": {
118
+ "access": "public"
119
+ },
120
+ "bugs": {
121
+ "url": "https://github.com/state-zero/statezero-client/issues"
122
+ },
123
+ "directories": {
124
+ "test": "tests"
125
+ }
126
+ }
package/readme.md CHANGED
@@ -192,7 +192,7 @@ npm install https://github.com/state-zero/statezero-client
192
192
  ### Generate TypeScript Models
193
193
 
194
194
  ```bash
195
- npx statezero sync-models
195
+ npx statezero sync
196
196
  ```
197
197
 
198
198
  ## Why Choose StateZero Over...