@withone/cli 2.14.1 → 2.14.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 +1 -1
- package/dist/{chunk-IM3OA7CU.js → chunk-33KUKSRH.js} +25 -5
- package/dist/{chunk-LEJKEGB6.js → chunk-AFZIE2QJ.js} +113 -70
- package/dist/{flow-runner-SRO6YL62.js → flow-runner-PUFQASEJ.js} +3 -1
- package/dist/index.js +407 -184
- package/dist/{migrate-RJ7F2LPT.js → migrate-E5QDJRM4.js} +1 -1
- package/package.json +1 -1
- package/skills/one/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -487,7 +487,7 @@ one sync run stripe --full-refresh
|
|
|
487
487
|
| `schedule add/list/status/remove/repair` | Cron-backed scheduled syncs with drift detection |
|
|
488
488
|
| `remove <platform>` | Delete synced data (`--dry-run` to preview) |
|
|
489
489
|
|
|
490
|
-
Change hooks (`onInsert`, `onUpdate`, `onChange`) fire per-page during sync — pipe to a shell command, a flow, or an event log. Root-array responses (e.g. Hacker News `/v0/topstories.json` → `[9129911, 9129199, ...]`) are supported by setting `resultsPath` to `""`, `"$"`, or `"."`; primitive elements are auto-wrapped as `{ [idField]: value }`. Run `one guide sync` or `one guide memory` for the full reference.
|
|
490
|
+
Change hooks (`onInsert`, `onUpdate`, `onChange`) fire per-page during sync — pipe to a shell command, a flow, or an event log. Shell commands in a profile (`transform` and hooks other than `"log"`) only run once approved for that project: commands you pass in `sync init --config` are approved automatically, and commands that arrive in a profile on disk (for example from a cloned repo) need `one sync approve <platform>`. A change to an approved command needs approving again. Root-array responses (e.g. Hacker News `/v0/topstories.json` → `[9129911, 9129199, ...]`) are supported by setting `resultsPath` to `""`, `"$"`, or `"."`; primitive elements are auto-wrapped as `{ [idField]: value }`. Run `one guide sync` or `one guide memory` for the full reference.
|
|
491
491
|
|
|
492
492
|
### `one relay`
|
|
493
493
|
|
|
@@ -3223,7 +3223,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
|
|
|
3223
3223
|
if (flowStack.includes(resolvedKey)) {
|
|
3224
3224
|
throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
|
|
3225
3225
|
}
|
|
3226
|
-
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-
|
|
3226
|
+
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-PUFQASEJ.js");
|
|
3227
3227
|
const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
|
|
3228
3228
|
const subContext = await executeFlow(
|
|
3229
3229
|
subFlow,
|
|
@@ -3330,7 +3330,7 @@ function resolveBashEnv(envConfig, context, stepId) {
|
|
|
3330
3330
|
os2.tmpdir(),
|
|
3331
3331
|
`one-flow-${stepId}-${key}-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.json`
|
|
3332
3332
|
);
|
|
3333
|
-
fs4.writeFileSync(tmp, json, { encoding: "utf-8" });
|
|
3333
|
+
fs4.writeFileSync(tmp, json, { encoding: "utf-8", mode: 384 });
|
|
3334
3334
|
tempFiles.push(tmp);
|
|
3335
3335
|
out[key] = tmp;
|
|
3336
3336
|
continue;
|
|
@@ -3768,9 +3768,21 @@ var RUNS_DIR = ".one/flows/.runs";
|
|
|
3768
3768
|
var LOGS_DIR = ".one/flows/.logs";
|
|
3769
3769
|
function ensureDir(dir) {
|
|
3770
3770
|
if (!fs5.existsSync(dir)) {
|
|
3771
|
-
fs5.mkdirSync(dir, { recursive: true });
|
|
3771
|
+
fs5.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3772
3772
|
}
|
|
3773
3773
|
}
|
|
3774
|
+
var PRIVATE_FILE_MODE = 384;
|
|
3775
|
+
var PRIVATE_DIR_MODE = 448;
|
|
3776
|
+
function restrictMode(p, mode) {
|
|
3777
|
+
try {
|
|
3778
|
+
fs5.chmodSync(p, mode);
|
|
3779
|
+
} catch {
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
function persistableState(state) {
|
|
3783
|
+
if (!state.context) return state;
|
|
3784
|
+
return { ...state, context: { ...state.context, env: {} } };
|
|
3785
|
+
}
|
|
3774
3786
|
function generateRunId() {
|
|
3775
3787
|
return crypto.randomBytes(6).toString("hex");
|
|
3776
3788
|
}
|
|
@@ -3789,6 +3801,8 @@ var FlowRunner = class _FlowRunner {
|
|
|
3789
3801
|
this.flowKey = flow.key;
|
|
3790
3802
|
ensureDir(RUNS_DIR);
|
|
3791
3803
|
ensureDir(LOGS_DIR);
|
|
3804
|
+
restrictMode(RUNS_DIR, PRIVATE_DIR_MODE);
|
|
3805
|
+
restrictMode(LOGS_DIR, PRIVATE_DIR_MODE);
|
|
3792
3806
|
this.statePath = path6.join(RUNS_DIR, `${flow.key}-${this.runId}.state.json`);
|
|
3793
3807
|
this.logPath = path6.join(LOGS_DIR, `${flow.key}-${this.runId}.log`);
|
|
3794
3808
|
const resolvedInputs = { ...inputs };
|
|
@@ -3831,10 +3845,15 @@ var FlowRunner = class _FlowRunner {
|
|
|
3831
3845
|
msg,
|
|
3832
3846
|
...data
|
|
3833
3847
|
};
|
|
3834
|
-
fs5.appendFileSync(this.logPath, JSON.stringify(entry) + "\n");
|
|
3848
|
+
fs5.appendFileSync(this.logPath, JSON.stringify(entry) + "\n", { mode: PRIVATE_FILE_MODE });
|
|
3835
3849
|
}
|
|
3836
3850
|
saveState() {
|
|
3837
|
-
fs5.writeFileSync(
|
|
3851
|
+
fs5.writeFileSync(
|
|
3852
|
+
this.statePath,
|
|
3853
|
+
JSON.stringify(persistableState(this.state), stripStepsAlias, 2),
|
|
3854
|
+
{ mode: PRIVATE_FILE_MODE }
|
|
3855
|
+
);
|
|
3856
|
+
restrictMode(this.statePath, PRIVATE_FILE_MODE);
|
|
3838
3857
|
}
|
|
3839
3858
|
createEventHandler(externalHandler) {
|
|
3840
3859
|
return (event) => {
|
|
@@ -4169,6 +4188,7 @@ export {
|
|
|
4169
4188
|
getStepTypeDescriptor,
|
|
4170
4189
|
getNestedStepsKeys,
|
|
4171
4190
|
generateFlowGuide,
|
|
4191
|
+
persistableState,
|
|
4172
4192
|
stripStepsAlias,
|
|
4173
4193
|
FlowRunner,
|
|
4174
4194
|
resolveFlowPath,
|
|
@@ -15,23 +15,57 @@ import {
|
|
|
15
15
|
} from "./chunk-4H5L3SBY.js";
|
|
16
16
|
|
|
17
17
|
// src/commands/mem/migrate.ts
|
|
18
|
-
import
|
|
19
|
-
import
|
|
18
|
+
import fs5 from "fs";
|
|
19
|
+
import path5 from "path";
|
|
20
20
|
import * as p from "@clack/prompts";
|
|
21
21
|
|
|
22
22
|
// src/lib/memory/sync/profile.ts
|
|
23
|
+
import fs2 from "fs";
|
|
24
|
+
import path2 from "path";
|
|
25
|
+
|
|
26
|
+
// src/lib/memory/sync/names.ts
|
|
23
27
|
import fs from "fs";
|
|
24
28
|
import path from "path";
|
|
25
|
-
var
|
|
29
|
+
var SAFE_SYNC_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
30
|
+
function isSafeSyncName(value) {
|
|
31
|
+
return typeof value === "string" && value.length <= 128 && SAFE_SYNC_NAME.test(value) && !value.includes("..");
|
|
32
|
+
}
|
|
33
|
+
var UnsafeSyncNameError = class extends Error {
|
|
34
|
+
constructor(kind, value) {
|
|
35
|
+
super(
|
|
36
|
+
`Invalid sync ${kind} name ${JSON.stringify(value)}: use letters, digits, ".", "_" or "-", starting with a letter or digit, and no "..".`
|
|
37
|
+
);
|
|
38
|
+
this.name = "UnsafeSyncNameError";
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
function assertSafeSyncNames(platform, model) {
|
|
42
|
+
if (!isSafeSyncName(platform)) throw new UnsafeSyncNameError("platform", platform);
|
|
43
|
+
if (model !== void 0 && !isSafeSyncName(model)) throw new UnsafeSyncNameError("model", model);
|
|
44
|
+
}
|
|
45
|
+
function ensureDirInsideProject(dirRel) {
|
|
46
|
+
fs.mkdirSync(dirRel, { recursive: true });
|
|
47
|
+
const root = fs.realpathSync(process.cwd());
|
|
48
|
+
const real = fs.realpathSync(dirRel);
|
|
49
|
+
if (real !== root && !real.startsWith(root + path.sep)) {
|
|
50
|
+
throw new Error(`Refusing to use ${dirRel}: it resolves outside the project (${real}).`);
|
|
51
|
+
}
|
|
52
|
+
return dirRel;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/lib/memory/sync/profile.ts
|
|
56
|
+
var PROFILES_DIR = path2.join(".one", "sync", "profiles");
|
|
26
57
|
function profilePath(platform, model) {
|
|
27
|
-
|
|
58
|
+
assertSafeSyncNames(platform, model);
|
|
59
|
+
return path2.join(PROFILES_DIR, `${platform}_${model}.json`);
|
|
28
60
|
}
|
|
29
61
|
function readProfile(platform, model) {
|
|
30
62
|
const filePath = profilePath(platform, model);
|
|
31
63
|
try {
|
|
32
|
-
if (!
|
|
33
|
-
const raw =
|
|
34
|
-
|
|
64
|
+
if (!fs2.existsSync(filePath)) return null;
|
|
65
|
+
const raw = fs2.readFileSync(filePath, "utf-8");
|
|
66
|
+
const profile = JSON.parse(raw);
|
|
67
|
+
if (!isSafeSyncName(profile?.platform) || !isSafeSyncName(profile?.model)) return null;
|
|
68
|
+
return profile;
|
|
35
69
|
} catch {
|
|
36
70
|
return null;
|
|
37
71
|
}
|
|
@@ -61,9 +95,9 @@ function writeProfile(profile) {
|
|
|
61
95
|
if (!profile.pagination.type) {
|
|
62
96
|
throw new Error("Missing required field: pagination.type");
|
|
63
97
|
}
|
|
64
|
-
|
|
98
|
+
fs2.mkdirSync(PROFILES_DIR, { recursive: true });
|
|
65
99
|
const filePath = profilePath(profile.platform, profile.model);
|
|
66
|
-
|
|
100
|
+
fs2.writeFileSync(filePath, JSON.stringify(profile, null, 2));
|
|
67
101
|
}
|
|
68
102
|
async function resolveProfileConnectionKey(api, profile, cache) {
|
|
69
103
|
if (profile.connectionKey) return profile.connectionKey;
|
|
@@ -76,18 +110,25 @@ async function resolveProfileConnectionKey(api, profile, cache) {
|
|
|
76
110
|
return conn.key;
|
|
77
111
|
}
|
|
78
112
|
function writeDraftProfile(platform, model, draft) {
|
|
79
|
-
|
|
113
|
+
fs2.mkdirSync(PROFILES_DIR, { recursive: true });
|
|
80
114
|
const filePath = profilePath(platform, model);
|
|
81
|
-
|
|
115
|
+
fs2.writeFileSync(filePath, JSON.stringify(draft, null, 2));
|
|
82
116
|
}
|
|
83
117
|
function listProfiles(platform) {
|
|
84
|
-
if (!
|
|
85
|
-
const files =
|
|
118
|
+
if (!fs2.existsSync(PROFILES_DIR)) return [];
|
|
119
|
+
const files = fs2.readdirSync(PROFILES_DIR).filter((f) => f.endsWith(".json"));
|
|
86
120
|
const profiles = [];
|
|
87
121
|
for (const file of files) {
|
|
88
122
|
try {
|
|
89
|
-
const raw =
|
|
123
|
+
const raw = fs2.readFileSync(path2.join(PROFILES_DIR, file), "utf-8");
|
|
90
124
|
const profile = JSON.parse(raw);
|
|
125
|
+
if (!isSafeSyncName(profile?.platform) || !isSafeSyncName(profile?.model)) {
|
|
126
|
+
process.stderr.write(
|
|
127
|
+
`Skipping sync profile ${file}: platform and model must be plain names (letters, digits, ".", "_", "-", no "..").
|
|
128
|
+
`
|
|
129
|
+
);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
91
132
|
if (!platform || profile.platform === platform) {
|
|
92
133
|
profiles.push(profile);
|
|
93
134
|
}
|
|
@@ -121,25 +162,25 @@ function generateTemplate(platform, model, actionId) {
|
|
|
121
162
|
}
|
|
122
163
|
|
|
123
164
|
// src/lib/memory/sync/builtin-profiles.ts
|
|
124
|
-
import
|
|
125
|
-
import
|
|
165
|
+
import fs3 from "fs";
|
|
166
|
+
import path3 from "path";
|
|
126
167
|
import { fileURLToPath } from "url";
|
|
127
168
|
function getProfilesDir() {
|
|
128
169
|
const thisFile = fileURLToPath(import.meta.url);
|
|
129
|
-
const thisDir =
|
|
170
|
+
const thisDir = path3.dirname(thisFile);
|
|
130
171
|
for (let i = 1; i <= 4; i++) {
|
|
131
|
-
const candidate =
|
|
132
|
-
if (
|
|
172
|
+
const candidate = path3.resolve(thisDir, ...Array(i).fill(".."), "profiles");
|
|
173
|
+
if (fs3.existsSync(candidate)) return candidate;
|
|
133
174
|
}
|
|
134
175
|
return "";
|
|
135
176
|
}
|
|
136
177
|
function loadBuiltinProfile(platform, model) {
|
|
137
178
|
const dir = getProfilesDir();
|
|
138
179
|
if (!dir) return null;
|
|
139
|
-
const filePath =
|
|
180
|
+
const filePath = path3.join(dir, platform, `${model}.json`);
|
|
140
181
|
try {
|
|
141
|
-
if (!
|
|
142
|
-
const raw =
|
|
182
|
+
if (!fs3.existsSync(filePath)) return null;
|
|
183
|
+
const raw = fs3.readFileSync(filePath, "utf-8");
|
|
143
184
|
return JSON.parse(raw);
|
|
144
185
|
} catch {
|
|
145
186
|
return null;
|
|
@@ -159,20 +200,20 @@ function listBuiltinProfiles(platform) {
|
|
|
159
200
|
if (!dir) return [];
|
|
160
201
|
const profiles = [];
|
|
161
202
|
try {
|
|
162
|
-
const platforms = platform ? [platform] :
|
|
203
|
+
const platforms = platform ? [platform] : fs3.readdirSync(dir).filter((f) => {
|
|
163
204
|
try {
|
|
164
|
-
return
|
|
205
|
+
return fs3.statSync(path3.join(dir, f)).isDirectory();
|
|
165
206
|
} catch {
|
|
166
207
|
return false;
|
|
167
208
|
}
|
|
168
209
|
});
|
|
169
210
|
for (const plat of platforms) {
|
|
170
|
-
const platDir =
|
|
171
|
-
if (!
|
|
172
|
-
const files =
|
|
211
|
+
const platDir = path3.join(dir, plat);
|
|
212
|
+
if (!fs3.existsSync(platDir)) continue;
|
|
213
|
+
const files = fs3.readdirSync(platDir).filter((f) => f.endsWith(".json"));
|
|
173
214
|
for (const file of files) {
|
|
174
215
|
try {
|
|
175
|
-
const raw =
|
|
216
|
+
const raw = fs3.readFileSync(path3.join(platDir, file), "utf-8");
|
|
176
217
|
const profile = JSON.parse(raw);
|
|
177
218
|
profiles.push(profile);
|
|
178
219
|
} catch {
|
|
@@ -185,8 +226,8 @@ function listBuiltinProfiles(platform) {
|
|
|
185
226
|
}
|
|
186
227
|
|
|
187
228
|
// src/lib/memory/sync/db.ts
|
|
188
|
-
import
|
|
189
|
-
import
|
|
229
|
+
import fs4 from "fs";
|
|
230
|
+
import path4 from "path";
|
|
190
231
|
|
|
191
232
|
// src/lib/memory/sync/sqlite-loader.ts
|
|
192
233
|
var cached = null;
|
|
@@ -222,10 +263,10 @@ async function isSqliteAvailable() {
|
|
|
222
263
|
}
|
|
223
264
|
|
|
224
265
|
// src/lib/memory/sync/db.ts
|
|
225
|
-
var DATA_DIR =
|
|
266
|
+
var DATA_DIR = path4.join(".one", "sync", "data");
|
|
226
267
|
function listSyncedPlatforms() {
|
|
227
|
-
if (!
|
|
228
|
-
return
|
|
268
|
+
if (!fs4.existsSync(DATA_DIR)) return [];
|
|
269
|
+
return fs4.readdirSync(DATA_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(/\.db$/, ""));
|
|
229
270
|
}
|
|
230
271
|
function isDriverFault(err) {
|
|
231
272
|
const code = err?.code;
|
|
@@ -255,8 +296,8 @@ function backupPathFor(dbPath, now = /* @__PURE__ */ new Date()) {
|
|
|
255
296
|
}
|
|
256
297
|
async function openDatabase(platform, opts = {}) {
|
|
257
298
|
const Database = await loadSqlite();
|
|
258
|
-
|
|
259
|
-
const dbPath =
|
|
299
|
+
fs4.mkdirSync(DATA_DIR, { recursive: true });
|
|
300
|
+
const dbPath = path4.join(DATA_DIR, `${platform}.db`);
|
|
260
301
|
if (opts.readonly) {
|
|
261
302
|
return new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
262
303
|
}
|
|
@@ -280,7 +321,7 @@ Rebuild it against this Node with:
|
|
|
280
321
|
Underlying error: ${detail}`
|
|
281
322
|
);
|
|
282
323
|
}
|
|
283
|
-
if (!
|
|
324
|
+
if (!fs4.existsSync(dbPath)) throw err;
|
|
284
325
|
if (passesIntegrityCheck(Database, dbPath)) {
|
|
285
326
|
const detail = err instanceof Error ? err.message.split("\n")[0] : String(err);
|
|
286
327
|
throw new Error(
|
|
@@ -290,7 +331,7 @@ Underlying error: ${detail}`
|
|
|
290
331
|
);
|
|
291
332
|
}
|
|
292
333
|
const backupPath = backupPathFor(dbPath);
|
|
293
|
-
|
|
334
|
+
fs4.renameSync(dbPath, backupPath);
|
|
294
335
|
process.stderr.write(
|
|
295
336
|
`Database at ${dbPath} failed its integrity check. Backup saved at ${backupPath}, starting fresh.
|
|
296
337
|
`
|
|
@@ -303,12 +344,12 @@ Underlying error: ${detail}`
|
|
|
303
344
|
return db;
|
|
304
345
|
}
|
|
305
346
|
function getDatabasePath(platform) {
|
|
306
|
-
return
|
|
347
|
+
return path4.join(DATA_DIR, `${platform}.db`);
|
|
307
348
|
}
|
|
308
349
|
function getDatabaseSize(platform) {
|
|
309
350
|
const dbPath = getDatabasePath(platform);
|
|
310
|
-
if (!
|
|
311
|
-
const stats =
|
|
351
|
+
if (!fs4.existsSync(dbPath)) return "0 B";
|
|
352
|
+
const stats = fs4.statSync(dbPath);
|
|
312
353
|
const bytes = stats.size;
|
|
313
354
|
if (bytes < 1024) return `${bytes} B`;
|
|
314
355
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -444,16 +485,16 @@ function countRecords(db, model) {
|
|
|
444
485
|
}
|
|
445
486
|
function deleteDatabase(platform) {
|
|
446
487
|
const dbPath = getDatabasePath(platform);
|
|
447
|
-
if (
|
|
448
|
-
if (
|
|
449
|
-
if (
|
|
488
|
+
if (fs4.existsSync(dbPath)) fs4.unlinkSync(dbPath);
|
|
489
|
+
if (fs4.existsSync(dbPath + "-wal")) fs4.unlinkSync(dbPath + "-wal");
|
|
490
|
+
if (fs4.existsSync(dbPath + "-shm")) fs4.unlinkSync(dbPath + "-shm");
|
|
450
491
|
}
|
|
451
492
|
|
|
452
493
|
// src/lib/memory/sync/mem-writer.ts
|
|
453
|
-
function resolveWildcardPath(root,
|
|
454
|
-
const segments =
|
|
494
|
+
function resolveWildcardPath(root, path6) {
|
|
495
|
+
const segments = path6.split("[]");
|
|
455
496
|
if (segments.length === 1) {
|
|
456
|
-
return [getByDotPath(root,
|
|
497
|
+
return [getByDotPath(root, path6)];
|
|
457
498
|
}
|
|
458
499
|
const recurse = (value, idx) => {
|
|
459
500
|
if (value === null || value === void 0) return [];
|
|
@@ -479,8 +520,8 @@ function resolveWildcardPath(root, path5) {
|
|
|
479
520
|
function extractSearchableFromPaths(record, paths) {
|
|
480
521
|
const parts = [];
|
|
481
522
|
const perPath = [];
|
|
482
|
-
for (const
|
|
483
|
-
const values = resolveWildcardPath(record,
|
|
523
|
+
for (const path6 of paths) {
|
|
524
|
+
const values = resolveWildcardPath(record, path6);
|
|
484
525
|
const collected = [];
|
|
485
526
|
const absorb = (v) => {
|
|
486
527
|
if (v === null || v === void 0) return;
|
|
@@ -496,9 +537,9 @@ function extractSearchableFromPaths(record, paths) {
|
|
|
496
537
|
for (const v of values) absorb(v);
|
|
497
538
|
if (collected.length > 0) {
|
|
498
539
|
parts.push(...collected);
|
|
499
|
-
perPath.push({ path:
|
|
540
|
+
perPath.push({ path: path6, found: true, sample: collected.join(" ").slice(0, 80) });
|
|
500
541
|
} else {
|
|
501
|
-
perPath.push({ path:
|
|
542
|
+
perPath.push({ path: path6, found: false, sample: "" });
|
|
502
543
|
}
|
|
503
544
|
}
|
|
504
545
|
const text = parts.join(" ").replace(/\s+/g, " ").trim();
|
|
@@ -616,9 +657,9 @@ function deriveFields(record, derive) {
|
|
|
616
657
|
const out = {};
|
|
617
658
|
if (!derive) return out;
|
|
618
659
|
for (const [field, spec] of Object.entries(derive)) {
|
|
619
|
-
const { path:
|
|
620
|
-
if (!
|
|
621
|
-
const values = resolveIdentityPath(record,
|
|
660
|
+
const { path: path6, extract } = typeof spec === "string" ? { path: spec, extract: void 0 } : spec;
|
|
661
|
+
if (!path6) continue;
|
|
662
|
+
const values = resolveIdentityPath(record, path6).filter((v) => v !== null && v !== void 0 && typeof v !== "object");
|
|
622
663
|
if (values.length === 0) continue;
|
|
623
664
|
if (extract === "email") {
|
|
624
665
|
const emails = values.flatMap((v) => identityValuesFor("email", v));
|
|
@@ -630,11 +671,11 @@ function deriveFields(record, derive) {
|
|
|
630
671
|
}
|
|
631
672
|
return out;
|
|
632
673
|
}
|
|
633
|
-
function tokenizeIdentityPath(
|
|
674
|
+
function tokenizeIdentityPath(path6) {
|
|
634
675
|
const tokens = [];
|
|
635
676
|
const re = /([^.[\]]+)|\[([^\]]*)\]/g;
|
|
636
677
|
let m;
|
|
637
|
-
while ((m = re.exec(
|
|
678
|
+
while ((m = re.exec(path6)) !== null) {
|
|
638
679
|
if (m[1] !== void 0) {
|
|
639
680
|
tokens.push({ type: "field", name: m[1] });
|
|
640
681
|
} else {
|
|
@@ -653,9 +694,9 @@ function tokenizeIdentityPath(path5) {
|
|
|
653
694
|
}
|
|
654
695
|
return tokens;
|
|
655
696
|
}
|
|
656
|
-
function resolveIdentityPath(root,
|
|
697
|
+
function resolveIdentityPath(root, path6) {
|
|
657
698
|
let frontier = [root];
|
|
658
|
-
for (const tok of tokenizeIdentityPath(
|
|
699
|
+
for (const tok of tokenizeIdentityPath(path6)) {
|
|
659
700
|
const next = [];
|
|
660
701
|
for (const cur of frontier) {
|
|
661
702
|
if (cur === null || cur === void 0) continue;
|
|
@@ -683,10 +724,10 @@ function resolveIdentityPath(root, path5) {
|
|
|
683
724
|
}
|
|
684
725
|
return frontier;
|
|
685
726
|
}
|
|
686
|
-
function keysForEntry(record, prefix,
|
|
687
|
-
if (!prefix || !
|
|
727
|
+
function keysForEntry(record, prefix, path6) {
|
|
728
|
+
if (!prefix || !path6) return [];
|
|
688
729
|
const out = [];
|
|
689
|
-
for (const raw of resolveIdentityPath(record,
|
|
730
|
+
for (const raw of resolveIdentityPath(record, path6)) {
|
|
690
731
|
for (const value of identityValuesFor(prefix, raw)) out.push(`${prefix}:${value}`);
|
|
691
732
|
}
|
|
692
733
|
return out;
|
|
@@ -926,10 +967,10 @@ async function memMigrateCommand(flags) {
|
|
|
926
967
|
}
|
|
927
968
|
}
|
|
928
969
|
}
|
|
929
|
-
const dataDir =
|
|
970
|
+
const dataDir = path5.join(".one", "sync", "data");
|
|
930
971
|
let cleanupFiles = [];
|
|
931
|
-
if (flags.cleanup &&
|
|
932
|
-
cleanupFiles =
|
|
972
|
+
if (flags.cleanup && fs5.existsSync(dataDir)) {
|
|
973
|
+
cleanupFiles = fs5.readdirSync(dataDir).map((f) => path5.join(dataDir, f));
|
|
933
974
|
}
|
|
934
975
|
let cleanupDeleted = false;
|
|
935
976
|
if (flags.cleanup) {
|
|
@@ -943,7 +984,7 @@ async function memMigrateCommand(flags) {
|
|
|
943
984
|
} else {
|
|
944
985
|
for (const full of cleanupFiles) {
|
|
945
986
|
try {
|
|
946
|
-
|
|
987
|
+
fs5.unlinkSync(full);
|
|
947
988
|
} catch {
|
|
948
989
|
}
|
|
949
990
|
}
|
|
@@ -1056,12 +1097,12 @@ function reviveStringifiedJson(row) {
|
|
|
1056
1097
|
}
|
|
1057
1098
|
function isBuiltinNewerThanInstalled(platform, model) {
|
|
1058
1099
|
try {
|
|
1059
|
-
const installed =
|
|
1060
|
-
if (!
|
|
1061
|
-
const installedStat =
|
|
1100
|
+
const installed = path5.join(".one", "sync", "profiles", `${platform}_${model}.json`);
|
|
1101
|
+
if (!fs5.existsSync(installed)) return void 0;
|
|
1102
|
+
const installedStat = fs5.statSync(installed);
|
|
1062
1103
|
const builtinPath = resolveBuiltinProfilePath(platform, model);
|
|
1063
1104
|
if (!builtinPath) return void 0;
|
|
1064
|
-
const builtinStat =
|
|
1105
|
+
const builtinStat = fs5.statSync(builtinPath);
|
|
1065
1106
|
return builtinStat.mtimeMs > installedStat.mtimeMs;
|
|
1066
1107
|
} catch {
|
|
1067
1108
|
return void 0;
|
|
@@ -1070,11 +1111,13 @@ function isBuiltinNewerThanInstalled(platform, model) {
|
|
|
1070
1111
|
function resolveBuiltinProfilePath(platform, model) {
|
|
1071
1112
|
const dir = getProfilesDir();
|
|
1072
1113
|
if (!dir) return null;
|
|
1073
|
-
const candidate =
|
|
1074
|
-
return
|
|
1114
|
+
const candidate = path5.join(dir, platform, `${model}.json`);
|
|
1115
|
+
return fs5.existsSync(candidate) ? candidate : null;
|
|
1075
1116
|
}
|
|
1076
1117
|
|
|
1077
1118
|
export {
|
|
1119
|
+
assertSafeSyncNames,
|
|
1120
|
+
ensureDirInsideProject,
|
|
1078
1121
|
readProfile,
|
|
1079
1122
|
writeProfile,
|
|
1080
1123
|
resolveProfileConnectionKey,
|
|
@@ -7,12 +7,13 @@ import {
|
|
|
7
7
|
listFlows,
|
|
8
8
|
loadFlow,
|
|
9
9
|
loadFlowWithMeta,
|
|
10
|
+
persistableState,
|
|
10
11
|
resolveFlowPath,
|
|
11
12
|
saveFlow,
|
|
12
13
|
stripStepsAlias,
|
|
13
14
|
summarizeFlowInputs,
|
|
14
15
|
walkSteps
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-33KUKSRH.js";
|
|
16
17
|
import "./chunk-44CV5IMX.js";
|
|
17
18
|
import "./chunk-Q6PWTATS.js";
|
|
18
19
|
import "./chunk-XUAUDMQE.js";
|
|
@@ -25,6 +26,7 @@ export {
|
|
|
25
26
|
listFlows,
|
|
26
27
|
loadFlow,
|
|
27
28
|
loadFlowWithMeta,
|
|
29
|
+
persistableState,
|
|
28
30
|
resolveFlowPath,
|
|
29
31
|
saveFlow,
|
|
30
32
|
stripStepsAlias,
|