poi-plugin-kai-planner 1.0.2 → 1.0.3

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/README.md CHANGED
@@ -22,7 +22,9 @@
22
22
 
23
23
  ## 本地数据
24
24
 
25
- - 用户计划优先写入:`runtime_data/userPlans/plans.v1.json`
25
+ - 用户计划优先写入:
26
+ - 若 Electron 可提供 `userData` 目录,则写入 `<userData>/poi-plugin-kai-planner/userPlans/plans.v1.json`
27
+ - 若无法获取稳定用户目录,则回退到 `<plugin_root>/runtime_data/userPlans/plans.v1.json`
26
28
  - 文件存储不可用时回退 `localStorage`:`kai_planner_user_plans_v1`
27
29
  - 远端静态数据缓存:
28
30
  - `runtime_data/static_data/meta.json`
@@ -43,4 +45,4 @@
43
45
  - Wishlist 状态字段:[docs/WISHLIST_STATE_FIELDS.md](docs/WISHLIST_STATE_FIELDS.md)
44
46
  - npm/POI 发布流程:[docs/RELEASE_POI_NPM.md](docs/RELEASE_POI_NPM.md)
45
47
  - 私有仓库更新流程:[docs/PRIVATE_REPO_UPDATE.md](docs/PRIVATE_REPO_UPDATE.md)
46
- - 远端静态数据更新流程:[docs/REMOTE_DATA_UPDATE.md](docs/REMOTE_DATA_UPDATE.md)
48
+ - 远端静态数据更新流程:[docs/REMOTE_DATA_UPDATE.md](docs/REMOTE_DATA_UPDATE.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poi-plugin-kai-planner",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "main": "index.js",
5
5
  "author": "aulu",
6
6
  "contributors": ["aulu"],
@@ -15,60 +15,113 @@ function getNodeModule(name) {
15
15
  }
16
16
  }
17
17
 
18
- const fs = getNodeModule("fs");
19
- const path = getNodeModule("path");
18
+ const fsMod = getNodeModule("fs");
19
+ const pathMod = getNodeModule("path");
20
+
21
+ function getEnvValue(name) {
22
+ try {
23
+ if (typeof process !== "undefined" && process && process.env && process.env[name]) {
24
+ return String(process.env[name]);
25
+ }
26
+ } catch {}
27
+ return null;
28
+ }
20
29
 
21
30
  function isAvailable() {
22
- return !!(fs && path);
31
+ return !!(fsMod && pathMod);
32
+ }
33
+
34
+ function getElectronApp() {
35
+ const electron = getNodeModule("electron");
36
+ if (!electron) return null;
37
+ if (electron.app && typeof electron.app.getPath === "function") return electron.app;
38
+ if (electron.remote && electron.remote.app && typeof electron.remote.app.getPath === "function") {
39
+ return electron.remote.app;
40
+ }
41
+ return null;
23
42
  }
24
43
 
