@tenonhq/sincronia-core 0.0.63 → 0.0.64

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.
@@ -120,13 +120,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
120
120
  return fullMessage;
121
121
  }
122
122
  /**
123
- * Debug level logging - replaces console.log
123
+ * Debug level logging - file only, no console output
124
124
  */
125
125
  debug(message, ...args) {
126
126
  const formattedMessage = this.formatMessage('DEBUG', message, ...args);
127
- // Write to console (preserving original console.log behavior)
128
- console.log(message, ...args);
129
- // Write to file
130
127
  this.writeToFile(`[DEBUG] ${formattedMessage}`);
131
128
  }
132
129
  /**
package/dist/FileUtils.js CHANGED
@@ -63,86 +63,51 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
63
63
  };
64
64
  exports.SNFileExists = SNFileExists;
65
65
  const writeManifestFile = async (man, scope) => {
66
- FileLogger_1.fileLogger.debug('\n--- writeManifestFile DEBUG ---');
67
- FileLogger_1.fileLogger.debug('Scope:', scope || 'No scope (legacy)');
68
66
  if (scope) {
69
- // Write scope-specific manifest
70
67
  const manifestPath = ConfigManager.getScopeManifestPath(scope);
71
- FileLogger_1.fileLogger.debug('Writing scope-specific manifest to:', manifestPath);
68
+ FileLogger_1.fileLogger.debug("Writing manifest for scope " + scope + " to " + manifestPath);
72
69
  return fs_1.promises.writeFile(manifestPath, JSON.stringify(man, null, 2));
73
70
  }
74
- // Write legacy single manifest
75
71
  const manifestPath = ConfigManager.getManifestPath();
76
- FileLogger_1.fileLogger.debug('Writing legacy manifest to:', manifestPath);
72
+ FileLogger_1.fileLogger.debug("Writing manifest to " + manifestPath);
77
73
  return fs_1.promises.writeFile(manifestPath, JSON.stringify(man, null, 2));
78
74
  };
79
75
  exports.writeManifestFile = writeManifestFile;
80
76
  const writeScopeManifest = async (scope, man) => {
81
77
  const manifestPath = ConfigManager.getScopeManifestPath(scope);
82
- FileLogger_1.fileLogger.debug('\n--- writeScopeManifest DEBUG ---');
83
- FileLogger_1.fileLogger.debug('Scope:', scope);
84
- FileLogger_1.fileLogger.debug('Manifest path:', manifestPath);
85
- FileLogger_1.fileLogger.debug('--- writeScopeManifest DEBUG END ---\n');
78
+ FileLogger_1.fileLogger.debug("Writing scope manifest: " + scope + " -> " + manifestPath);
86
79
  return fs_1.promises.writeFile(manifestPath, JSON.stringify(man, null, 2));
87
80
  };
88
81
  exports.writeScopeManifest = writeScopeManifest;
89
82
  const writeSNFileCurry = (checkExists) => async (file, parentPath) => {
90
- FileLogger_1.fileLogger.debug('\n--- writeSNFileCurry DEBUG ---');
91
- FileLogger_1.fileLogger.debug('Check exists:', checkExists);
92
- FileLogger_1.fileLogger.debug('Parent path:', parentPath);
93
- FileLogger_1.fileLogger.debug('File to write:', {
94
- name: file.name,
95
- type: file.type,
96
- hasContent: !!file.content,
97
- contentLength: file.content ? file.content.length : 0
98
- });
99
83
  let { name, type, content = "" } = file;
100
- // content can sometimes be null
101
84
  if (!content) {
102
- FileLogger_1.fileLogger.debug('Content is null/undefined, using empty string');
103
85
  content = "";
104
86
  }
105
87
  const fullPath = path_1.default.join(parentPath, `${name}.${type}`);
106
- FileLogger_1.fileLogger.debug('Full file path:', fullPath);
107
- // Special logging for metadata files
108
- if (name.toLowerCase().includes('metadata') || name.toLowerCase() === 'metadata') {
109
- FileLogger_1.fileLogger.debug('*** METADATA FILE DETECTED ***');
110
- FileLogger_1.fileLogger.debug(' Name:', name);
111
- FileLogger_1.fileLogger.debug(' Type:', type);
112
- FileLogger_1.fileLogger.debug(' Path:', fullPath);
113
- FileLogger_1.fileLogger.debug(' Content preview:', content ? content.substring(0, 100) : 'NO CONTENT');
114
- }
115
88
  const write = async () => {
116
- FileLogger_1.fileLogger.debug(`Writing file: ${fullPath}`);
89
+ FileLogger_1.fileLogger.debug("Writing: " + fullPath);
117
90
  try {
118
91
  const result = await fs_1.promises.writeFile(fullPath, content);
119
- FileLogger_1.fileLogger.debug(`✓ File written successfully: ${fullPath}`);
120
- // Verify metaData.json was actually written
121
- if (name.toLowerCase() === 'metadata' && type === 'json') {
122
- const exists = await fs_1.promises.access(fullPath).then(() => true).catch(() => false);
123
- FileLogger_1.fileLogger.debug(`*** METADATA FILE VERIFICATION: File exists on disk = ${exists} ***`);
124
- }
125
92
  return result;
126
93
  }
127
94
  catch (error) {
128
- FileLogger_1.fileLogger.error(`✗ ERROR writing file ${fullPath}:`, error);
95
+ FileLogger_1.fileLogger.error("Failed to write " + fullPath + ":", error);
129
96
  throw error;
130
97
  }
131
98
  };
132
99
  if (checkExists) {
133
100
  const exists = await (0, exports.SNFileExists)(parentPath)(file);
134
- FileLogger_1.fileLogger.debug(`File exists check: ${exists}`);
135
101
  if (!exists) {
136
102
  await write();
137
103
  }
138
104
  else {
139
- FileLogger_1.fileLogger.debug(`File already exists, skipping: ${fullPath}`);
105
+ FileLogger_1.fileLogger.debug("Skipped (exists): " + fullPath);
140
106
  }
141
107
  }
142
108
  else {
143
109
  await write();
144
110
  }
145
- FileLogger_1.fileLogger.debug('--- writeSNFileCurry DEBUG END ---\n');
146
111
  };
147
112
  exports.writeSNFileCurry = writeSNFileCurry;
148
113
  const createDirRecursively = async (path) => {
@@ -40,7 +40,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
40
40
  if (v !== undefined) module.exports = v;
41
41
  }
42
42
  else if (typeof define === "function" && define.amd) {
43
- define(["require", "exports", "chokidar", "./logMessages", "lodash", "./FileUtils", "./appUtils", "./Logger", "path", "./config"], factory);
43
+ define(["require", "exports", "chokidar", "./logMessages", "lodash", "./FileUtils", "./appUtils", "./recentEdits", "./Logger", "path", "fs", "./config"], factory);
44
44
  }
45
45
  })(function (require, exports) {
46
46
  "use strict";
@@ -54,13 +54,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
54
54
  const lodash_1 = require("lodash");
55
55
  const FileUtils_1 = require("./FileUtils");
56
56
  const appUtils_1 = require("./appUtils");
57
+ const recentEdits_1 = require("./recentEdits");
57
58
  const Logger_1 = require("./Logger");
58
59
  const path = __importStar(require("path"));
60
+ const fs = __importStar(require("fs"));
59
61
  const ConfigManager = __importStar(require("./config"));
60
62
  const DEBOUNCE_MS = 300;
61
63
  class MultiScopeWatcherManager {
62
64
  scopeWatchers = new Map();
63
65
  updateSetCheckInterval = null;
66
+ scopeLock = Promise.resolve();
64
67
  async startWatchingAllScopes() {
65
68
  try {
66
69
  // Load configuration
@@ -131,6 +134,116 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
131
134
  });
132
135
  this.scopeWatchers.set(scopeName, scopeWatcher);
133
136
  }
137
+ async withScopeLock(fn) {
138
+ var resolve;
139
+ var next = new Promise(function (r) { resolve = r; });
140
+ var prev = this.scopeLock;
141
+ this.scopeLock = next;
142
+ await prev;
143
+ try {
144
+ return await fn();
145
+ }
146
+ finally {
147
+ resolve();
148
+ }
149
+ }
150
+ getUpdateSetConfig() {
151
+ var configPath = path.resolve(process.cwd(), ".sinc-update-sets.json");
152
+ try {
153
+ if (fs.existsSync(configPath)) {
154
+ return JSON.parse(fs.readFileSync(configPath, "utf8"));
155
+ }
156
+ }
157
+ catch (e) {
158
+ // Ignore parse errors
159
+ }
160
+ return {};
161
+ }
162
+ readActiveTask() {
163
+ var taskPath = path.resolve(process.cwd(), ".sinc-active-task.json");
164
+ try {
165
+ if (fs.existsSync(taskPath)) {
166
+ return JSON.parse(fs.readFileSync(taskPath, "utf8"));
167
+ }
168
+ }
169
+ catch (e) {
170
+ // Ignore parse errors
171
+ }
172
+ return null;
173
+ }
174
+ saveUpdateSetConfig(config) {
175
+ var configPath = path.resolve(process.cwd(), ".sinc-update-sets.json");
176
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
177
+ }
178
+ async ensureUpdateSetForScope(scopeName) {
179
+ var config = this.getUpdateSetConfig();
180
+ if (config[scopeName]) {
181
+ return; // Already has an update set mapped
182
+ }
183
+ var activeTask = this.readActiveTask();
184
+ if (!activeTask) {
185
+ Logger_1.logger.warn(`[${scopeName}] No update set configured and no active task to auto-create one. Pushing without update set routing.`);
186
+ return;
187
+ }
188
+ var taskId = activeTask.taskId;
189
+ var updateSetName = activeTask.updateSetName;
190
+ var description = activeTask.description || "";
191
+ Logger_1.logger.info(`[${scopeName}] No update set found — auto-creating for task CU-${taskId}...`);
192
+ try {
193
+ var { defaultClient, unwrapSNResponse } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./snClient"))) : new Promise((resolve_1, reject_1) => { require(["./snClient"], resolve_1, reject_1); }).then(__importStar));
194
+ var client = defaultClient();
195
+ // Switch to the target scope before creating
196
+ await client.changeScope(scopeName);
197
+ // Search for an existing update set matching this task in this scope
198
+ var query = "application.scope=" + scopeName +
199
+ "^nameLIKECU-" + taskId +
200
+ "^state=in progress" +
201
+ "^ORDERBYDESCsys_created_on";
202
+ var searchResp = await client.client.get("api/now/table/sys_update_set", {
203
+ params: {
204
+ sysparm_query: query,
205
+ sysparm_fields: "sys_id,name,state,application,sys_created_on",
206
+ sysparm_limit: "10",
207
+ },
208
+ });
209
+ var existing = (searchResp.data && searchResp.data.result) || [];
210
+ var updateSet = null;
211
+ if (existing.length > 0) {
212
+ updateSet = { sys_id: existing[0].sys_id, name: existing[0].name };
213
+ Logger_1.logger.info(`[${scopeName}] Found existing update set: ${updateSet.name}`);
214
+ }
215
+ else {
216
+ // Create a new one (scope already switched above)
217
+ var createResp = await unwrapSNResponse(client.createUpdateSet(updateSetName, undefined, description));
218
+ updateSet = { sys_id: createResp.sys_id, name: updateSetName };
219
+ Logger_1.logger.info(`[${scopeName}] Auto-created update set: ${updateSet.name}`);
220
+ }
221
+ // Switch the active update set on the instance
222
+ try {
223
+ await client.changeUpdateSet({ sysId: updateSet.sys_id });
224
+ }
225
+ catch (changeErr) {
226
+ Logger_1.logger.warn(`[${scopeName}] Could not auto-switch update set on instance`);
227
+ }
228
+ // Persist the mapping
229
+ config = this.getUpdateSetConfig(); // Re-read in case another scope wrote
230
+ config[scopeName] = { sys_id: updateSet.sys_id, name: updateSet.name };
231
+ this.saveUpdateSetConfig(config);
232
+ // Also update the active task file
233
+ if (activeTask) {
234
+ if (!activeTask.scopes) {
235
+ activeTask.scopes = {};
236
+ }
237
+ activeTask.scopes[scopeName] = { sys_id: updateSet.sys_id, name: updateSet.name };
238
+ var taskPath = path.resolve(process.cwd(), ".sinc-active-task.json");
239
+ fs.writeFileSync(taskPath, JSON.stringify(activeTask, null, 2));
240
+ }
241
+ }
242
+ catch (error) {
243
+ Logger_1.logger.error(`[${scopeName}] Failed to auto-create update set: ${error}`);
244
+ Logger_1.logger.warn(`[${scopeName}] Pushing without update set routing.`);
245
+ }
246
+ }
134
247
  async processScopeQueue(scopeWatcher) {
135
248
  if (scopeWatcher.pushQueue.length === 0)
136
249
  return;
@@ -138,26 +251,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
138
251
  scopeWatcher.pushQueue = [];
139
252
  Logger_1.logger.info(`[${scopeWatcher.scope}] Processing ${toProcess.length} file(s)...`);
140
253
  try {
141
- // First, switch to the correct scope
142
- await this.switchToScope(scopeWatcher.scope);
143
- // Load the manifest for this specific scope
144
- await this.loadScopeManifest(scopeWatcher.scope, scopeWatcher.sourceDirectory);
145
- // Process the files
146
- const fileContexts = toProcess
147
- .map(FileUtils_1.getFileContextFromPath)
148
- .filter((ctx) => !!ctx);
149
- if (fileContexts.length === 0) {
150
- Logger_1.logger.warn(`[${scopeWatcher.scope}] No valid file contexts found`);
151
- return;
152
- }
153
- const buildables = (0, appUtils_1.groupAppFiles)(fileContexts);
154
- const updateResults = await (0, appUtils_1.pushFiles)(buildables);
155
- updateResults.forEach((res, index) => {
156
- if (index < fileContexts.length) {
157
- (0, logMessages_1.logFilePush)(fileContexts[index], res);
254
+ await this.withScopeLock(async () => {
255
+ // First, switch to the correct scope
256
+ await this.switchToScope(scopeWatcher.scope);
257
+ // Ensure an update set exists for this scope
258
+ await this.ensureUpdateSetForScope(scopeWatcher.scope);
259
+ // Load the manifest for this specific scope
260
+ await this.loadScopeManifest(scopeWatcher.scope, scopeWatcher.sourceDirectory);
261
+ // Process the files
262
+ const fileContexts = toProcess
263
+ .map(FileUtils_1.getFileContextFromPath)
264
+ .filter((ctx) => !!ctx);
265
+ if (fileContexts.length === 0) {
266
+ Logger_1.logger.warn(`[${scopeWatcher.scope}] No valid file contexts found`);
267
+ return;
158
268
  }
269
+ const buildables = (0, appUtils_1.groupAppFiles)(fileContexts);
270
+ const updateResults = await (0, appUtils_1.pushFiles)(buildables);
271
+ updateResults.forEach((res, index) => {
272
+ if (index < fileContexts.length) {
273
+ (0, logMessages_1.logFilePush)(fileContexts[index], res);
274
+ if (res.success) {
275
+ (0, recentEdits_1.writeRecentEdit)(fileContexts[index]);
276
+ }
277
+ }
278
+ });
279
+ Logger_1.logger.success(`[${scopeWatcher.scope}] Successfully pushed ${updateResults.length} file(s)`);
159
280
  });
160
- Logger_1.logger.success(`[${scopeWatcher.scope}] Successfully pushed ${updateResults.length} file(s)`);
161
281
  }
162
282
  catch (error) {
163
283
  Logger_1.logger.error(`[${scopeWatcher.scope}] Error processing queue: ${error}`);
@@ -168,7 +288,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
168
288
  // The sourceDirectory is like /path/to/ServiceNow/src/x_cadso_core
169
289
  // We need to go up two levels to get to the ServiceNow directory where manifests are stored
170
290
  const projectRoot = path.dirname(path.dirname(sourceDirectory)); // Go up from src/scope to project root
171
- const fs = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("fs"))) : new Promise((resolve_1, reject_1) => { require(["fs"], resolve_1, reject_1); }).then(__importStar));
291
+ const fs = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("fs"))) : new Promise((resolve_2, reject_2) => { require(["fs"], resolve_2, reject_2); }).then(__importStar));
172
292
  // First try to load scope-specific manifest file
173
293
  const scopeManifestPath = path.join(projectRoot, `sinc.manifest.${scopeName}.json`);
174
294
  if (fs.existsSync(scopeManifestPath)) {
@@ -221,7 +341,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
221
341
  }
222
342
  async switchToScope(scopeName) {
223
343
  try {
224
- const { defaultClient, unwrapSNResponse } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./snClient"))) : new Promise((resolve_2, reject_2) => { require(["./snClient"], resolve_2, reject_2); }).then(__importStar));
344
+ const { defaultClient, unwrapSNResponse } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./snClient"))) : new Promise((resolve_3, reject_3) => { require(["./snClient"], resolve_3, reject_3); }).then(__importStar));
225
345
  const client = defaultClient();
226
346
  // Get the scope ID
227
347
  const scopeResponse = await unwrapSNResponse(client.getScopeId(scopeName));
@@ -260,7 +380,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
260
380
  }
261
381
  async checkAllUpdateSets() {
262
382
  try {
263
- const { defaultClient, unwrapSNResponse } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./snClient"))) : new Promise((resolve_3, reject_3) => { require(["./snClient"], resolve_3, reject_3); }).then(__importStar));
383
+ const { defaultClient, unwrapSNResponse } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./snClient"))) : new Promise((resolve_4, reject_4) => { require(["./snClient"], resolve_4, reject_4); }).then(__importStar));
264
384
  const client = defaultClient();
265
385
  const config = ConfigManager.getConfig();
266
386
  if (!config.scopes)
@@ -315,10 +435,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
315
435
  }
316
436
  async getUpdateSetDetails(updateSetId) {
317
437
  try {
318
- const { defaultClient } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./snClient"))) : new Promise((resolve_4, reject_4) => { require(["./snClient"], resolve_4, reject_4); }).then(__importStar));
438
+ const { defaultClient } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./snClient"))) : new Promise((resolve_5, reject_5) => { require(["./snClient"], resolve_5, reject_5); }).then(__importStar));
319
439
  const client = defaultClient();
320
440
  // Create axios client directly to get update set details
321
- const axios = (await (__syncRequire ? Promise.resolve().then(() => __importStar(require("axios"))) : new Promise((resolve_5, reject_5) => { require(["axios"], resolve_5, reject_5); }).then(__importStar))).default;
441
+ const axios = (await (__syncRequire ? Promise.resolve().then(() => __importStar(require("axios"))) : new Promise((resolve_6, reject_6) => { require(["axios"], resolve_6, reject_6); }).then(__importStar))).default;
322
442
  const { SN_USER = "", SN_PASSWORD = "", SN_INSTANCE = "" } = process.env;
323
443
  const axiosClient = axios.create({
324
444
  auth: {
package/dist/Watcher.js CHANGED
@@ -7,7 +7,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
7
7
  if (v !== undefined) module.exports = v;
8
8
  }
9
9
  else if (typeof define === "function" && define.amd) {
10
- define(["require", "exports", "chokidar", "./logMessages", "./Logger", "lodash", "./FileUtils", "./appUtils"], factory);
10
+ define(["require", "exports", "chokidar", "./logMessages", "./Logger", "lodash", "./FileUtils", "./appUtils", "./recentEdits"], factory);
11
11
  }
12
12
  })(function (require, exports) {
13
13
  "use strict";
@@ -20,6 +20,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
20
20
  const lodash_1 = require("lodash");
21
21
  const FileUtils_1 = require("./FileUtils");
22
22
  const appUtils_1 = require("./appUtils");
23
+ const recentEdits_1 = require("./recentEdits");
23
24
  const DEBOUNCE_MS = 300;
24
25
  let pushQueue = [];
25
26
  let watcher = undefined;
@@ -35,6 +36,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
36
  const updateResults = await (0, appUtils_1.pushFiles)(buildables);
36
37
  updateResults.forEach((res, index) => {
37
38
  (0, logMessages_1.logFilePush)(fileContexts[index], res);
39
+ if (res.success) {
40
+ (0, recentEdits_1.writeRecentEdit)(fileContexts[index]);
41
+ }
38
42
  });
39
43
  }
40
44
  }, DEBOUNCE_MS);
@@ -0,0 +1,54 @@
1
+ (function (factory) {
2
+ if (typeof module === "object" && typeof module.exports === "object") {
3
+ var v = factory(require, exports);
4
+ if (v !== undefined) module.exports = v;
5
+ }
6
+ else if (typeof define === "function" && define.amd) {
7
+ define(["require", "exports"], factory);
8
+ }
9
+ })(function (require, exports) {
10
+ "use strict";
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.tableOptions = exports.scopes = exports.includes = exports.excludes = void 0;
13
+ let excludes = {
14
+ sys_scope_privilege: true,
15
+ sys_dictionary: true,
16
+ sys_impex_entry: true,
17
+ sys_security_acl: true,
18
+ sys_transform_map: true,
19
+ sys_ui_policy: true,
20
+ sys_ui_list_control: true,
21
+ sys_relationship: true,
22
+ sys_report: true,
23
+ item_option_new: true,
24
+ sys_process_flow: true,
25
+ content_block_programmatic: true,
26
+ sp_instance: true,
27
+ sys_transform_script: true,
28
+ sc_category: true,
29
+ sysrule_view: true,
30
+ sc_cat_item: true,
31
+ sysevent_in_email_action: true,
32
+ sys_navigator: true,
33
+ sys_transform_entry: true,
34
+ metric_definition: true,
35
+ content_block_lists: true,
36
+ content_block_detail: true,
37
+ sp_portal: true,
38
+ sc_cat_item_producer: true,
39
+ sys_impex_map: true,
40
+ };
41
+ exports.excludes = excludes;
42
+ let includes = {
43
+ content_css: {
44
+ style: {
45
+ type: "css",
46
+ },
47
+ },
48
+ };
49
+ exports.includes = includes;
50
+ let tableOptions = {};
51
+ exports.tableOptions = tableOptions;
52
+ let scopes = {};
53
+ exports.scopes = scopes;
54
+ });