@tenonhq/sincronia-core 0.0.82 → 0.0.83
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/allScopesCommands.js +4 -4
- package/dist/appUtils.js +69 -19
- package/dist/updateSetCommands.js +3 -3
- package/package.json +2 -2
|
@@ -90,7 +90,7 @@ async function processManifestForScope(manifest, sourceDirectory, forceWrite = f
|
|
|
90
90
|
const recordDirName = record.name || recordName;
|
|
91
91
|
const recordPath = path.join(tablePath, recordDirName);
|
|
92
92
|
// Check if metadata file exists in the files from server
|
|
93
|
-
const hasMetadataFromServer = record.files
|
|
93
|
+
const hasMetadataFromServer = record.files && record.files.some((f) => f.name === 'metaData' && f.type === 'json');
|
|
94
94
|
// Ensure the record directory exists
|
|
95
95
|
await fsp.mkdir(recordPath, { recursive: true });
|
|
96
96
|
// Process each file in the record
|
|
@@ -243,7 +243,7 @@ async function processScope(scopeName, scopeConfig, apiDelay = 0) {
|
|
|
243
243
|
}
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
|
-
const tableCount = Object.keys(manifest
|
|
246
|
+
const tableCount = Object.keys((manifest && manifest.tables) || {}).length;
|
|
247
247
|
Logger_1.logger.info("Writing " + tableCount + " tables for " + scopeName + "...");
|
|
248
248
|
await processManifestForScope(manifest, sourceDirectory, true);
|
|
249
249
|
// Create the scope-specific manifest structure
|
|
@@ -325,8 +325,8 @@ async function initScopesCommand(args) {
|
|
|
325
325
|
}
|
|
326
326
|
else {
|
|
327
327
|
failCount++;
|
|
328
|
-
const error = result.status === "rejected" ? result.reason : result.value
|
|
329
|
-
Logger_1.logger.error(`Failed to process ${scopeName}: ${error
|
|
328
|
+
const error = result.status === "rejected" ? result.reason : (result.value && result.value.error);
|
|
329
|
+
Logger_1.logger.error(`Failed to process ${scopeName}: ${(error && error.message) || "Unknown error"}`);
|
|
330
330
|
}
|
|
331
331
|
});
|
|
332
332
|
// Write per-scope manifest files instead of a single combined one
|
package/dist/appUtils.js
CHANGED
|
@@ -61,19 +61,46 @@ const getUpdateSetConfig = () => {
|
|
|
61
61
|
}
|
|
62
62
|
return {};
|
|
63
63
|
};
|
|
64
|
+
// Merge _lastUpdatedOn into the server-provided metadata content. Preserves all
|
|
65
|
+
// record fields (sys_id, sys_scope, field value/display_value pairs, etc.) so
|
|
66
|
+
// the local metaData.json is a full snapshot of the record, not just a stub.
|
|
67
|
+
const stampMetadataContent = (file) => {
|
|
68
|
+
if (file.name !== "metaData" || file.type !== "json")
|
|
69
|
+
return file;
|
|
70
|
+
const stamp = new Date().toISOString();
|
|
71
|
+
if (!file.content) {
|
|
72
|
+
return { ...file, content: JSON.stringify({ _lastUpdatedOn: stamp }, null, 2) };
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const metadata = JSON.parse(file.content);
|
|
76
|
+
if (metadata.sys_updated_on && metadata.sys_updated_on.value) {
|
|
77
|
+
metadata._lastUpdatedOn = metadata.sys_updated_on.value;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
metadata._lastUpdatedOn = stamp;
|
|
81
|
+
}
|
|
82
|
+
return { ...file, content: JSON.stringify(metadata, null, 2) };
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
// Content isn't JSON — leave as-is, it will be written verbatim.
|
|
86
|
+
return file;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const hasServerMetadata = (files) => files.some((f) => f.name === "metaData" && f.type === "json" && !!f.content);
|
|
64
90
|
const processFilesInManRec = async (recPath, rec, forceWrite) => {
|
|
65
91
|
FileLogger_1.fileLogger.debug("Processing record: " + rec.name + " (" + rec.files.length + " files)");
|
|
66
92
|
const fileWrite = fUtils.writeSNFileCurry(forceWrite);
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
93
|
+
// If the server did not provide a metadata file, fall back to a timestamp-only
|
|
94
|
+
// stub so the record directory always has a metaData.json.
|
|
95
|
+
if (!hasServerMetadata(rec.files)) {
|
|
96
|
+
const stubMetadata = {
|
|
97
|
+
name: "metaData",
|
|
98
|
+
type: "json",
|
|
99
|
+
content: JSON.stringify({ _lastUpdatedOn: new Date().toISOString() }, null, 2),
|
|
100
|
+
};
|
|
101
|
+
await fileWrite(stubMetadata, recPath);
|
|
102
|
+
}
|
|
103
|
+
const writeResults = await (0, genericUtils_1.allSettledBatched)(rec.files, constants_1.CONCURRENCY_FILES, function (file) { return fileWrite(stampMetadataContent(file), recPath); });
|
|
77
104
|
const writeFailures = writeResults.filter((r) => r.status === "rejected");
|
|
78
105
|
if (writeFailures.length > 0) {
|
|
79
106
|
writeFailures.forEach((f) => {
|
|
@@ -461,7 +488,22 @@ const refreshAllFiles = async (newManifest, sourcePath, options = {}) => {
|
|
|
461
488
|
await (0, genericUtils_1.processBatched)(recKeys, constants_1.CONCURRENCY_RECORDS, async function (recKey) {
|
|
462
489
|
var rec = recs[recKey];
|
|
463
490
|
var recPath = path_1.default.join(tablePath, rec.name);
|
|
464
|
-
|
|
491
|
+
// Split server-provided metadata off from the regular files so we can
|
|
492
|
+
// track whether any regular file actually changed — metaData shouldn't
|
|
493
|
+
// be the trigger for "this record changed" since we stamp it on every
|
|
494
|
+
// touch.
|
|
495
|
+
var metadataFiles = [];
|
|
496
|
+
var regularFiles = [];
|
|
497
|
+
for (var mi = 0; mi < rec.files.length; mi++) {
|
|
498
|
+
var rf = rec.files[mi];
|
|
499
|
+
if (rf.name === "metaData" && rf.type === "json") {
|
|
500
|
+
metadataFiles.push(rf);
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
regularFiles.push(rf);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
var results = await (0, genericUtils_1.allSettledBatched)(regularFiles, constants_1.CONCURRENCY_FILES, async function (file) {
|
|
465
507
|
if (forceWrite) {
|
|
466
508
|
await forceWriter(file, recPath);
|
|
467
509
|
return true;
|
|
@@ -483,15 +525,23 @@ const refreshAllFiles = async (newManifest, sourcePath, options = {}) => {
|
|
|
483
525
|
unchangedCount++;
|
|
484
526
|
}
|
|
485
527
|
}
|
|
486
|
-
// Only touch metaData when at least one file in the record
|
|
487
|
-
// changed. Avoids rewriting _lastUpdatedOn for records that
|
|
488
|
-
// already in sync with the instance.
|
|
528
|
+
// Only touch metaData when at least one regular file in the record
|
|
529
|
+
// actually changed. Avoids rewriting _lastUpdatedOn for records that
|
|
530
|
+
// were already in sync with the instance. Prefer the server-provided
|
|
531
|
+
// metadata (full field snapshot) over a stub; fall back to a stub only
|
|
532
|
+
// when the server didn't send metadata at all.
|
|
489
533
|
if (anyChanged || forceWrite) {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
534
|
+
let metadataFile;
|
|
535
|
+
if (metadataFiles.length > 0 && metadataFiles[0].content) {
|
|
536
|
+
metadataFile = stampMetadataContent(metadataFiles[0]);
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
metadataFile = {
|
|
540
|
+
name: "metaData",
|
|
541
|
+
type: "json",
|
|
542
|
+
content: JSON.stringify({ _lastUpdatedOn: new Date().toISOString() }, null, 2),
|
|
543
|
+
};
|
|
544
|
+
}
|
|
495
545
|
await forceWriter(metadataFile, recPath);
|
|
496
546
|
}
|
|
497
547
|
// Strip content from manifest entries to keep memory bounded.
|
|
@@ -283,7 +283,7 @@ async function switchUpdateSetCommand(args) {
|
|
|
283
283
|
// Extract the actual values from display_value objects
|
|
284
284
|
const sysId = typeof targetUpdateSet.sys_id === 'object' && targetUpdateSet.sys_id !== null ? targetUpdateSet.sys_id.value : targetUpdateSet.sys_id;
|
|
285
285
|
const name = typeof targetUpdateSet.name === 'object' && targetUpdateSet.name !== null ? targetUpdateSet.name.value : targetUpdateSet.name;
|
|
286
|
-
const applicationName = targetUpdateSet.application
|
|
286
|
+
const applicationName = (targetUpdateSet.application && targetUpdateSet.application.display_value) || (typeof targetUpdateSet.application === 'object' && targetUpdateSet.application !== null ? targetUpdateSet.application.value : targetUpdateSet.application);
|
|
287
287
|
const applicationScope = typeof targetUpdateSet.application === 'object' && targetUpdateSet.application !== null ? targetUpdateSet.application.value : targetUpdateSet.application;
|
|
288
288
|
// Switch to the selected update set
|
|
289
289
|
await switchToUpdateSet(sysId, name, args.scope || applicationScope);
|
|
@@ -334,7 +334,7 @@ async function listUpdateSetsCommand(args) {
|
|
|
334
334
|
const name = typeof updateSet.name === 'object' && updateSet.name !== null ? updateSet.name.value : updateSet.name;
|
|
335
335
|
const description = typeof updateSet.description === 'object' && updateSet.description !== null ? updateSet.description.value : updateSet.description;
|
|
336
336
|
const createdBy = typeof updateSet.sys_created_by === 'object' && updateSet.sys_created_by !== null ? updateSet.sys_created_by.display_value || updateSet.sys_created_by.value : updateSet.sys_created_by;
|
|
337
|
-
const applicationName = updateSet.application
|
|
337
|
+
const applicationName = (updateSet.application && updateSet.application.display_value) || (typeof updateSet.application === 'object' && updateSet.application !== null ? updateSet.application.value : updateSet.application);
|
|
338
338
|
const isCurrent = sysId === currentUpdateSetId;
|
|
339
339
|
const marker = isCurrent ? chalk_1.default.green("► ") : " ";
|
|
340
340
|
const displayName = isCurrent ? chalk_1.default.green(name) : name;
|
|
@@ -616,7 +616,7 @@ async function selectUpdateSet(nameFilter, scopeFilter) {
|
|
|
616
616
|
const choices = filteredSets.map(us => {
|
|
617
617
|
const name = typeof us.name === 'object' && us.name !== null ? us.name.value : us.name;
|
|
618
618
|
const description = typeof us.description === 'object' && us.description !== null ? us.description.value : us.description;
|
|
619
|
-
const applicationName = us.application
|
|
619
|
+
const applicationName = (us.application && us.application.display_value) || (typeof us.application === 'object' && us.application !== null ? us.application.value : us.application);
|
|
620
620
|
return {
|
|
621
621
|
name: `${name}${applicationName ? ` (${applicationName})` : ""} - ${description || "No description"}`,
|
|
622
622
|
value: us
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenonhq/sincronia-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.83",
|
|
4
4
|
"description": "Next-gen file syncer",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"typescript": "^5.2.2"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@tenonhq/sincronia-clickup": "^0.0.
|
|
41
|
+
"@tenonhq/sincronia-clickup": "^0.0.6",
|
|
42
42
|
"@tenonhq/sincronia-schema": "^0.0.1",
|
|
43
43
|
"axios": "^1.5.1",
|
|
44
44
|
"axios-cookiejar-support": "^4.0.7",
|