poi-plugin-kai-planner 1.0.2 → 1.0.4
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 +4 -2
- package/package.json +1 -1
- package/src/storage/userPlans/fileStore.js +142 -38
- package/src/storage/userPlans/storeAdapter.js +16 -10
package/README.md
CHANGED
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
|
|
23
23
|
## 本地数据
|
|
24
24
|
|
|
25
|
-
-
|
|
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
|
@@ -15,60 +15,113 @@ function getNodeModule(name) {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
const
|
|
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 !!(
|
|
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
|
|
44
|
+
function getStableBaseDir() {
|
|
45
|
+
const envDir = getEnvValue("KAI_PLANNER_USER_DATA_DIR");
|
|
46
|
+
if (envDir) return envDir;
|
|
26
47
|
if (!isAvailable()) return null;
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
39
|
-
if (!dir) return null;
|
|
40
|
-
return path.join(dir, "plans.v1.json");
|
|
99
|
+
return getStableStoreFilePath() || getLegacyStoreFilePath();
|
|
41
100
|
}
|
|
42
101
|
|
|
43
|
-
function
|
|
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
|
-
|
|
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
|
|
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
|
|
115
|
+
return fsMod.existsSync(fp);
|
|
61
116
|
} catch {
|
|
62
117
|
return false;
|
|
63
118
|
}
|
|
64
119
|
}
|
|
65
120
|
|
|
66
|
-
function
|
|
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 =
|
|
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
|
|
80
|
-
if (!isAvailable()) return false;
|
|
81
|
-
if (!
|
|
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
|
-
|
|
89
|
-
|
|
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 (
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
+
};
|