25
- function getPluginRoot() {
44
+ function getStableBaseDir() {
45
+ const envDir = getEnvValue("KAI_PLANNER_USER_DATA_DIR");
46
+ if (envDir) return envDir;
26
47
  if (!isAvailable()) return null;
27
- // current file: src/storage/userPlans/fileStore.js
28
- return path.resolve(__dirname, "../../../");
48
+
49
+ const app = getElectronApp();
50
+ if (!app) return null;
51
+ try {
52
+ const dir = app.getPath("userData");
53
+ return dir ? String(dir) : null;
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ function hasStableStoreSupport() {
60
+ return !!getStableBaseDir();
61
+ }
62
+
63
+ function getStableStoreDir() {
64
+ const base = getStableBaseDir();
65
+ if (!base || !pathMod) return null;
66
+ return pathMod.join(base, "poi-plugin-kai-planner", "userPlans");
67
+ }
68
+
69
+ function getStableStoreFilePath() {
70
+ const dir = getStableStoreDir();
71
+ if (!dir || !pathMod) return null;
72
+ return pathMod.join(dir, "plans.v1.json");
73
+ }
74
+
75
+ function getLegacyPluginRoot() {
76
+ const envRoot = getEnvValue("KAI_PLANNER_PLUGIN_ROOT");
77
+ if (envRoot) return envRoot;
78
+ if (!isAvailable()) return null;
79
+ return pathMod.resolve(__dirname, "../../../");
80
+ }
81
+
82
+ function getLegacyStoreDir() {
83
+ const root = getLegacyPluginRoot();
84
+ if (!root || !pathMod) return null;
85
+ return pathMod.join(root, "runtime_data", "userPlans");
86
+ }
87
+
88
+ function getLegacyStoreFilePath() {
89
+ const dir = getLegacyStoreDir();
90
+ if (!dir || !pathMod) return null;
91
+ return pathMod.join(dir, "plans.v1.json");
29
92
  }
30
93
 
31
94
  function getStoreDir() {
32
- const root = getPluginRoot();
33
- if (!root) return null;
34
- return path.join(root, "runtime_data", "userPlans");
95
+ return getStableStoreDir() || getLegacyStoreDir();
35
96
  }
36
97
 
37
98
  function getStoreFilePath() {
38
- const dir = getStoreDir();
39
- if (!dir) return null;
40
- return path.join(dir, "plans.v1.json");
99
+ return getStableStoreFilePath() || getLegacyStoreFilePath();
41
100
  }
42
101
 
43
- function ensureStoreDir() {
44
- if (!isAvailable()) return false;
45
- const dir = getStoreDir();
46
- if (!dir) return false;
102
+ function ensureDir(dir) {
103
+ if (!isAvailable() || !dir) return false;
47
104
  try {
48
- fs.mkdirSync(dir, { recursive: true });
105
+ fsMod.mkdirSync(dir, { recursive: true });
49
106
  return true;
50
107
  } catch {
51
108
  return false;
52
109
  }
53
110
  }
54
111
 
55
- function exists() {
56
- if (!isAvailable()) return false;
57
- const fp = getStoreFilePath();
58
- if (!fp) return false;
112
+ function fileExists(fp) {
113
+ if (!isAvailable() || !fp) return false;
59
114
  try {
60
- return fs.existsSync(fp);
115
+ return fsMod.existsSync(fp);
61
116
  } catch {
62
117
  return false;
63
118
  }
64
119
  }
65
120
 
66
- function readRaw() {
67
- if (!isAvailable()) return null;
68
- const fp = getStoreFilePath();
69
- if (!fp || !exists()) return null;
121
+ function readJsonFile(fp) {
122
+ if (!isAvailable() || !fp || !fileExists(fp)) return null;
70
123
  try {
71
- const s = fs.readFileSync(fp, "utf8");
124
+ const s = fsMod.readFileSync(fp, "utf8");
72
125
  if (!s) return null;
73
126
  return JSON.parse(s);
74
127
  } catch {
@@ -76,31 +129,82 @@ function readRaw() {
76
129
  }
77
130
  }
78
131
 
79
- function writeRaw(payload) {
80
- if (!isAvailable()) return false;
81
- if (!ensureStoreDir()) return false;
82
-
83
- const fp = getStoreFilePath();
84
- if (!fp) return false;
132
+ function writeJsonFile(fp, payload) {
133
+ if (!isAvailable() || !fp || !pathMod) return false;
134
+ if (!ensureDir(pathMod.dirname(fp))) return false;
85
135
  const tmp = `${fp}.tmp`;
86
-
87
136
  try {
88
- fs.writeFileSync(tmp, JSON.stringify(payload, null, 2), "utf8");
89
- fs.renameSync(tmp, fp);
137
+ fsMod.writeFileSync(tmp, JSON.stringify(payload, null, 2), "utf8");
138
+ fsMod.renameSync(tmp, fp);
90
139
  return true;
91
140
  } catch {
92
141
  try {
93
- if (fs.existsSync(tmp)) fs.unlinkSync(tmp);
142
+ if (fsMod.existsSync(tmp)) fsMod.unlinkSync(tmp);
94
143
  } catch {}
95
144
  return false;
96
145
  }
97
146
  }
98
147
 
148
+ function stableExists() {
149
+ return fileExists(getStableStoreFilePath());
150
+ }
151
+
152
+ function legacyExists() {
153
+ return fileExists(getLegacyStoreFilePath());
154
+ }
155
+
156
+ function exists() {
157
+ if (hasStableStoreSupport()) return stableExists() || legacyExists();
158
+ return legacyExists();
159
+ }
160
+
161
+ function readStableRaw() {
162
+ return readJsonFile(getStableStoreFilePath());
163
+ }
164
+
165
+ function readLegacyRaw() {
166
+ return readJsonFile(getLegacyStoreFilePath());
167
+ }
168
+
169
+ function readRaw() {
170
+ if (hasStableStoreSupport()) {
171
+ const stable = readStableRaw();
172
+ if (stable != null) return stable;
173
+ }
174
+ return readLegacyRaw();
175
+ }
176
+
177
+ function writeStableRaw(payload) {
178
+ return writeJsonFile(getStableStoreFilePath(), payload);
179
+ }
180
+
181
+ function writeLegacyRaw(payload) {
182
+ return writeJsonFile(getLegacyStoreFilePath(), payload);
183
+ }
184
+
185
+ function writeRaw(payload) {
186
+ if (hasStableStoreSupport() && writeStableRaw(payload)) return true;
187
+ return writeLegacyRaw(payload);
188
+ }
189
+
99
190
  module.exports = {
100
191
  isAvailable,
192
+ hasStableStoreSupport,
193
+ getStableBaseDir,
194
+ getStableStoreDir,
195
+ getStableStoreFilePath,
196
+ getLegacyPluginRoot,
197
+ getLegacyStoreDir,
198
+ getLegacyStoreFilePath,
101
199
  getStoreDir,
102
200
  getStoreFilePath,
103
201
  exists,
202
+ stableExists,
203
+ legacyExists,
104
204
  readRaw,
205
+ readStableRaw,
206
+ readLegacyRaw,
105
207
  writeRaw,
106
- };
208
+ writeStableRaw,
209
+ writeLegacyRaw,
210
+ };
@@ -24,22 +24,28 @@ function writeToPreferredBackend(payload) {
24
24
  return localStorageStore.writeRaw(payload);
25
25
  }
26
26
 
27
+ function migrateFrom(readRaw, writeRaw) {
28
+ const raw = readRaw();
29
+ if (!raw) return false;
30
+ const migrated = migrateStore(raw || emptyStore());
31
+ return !!writeRaw(migrated);
32
+ }
33
+
27
34
  function initMigrationIfNeeded() {
28
35
  if (initialized) return;
29
36
  initialized = true;
30
37
 
31
- // one-time migration: localStorage -> fileStore
32
38
  if (!fileStore.isAvailable()) return;
33
- if (fileStore.exists()) return;
34
39
 
35
- const oldRaw = localStorageStore.readRaw();
36
- if (!oldRaw) return;
37
-
38
- const migrated = migrateStore(oldRaw || emptyStore());
39
- const ok = fileStore.writeRaw(migrated);
40
- if (ok) {
41
- localStorageStore.clear();
40
+ if (fileStore.hasStableStoreSupport()) {
41
+ if (fileStore.stableExists()) return;
42
+ if (migrateFrom(() => fileStore.readLegacyRaw(), (payload) => fileStore.writeStableRaw(payload))) return;
43
+ migrateFrom(() => localStorageStore.readRaw(), (payload) => fileStore.writeStableRaw(payload));
44
+ return;
42
45
  }
46
+
47
+ if (fileStore.exists()) return;
48
+ migrateFrom(() => localStorageStore.readRaw(), (payload) => fileStore.writeRaw(payload));
43
49
  }
44
50
 
45
51
  function readStore() {
@@ -74,4 +80,4 @@ module.exports = {
74
80
  readStore,
75
81
  writeStore,
76
82
  getStorageInfo,
77
- };
83
+ };