@liujitcn/kratos-uni-app-core 0.0.18 → 0.0.20
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/vite.mjs +235 -68
- package/package.json +1 -1
- package/src/navigation-tree.d.mts +14 -0
- package/src/rpc/base/v1/config.ts +1 -1
- package/src/rpc/{common → base}/v1/enum.ts +21 -38
- package/src/rpc/base/v1/login.ts +1 -1
- package/src/stores/modules/setting.ts +1 -1
- package/src/utils/passwordCrypto.ts +1 -1
- package/src/vite.ts +266 -74
package/dist/vite.mjs
CHANGED
|
@@ -16,15 +16,16 @@ import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
|
16
16
|
import uniPlugin from "@dcloudio/vite-plugin-uni";
|
|
17
17
|
import { defineConfig, loadEnv } from "vite";
|
|
18
18
|
var sourceVersionCounter = 0;
|
|
19
|
+
var PAGE_ASSEMBLY_WAIT_TIMEOUT_MS = 3e4;
|
|
20
|
+
var PAGE_ASSEMBLY_POLL_INTERVAL_MS = 25;
|
|
19
21
|
function createKratosUniPlugin() {
|
|
22
|
+
recoverStalePageTransaction();
|
|
20
23
|
const createPlugin = typeof uniPlugin === "function" ? uniPlugin : uniPlugin.default;
|
|
21
24
|
return createPlugin();
|
|
22
25
|
}
|
|
23
26
|
function kratosApp(options) {
|
|
24
27
|
const sourceVersion = `${process.pid}-${Date.now()}-${++sourceVersionCounter}`;
|
|
25
28
|
const state = {
|
|
26
|
-
generatedFiles: [],
|
|
27
|
-
generatedStaticFiles: [],
|
|
28
29
|
cleaned: false,
|
|
29
30
|
persistent: false,
|
|
30
31
|
moduleRoots: /* @__PURE__ */ new Map()
|
|
@@ -36,20 +37,11 @@ function kratosApp(options) {
|
|
|
36
37
|
process.removeListener("exit", cleanup);
|
|
37
38
|
process.removeListener("SIGINT", handleSigint);
|
|
38
39
|
process.removeListener("SIGTERM", handleSigterm);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
removeEmptyParents(dirname(file), state.inputDir ?? "");
|
|
43
|
-
}
|
|
44
|
-
if (state.inputDir) {
|
|
45
|
-
removeGeneratedStaticFiles(state.generatedStaticFiles, resolve(state.inputDir, "static"));
|
|
46
|
-
}
|
|
47
|
-
if (state.pagesFile && state.originalPages !== void 0) {
|
|
40
|
+
if (state.transactionFile && state.leaseFile) {
|
|
41
|
+
releasePageAssembly(state.transactionFile, state.leaseFile);
|
|
42
|
+
} else if (state.pagesFile && state.originalPages !== void 0) {
|
|
48
43
|
writeFileSync(state.pagesFile, state.originalPages);
|
|
49
44
|
}
|
|
50
|
-
if (state.transactionFile && existsSync(state.transactionFile)) {
|
|
51
|
-
unlinkSync(state.transactionFile);
|
|
52
|
-
}
|
|
53
45
|
};
|
|
54
46
|
const handleSigint = () => {
|
|
55
47
|
cleanup();
|
|
@@ -129,11 +121,8 @@ function kratosApp(options) {
|
|
|
129
121
|
const inputDir = process.env.UNI_INPUT_DIR || resolve(process.cwd(), "src");
|
|
130
122
|
const pagesFile = resolve(inputDir, "pages.json");
|
|
131
123
|
const transactionFile = resolve(inputDir, "../.kratos-uni-app-pages-state.json");
|
|
132
|
-
recoverBuildTransaction(transactionFile, inputDir, pagesFile);
|
|
133
124
|
const hostRequire = createRequire(resolve(inputDir, "../package.json"));
|
|
134
125
|
const originalPages = readFileSync(pagesFile, "utf8");
|
|
135
|
-
const manifest = JSON.parse(originalPages);
|
|
136
|
-
manifest.pages ??= [];
|
|
137
126
|
const pageMap = /* @__PURE__ */ new Map();
|
|
138
127
|
const moduleRoots = options.modules.map((module) => {
|
|
139
128
|
const linkedRoot = resolve(inputDir, "../node_modules", ...module.name.split("/"));
|
|
@@ -154,48 +143,19 @@ function kratosApp(options) {
|
|
|
154
143
|
});
|
|
155
144
|
});
|
|
156
145
|
});
|
|
157
|
-
state.inputDir = inputDir;
|
|
158
146
|
state.pagesFile = pagesFile;
|
|
159
|
-
state.originalPages = originalPages;
|
|
160
147
|
state.transactionFile = transactionFile;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
moduleRoots.map(({ root }) => resolve(root, "src/static")),
|
|
165
|
-
staticTarget
|
|
166
|
-
);
|
|
167
|
-
state.generatedStaticFiles = staticFiles.map(({ target }) => target);
|
|
168
|
-
writeFileSync(
|
|
148
|
+
const pageAssembly = preparePageAssembly({
|
|
149
|
+
inputDir,
|
|
150
|
+
pagesFile,
|
|
169
151
|
transactionFile,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
originalPages,
|
|
175
|
-
generatedFiles: state.generatedFiles,
|
|
176
|
-
generatedStaticFiles: state.generatedStaticFiles,
|
|
177
|
-
ownerPid: process.pid
|
|
178
|
-
},
|
|
179
|
-
null,
|
|
180
|
-
2
|
|
181
|
-
)}
|
|
182
|
-
`,
|
|
183
|
-
{ flag: "wx" }
|
|
184
|
-
);
|
|
185
|
-
pageMap.forEach((page) => {
|
|
186
|
-
const target = resolve(inputDir, `${page.route}.vue`);
|
|
187
|
-
if (existsSync(target))
|
|
188
|
-
return;
|
|
189
|
-
mkdirSync(dirname(target), { recursive: true });
|
|
190
|
-
writeFileSync(target, createPageWrapper(page));
|
|
191
|
-
appendPage(manifest, page);
|
|
192
|
-
});
|
|
193
|
-
staticFiles.forEach(({ source, target }) => {
|
|
194
|
-
mkdirSync(dirname(target), { recursive: true });
|
|
195
|
-
copyFileSync(source, target);
|
|
152
|
+
originalPages,
|
|
153
|
+
moduleRoots,
|
|
154
|
+
pageMap: [...pageMap.values()],
|
|
155
|
+
sourceVersion
|
|
196
156
|
});
|
|
197
|
-
|
|
198
|
-
|
|
157
|
+
state.originalPages = pageAssembly.transaction.originalPages;
|
|
158
|
+
state.leaseFile = pageAssembly.leaseFile;
|
|
199
159
|
process.once("exit", cleanup);
|
|
200
160
|
process.prependOnceListener("SIGINT", handleSigint);
|
|
201
161
|
process.prependOnceListener("SIGTERM", handleSigterm);
|
|
@@ -233,29 +193,233 @@ function kratosApp(options) {
|
|
|
233
193
|
closeWatcher: cleanup
|
|
234
194
|
};
|
|
235
195
|
}
|
|
236
|
-
function
|
|
196
|
+
function preparePageAssembly(options) {
|
|
197
|
+
const lockFile = `${options.transactionFile}.lock`;
|
|
198
|
+
acquirePageAssemblyLock(lockFile);
|
|
199
|
+
try {
|
|
200
|
+
let transaction = readBuildTransaction(
|
|
201
|
+
options.transactionFile,
|
|
202
|
+
options.inputDir,
|
|
203
|
+
options.pagesFile
|
|
204
|
+
);
|
|
205
|
+
if (transaction && isPageAssemblyActive(transaction)) {
|
|
206
|
+
return {
|
|
207
|
+
transaction,
|
|
208
|
+
leaseFile: createPageAssemblyLease(options.transactionFile, options.sourceVersion)
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
let originalPages = options.originalPages;
|
|
212
|
+
if (transaction) {
|
|
213
|
+
originalPages = transaction.originalPages;
|
|
214
|
+
restoreBuildTransaction(transaction, options.transactionFile);
|
|
215
|
+
}
|
|
216
|
+
const manifest = JSON.parse(originalPages);
|
|
217
|
+
manifest.pages ??= [];
|
|
218
|
+
const generatedFiles = options.pageMap.map((page) => resolve(options.inputDir, `${page.route}.vue`)).filter((target) => !existsSync(target));
|
|
219
|
+
const staticTarget = resolve(options.inputDir, "static");
|
|
220
|
+
const staticFiles = collectModuleStaticFiles(
|
|
221
|
+
options.moduleRoots.map(({ root }) => resolve(root, "src/static")),
|
|
222
|
+
staticTarget
|
|
223
|
+
);
|
|
224
|
+
const generatedStaticFiles = staticFiles.map(({ target }) => target);
|
|
225
|
+
transaction = {
|
|
226
|
+
inputDir: options.inputDir,
|
|
227
|
+
pagesFile: options.pagesFile,
|
|
228
|
+
originalPages,
|
|
229
|
+
generatedFiles,
|
|
230
|
+
generatedStaticFiles,
|
|
231
|
+
ownerPid: process.pid,
|
|
232
|
+
ready: false
|
|
233
|
+
};
|
|
234
|
+
writeBuildTransaction(options.transactionFile, transaction, "wx");
|
|
235
|
+
const leaseFile = createPageAssemblyLease(options.transactionFile, options.sourceVersion);
|
|
236
|
+
try {
|
|
237
|
+
options.pageMap.forEach((page) => {
|
|
238
|
+
const target = resolve(options.inputDir, `${page.route}.vue`);
|
|
239
|
+
if (existsSync(target))
|
|
240
|
+
return;
|
|
241
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
242
|
+
writeFileSync(target, createPageWrapper(page));
|
|
243
|
+
appendPage(manifest, page);
|
|
244
|
+
});
|
|
245
|
+
staticFiles.forEach(({ source, target }) => {
|
|
246
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
247
|
+
copyFileSync(source, target);
|
|
248
|
+
});
|
|
249
|
+
writeFileSync(options.pagesFile, `${JSON.stringify(manifest, null, 2)}
|
|
250
|
+
`);
|
|
251
|
+
transaction.ready = true;
|
|
252
|
+
writeBuildTransaction(options.transactionFile, transaction);
|
|
253
|
+
return { transaction, leaseFile };
|
|
254
|
+
} catch (error) {
|
|
255
|
+
releasePageAssemblyLease(leaseFile);
|
|
256
|
+
restoreBuildTransaction(transaction, options.transactionFile);
|
|
257
|
+
throw error;
|
|
258
|
+
}
|
|
259
|
+
} finally {
|
|
260
|
+
releasePageAssemblyLock(lockFile);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function readBuildTransaction(transactionFile, inputDir, pagesFile) {
|
|
237
264
|
if (!existsSync(transactionFile))
|
|
238
265
|
return;
|
|
239
266
|
const transaction = JSON.parse(readFileSync(transactionFile, "utf8"));
|
|
240
267
|
if (transaction.inputDir !== inputDir || transaction.pagesFile !== pagesFile) {
|
|
241
268
|
throw new Error(`uni-app \u6784\u5EFA\u4E8B\u52A1\u76EE\u5F55\u4E0D\u5339\u914D\uFF1A${transactionFile}`);
|
|
242
269
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
270
|
+
return transaction;
|
|
271
|
+
}
|
|
272
|
+
function writeBuildTransaction(transactionFile, transaction, flag) {
|
|
273
|
+
writeFileSync(
|
|
274
|
+
transactionFile,
|
|
275
|
+
`${JSON.stringify(transaction, null, 2)}
|
|
276
|
+
`,
|
|
277
|
+
flag ? { flag } : void 0
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
function restoreBuildTransaction(transaction, transactionFile) {
|
|
248
281
|
for (const file of [...transaction.generatedFiles].reverse()) {
|
|
249
282
|
if (existsSync(file))
|
|
250
283
|
unlinkSync(file);
|
|
251
|
-
removeEmptyParents(dirname(file), inputDir);
|
|
284
|
+
removeEmptyParents(dirname(file), transaction.inputDir);
|
|
252
285
|
}
|
|
253
|
-
removeGeneratedStaticFiles(
|
|
286
|
+
removeGeneratedStaticFiles(
|
|
287
|
+
transaction.generatedStaticFiles ?? [],
|
|
288
|
+
resolve(transaction.inputDir, "static")
|
|
289
|
+
);
|
|
254
290
|
if (transaction.generatedStatic && transaction.generatedStaticFiles === void 0) {
|
|
255
|
-
rmSync(resolve(inputDir, "static"), { recursive: true, force: true });
|
|
291
|
+
rmSync(resolve(transaction.inputDir, "static"), { recursive: true, force: true });
|
|
292
|
+
}
|
|
293
|
+
writeFileSync(transaction.pagesFile, transaction.originalPages);
|
|
294
|
+
if (existsSync(transactionFile))
|
|
295
|
+
unlinkSync(transactionFile);
|
|
296
|
+
}
|
|
297
|
+
function releasePageAssembly(transactionFile, leaseFile) {
|
|
298
|
+
releasePageAssemblyLease(leaseFile);
|
|
299
|
+
const lockFile = `${transactionFile}.lock`;
|
|
300
|
+
acquirePageAssemblyLock(lockFile);
|
|
301
|
+
try {
|
|
302
|
+
if (!existsSync(transactionFile))
|
|
303
|
+
return;
|
|
304
|
+
const transaction = JSON.parse(readFileSync(transactionFile, "utf8"));
|
|
305
|
+
const current = readBuildTransaction(
|
|
306
|
+
transactionFile,
|
|
307
|
+
transaction.inputDir,
|
|
308
|
+
transaction.pagesFile
|
|
309
|
+
);
|
|
310
|
+
if (!current || isPageAssemblyActive(current))
|
|
311
|
+
return;
|
|
312
|
+
restoreBuildTransaction(current, transactionFile);
|
|
313
|
+
} finally {
|
|
314
|
+
releasePageAssemblyLock(lockFile);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function createPageAssemblyLease(transactionFile, sourceVersion) {
|
|
318
|
+
const leaseDirectory = `${transactionFile}.leases`;
|
|
319
|
+
mkdirSync(leaseDirectory, { recursive: true });
|
|
320
|
+
const leaseFile = resolve(leaseDirectory, `${process.pid}-${sourceVersion}.lease`);
|
|
321
|
+
writeFileSync(leaseFile, `${JSON.stringify({ ownerPid: process.pid })}
|
|
322
|
+
`, { flag: "wx" });
|
|
323
|
+
return leaseFile;
|
|
324
|
+
}
|
|
325
|
+
function releasePageAssemblyLease(leaseFile) {
|
|
326
|
+
if (existsSync(leaseFile))
|
|
327
|
+
unlinkSync(leaseFile);
|
|
328
|
+
const leaseDirectory = dirname(leaseFile);
|
|
329
|
+
if (existsSync(leaseDirectory) && !readdirSync(leaseDirectory).length) {
|
|
330
|
+
try {
|
|
331
|
+
rmdirSync(leaseDirectory);
|
|
332
|
+
} catch (error) {
|
|
333
|
+
const code = error.code;
|
|
334
|
+
if (code !== "ENOTEMPTY" && code !== "EEXIST")
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function isPageAssemblyActive(transaction) {
|
|
340
|
+
const leaseDirectory = resolve(
|
|
341
|
+
dirname(transaction.pagesFile),
|
|
342
|
+
"../.kratos-uni-app-pages-state.json.leases"
|
|
343
|
+
);
|
|
344
|
+
if (listActivePageLeases(leaseDirectory).length)
|
|
345
|
+
return true;
|
|
346
|
+
return transaction.ownerPid !== void 0 && transaction.ownerPid !== process.pid && isProcessRunning(transaction.ownerPid);
|
|
347
|
+
}
|
|
348
|
+
function listActivePageLeases(leaseDirectory) {
|
|
349
|
+
if (!existsSync(leaseDirectory))
|
|
350
|
+
return [];
|
|
351
|
+
const activePids = [];
|
|
352
|
+
for (const entry of readdirSync(leaseDirectory)) {
|
|
353
|
+
const leaseFile = resolve(leaseDirectory, entry);
|
|
354
|
+
try {
|
|
355
|
+
const lease = JSON.parse(readFileSync(leaseFile, "utf8"));
|
|
356
|
+
if (lease.ownerPid && isProcessRunning(lease.ownerPid)) {
|
|
357
|
+
activePids.push(lease.ownerPid);
|
|
358
|
+
} else {
|
|
359
|
+
unlinkSync(leaseFile);
|
|
360
|
+
}
|
|
361
|
+
} catch {
|
|
362
|
+
unlinkSync(leaseFile);
|
|
363
|
+
}
|
|
256
364
|
}
|
|
257
|
-
|
|
258
|
-
|
|
365
|
+
return activePids;
|
|
366
|
+
}
|
|
367
|
+
function acquirePageAssemblyLock(lockFile) {
|
|
368
|
+
const deadline = Date.now() + PAGE_ASSEMBLY_WAIT_TIMEOUT_MS;
|
|
369
|
+
while (true) {
|
|
370
|
+
try {
|
|
371
|
+
writeFileSync(lockFile, `${JSON.stringify({ ownerPid: process.pid })}
|
|
372
|
+
`, { flag: "wx" });
|
|
373
|
+
return;
|
|
374
|
+
} catch (error) {
|
|
375
|
+
if (error.code !== "EEXIST")
|
|
376
|
+
throw error;
|
|
377
|
+
const ownerPid = readPageAssemblyLockOwner(lockFile);
|
|
378
|
+
if (ownerPid !== void 0 && !isProcessRunning(ownerPid)) {
|
|
379
|
+
unlinkSync(lockFile);
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (Date.now() >= deadline) {
|
|
383
|
+
throw new Error(`\u7B49\u5F85 uni-app \u9875\u9762\u88C5\u914D\u9501\u8D85\u65F6\uFF1A${lockFile}`);
|
|
384
|
+
}
|
|
385
|
+
waitForPageAssembly(PAGE_ASSEMBLY_POLL_INTERVAL_MS);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function releasePageAssemblyLock(lockFile) {
|
|
390
|
+
if (!existsSync(lockFile))
|
|
391
|
+
return;
|
|
392
|
+
if (readPageAssemblyLockOwner(lockFile) === process.pid)
|
|
393
|
+
unlinkSync(lockFile);
|
|
394
|
+
}
|
|
395
|
+
function readPageAssemblyLockOwner(lockFile) {
|
|
396
|
+
try {
|
|
397
|
+
return JSON.parse(readFileSync(lockFile, "utf8")).ownerPid;
|
|
398
|
+
} catch {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function waitForPageAssembly(milliseconds) {
|
|
403
|
+
const buffer = new SharedArrayBuffer(4);
|
|
404
|
+
Atomics.wait(new Int32Array(buffer), 0, 0, milliseconds);
|
|
405
|
+
}
|
|
406
|
+
function recoverStalePageTransaction() {
|
|
407
|
+
const inputDir = process.env.UNI_INPUT_DIR || resolve(process.cwd(), "src");
|
|
408
|
+
const transactionFile = resolve(inputDir, "../.kratos-uni-app-pages-state.json");
|
|
409
|
+
const pagesFile = resolve(inputDir, "pages.json");
|
|
410
|
+
const lockFile = `${transactionFile}.lock`;
|
|
411
|
+
acquirePageAssemblyLock(lockFile);
|
|
412
|
+
try {
|
|
413
|
+
recoverBuildTransaction(transactionFile, inputDir, pagesFile);
|
|
414
|
+
} finally {
|
|
415
|
+
releasePageAssemblyLock(lockFile);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
function recoverBuildTransaction(transactionFile, inputDir, pagesFile) {
|
|
419
|
+
const transaction = readBuildTransaction(transactionFile, inputDir, pagesFile);
|
|
420
|
+
if (!transaction || isPageAssemblyActive(transaction))
|
|
421
|
+
return;
|
|
422
|
+
restoreBuildTransaction(transaction, transactionFile);
|
|
259
423
|
}
|
|
260
424
|
function isProcessRunning(pid) {
|
|
261
425
|
try {
|
|
@@ -337,14 +501,16 @@ function appendPage(manifest, page) {
|
|
|
337
501
|
function createPageWrapper(page) {
|
|
338
502
|
const source = page.source.replace(/\\/g, "/");
|
|
339
503
|
return `<script setup lang="ts">
|
|
504
|
+
import type { Component } from 'vue'
|
|
340
505
|
import KratosPage from ${JSON.stringify(source)}
|
|
341
506
|
import KratosTabBar from '@liujitcn/kratos-uni-app-core/components/KratosTabBar.vue'
|
|
342
507
|
|
|
343
508
|
defineOptions({ inheritAttrs: false })
|
|
509
|
+
const Page = KratosPage as Component
|
|
344
510
|
</script>
|
|
345
511
|
|
|
346
512
|
<template>
|
|
347
|
-
<
|
|
513
|
+
<Page v-bind="$attrs" />
|
|
348
514
|
<KratosTabBar route=${JSON.stringify(page.route)} />
|
|
349
515
|
</template>
|
|
350
516
|
`;
|
|
@@ -401,5 +567,6 @@ export {
|
|
|
401
567
|
createKratosUniPlugin,
|
|
402
568
|
defineConfig,
|
|
403
569
|
kratosApp,
|
|
404
|
-
loadEnv
|
|
570
|
+
loadEnv,
|
|
571
|
+
recoverStalePageTransaction
|
|
405
572
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface MenuNode<T extends { id: number; parentId?: number }> extends T {
|
|
2
|
+
children: MenuNode<T>[]
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function buildMenuTree<T extends { id: number; parentId?: number }>(
|
|
6
|
+
menus: readonly T[],
|
|
7
|
+
rootId: number,
|
|
8
|
+
): MenuNode<T>[]
|
|
9
|
+
|
|
10
|
+
export function resolveRootMenuId(
|
|
11
|
+
menus: readonly { id: number; parentId?: number }[],
|
|
12
|
+
menuId: number,
|
|
13
|
+
rootId: number,
|
|
14
|
+
): number | undefined
|
|
@@ -2,17 +2,30 @@
|
|
|
2
2
|
// versions:
|
|
3
3
|
// protoc-gen-ts_proto v2.11.8
|
|
4
4
|
// protoc unknown
|
|
5
|
-
// source:
|
|
5
|
+
// source: base/v1/enum.proto
|
|
6
6
|
|
|
7
7
|
/* eslint-disable */
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
export enum
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
/** AI 助手消息状态 */
|
|
10
|
+
export enum AiMessageStatus {
|
|
11
|
+
/** UNKNOWN_AMS - 未知AI助手消息状态 */
|
|
12
|
+
UNKNOWN_AMS = 0,
|
|
13
|
+
/** GENERATING_AMS - 生成中 */
|
|
14
|
+
GENERATING_AMS = 1,
|
|
15
|
+
/** SUCCESS_AMS - 成功 */
|
|
16
|
+
SUCCESS_AMS = 2,
|
|
17
|
+
/** FAILED_AMS - 失败 */
|
|
18
|
+
FAILED_AMS = 3,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** 终端类型 */
|
|
22
|
+
export enum Terminal {
|
|
23
|
+
/** UNKNOWN_TERMINAL - 未知终端 */
|
|
24
|
+
UNKNOWN_TERMINAL = 0,
|
|
25
|
+
/** TERMINAL_APP - 移动端 */
|
|
26
|
+
TERMINAL_APP = 1,
|
|
27
|
+
/** TERMINAL_ADMIN - 管理端 */
|
|
28
|
+
TERMINAL_ADMIN = 2,
|
|
16
29
|
}
|
|
17
30
|
|
|
18
31
|
/** 系统配置位置 */
|
|
@@ -39,33 +52,3 @@ export enum PasswordCryptoScene {
|
|
|
39
52
|
/** UPDATE_USER_PASSWORD - 个人修改密码加密场景 */
|
|
40
53
|
UPDATE_USER_PASSWORD = 4,
|
|
41
54
|
}
|
|
42
|
-
|
|
43
|
-
/** AI 助手消息状态 */
|
|
44
|
-
export enum AiMessageStatus {
|
|
45
|
-
/** UNKNOWN_AAMS - 未知AI助手消息状态 */
|
|
46
|
-
UNKNOWN_AAMS = 0,
|
|
47
|
-
/** GENERATING_AAMS - 生成中 */
|
|
48
|
-
GENERATING_AAMS = 1,
|
|
49
|
-
/** SUCCESS_AAMS - 成功 */
|
|
50
|
-
SUCCESS_AAMS = 2,
|
|
51
|
-
/** FAILED_AAMS - 失败 */
|
|
52
|
-
FAILED_AAMS = 3,
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** 支付通知资源类型 */
|
|
56
|
-
export enum ResourceType {
|
|
57
|
-
/** TRANSACTION - 支付 */
|
|
58
|
-
TRANSACTION = 0,
|
|
59
|
-
/** REFUND - 退款 */
|
|
60
|
-
REFUND = 1,
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** 终端类型 */
|
|
64
|
-
export enum Terminal {
|
|
65
|
-
/** TERMINAL_UNSPECIFIED - 未知终端 */
|
|
66
|
-
TERMINAL_UNSPECIFIED = 0,
|
|
67
|
-
/** TERMINAL_APP - 移动端 */
|
|
68
|
-
TERMINAL_APP = 1,
|
|
69
|
-
/** TERMINAL_ADMIN - 管理端 */
|
|
70
|
-
TERMINAL_ADMIN = 2,
|
|
71
|
-
}
|
package/src/rpc/base/v1/login.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
// source: base/v1/login.proto
|
|
6
6
|
|
|
7
7
|
/* eslint-disable */
|
|
8
|
-
import type { PasswordCryptoScene } from "../../common/v1/enum";
|
|
9
8
|
import type { PasswordCrypto } from "../../common/v1/types";
|
|
10
9
|
import type { Empty } from "../../google/protobuf/empty";
|
|
10
|
+
import type { PasswordCryptoScene } from "./enum";
|
|
11
11
|
|
|
12
12
|
/** 验证码获取条件 */
|
|
13
13
|
export interface CaptchaRequest {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defConfigService } from '../../api/base/config'
|
|
2
2
|
import { defineStore } from 'pinia'
|
|
3
3
|
import { ref } from 'vue'
|
|
4
|
-
import { BaseConfigSite } from '../../rpc/
|
|
4
|
+
import { BaseConfigSite } from '../../rpc/base/v1/enum'
|
|
5
5
|
|
|
6
6
|
const REQUIRED_APP_CONFIGS = [
|
|
7
7
|
{ key: 'serviceProtocol', name: '服务条款' },
|
package/src/vite.ts
CHANGED
|
@@ -41,8 +41,17 @@ type BuildTransaction = {
|
|
|
41
41
|
generatedStaticFiles: string[]
|
|
42
42
|
generatedStatic?: boolean
|
|
43
43
|
ownerPid?: number
|
|
44
|
+
ready?: boolean
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
type PageAssembly = {
|
|
48
|
+
transaction: BuildTransaction
|
|
49
|
+
leaseFile: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const PAGE_ASSEMBLY_WAIT_TIMEOUT_MS = 30_000
|
|
53
|
+
const PAGE_ASSEMBLY_POLL_INTERVAL_MS = 25
|
|
54
|
+
|
|
46
55
|
/** uni-app Vite 插件参数。 */
|
|
47
56
|
export interface KratosAppViteOptions {
|
|
48
57
|
/** 宿主模块清单,顺序同时决定覆盖优先级。 */
|
|
@@ -51,6 +60,7 @@ export interface KratosAppViteOptions {
|
|
|
51
60
|
|
|
52
61
|
/** 创建 uni-app 官方 Vite 插件。 */
|
|
53
62
|
export function createKratosUniPlugin() {
|
|
63
|
+
recoverStalePageTransaction()
|
|
54
64
|
const createPlugin =
|
|
55
65
|
typeof uniPlugin === 'function'
|
|
56
66
|
? uniPlugin
|
|
@@ -62,18 +72,14 @@ export function createKratosUniPlugin() {
|
|
|
62
72
|
export function kratosApp(options: KratosAppViteOptions): Plugin {
|
|
63
73
|
const sourceVersion = `${process.pid}-${Date.now()}-${++sourceVersionCounter}`
|
|
64
74
|
const state: {
|
|
65
|
-
inputDir?: string
|
|
66
75
|
pagesFile?: string
|
|
67
76
|
originalPages?: string
|
|
68
|
-
generatedFiles: string[]
|
|
69
|
-
generatedStaticFiles: string[]
|
|
70
77
|
cleaned: boolean
|
|
71
78
|
persistent: boolean
|
|
72
79
|
transactionFile?: string
|
|
80
|
+
leaseFile?: string
|
|
73
81
|
moduleRoots: Map<string, string>
|
|
74
82
|
} = {
|
|
75
|
-
generatedFiles: [],
|
|
76
|
-
generatedStaticFiles: [],
|
|
77
83
|
cleaned: false,
|
|
78
84
|
persistent: false,
|
|
79
85
|
moduleRoots: new Map(),
|
|
@@ -85,19 +91,11 @@ export function kratosApp(options: KratosAppViteOptions): Plugin {
|
|
|
85
91
|
process.removeListener('exit', cleanup)
|
|
86
92
|
process.removeListener('SIGINT', handleSigint)
|
|
87
93
|
process.removeListener('SIGTERM', handleSigterm)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
if (state.inputDir) {
|
|
93
|
-
removeGeneratedStaticFiles(state.generatedStaticFiles, resolve(state.inputDir, 'static'))
|
|
94
|
-
}
|
|
95
|
-
if (state.pagesFile && state.originalPages !== undefined) {
|
|
94
|
+
if (state.transactionFile && state.leaseFile) {
|
|
95
|
+
releasePageAssembly(state.transactionFile, state.leaseFile)
|
|
96
|
+
} else if (state.pagesFile && state.originalPages !== undefined) {
|
|
96
97
|
writeFileSync(state.pagesFile, state.originalPages)
|
|
97
98
|
}
|
|
98
|
-
if (state.transactionFile && existsSync(state.transactionFile)) {
|
|
99
|
-
unlinkSync(state.transactionFile)
|
|
100
|
-
}
|
|
101
99
|
}
|
|
102
100
|
const handleSigint = () => {
|
|
103
101
|
cleanup()
|
|
@@ -184,11 +182,8 @@ export function kratosApp(options: KratosAppViteOptions): Plugin {
|
|
|
184
182
|
const inputDir = process.env.UNI_INPUT_DIR || resolve(process.cwd(), 'src')
|
|
185
183
|
const pagesFile = resolve(inputDir, 'pages.json')
|
|
186
184
|
const transactionFile = resolve(inputDir, '../.kratos-uni-app-pages-state.json')
|
|
187
|
-
recoverBuildTransaction(transactionFile, inputDir, pagesFile)
|
|
188
185
|
const hostRequire = createRequire(resolve(inputDir, '../package.json'))
|
|
189
186
|
const originalPages = readFileSync(pagesFile, 'utf8')
|
|
190
|
-
const manifest = JSON.parse(originalPages) as PagesManifest
|
|
191
|
-
manifest.pages ??= []
|
|
192
187
|
const pageMap = new Map<string, ScannedPage>()
|
|
193
188
|
const moduleRoots = options.modules.map((module) => {
|
|
194
189
|
const linkedRoot = resolve(inputDir, '../node_modules', ...module.name.split('/'))
|
|
@@ -213,48 +208,19 @@ export function kratosApp(options: KratosAppViteOptions): Plugin {
|
|
|
213
208
|
})
|
|
214
209
|
})
|
|
215
210
|
|
|
216
|
-
state.inputDir = inputDir
|
|
217
211
|
state.pagesFile = pagesFile
|
|
218
|
-
state.originalPages = originalPages
|
|
219
212
|
state.transactionFile = transactionFile
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const staticTarget = resolve(inputDir, 'static')
|
|
224
|
-
const staticFiles = collectModuleStaticFiles(
|
|
225
|
-
moduleRoots.map(({ root }) => resolve(root, 'src/static')),
|
|
226
|
-
staticTarget,
|
|
227
|
-
)
|
|
228
|
-
state.generatedStaticFiles = staticFiles.map(({ target }) => target)
|
|
229
|
-
writeFileSync(
|
|
213
|
+
const pageAssembly = preparePageAssembly({
|
|
214
|
+
inputDir,
|
|
215
|
+
pagesFile,
|
|
230
216
|
transactionFile,
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
originalPages,
|
|
236
|
-
generatedFiles: state.generatedFiles,
|
|
237
|
-
generatedStaticFiles: state.generatedStaticFiles,
|
|
238
|
-
ownerPid: process.pid,
|
|
239
|
-
} satisfies BuildTransaction,
|
|
240
|
-
null,
|
|
241
|
-
2,
|
|
242
|
-
)}\n`,
|
|
243
|
-
{ flag: 'wx' },
|
|
244
|
-
)
|
|
245
|
-
pageMap.forEach((page) => {
|
|
246
|
-
const target = resolve(inputDir, `${page.route}.vue`)
|
|
247
|
-
if (existsSync(target)) return
|
|
248
|
-
mkdirSync(dirname(target), { recursive: true })
|
|
249
|
-
writeFileSync(target, createPageWrapper(page))
|
|
250
|
-
appendPage(manifest, page)
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
staticFiles.forEach(({ source, target }) => {
|
|
254
|
-
mkdirSync(dirname(target), { recursive: true })
|
|
255
|
-
copyFileSync(source, target)
|
|
217
|
+
originalPages,
|
|
218
|
+
moduleRoots,
|
|
219
|
+
pageMap: [...pageMap.values()],
|
|
220
|
+
sourceVersion,
|
|
256
221
|
})
|
|
257
|
-
|
|
222
|
+
state.originalPages = pageAssembly.transaction.originalPages
|
|
223
|
+
state.leaseFile = pageAssembly.leaseFile
|
|
258
224
|
process.once('exit', cleanup)
|
|
259
225
|
process.prependOnceListener('SIGINT', handleSigint)
|
|
260
226
|
process.prependOnceListener('SIGTERM', handleSigterm)
|
|
@@ -292,36 +258,260 @@ export function kratosApp(options: KratosAppViteOptions): Plugin {
|
|
|
292
258
|
}
|
|
293
259
|
}
|
|
294
260
|
|
|
295
|
-
function
|
|
261
|
+
function preparePageAssembly(options: {
|
|
262
|
+
inputDir: string
|
|
263
|
+
pagesFile: string
|
|
264
|
+
transactionFile: string
|
|
265
|
+
originalPages: string
|
|
266
|
+
moduleRoots: Array<{ root: string }>
|
|
267
|
+
pageMap: ScannedPage[]
|
|
268
|
+
sourceVersion: string
|
|
269
|
+
}): PageAssembly {
|
|
270
|
+
const lockFile = `${options.transactionFile}.lock`
|
|
271
|
+
acquirePageAssemblyLock(lockFile)
|
|
272
|
+
try {
|
|
273
|
+
let transaction = readBuildTransaction(
|
|
274
|
+
options.transactionFile,
|
|
275
|
+
options.inputDir,
|
|
276
|
+
options.pagesFile,
|
|
277
|
+
)
|
|
278
|
+
if (transaction && isPageAssemblyActive(transaction)) {
|
|
279
|
+
return {
|
|
280
|
+
transaction,
|
|
281
|
+
leaseFile: createPageAssemblyLease(options.transactionFile, options.sourceVersion),
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
let originalPages = options.originalPages
|
|
286
|
+
if (transaction) {
|
|
287
|
+
originalPages = transaction.originalPages
|
|
288
|
+
restoreBuildTransaction(transaction, options.transactionFile)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const manifest = JSON.parse(originalPages) as PagesManifest
|
|
292
|
+
manifest.pages ??= []
|
|
293
|
+
const generatedFiles = options.pageMap
|
|
294
|
+
.map((page) => resolve(options.inputDir, `${page.route}.vue`))
|
|
295
|
+
.filter((target) => !existsSync(target))
|
|
296
|
+
const staticTarget = resolve(options.inputDir, 'static')
|
|
297
|
+
const staticFiles = collectModuleStaticFiles(
|
|
298
|
+
options.moduleRoots.map(({ root }) => resolve(root, 'src/static')),
|
|
299
|
+
staticTarget,
|
|
300
|
+
)
|
|
301
|
+
const generatedStaticFiles = staticFiles.map(({ target }) => target)
|
|
302
|
+
transaction = {
|
|
303
|
+
inputDir: options.inputDir,
|
|
304
|
+
pagesFile: options.pagesFile,
|
|
305
|
+
originalPages,
|
|
306
|
+
generatedFiles,
|
|
307
|
+
generatedStaticFiles,
|
|
308
|
+
ownerPid: process.pid,
|
|
309
|
+
ready: false,
|
|
310
|
+
}
|
|
311
|
+
writeBuildTransaction(options.transactionFile, transaction, 'wx')
|
|
312
|
+
const leaseFile = createPageAssemblyLease(options.transactionFile, options.sourceVersion)
|
|
313
|
+
try {
|
|
314
|
+
options.pageMap.forEach((page) => {
|
|
315
|
+
const target = resolve(options.inputDir, `${page.route}.vue`)
|
|
316
|
+
if (existsSync(target)) return
|
|
317
|
+
mkdirSync(dirname(target), { recursive: true })
|
|
318
|
+
writeFileSync(target, createPageWrapper(page))
|
|
319
|
+
appendPage(manifest, page)
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
staticFiles.forEach(({ source, target }) => {
|
|
323
|
+
mkdirSync(dirname(target), { recursive: true })
|
|
324
|
+
copyFileSync(source, target)
|
|
325
|
+
})
|
|
326
|
+
writeFileSync(options.pagesFile, `${JSON.stringify(manifest, null, 2)}\n`)
|
|
327
|
+
transaction.ready = true
|
|
328
|
+
writeBuildTransaction(options.transactionFile, transaction)
|
|
329
|
+
return { transaction, leaseFile }
|
|
330
|
+
} catch (error) {
|
|
331
|
+
releasePageAssemblyLease(leaseFile)
|
|
332
|
+
restoreBuildTransaction(transaction, options.transactionFile)
|
|
333
|
+
throw error
|
|
334
|
+
}
|
|
335
|
+
} finally {
|
|
336
|
+
releasePageAssemblyLock(lockFile)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function readBuildTransaction(
|
|
296
341
|
transactionFile: string,
|
|
297
342
|
inputDir: string,
|
|
298
343
|
pagesFile: string,
|
|
299
|
-
):
|
|
344
|
+
): BuildTransaction | undefined {
|
|
300
345
|
if (!existsSync(transactionFile)) return
|
|
301
346
|
const transaction = JSON.parse(readFileSync(transactionFile, 'utf8')) as BuildTransaction
|
|
302
347
|
if (transaction.inputDir !== inputDir || transaction.pagesFile !== pagesFile) {
|
|
303
348
|
throw new Error(`uni-app 构建事务目录不匹配:${transactionFile}`)
|
|
304
349
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
350
|
+
return transaction
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function writeBuildTransaction(
|
|
354
|
+
transactionFile: string,
|
|
355
|
+
transaction: BuildTransaction,
|
|
356
|
+
flag?: 'wx',
|
|
357
|
+
): void {
|
|
358
|
+
writeFileSync(
|
|
359
|
+
transactionFile,
|
|
360
|
+
`${JSON.stringify(transaction, null, 2)}\n`,
|
|
361
|
+
flag ? { flag } : undefined,
|
|
362
|
+
)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function restoreBuildTransaction(transaction: BuildTransaction, transactionFile: string): void {
|
|
314
366
|
for (const file of [...transaction.generatedFiles].reverse()) {
|
|
315
367
|
if (existsSync(file)) unlinkSync(file)
|
|
316
|
-
removeEmptyParents(dirname(file), inputDir)
|
|
368
|
+
removeEmptyParents(dirname(file), transaction.inputDir)
|
|
317
369
|
}
|
|
318
|
-
removeGeneratedStaticFiles(
|
|
370
|
+
removeGeneratedStaticFiles(
|
|
371
|
+
transaction.generatedStaticFiles ?? [],
|
|
372
|
+
resolve(transaction.inputDir, 'static'),
|
|
373
|
+
)
|
|
319
374
|
// 兼容旧事务:旧格式仅在 static 原本不存在时记录整个目录由插件生成。
|
|
320
375
|
if (transaction.generatedStatic && transaction.generatedStaticFiles === undefined) {
|
|
321
|
-
rmSync(resolve(inputDir, 'static'), { recursive: true, force: true })
|
|
376
|
+
rmSync(resolve(transaction.inputDir, 'static'), { recursive: true, force: true })
|
|
377
|
+
}
|
|
378
|
+
writeFileSync(transaction.pagesFile, transaction.originalPages)
|
|
379
|
+
if (existsSync(transactionFile)) unlinkSync(transactionFile)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function releasePageAssembly(transactionFile: string, leaseFile: string): void {
|
|
383
|
+
releasePageAssemblyLease(leaseFile)
|
|
384
|
+
const lockFile = `${transactionFile}.lock`
|
|
385
|
+
acquirePageAssemblyLock(lockFile)
|
|
386
|
+
try {
|
|
387
|
+
if (!existsSync(transactionFile)) return
|
|
388
|
+
const transaction = JSON.parse(readFileSync(transactionFile, 'utf8')) as BuildTransaction
|
|
389
|
+
const current = readBuildTransaction(
|
|
390
|
+
transactionFile,
|
|
391
|
+
transaction.inputDir,
|
|
392
|
+
transaction.pagesFile,
|
|
393
|
+
)
|
|
394
|
+
if (!current || isPageAssemblyActive(current)) return
|
|
395
|
+
restoreBuildTransaction(current, transactionFile)
|
|
396
|
+
} finally {
|
|
397
|
+
releasePageAssemblyLock(lockFile)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function createPageAssemblyLease(transactionFile: string, sourceVersion: string): string {
|
|
402
|
+
const leaseDirectory = `${transactionFile}.leases`
|
|
403
|
+
mkdirSync(leaseDirectory, { recursive: true })
|
|
404
|
+
const leaseFile = resolve(leaseDirectory, `${process.pid}-${sourceVersion}.lease`)
|
|
405
|
+
writeFileSync(leaseFile, `${JSON.stringify({ ownerPid: process.pid })}\n`, { flag: 'wx' })
|
|
406
|
+
return leaseFile
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function releasePageAssemblyLease(leaseFile: string): void {
|
|
410
|
+
if (existsSync(leaseFile)) unlinkSync(leaseFile)
|
|
411
|
+
const leaseDirectory = dirname(leaseFile)
|
|
412
|
+
if (existsSync(leaseDirectory) && !readdirSync(leaseDirectory).length) {
|
|
413
|
+
try {
|
|
414
|
+
rmdirSync(leaseDirectory)
|
|
415
|
+
} catch (error) {
|
|
416
|
+
const code = (error as NodeJS.ErrnoException).code
|
|
417
|
+
if (code !== 'ENOTEMPTY' && code !== 'EEXIST') throw error
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function isPageAssemblyActive(transaction: BuildTransaction): boolean {
|
|
423
|
+
const leaseDirectory = resolve(
|
|
424
|
+
dirname(transaction.pagesFile),
|
|
425
|
+
'../.kratos-uni-app-pages-state.json.leases',
|
|
426
|
+
)
|
|
427
|
+
if (listActivePageLeases(leaseDirectory).length) return true
|
|
428
|
+
return (
|
|
429
|
+
transaction.ownerPid !== undefined &&
|
|
430
|
+
transaction.ownerPid !== process.pid &&
|
|
431
|
+
isProcessRunning(transaction.ownerPid)
|
|
432
|
+
)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function listActivePageLeases(leaseDirectory: string): number[] {
|
|
436
|
+
if (!existsSync(leaseDirectory)) return []
|
|
437
|
+
const activePids: number[] = []
|
|
438
|
+
for (const entry of readdirSync(leaseDirectory)) {
|
|
439
|
+
const leaseFile = resolve(leaseDirectory, entry)
|
|
440
|
+
try {
|
|
441
|
+
const lease = JSON.parse(readFileSync(leaseFile, 'utf8')) as { ownerPid?: number }
|
|
442
|
+
if (lease.ownerPid && isProcessRunning(lease.ownerPid)) {
|
|
443
|
+
activePids.push(lease.ownerPid)
|
|
444
|
+
} else {
|
|
445
|
+
unlinkSync(leaseFile)
|
|
446
|
+
}
|
|
447
|
+
} catch {
|
|
448
|
+
unlinkSync(leaseFile)
|
|
449
|
+
}
|
|
322
450
|
}
|
|
323
|
-
|
|
324
|
-
|
|
451
|
+
return activePids
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function acquirePageAssemblyLock(lockFile: string): void {
|
|
455
|
+
const deadline = Date.now() + PAGE_ASSEMBLY_WAIT_TIMEOUT_MS
|
|
456
|
+
while (true) {
|
|
457
|
+
try {
|
|
458
|
+
writeFileSync(lockFile, `${JSON.stringify({ ownerPid: process.pid })}\n`, { flag: 'wx' })
|
|
459
|
+
return
|
|
460
|
+
} catch (error) {
|
|
461
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error
|
|
462
|
+
const ownerPid = readPageAssemblyLockOwner(lockFile)
|
|
463
|
+
if (ownerPid !== undefined && !isProcessRunning(ownerPid)) {
|
|
464
|
+
unlinkSync(lockFile)
|
|
465
|
+
continue
|
|
466
|
+
}
|
|
467
|
+
if (Date.now() >= deadline) {
|
|
468
|
+
throw new Error(`等待 uni-app 页面装配锁超时:${lockFile}`)
|
|
469
|
+
}
|
|
470
|
+
waitForPageAssembly(PAGE_ASSEMBLY_POLL_INTERVAL_MS)
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function releasePageAssemblyLock(lockFile: string): void {
|
|
476
|
+
if (!existsSync(lockFile)) return
|
|
477
|
+
if (readPageAssemblyLockOwner(lockFile) === process.pid) unlinkSync(lockFile)
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function readPageAssemblyLockOwner(lockFile: string): number | undefined {
|
|
481
|
+
try {
|
|
482
|
+
return (JSON.parse(readFileSync(lockFile, 'utf8')) as { ownerPid?: number }).ownerPid
|
|
483
|
+
} catch {
|
|
484
|
+
return
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function waitForPageAssembly(milliseconds: number): void {
|
|
489
|
+
const buffer = new SharedArrayBuffer(4)
|
|
490
|
+
Atomics.wait(new Int32Array(buffer), 0, 0, milliseconds)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// recoverStalePageTransaction 在官方 uni 插件创建前恢复页面事务,避免官方插件先读取到空 pages.json。
|
|
494
|
+
export function recoverStalePageTransaction(): void {
|
|
495
|
+
const inputDir = process.env.UNI_INPUT_DIR || resolve(process.cwd(), 'src')
|
|
496
|
+
const transactionFile = resolve(inputDir, '../.kratos-uni-app-pages-state.json')
|
|
497
|
+
const pagesFile = resolve(inputDir, 'pages.json')
|
|
498
|
+
const lockFile = `${transactionFile}.lock`
|
|
499
|
+
acquirePageAssemblyLock(lockFile)
|
|
500
|
+
try {
|
|
501
|
+
recoverBuildTransaction(transactionFile, inputDir, pagesFile)
|
|
502
|
+
} finally {
|
|
503
|
+
releasePageAssemblyLock(lockFile)
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function recoverBuildTransaction(
|
|
508
|
+
transactionFile: string,
|
|
509
|
+
inputDir: string,
|
|
510
|
+
pagesFile: string,
|
|
511
|
+
): void {
|
|
512
|
+
const transaction = readBuildTransaction(transactionFile, inputDir, pagesFile)
|
|
513
|
+
if (!transaction || isPageAssemblyActive(transaction)) return
|
|
514
|
+
restoreBuildTransaction(transaction, transactionFile)
|
|
325
515
|
}
|
|
326
516
|
|
|
327
517
|
// isProcessRunning 判断页面事务的所属进程是否仍然存活。
|
|
@@ -407,14 +597,16 @@ function appendPage(manifest: PagesManifest, page: ScannedPage): void {
|
|
|
407
597
|
function createPageWrapper(page: ScannedPage): string {
|
|
408
598
|
const source = page.source.replace(/\\/g, '/')
|
|
409
599
|
return `<script setup lang="ts">
|
|
600
|
+
import type { Component } from 'vue'
|
|
410
601
|
import KratosPage from ${JSON.stringify(source)}
|
|
411
602
|
import KratosTabBar from '@liujitcn/kratos-uni-app-core/components/KratosTabBar.vue'
|
|
412
603
|
|
|
413
604
|
defineOptions({ inheritAttrs: false })
|
|
605
|
+
const Page = KratosPage as Component
|
|
414
606
|
</script>
|
|
415
607
|
|
|
416
608
|
<template>
|
|
417
|
-
<
|
|
609
|
+
<Page v-bind="$attrs" />
|
|
418
610
|
<KratosTabBar route=${JSON.stringify(page.route)} />
|
|
419
611
|
</template>
|
|
420
612
|
`
|