@adep/cli 0.4.4 → 0.4.6
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 +107 -11
- package/dist/index.js +33802 -27354
- package/dist/vite.js +247 -17
- package/dist/worker-entry.js +163 -1
- package/package.json +7 -6
- package/templates/app-desktop/README.md +67 -2
- package/templates/app-desktop/identity-store.mjs +309 -0
- package/templates/app-desktop/identity.mjs +517 -0
- package/templates/app-desktop/main.cjs +17 -0
- package/templates/app-desktop/main.mjs +218 -2
- package/templates/app-desktop/offline-runtime.mjs +72 -3
- package/templates/app-desktop/package.json +10 -6
- package/templates/app-desktop/recovery-ui.mjs +300 -0
- package/templates/app-desktop/sync-loop.mjs +137 -0
- package/templates/app-mobile/README.md +47 -9
- package/templates/app-mobile/package.json +2 -1
- package/templates/app-mobile/plugins/adep-bridge/Package.swift +5 -1
- package/templates/app-mobile/plugins/adep-bridge/android/build.gradle +34 -3
- package/templates/app-mobile/plugins/adep-bridge/android/src/main/AndroidManifest.xml +12 -5
- package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepBridge.kt +198 -12
- package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepIdentity.kt +342 -0
- package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepKeystore.kt +56 -2
- package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepSqlite.kt +506 -0
- package/templates/app-mobile/plugins/adep-bridge/android/src/main/java/com/adep/bridge/AdepSqliteLogic.kt +235 -0
- package/templates/app-mobile/plugins/adep-bridge/dist/plugin.js +30 -0
- package/templates/app-mobile/plugins/adep-bridge/ios/AdepBridge.podspec +3 -0
- package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepBridge.swift +221 -9
- package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepIdentity.swift +500 -0
- package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepKeychain.swift +69 -17
- package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepPermissionGate.swift +25 -4
- package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepShellConfig.swift +54 -0
- package/templates/app-mobile/plugins/adep-bridge/ios/Sources/AdepSqlite.swift +614 -0
- package/templates/app-mobile/plugins/adep-bridge/package.json +10 -0
- package/templates/app-mobile/template.json +12 -3
- package/templates/app-mobile/web/adep-bridge.js +103 -9
- package/templates/app-mobile/web/offline-runtime.js +230 -0
- package/templates/app-mobile-xtool/AdepShell-Info.plist +24 -0
- package/templates/app-mobile-xtool/Package.swift +59 -0
- package/templates/app-mobile-xtool/README.md +81 -0
- package/templates/app-mobile-xtool/Sources/AdepShell/App.swift +36 -0
- package/templates/app-mobile-xtool/Sources/AdepShell/ShellViewController.swift +223 -0
- package/templates/app-mobile-xtool/adep.permissions.json +4 -0
- package/templates/app-mobile-xtool/app/site/.gitkeep +0 -0
- package/templates/app-mobile-xtool/template.json +15 -0
- package/templates/app-mobile-xtool/xtool.yml +35 -0
- package/templates/app-mobile/plugins/adep-bridge/capacitor.plugin.json +0 -10
package/dist/vite.js
CHANGED
|
@@ -237,6 +237,9 @@ function depsKeyOf(dependencies) {
|
|
|
237
237
|
const canonical = Object.entries(dependencies).map(([name, version]) => `${name}@${version}`).toSorted().join("\n");
|
|
238
238
|
return createHash("sha256").update(canonical).digest("hex").slice(0, 16);
|
|
239
239
|
}
|
|
240
|
+
function parseNameList(value) {
|
|
241
|
+
return value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
242
|
+
}
|
|
240
243
|
|
|
241
244
|
// packages/runtime/src/functions/deps/resolve.ts
|
|
242
245
|
function resolveExecutionDeps(config, projectId, manifestContent) {
|
|
@@ -742,10 +745,21 @@ function compileSelect(state, dialect) {
|
|
|
742
745
|
if (state.orderBys.length > 0) {
|
|
743
746
|
sql += ` ORDER BY ${state.orderBys.map((order) => `${dialect.quote(order.column)} ${order.direction.toUpperCase()}`).join(", ")}`;
|
|
744
747
|
}
|
|
745
|
-
if (state.limit !== void 0)
|
|
746
|
-
|
|
748
|
+
if (state.limit !== void 0) {
|
|
749
|
+
assertInlineableInt(state.limit, "limit");
|
|
750
|
+
sql += ` LIMIT ${state.limit}`;
|
|
751
|
+
}
|
|
752
|
+
if (state.offset !== void 0) {
|
|
753
|
+
assertInlineableInt(state.offset, "offset");
|
|
754
|
+
sql += ` OFFSET ${state.offset}`;
|
|
755
|
+
}
|
|
747
756
|
return { sql, params };
|
|
748
757
|
}
|
|
758
|
+
function assertInlineableInt(value, name) {
|
|
759
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
760
|
+
throw unsafeOperation(`${name} \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570`);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
749
763
|
function compileCount(state, dialect) {
|
|
750
764
|
const params = [];
|
|
751
765
|
let sql = `SELECT count(*) AS n FROM ${dialect.quote(state.table)}`;
|
|
@@ -1299,11 +1313,21 @@ function parseWhereClauses(whereRaw, cursor) {
|
|
|
1299
1313
|
const t = part.trim();
|
|
1300
1314
|
if (t.length === 0) continue;
|
|
1301
1315
|
if (/\bIS\s+NULL\b/i.test(t)) {
|
|
1302
|
-
clauses.push({
|
|
1316
|
+
clauses.push({
|
|
1317
|
+
column: unqualifyColumn(ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "")),
|
|
1318
|
+
operator: "IS NULL",
|
|
1319
|
+
value: null,
|
|
1320
|
+
list: false
|
|
1321
|
+
});
|
|
1303
1322
|
continue;
|
|
1304
1323
|
}
|
|
1305
1324
|
if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
|
|
1306
|
-
clauses.push({
|
|
1325
|
+
clauses.push({
|
|
1326
|
+
column: unqualifyColumn(ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "")),
|
|
1327
|
+
operator: "IS NOT NULL",
|
|
1328
|
+
value: null,
|
|
1329
|
+
list: false
|
|
1330
|
+
});
|
|
1307
1331
|
continue;
|
|
1308
1332
|
}
|
|
1309
1333
|
const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_.]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
|
|
@@ -1480,7 +1504,10 @@ function parseConflictClause(clause, cursor, fallbackCols) {
|
|
|
1480
1504
|
clause.trim()
|
|
1481
1505
|
);
|
|
1482
1506
|
if (m === null) {
|
|
1483
|
-
throw new SimDbError(
|
|
1507
|
+
throw new SimDbError(
|
|
1508
|
+
"DB_UNSAFE_OP",
|
|
1509
|
+
`\u65E0\u6CD5\u89E3\u6790 ON CONFLICT \u5B50\u53E5\uFF1A${clause.trim().slice(0, 60)}\u2026`
|
|
1510
|
+
);
|
|
1484
1511
|
}
|
|
1485
1512
|
const colsRaw = m[1];
|
|
1486
1513
|
const cols = colsRaw === void 0 ? fallbackCols : colsRaw.split(",").map(ident);
|
|
@@ -1684,16 +1711,16 @@ var SimSqlEngine = class {
|
|
|
1684
1711
|
row[col] = values[i] ?? null;
|
|
1685
1712
|
});
|
|
1686
1713
|
if (conflictSpec !== null) {
|
|
1687
|
-
const existing = table.rows.find(
|
|
1688
|
-
(r) => conflictSpec.cols.every((c) => r[c] === row[c])
|
|
1689
|
-
);
|
|
1714
|
+
const existing = table.rows.find((r) => conflictSpec.cols.every((c) => r[c] === row[c]));
|
|
1690
1715
|
if (existing !== void 0) {
|
|
1691
1716
|
const oldRow = { ...existing };
|
|
1692
1717
|
for (const set of conflictSpec.sets) {
|
|
1693
1718
|
existing[set.col] = resolveSetValue(set.value, oldRow, row);
|
|
1694
1719
|
}
|
|
1695
1720
|
inserted += 1;
|
|
1696
|
-
|
|
1721
|
+
this.persist().catch((error) => {
|
|
1722
|
+
console.warn("[sim] \u6301\u4E45\u5316\u5931\u8D25\uFF1A", error);
|
|
1723
|
+
});
|
|
1697
1724
|
continue;
|
|
1698
1725
|
}
|
|
1699
1726
|
}
|
|
@@ -1701,7 +1728,9 @@ var SimSqlEngine = class {
|
|
|
1701
1728
|
table.rows.push(row);
|
|
1702
1729
|
inserted += 1;
|
|
1703
1730
|
}
|
|
1704
|
-
|
|
1731
|
+
this.persist().catch((error) => {
|
|
1732
|
+
console.warn("[sim] \u6301\u4E45\u5316\u5931\u8D25\uFF1A", error);
|
|
1733
|
+
});
|
|
1705
1734
|
return { changes: inserted };
|
|
1706
1735
|
}
|
|
1707
1736
|
execUpdate(sql, params) {
|
|
@@ -1731,7 +1760,9 @@ var SimSqlEngine = class {
|
|
|
1731
1760
|
}
|
|
1732
1761
|
changes += 1;
|
|
1733
1762
|
}
|
|
1734
|
-
|
|
1763
|
+
this.persist().catch((error) => {
|
|
1764
|
+
console.warn("[sim] \u6301\u4E45\u5316\u5931\u8D25\uFF1A", error);
|
|
1765
|
+
});
|
|
1735
1766
|
return { changes };
|
|
1736
1767
|
}
|
|
1737
1768
|
execDelete(sql, params) {
|
|
@@ -1749,7 +1780,9 @@ var SimSqlEngine = class {
|
|
|
1749
1780
|
else changes += 1;
|
|
1750
1781
|
}
|
|
1751
1782
|
table.rows = keep;
|
|
1752
|
-
|
|
1783
|
+
this.persist().catch((error) => {
|
|
1784
|
+
console.warn("[sim] \u6301\u4E45\u5316\u5931\u8D25\uFF1A", error);
|
|
1785
|
+
});
|
|
1753
1786
|
return { changes };
|
|
1754
1787
|
}
|
|
1755
1788
|
select(sql, params) {
|
|
@@ -1771,7 +1804,9 @@ var SimSqlEngine = class {
|
|
|
1771
1804
|
rows = table.rows.map((row) => {
|
|
1772
1805
|
const merged = { ...row };
|
|
1773
1806
|
for (const j of joins) {
|
|
1774
|
-
const joined = this.tables[j.table]?.rows.find(
|
|
1807
|
+
const joined = this.tables[j.table]?.rows.find(
|
|
1808
|
+
(jr) => jr[j.leftCol] === merged[j.rightCol]
|
|
1809
|
+
);
|
|
1775
1810
|
if (joined !== void 0) {
|
|
1776
1811
|
for (const [k, v] of Object.entries(joined)) merged[`${j.alias}.${k}`] = v;
|
|
1777
1812
|
}
|
|
@@ -2872,7 +2907,7 @@ function envDbFile() {
|
|
|
2872
2907
|
function displayPath(cwd, target) {
|
|
2873
2908
|
if (target === ":memory:") return target;
|
|
2874
2909
|
const rel = relative(cwd, target);
|
|
2875
|
-
return rel.startsWith("..") ? target : rel;
|
|
2910
|
+
return rel.startsWith("..") ? target : rel.split(/[\\/]/u).join("/");
|
|
2876
2911
|
}
|
|
2877
2912
|
function simDbTarget(cwd) {
|
|
2878
2913
|
return displayPath(cwd, join5(simDir(cwd), "db.json"));
|
|
@@ -2980,6 +3015,25 @@ async function loadSimEnv(cwd, config = {}) {
|
|
|
2980
3015
|
return merged;
|
|
2981
3016
|
}
|
|
2982
3017
|
|
|
3018
|
+
// packages/cli/src/sim/fetch-config.ts
|
|
3019
|
+
var LOCAL_FETCH_TIMEOUT_MS_DEFAULT = 1e4;
|
|
3020
|
+
function resolveLocalFetchConfig(simEnv) {
|
|
3021
|
+
const rawAllowlist = simEnv.FUNCTIONS_FETCH_ALLOWLIST;
|
|
3022
|
+
if (rawAllowlist === void 0) return void 0;
|
|
3023
|
+
const rawTimeout = simEnv.FUNCTIONS_FETCH_TIMEOUT_MS;
|
|
3024
|
+
let timeoutMs = LOCAL_FETCH_TIMEOUT_MS_DEFAULT;
|
|
3025
|
+
if (rawTimeout !== void 0 && rawTimeout.trim() !== "") {
|
|
3026
|
+
const parsed = Number(rawTimeout);
|
|
3027
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
3028
|
+
throw new Error(
|
|
3029
|
+
`[adep] FUNCTIONS_FETCH_TIMEOUT_MS \u975E\u6CD5\uFF1A"${rawTimeout}"\uFF08\u987B\u4E3A\u6B63\u6574\u6570\u6BEB\u79D2\u6570\uFF1B\u4E0D\u914D\u5219\u7F3A\u7701 ${LOCAL_FETCH_TIMEOUT_MS_DEFAULT}\uFF09`
|
|
3030
|
+
);
|
|
3031
|
+
}
|
|
3032
|
+
timeoutMs = parsed;
|
|
3033
|
+
}
|
|
3034
|
+
return { allowlist: parseNameList(rawAllowlist), timeoutMs };
|
|
3035
|
+
}
|
|
3036
|
+
|
|
2983
3037
|
// packages/cli/src/sim/invoke.ts
|
|
2984
3038
|
function resolveFunctionEntry(files, fnName) {
|
|
2985
3039
|
const flat = `${fnName}.ts`;
|
|
@@ -3087,6 +3141,11 @@ var SIM_BOUNDARIES = [
|
|
|
3087
3141
|
kind: "diff",
|
|
3088
3142
|
title: "\u4E0D\u8BA1\u91CF",
|
|
3089
3143
|
detail: "\u672C\u6A21\u62DF\u8FD0\u884C\u65F6\u4E0D\u4EA7\u51FA\u8BA1\u91CF\u4E8B\u4EF6\uFF0C\u4E5F\u4E0D\u5199 billing\uFF1B\u79BB\u7EBF\u5F00\u53D1\u4E0D\u8BA1\u8D39\u3002"
|
|
3144
|
+
},
|
|
3145
|
+
{
|
|
3146
|
+
kind: "diff",
|
|
3147
|
+
title: "\u51FA\u7F51\u7531\u767D\u540D\u5355\u63A7\u5236",
|
|
3148
|
+
detail: "cloud.fetch \u9ED8\u8BA4\u65E0\u7F51\u7EDC\uFF08\u672A\u914D\u7F6E\u65F6\u8C03\u7528\u629B FN_FETCH_DISABLED\uFF09\uFF1B.env \u914D FUNCTIONS_FETCH_ALLOWLIST\uFF08\u9017\u53F7\u5206\u9694\u4E3B\u673A\uFF0C*. \u901A\u914D\uFF1BFUNCTIONS_FETCH_TIMEOUT_MS \u7F3A\u7701 10s\uFF09\u540E\u91CD\u542F\u6CE8\u5165\u53D7\u63A7 fetch\u2014\u2014\u95E8\u7981\u4E0E\u7EBF\u4E0A\u4E00\u81F4\uFF08\u767D\u540D\u5355 / \u8D85\u65F6 / \u91CD\u5B9A\u5411\u9010\u8DF3\u590D\u68C0\uFF09\uFF0C\u4F46\u672C\u5730\u7531\u5F00\u53D1\u673A\u7F51\u7EDC\u6808\u76F4\u8FDE\uFF0C\u65E0\u5E73\u53F0\u51FA\u7F51\u4E2D\u7EE7\u4E0E\u5BA1\u8BA1\u3002"
|
|
3090
3149
|
}
|
|
3091
3150
|
];
|
|
3092
3151
|
|
|
@@ -3660,6 +3719,158 @@ function parseExportClause(clause) {
|
|
|
3660
3719
|
}
|
|
3661
3720
|
return entries;
|
|
3662
3721
|
}
|
|
3722
|
+
var CONTINUES_AFTER = "=+-*/%&|^<>?:,.[(";
|
|
3723
|
+
var CONTINUES_BEFORE = "`([.?:,+-*/%&|^<>=";
|
|
3724
|
+
var REGEX_PRECEDERS = "(,=:[!&|?{};+-*%~^<>";
|
|
3725
|
+
var MATCHING_OPEN = { ")": "(", "]": "[", "}": "{" };
|
|
3726
|
+
function lineNumberAt(code, index) {
|
|
3727
|
+
let line = 1;
|
|
3728
|
+
for (let i = 0; i < index; i += 1) if (code.charCodeAt(i) === 10) line += 1;
|
|
3729
|
+
return line;
|
|
3730
|
+
}
|
|
3731
|
+
function skipQuoted(code, start) {
|
|
3732
|
+
const quote = code.charAt(start);
|
|
3733
|
+
let i = start + 1;
|
|
3734
|
+
while (i < code.length) {
|
|
3735
|
+
const ch = code.charAt(i);
|
|
3736
|
+
if (ch === "\\") {
|
|
3737
|
+
i += 2;
|
|
3738
|
+
continue;
|
|
3739
|
+
}
|
|
3740
|
+
if (ch === quote) return i + 1;
|
|
3741
|
+
if (ch === "\n") return i;
|
|
3742
|
+
i += 1;
|
|
3743
|
+
}
|
|
3744
|
+
return code.length;
|
|
3745
|
+
}
|
|
3746
|
+
function skipRegex(code, start) {
|
|
3747
|
+
let i = start + 1;
|
|
3748
|
+
let inClass = false;
|
|
3749
|
+
while (i < code.length) {
|
|
3750
|
+
const ch = code.charAt(i);
|
|
3751
|
+
if (ch === "\\") {
|
|
3752
|
+
i += 2;
|
|
3753
|
+
continue;
|
|
3754
|
+
}
|
|
3755
|
+
if (ch === "\n") return start + 1;
|
|
3756
|
+
if (ch === "[") inClass = true;
|
|
3757
|
+
else if (ch === "]") inClass = false;
|
|
3758
|
+
else if (ch === "/" && !inClass) return i + 1;
|
|
3759
|
+
i += 1;
|
|
3760
|
+
}
|
|
3761
|
+
return code.length;
|
|
3762
|
+
}
|
|
3763
|
+
function regexCanStart(prev) {
|
|
3764
|
+
return prev === "" || REGEX_PRECEDERS.includes(prev);
|
|
3765
|
+
}
|
|
3766
|
+
function continuesOnto(code, newline, prev) {
|
|
3767
|
+
if (prev !== "" && CONTINUES_AFTER.includes(prev)) return true;
|
|
3768
|
+
let i = newline + 1;
|
|
3769
|
+
while (i < code.length && /\s/.test(code.charAt(i))) i += 1;
|
|
3770
|
+
const next = code.charAt(i);
|
|
3771
|
+
return next !== "" && CONTINUES_BEFORE.includes(next);
|
|
3772
|
+
}
|
|
3773
|
+
function scanDeclaration(code, from) {
|
|
3774
|
+
const commas = [];
|
|
3775
|
+
const stack = [];
|
|
3776
|
+
let prev = "";
|
|
3777
|
+
let i = from;
|
|
3778
|
+
while (i < code.length) {
|
|
3779
|
+
const ch = code.charAt(i);
|
|
3780
|
+
if (stack[stack.length - 1] === "`") {
|
|
3781
|
+
if (ch === "\\") {
|
|
3782
|
+
i += 2;
|
|
3783
|
+
continue;
|
|
3784
|
+
}
|
|
3785
|
+
if (ch === "`") {
|
|
3786
|
+
stack.pop();
|
|
3787
|
+
prev = "`";
|
|
3788
|
+
i += 1;
|
|
3789
|
+
continue;
|
|
3790
|
+
}
|
|
3791
|
+
if (ch === "$" && code.charAt(i + 1) === "{") {
|
|
3792
|
+
stack.push("{");
|
|
3793
|
+
prev = "{";
|
|
3794
|
+
i += 2;
|
|
3795
|
+
continue;
|
|
3796
|
+
}
|
|
3797
|
+
i += 1;
|
|
3798
|
+
continue;
|
|
3799
|
+
}
|
|
3800
|
+
if (ch === "/" && code.charAt(i + 1) === "/") {
|
|
3801
|
+
const newline = code.indexOf("\n", i);
|
|
3802
|
+
i = newline === -1 ? code.length : newline;
|
|
3803
|
+
continue;
|
|
3804
|
+
}
|
|
3805
|
+
if (ch === "/" && code.charAt(i + 1) === "*") {
|
|
3806
|
+
const close = code.indexOf("*/", i + 2);
|
|
3807
|
+
i = close === -1 ? code.length : close + 2;
|
|
3808
|
+
continue;
|
|
3809
|
+
}
|
|
3810
|
+
if (ch === '"' || ch === "'") {
|
|
3811
|
+
i = skipQuoted(code, i);
|
|
3812
|
+
prev = ch;
|
|
3813
|
+
continue;
|
|
3814
|
+
}
|
|
3815
|
+
if (ch === "`") {
|
|
3816
|
+
stack.push("`");
|
|
3817
|
+
i += 1;
|
|
3818
|
+
continue;
|
|
3819
|
+
}
|
|
3820
|
+
if (ch === "/" && regexCanStart(prev)) {
|
|
3821
|
+
i = skipRegex(code, i);
|
|
3822
|
+
prev = "/";
|
|
3823
|
+
continue;
|
|
3824
|
+
}
|
|
3825
|
+
if (ch === "(" || ch === "[" || ch === "{") {
|
|
3826
|
+
stack.push(ch);
|
|
3827
|
+
prev = ch;
|
|
3828
|
+
i += 1;
|
|
3829
|
+
continue;
|
|
3830
|
+
}
|
|
3831
|
+
if (ch === ")" || ch === "]" || ch === "}") {
|
|
3832
|
+
if (stack[stack.length - 1] !== MATCHING_OPEN[ch]) return { commas, end: i };
|
|
3833
|
+
stack.pop();
|
|
3834
|
+
prev = ch;
|
|
3835
|
+
i += 1;
|
|
3836
|
+
continue;
|
|
3837
|
+
}
|
|
3838
|
+
if (stack.length === 0) {
|
|
3839
|
+
if (ch === ";") return { commas, end: i };
|
|
3840
|
+
if (ch === ",") commas.push(i);
|
|
3841
|
+
if (ch === "\n" && !continuesOnto(code, i, prev)) return { commas, end: i };
|
|
3842
|
+
}
|
|
3843
|
+
if (!/\s/.test(ch)) prev = ch;
|
|
3844
|
+
i += 1;
|
|
3845
|
+
}
|
|
3846
|
+
return { commas, end: code.length };
|
|
3847
|
+
}
|
|
3848
|
+
function declaratorName(segment) {
|
|
3849
|
+
const match = /^\s*([A-Za-z_$][\w$]*)\s*(?:=(?![=>])|$)/.exec(segment);
|
|
3850
|
+
return match === null ? null : match[1] ?? null;
|
|
3851
|
+
}
|
|
3852
|
+
function restDeclarators(code, from) {
|
|
3853
|
+
const { commas, end } = scanDeclaration(code, from);
|
|
3854
|
+
if (commas.length === 0) return [];
|
|
3855
|
+
const segments = [];
|
|
3856
|
+
let cursor = from;
|
|
3857
|
+
for (const comma of commas) {
|
|
3858
|
+
segments.push(code.slice(cursor, comma));
|
|
3859
|
+
cursor = comma + 1;
|
|
3860
|
+
}
|
|
3861
|
+
segments.push(code.slice(cursor, end));
|
|
3862
|
+
const names = [];
|
|
3863
|
+
for (const segment of segments.slice(1)) {
|
|
3864
|
+
const name = declaratorName(segment);
|
|
3865
|
+
if (name === null) {
|
|
3866
|
+
throw new Error(
|
|
3867
|
+
`\u4E0D\u652F\u6301\u7684\u5BFC\u51FA\u58F0\u660E\u5F62\u6001\uFF1A"${segment.trim()}"\uFF08\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7\u9017\u53F7\u5206\u9694\u7684\u7B80\u5355\u6807\u8BC6\u7B26\u58F0\u660E\uFF0C\u5982 \`export const a = 1, b = 2\`\uFF1B\u542B\u89E3\u6784\u6216\u590D\u6742\u521D\u503C\u65F6\u8BF7\u62C6\u6210\u591A\u6761 export\uFF09`
|
|
3868
|
+
);
|
|
3869
|
+
}
|
|
3870
|
+
names.push(name);
|
|
3871
|
+
}
|
|
3872
|
+
return names;
|
|
3873
|
+
}
|
|
3663
3874
|
function transformModule(code) {
|
|
3664
3875
|
let out = code;
|
|
3665
3876
|
const named = [];
|
|
@@ -3722,10 +3933,20 @@ function transformModule(code) {
|
|
|
3722
3933
|
return `${lead}${indent}const ${temp} = require(${source})${pad}`;
|
|
3723
3934
|
}
|
|
3724
3935
|
);
|
|
3936
|
+
const destructured = /(^|\n)[ \t]*export\s+(const|let|var)\s*[{[]/.exec(out);
|
|
3937
|
+
if (destructured !== null) {
|
|
3938
|
+
const offset = destructured.index + (destructured[1] === "\n" ? 1 : 0);
|
|
3939
|
+
throw new Error(
|
|
3940
|
+
`\u4E0D\u652F\u6301\u7684\u5BFC\u51FA\u58F0\u660E\u5F62\u6001\uFF08\u7B2C ${lineNumberAt(out, offset)} \u884C\uFF09\uFF1A\u89E3\u6784\u5BFC\u51FA \`export ${destructured[2] ?? ""} { \u2026 } = \u2026\`\u3002\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7\u7B80\u5355\u6807\u8BC6\u7B26\u58F0\u660E\uFF1A\u8BF7\u5148\u58F0\u660E\u518D \`export { a, b }\`\uFF0C\u6216\u62C6\u6210\u591A\u6761 \`export const\``
|
|
3941
|
+
);
|
|
3942
|
+
}
|
|
3725
3943
|
out = out.replace(
|
|
3726
3944
|
/export\s+(const|let|var)\s+([A-Za-z_$][\w$]*)/g,
|
|
3727
|
-
(
|
|
3945
|
+
(match, kw, name, offset, source) => {
|
|
3728
3946
|
named.push({ local: name, exported: name });
|
|
3947
|
+
for (const extra of restDeclarators(source, offset + match.length)) {
|
|
3948
|
+
named.push({ local: extra, exported: extra });
|
|
3949
|
+
}
|
|
3729
3950
|
return `${kw} ${name}`;
|
|
3730
3951
|
}
|
|
3731
3952
|
);
|
|
@@ -4804,9 +5025,18 @@ async function startDevServer(options) {
|
|
|
4804
5025
|
...options.dbFile === void 0 ? {} : { dbFile: options.dbFile }
|
|
4805
5026
|
});
|
|
4806
5027
|
const bearerUser = bearerUserResolverFromEnv();
|
|
5028
|
+
const simEnv = await loadSimEnv(cwd).catch(() => ({}));
|
|
5029
|
+
const fetchConfig = resolveLocalFetchConfig(simEnv);
|
|
4807
5030
|
const executor = new WorkerFunctionExecutor({
|
|
4808
|
-
deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS }
|
|
5031
|
+
deps: { rootDir: cwd, builtin: LOCAL_BUILTIN_DEPS },
|
|
5032
|
+
// GAME-007 本地接线:配置白名单才注入受控 fetch,语义与线上逐字一致。
|
|
5033
|
+
...fetchConfig === void 0 ? {} : { fetch: fetchConfig }
|
|
4809
5034
|
});
|
|
5035
|
+
if (fetchConfig !== void 0) {
|
|
5036
|
+
log(
|
|
5037
|
+
`[adep] \u53D7\u63A7 fetch \u5DF2\u6CE8\u5165\uFF08FUNCTIONS_FETCH_ALLOWLIST\uFF09\uFF1A\u767D\u540D\u5355 ${fetchConfig.allowlist.length} \u9879\uFF0C\u8D85\u65F6 ${fetchConfig.timeoutMs}ms`
|
|
5038
|
+
);
|
|
5039
|
+
}
|
|
4810
5040
|
await mkdir4(functionsDir, { recursive: true });
|
|
4811
5041
|
const db = await openLocalDbDriver(dbTarget, { cwd, tag: "adep", log });
|
|
4812
5042
|
const runtime = await createSimRuntime({
|
|
@@ -4829,7 +5059,7 @@ async function startDevServer(options) {
|
|
|
4829
5059
|
let files = mergeSharedIntoFunctions(await collectFunctions(functionsDir));
|
|
4830
5060
|
let env = {
|
|
4831
5061
|
...config.environment,
|
|
4832
|
-
...
|
|
5062
|
+
...simEnv
|
|
4833
5063
|
};
|
|
4834
5064
|
const dbBundle = runtime.bundle;
|
|
4835
5065
|
const invokeHandler = createSimInvokeHandler({ executor, files });
|
package/dist/worker-entry.js
CHANGED
|
@@ -127,6 +127,158 @@ function parseExportClause(clause) {
|
|
|
127
127
|
}
|
|
128
128
|
return entries;
|
|
129
129
|
}
|
|
130
|
+
var CONTINUES_AFTER = "=+-*/%&|^<>?:,.[(";
|
|
131
|
+
var CONTINUES_BEFORE = "`([.?:,+-*/%&|^<>=";
|
|
132
|
+
var REGEX_PRECEDERS = "(,=:[!&|?{};+-*%~^<>";
|
|
133
|
+
var MATCHING_OPEN = { ")": "(", "]": "[", "}": "{" };
|
|
134
|
+
function lineNumberAt(code, index) {
|
|
135
|
+
let line = 1;
|
|
136
|
+
for (let i = 0; i < index; i += 1) if (code.charCodeAt(i) === 10) line += 1;
|
|
137
|
+
return line;
|
|
138
|
+
}
|
|
139
|
+
function skipQuoted(code, start) {
|
|
140
|
+
const quote = code.charAt(start);
|
|
141
|
+
let i = start + 1;
|
|
142
|
+
while (i < code.length) {
|
|
143
|
+
const ch = code.charAt(i);
|
|
144
|
+
if (ch === "\\") {
|
|
145
|
+
i += 2;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (ch === quote) return i + 1;
|
|
149
|
+
if (ch === "\n") return i;
|
|
150
|
+
i += 1;
|
|
151
|
+
}
|
|
152
|
+
return code.length;
|
|
153
|
+
}
|
|
154
|
+
function skipRegex(code, start) {
|
|
155
|
+
let i = start + 1;
|
|
156
|
+
let inClass = false;
|
|
157
|
+
while (i < code.length) {
|
|
158
|
+
const ch = code.charAt(i);
|
|
159
|
+
if (ch === "\\") {
|
|
160
|
+
i += 2;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (ch === "\n") return start + 1;
|
|
164
|
+
if (ch === "[") inClass = true;
|
|
165
|
+
else if (ch === "]") inClass = false;
|
|
166
|
+
else if (ch === "/" && !inClass) return i + 1;
|
|
167
|
+
i += 1;
|
|
168
|
+
}
|
|
169
|
+
return code.length;
|
|
170
|
+
}
|
|
171
|
+
function regexCanStart(prev) {
|
|
172
|
+
return prev === "" || REGEX_PRECEDERS.includes(prev);
|
|
173
|
+
}
|
|
174
|
+
function continuesOnto(code, newline, prev) {
|
|
175
|
+
if (prev !== "" && CONTINUES_AFTER.includes(prev)) return true;
|
|
176
|
+
let i = newline + 1;
|
|
177
|
+
while (i < code.length && /\s/.test(code.charAt(i))) i += 1;
|
|
178
|
+
const next = code.charAt(i);
|
|
179
|
+
return next !== "" && CONTINUES_BEFORE.includes(next);
|
|
180
|
+
}
|
|
181
|
+
function scanDeclaration(code, from) {
|
|
182
|
+
const commas = [];
|
|
183
|
+
const stack = [];
|
|
184
|
+
let prev = "";
|
|
185
|
+
let i = from;
|
|
186
|
+
while (i < code.length) {
|
|
187
|
+
const ch = code.charAt(i);
|
|
188
|
+
if (stack[stack.length - 1] === "`") {
|
|
189
|
+
if (ch === "\\") {
|
|
190
|
+
i += 2;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (ch === "`") {
|
|
194
|
+
stack.pop();
|
|
195
|
+
prev = "`";
|
|
196
|
+
i += 1;
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (ch === "$" && code.charAt(i + 1) === "{") {
|
|
200
|
+
stack.push("{");
|
|
201
|
+
prev = "{";
|
|
202
|
+
i += 2;
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
i += 1;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (ch === "/" && code.charAt(i + 1) === "/") {
|
|
209
|
+
const newline = code.indexOf("\n", i);
|
|
210
|
+
i = newline === -1 ? code.length : newline;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (ch === "/" && code.charAt(i + 1) === "*") {
|
|
214
|
+
const close = code.indexOf("*/", i + 2);
|
|
215
|
+
i = close === -1 ? code.length : close + 2;
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (ch === '"' || ch === "'") {
|
|
219
|
+
i = skipQuoted(code, i);
|
|
220
|
+
prev = ch;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (ch === "`") {
|
|
224
|
+
stack.push("`");
|
|
225
|
+
i += 1;
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (ch === "/" && regexCanStart(prev)) {
|
|
229
|
+
i = skipRegex(code, i);
|
|
230
|
+
prev = "/";
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (ch === "(" || ch === "[" || ch === "{") {
|
|
234
|
+
stack.push(ch);
|
|
235
|
+
prev = ch;
|
|
236
|
+
i += 1;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (ch === ")" || ch === "]" || ch === "}") {
|
|
240
|
+
if (stack[stack.length - 1] !== MATCHING_OPEN[ch]) return { commas, end: i };
|
|
241
|
+
stack.pop();
|
|
242
|
+
prev = ch;
|
|
243
|
+
i += 1;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (stack.length === 0) {
|
|
247
|
+
if (ch === ";") return { commas, end: i };
|
|
248
|
+
if (ch === ",") commas.push(i);
|
|
249
|
+
if (ch === "\n" && !continuesOnto(code, i, prev)) return { commas, end: i };
|
|
250
|
+
}
|
|
251
|
+
if (!/\s/.test(ch)) prev = ch;
|
|
252
|
+
i += 1;
|
|
253
|
+
}
|
|
254
|
+
return { commas, end: code.length };
|
|
255
|
+
}
|
|
256
|
+
function declaratorName(segment) {
|
|
257
|
+
const match = /^\s*([A-Za-z_$][\w$]*)\s*(?:=(?![=>])|$)/.exec(segment);
|
|
258
|
+
return match === null ? null : match[1] ?? null;
|
|
259
|
+
}
|
|
260
|
+
function restDeclarators(code, from) {
|
|
261
|
+
const { commas, end } = scanDeclaration(code, from);
|
|
262
|
+
if (commas.length === 0) return [];
|
|
263
|
+
const segments = [];
|
|
264
|
+
let cursor = from;
|
|
265
|
+
for (const comma of commas) {
|
|
266
|
+
segments.push(code.slice(cursor, comma));
|
|
267
|
+
cursor = comma + 1;
|
|
268
|
+
}
|
|
269
|
+
segments.push(code.slice(cursor, end));
|
|
270
|
+
const names = [];
|
|
271
|
+
for (const segment of segments.slice(1)) {
|
|
272
|
+
const name = declaratorName(segment);
|
|
273
|
+
if (name === null) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
`\u4E0D\u652F\u6301\u7684\u5BFC\u51FA\u58F0\u660E\u5F62\u6001\uFF1A"${segment.trim()}"\uFF08\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7\u9017\u53F7\u5206\u9694\u7684\u7B80\u5355\u6807\u8BC6\u7B26\u58F0\u660E\uFF0C\u5982 \`export const a = 1, b = 2\`\uFF1B\u542B\u89E3\u6784\u6216\u590D\u6742\u521D\u503C\u65F6\u8BF7\u62C6\u6210\u591A\u6761 export\uFF09`
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
names.push(name);
|
|
279
|
+
}
|
|
280
|
+
return names;
|
|
281
|
+
}
|
|
130
282
|
function transformModule(code) {
|
|
131
283
|
let out = code;
|
|
132
284
|
const named = [];
|
|
@@ -189,10 +341,20 @@ function transformModule(code) {
|
|
|
189
341
|
return `${lead}${indent}const ${temp} = require(${source})${pad}`;
|
|
190
342
|
}
|
|
191
343
|
);
|
|
344
|
+
const destructured = /(^|\n)[ \t]*export\s+(const|let|var)\s*[{[]/.exec(out);
|
|
345
|
+
if (destructured !== null) {
|
|
346
|
+
const offset = destructured.index + (destructured[1] === "\n" ? 1 : 0);
|
|
347
|
+
throw new Error(
|
|
348
|
+
`\u4E0D\u652F\u6301\u7684\u5BFC\u51FA\u58F0\u660E\u5F62\u6001\uFF08\u7B2C ${lineNumberAt(out, offset)} \u884C\uFF09\uFF1A\u89E3\u6784\u5BFC\u51FA \`export ${destructured[2] ?? ""} { \u2026 } = \u2026\`\u3002\u6C99\u7BB1\u5B50\u96C6\u4EC5\u63A5\u53D7\u7B80\u5355\u6807\u8BC6\u7B26\u58F0\u660E\uFF1A\u8BF7\u5148\u58F0\u660E\u518D \`export { a, b }\`\uFF0C\u6216\u62C6\u6210\u591A\u6761 \`export const\``
|
|
349
|
+
);
|
|
350
|
+
}
|
|
192
351
|
out = out.replace(
|
|
193
352
|
/export\s+(const|let|var)\s+([A-Za-z_$][\w$]*)/g,
|
|
194
|
-
(
|
|
353
|
+
(match, kw, name, offset, source) => {
|
|
195
354
|
named.push({ local: name, exported: name });
|
|
355
|
+
for (const extra of restDeclarators(source, offset + match.length)) {
|
|
356
|
+
named.push({ local: extra, exported: extra });
|
|
357
|
+
}
|
|
196
358
|
return `${kw} ${name}`;
|
|
197
359
|
}
|
|
198
360
|
);
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"homepage": "https://adep.top",
|
|
9
9
|
"bugs": "https://gitcode.com/yunqiang_wu/ai-yunke/issues",
|
|
10
|
-
"version": "0.4.
|
|
10
|
+
"version": "0.4.6",
|
|
11
11
|
"type": "module",
|
|
12
12
|
"description": "`adep` 命令行工具包位:登录 / 初始化 / 本地调试 / 部署 / 数据库维护 / 云存储 / 静态托管 / 微前端组件(widget),实现见任务单 CLI-001 ~ CLI-003 与 FE-002;子路径 `@adep/cli/vite` 提供云函数 vite 插件(CLI-014)",
|
|
13
13
|
"bin": {
|
|
@@ -29,11 +29,12 @@
|
|
|
29
29
|
"commander": "14.0.2",
|
|
30
30
|
"esbuild": "0.25.12",
|
|
31
31
|
"yaml": "2.9.1",
|
|
32
|
-
"zod": "^4.
|
|
33
|
-
"@adep/
|
|
34
|
-
"@adep/runtime": "0.
|
|
35
|
-
"@adep/
|
|
36
|
-
"@adep/vite-plugin": "0.1.9"
|
|
32
|
+
"zod": "^4.6.6",
|
|
33
|
+
"@adep/runtime": "0.3.5",
|
|
34
|
+
"@adep/app-runtime": "0.1.1",
|
|
35
|
+
"@adep/cf-compat": "0.1.4",
|
|
36
|
+
"@adep/vite-plugin": "0.1.9",
|
|
37
|
+
"@adep/crypto": "0.1.1"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"@adep/types": "0.3.2"
|
|
@@ -18,7 +18,7 @@ GUI(前端产物)随包本地加载,云函数经 HTTP 在服务端执行
|
|
|
18
18
|
|
|
19
19
|
1. 把平台项目的前端构建产物放进 `app/site/`(`adep app build` 会自动拉取已发布产物);
|
|
20
20
|
2. `npm install`;
|
|
21
|
-
3. `npm start
|
|
21
|
+
3. `npm start`(或仓库根的 `adep app open`,等价——直接调壳工程内的 electron;配置从 `adep.app.json` 读取,无需环境变量)。
|
|
22
22
|
|
|
23
23
|
## 页面侧调用云函数(在线运行时)
|
|
24
24
|
|
|
@@ -31,12 +31,77 @@ const client = createAdepClient({ baseUrl: window.__ADEP_APP__.platformUrl })
|
|
|
31
31
|
const result = await client.invokeFunction('hello', { name: 'world' })
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
## 设备身份与同步(离线构建之后)
|
|
35
|
+
|
|
36
|
+
离线构建把设备端运行时注入 `app/offline/`,首次启动时在 `data/offline.sqlite` 建本地库:
|
|
37
|
+
白名单函数在本地执行,写 owned 表时同时追加变更流。
|
|
38
|
+
|
|
39
|
+
**设备身份是首启自动签发的**(APP-033 / PRD §2.11.5):主进程启动后在后台调一次
|
|
40
|
+
`POST /api/v1/projects/<slug>/app-installations`(`platform` 按**宿主 OS** 映射为
|
|
41
|
+
`macos` / `windows` / `linux`——服务端没有 `desktop` 这个取值),拿到 `ownerKey` +
|
|
42
|
+
一次性恢复码后写进受保护存储;此后每次启动只读不发请求。
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
identity.mjs 判定层(配置 / 端点 / 形态 / 响应解析 / 平台映射)+ 自举流程
|
|
46
|
+
identity-store.mjs 受保护存储:macOS 钥匙串 → Linux Secret Service → 0600 文件(明说降级)
|
|
47
|
+
recovery-ui.mjs 恢复码呈现与导出(APP-034;全在主进程,页面侧拿不到)
|
|
48
|
+
sync-loop.mjs 后台同步驱动(首轮延迟 → 每 5 分钟一轮;不重叠、失败不致命)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
存储后端:
|
|
52
|
+
|
|
53
|
+
- macOS:`security add-generic-password`(登录钥匙串);
|
|
54
|
+
- Linux:`secret-tool`(Secret Service);
|
|
55
|
+
- **Windows 与「系统库不可用」**:退化到 `data/identity/` 下的 0600 文件,并在日志与
|
|
56
|
+
`adep app doctor` 里**明说「非系统凭据」**——不会静默假装是钥匙串。
|
|
57
|
+
|
|
58
|
+
身份状态(**非机密**:只有存储类型 / 原因码 / 安装 id / 时间)写在
|
|
59
|
+
`data/identity/status.json`,`adep app doctor` 的 `identity` 项读它:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
adep app doctor # 已签发(系统凭据库 keychain) / 非系统凭据(file) / 首启签发失败(原因码)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
⚠️ **页面侧拿不到 `ownerKey`**(与移动壳同一条边界):同步跑在主进程,渲染进程不需要这枚
|
|
66
|
+
bearer 凭据,给它等于「任意 XSS 都能劫持该设备的数据分区」。
|
|
67
|
+
|
|
68
|
+
## 恢复码(APP-034:呈现 / 再次查看 / 导出)
|
|
69
|
+
|
|
70
|
+
签发响应里的恢复码**只出现一次**(服务端只存摘要、任何端点不重发),壳负责把它递到用户手里:
|
|
71
|
+
|
|
72
|
+
- **首次呈现**:自举成功后自动弹一次原生对话框(码可读且没呈现过才弹——老安装升级上来
|
|
73
|
+
同样有机会看到)。此后不再主动弹,标记写在 `data/identity/recovery-code-shown`;
|
|
74
|
+
- **再次查看 / 导出**:应用菜单 **「凭据」→「查看恢复码…」/「导出恢复码…」**(导出文件
|
|
75
|
+
头部写明「服务端无法重发,丢了码等于放弃认领」);
|
|
76
|
+
- **复制到剪贴板**:两个对话框里都有一键复制。
|
|
77
|
+
|
|
78
|
+
呈现与导出**全在主进程**(应用菜单 + 原生对话框):不开 IPC、不改 preload,恢复码与
|
|
79
|
+
`ownerKey` 一样不进渲染进程。码不可读时(未签发 / 存储失败)对话框会说明原因并指向
|
|
80
|
+
`adep app doctor`,不是静默空窗。
|
|
81
|
+
|
|
82
|
+
身份就绪后主进程自动把同步挂到运行时上:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
const runtime = await createOfflineRuntime() // 页面先可用
|
|
86
|
+
const sync = runtime.attachSync({ ownerKey }) // 身份到位后再挂(不重开库)
|
|
87
|
+
await sync.push() // 本地变更流 → outbox → 云端
|
|
88
|
+
await sync.pull() // 云端增量 → 本地库(直写驱动,不回灌 outbox)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
手动同步(开发期 / 排障)仍用 CLI:`adep app sync --push`(身份取 `--owner-key` 或
|
|
92
|
+
`ADEP_OWNER_KEY`)。**不要**在 `adep.app.json` 或环境变量里编一个 key:本地自造会写出一个
|
|
93
|
+
「看起来成功」的空分区(PRD §2.11.5 明确「本地自造判违规」)。
|
|
94
|
+
|
|
95
|
+
⚠️ 已知限制(已登记):打包形态下 `data/` 仍在应用目录内(`.app` / Program Files),
|
|
96
|
+
写入可能被系统拒绝——此时 `identity` 项会显示 `IDENTITY_STORE_FAILED`,属于**响亮失败**。
|
|
97
|
+
把本地数据目录迁到 `app.getPath('userData')` 是独立的一批(含 `data/offline.sqlite`)。
|
|
98
|
+
|
|
34
99
|
## 打安装包
|
|
35
100
|
|
|
36
101
|
推荐用 CLI(会自动拉取**已发布**的前端产物、回写产物版本、产出构建报告):
|
|
37
102
|
|
|
38
103
|
```bash
|
|
39
|
-
adep app build # 当前平台、走 package.json build 段的 target(mac dmg / win nsis / linux AppImage)
|
|
104
|
+
adep app build # 当前平台、走 package.json build 段的 target(mac dmg / win nsis+zip / linux AppImage+deb)
|
|
40
105
|
adep app build --target dir # 只出未压缩目录(macOS 即 .app),本地快速验证
|
|
41
106
|
adep app build --prepare-only # 只拉产物 + 注入 + 出构建报告,不调 electron-builder
|
|
42
107
|
```
|