@tenonhq/sincronia-core 0.0.19 → 0.0.22

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.
@@ -0,0 +1,311 @@
1
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
2
+ if (k2 === undefined) k2 = k;
3
+ var desc = Object.getOwnPropertyDescriptor(m, k);
4
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
5
+ desc = { enumerable: true, get: function() { return m[k]; } };
6
+ }
7
+ Object.defineProperty(o, k2, desc);
8
+ }) : (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ o[k2] = m[k];
11
+ }));
12
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
13
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
14
+ }) : function(o, v) {
15
+ o["default"] = v;
16
+ });
17
+ var __importStar = (this && this.__importStar) || (function () {
18
+ var ownKeys = function(o) {
19
+ ownKeys = Object.getOwnPropertyNames || function (o) {
20
+ var ar = [];
21
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
22
+ return ar;
23
+ };
24
+ return ownKeys(o);
25
+ };
26
+ return function (mod) {
27
+ if (mod && mod.__esModule) return mod;
28
+ var result = {};
29
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
30
+ __setModuleDefault(result, mod);
31
+ return result;
32
+ };
33
+ })();
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ (function (factory) {
38
+ if (typeof module === "object" && typeof module.exports === "object") {
39
+ var v = factory(require, exports);
40
+ if (v !== undefined) module.exports = v;
41
+ }
42
+ else if (typeof define === "function" && define.amd) {
43
+ define(["require", "exports", "chokidar", "./logMessages", "lodash", "./FileUtils", "./appUtils", "./Logger", "path", "./config"], factory);
44
+ }
45
+ })(function (require, exports) {
46
+ "use strict";
47
+ var __syncRequire = typeof module === "object" && typeof module.exports === "object";
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.multiScopeWatcher = void 0;
50
+ exports.startMultiScopeWatching = startMultiScopeWatching;
51
+ exports.stopMultiScopeWatching = stopMultiScopeWatching;
52
+ const chokidar_1 = __importDefault(require("chokidar"));
53
+ const logMessages_1 = require("./logMessages");
54
+ const lodash_1 = require("lodash");
55
+ const FileUtils_1 = require("./FileUtils");
56
+ const appUtils_1 = require("./appUtils");
57
+ const Logger_1 = require("./Logger");
58
+ const path = __importStar(require("path"));
59
+ const ConfigManager = __importStar(require("./config"));
60
+ const DEBOUNCE_MS = 300;
61
+ class MultiScopeWatcherManager {
62
+ constructor() {
63
+ this.scopeWatchers = new Map();
64
+ this.updateSetCheckInterval = null;
65
+ }
66
+ async startWatchingAllScopes() {
67
+ try {
68
+ // Load configuration
69
+ await ConfigManager.loadConfigs();
70
+ const config = ConfigManager.getConfig();
71
+ if (!config.scopes) {
72
+ Logger_1.logger.error("No scopes defined in sinc.config.js");
73
+ throw new Error("No scopes defined in configuration");
74
+ }
75
+ const scopes = Object.keys(config.scopes);
76
+ Logger_1.logger.info(`Starting multi-scope watch for ${scopes.length} scopes: ${scopes.join(", ")}`);
77
+ // Start watching each scope
78
+ for (const scopeName of scopes) {
79
+ const scopeConfig = config.scopes[scopeName];
80
+ let sourceDirectory;
81
+ if (typeof scopeConfig === "object" && scopeConfig.sourceDirectory) {
82
+ sourceDirectory = path.resolve(ConfigManager.getRootDir(), scopeConfig.sourceDirectory);
83
+ }
84
+ else {
85
+ // Default to src/{scope} if no sourceDirectory specified
86
+ sourceDirectory = path.resolve(ConfigManager.getRootDir(), "src", scopeName);
87
+ }
88
+ this.startWatchingScope(scopeName, sourceDirectory);
89
+ }
90
+ // Start periodic update set checking
91
+ this.startUpdateSetMonitoring();
92
+ Logger_1.logger.success("✅ Multi-scope watch started successfully!");
93
+ Logger_1.logger.info("Watching for file changes across all scopes...");
94
+ Logger_1.logger.info("Press Ctrl+C to stop watching\n");
95
+ }
96
+ catch (error) {
97
+ Logger_1.logger.error("Failed to start multi-scope watch: " + error);
98
+ throw error;
99
+ }
100
+ }
101
+ startWatchingScope(scopeName, sourceDirectory) {
102
+ Logger_1.logger.info(`Setting up watcher for scope ${scopeName} in ${sourceDirectory}`);
103
+ const watcher = chokidar_1.default.watch(sourceDirectory, {
104
+ persistent: true,
105
+ ignoreInitial: true,
106
+ awaitWriteFinish: {
107
+ stabilityThreshold: 300,
108
+ pollInterval: 100
109
+ }
110
+ });
111
+ const scopeWatcher = {
112
+ scope: scopeName,
113
+ watcher: watcher,
114
+ pushQueue: [],
115
+ sourceDirectory: sourceDirectory
116
+ };
117
+ // Create a debounced processor for this scope
118
+ const processQueue = (0, lodash_1.debounce)(async () => {
119
+ await this.processScopeQueue(scopeWatcher);
120
+ }, DEBOUNCE_MS);
121
+ watcher.on("change", (filePath) => {
122
+ Logger_1.logger.info(`[${scopeName}] File changed: ${path.relative(sourceDirectory, filePath)}`);
123
+ scopeWatcher.pushQueue.push(filePath);
124
+ processQueue();
125
+ });
126
+ watcher.on("add", (filePath) => {
127
+ Logger_1.logger.info(`[${scopeName}] File added: ${path.relative(sourceDirectory, filePath)}`);
128
+ scopeWatcher.pushQueue.push(filePath);
129
+ processQueue();
130
+ });
131
+ watcher.on("error", (error) => {
132
+ Logger_1.logger.error(`[${scopeName}] Watcher error: ${error.message}`);
133
+ });
134
+ this.scopeWatchers.set(scopeName, scopeWatcher);
135
+ }
136
+ async processScopeQueue(scopeWatcher) {
137
+ if (scopeWatcher.pushQueue.length === 0)
138
+ return;
139
+ const toProcess = Array.from(new Set([...scopeWatcher.pushQueue]));
140
+ scopeWatcher.pushQueue = [];
141
+ Logger_1.logger.info(`[${scopeWatcher.scope}] Processing ${toProcess.length} file(s)...`);
142
+ try {
143
+ // First, switch to the correct scope
144
+ await this.switchToScope(scopeWatcher.scope);
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);
158
+ }
159
+ });
160
+ Logger_1.logger.success(`[${scopeWatcher.scope}] Successfully pushed ${updateResults.length} file(s)`);
161
+ }
162
+ catch (error) {
163
+ Logger_1.logger.error(`[${scopeWatcher.scope}] Error processing queue: ${error}`);
164
+ }
165
+ }
166
+ async switchToScope(scopeName) {
167
+ try {
168
+ const { defaultClient, unwrapSNResponse } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./snClient"))) : new Promise((resolve_1, reject_1) => { require(["./snClient"], resolve_1, reject_1); }).then(__importStar));
169
+ const client = defaultClient();
170
+ // Get the scope ID
171
+ const scopeResponse = await unwrapSNResponse(client.getScopeId(scopeName));
172
+ if (!scopeResponse || !Array.isArray(scopeResponse) || scopeResponse.length === 0 || !scopeResponse[0].sys_id) {
173
+ throw new Error(`Scope ${scopeName} not found`);
174
+ }
175
+ // Get user sys_id
176
+ const userResponse = await unwrapSNResponse(client.getUserSysId());
177
+ if (!userResponse || !Array.isArray(userResponse) || userResponse.length === 0 || !userResponse[0].sys_id) {
178
+ throw new Error("Could not get user sys_id");
179
+ }
180
+ // Get current app preference
181
+ const prefResponse = await unwrapSNResponse(client.getCurrentAppUserPrefSysId(userResponse[0].sys_id));
182
+ if (prefResponse && Array.isArray(prefResponse) && prefResponse.length > 0 && prefResponse[0].sys_id) {
183
+ // Update existing preference
184
+ await client.updateCurrentAppUserPref(scopeResponse[0].sys_id, prefResponse[0].sys_id);
185
+ }
186
+ else {
187
+ // Create new preference
188
+ await client.createCurrentAppUserPref(scopeResponse[0].sys_id, userResponse[0].sys_id);
189
+ }
190
+ Logger_1.logger.debug(`Switched to scope: ${scopeName}`);
191
+ }
192
+ catch (error) {
193
+ Logger_1.logger.error(`Failed to switch to scope ${scopeName}: ${error}`);
194
+ throw error;
195
+ }
196
+ }
197
+ async startUpdateSetMonitoring() {
198
+ // Check update sets immediately on start
199
+ await this.checkAllUpdateSets();
200
+ // Then check every 30 seconds
201
+ this.updateSetCheckInterval = setInterval(async () => {
202
+ await this.checkAllUpdateSets();
203
+ }, 30000);
204
+ }
205
+ async checkAllUpdateSets() {
206
+ try {
207
+ 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));
208
+ const client = defaultClient();
209
+ const config = ConfigManager.getConfig();
210
+ if (!config.scopes)
211
+ return;
212
+ const scopes = Object.keys(config.scopes);
213
+ Logger_1.logger.info("\n" + "=".repeat(60));
214
+ Logger_1.logger.info("Update Set Status Check");
215
+ Logger_1.logger.info("=".repeat(60));
216
+ for (const scopeName of scopes) {
217
+ try {
218
+ // Switch to scope to check its update set
219
+ await this.switchToScope(scopeName);
220
+ // Get user sys_id
221
+ const userResponse = await unwrapSNResponse(client.getUserSysId());
222
+ if (!userResponse || !Array.isArray(userResponse) || userResponse.length === 0 || !userResponse[0].sys_id) {
223
+ Logger_1.logger.warn(`[${scopeName}] Could not get user information`);
224
+ continue;
225
+ }
226
+ // Get current update set preference
227
+ const updateSetPref = await unwrapSNResponse(client.getCurrentUpdateSetUserPref(userResponse[0].sys_id));
228
+ if (updateSetPref && Array.isArray(updateSetPref) && updateSetPref.length > 0 && updateSetPref[0].value) {
229
+ // Get update set details
230
+ const updateSetId = updateSetPref[0].value;
231
+ const updateSetDetails = await this.getUpdateSetDetails(updateSetId);
232
+ if (updateSetDetails) {
233
+ const isDefault = updateSetDetails.name === "Default" ||
234
+ updateSetDetails.name.toLowerCase().includes("default");
235
+ if (isDefault) {
236
+ Logger_1.logger.warn(`⚠️ [${scopeName}] Currently in DEFAULT update set!`);
237
+ }
238
+ else {
239
+ Logger_1.logger.info(`✅ [${scopeName}] Update Set: ${updateSetDetails.name}`);
240
+ }
241
+ }
242
+ else {
243
+ Logger_1.logger.info(`[${scopeName}] Update Set ID: ${updateSetId}`);
244
+ }
245
+ }
246
+ else {
247
+ Logger_1.logger.warn(`⚠️ [${scopeName}] No update set selected or in DEFAULT`);
248
+ }
249
+ }
250
+ catch (error) {
251
+ Logger_1.logger.error(`[${scopeName}] Error checking update set: ${error}`);
252
+ }
253
+ }
254
+ Logger_1.logger.info("=".repeat(60) + "\n");
255
+ }
256
+ catch (error) {
257
+ Logger_1.logger.error(`Error during update set monitoring: ${error}`);
258
+ }
259
+ }
260
+ async getUpdateSetDetails(updateSetId) {
261
+ try {
262
+ const { defaultClient } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./snClient"))) : new Promise((resolve_3, reject_3) => { require(["./snClient"], resolve_3, reject_3); }).then(__importStar));
263
+ const client = defaultClient();
264
+ // Create axios client directly to get update set details
265
+ const axios = (await (__syncRequire ? Promise.resolve().then(() => __importStar(require("axios"))) : new Promise((resolve_4, reject_4) => { require(["axios"], resolve_4, reject_4); }).then(__importStar))).default;
266
+ const { SN_USER = "", SN_PASSWORD = "", SN_INSTANCE = "" } = process.env;
267
+ const axiosClient = axios.create({
268
+ auth: {
269
+ username: SN_USER,
270
+ password: SN_PASSWORD
271
+ },
272
+ baseURL: SN_INSTANCE
273
+ });
274
+ const response = await axiosClient.get(`/api/now/table/sys_update_set/${updateSetId}`, {
275
+ params: {
276
+ sysparm_fields: "name,state,sys_id"
277
+ }
278
+ });
279
+ if (response.data && response.data.result) {
280
+ return response.data.result;
281
+ }
282
+ return null;
283
+ }
284
+ catch (error) {
285
+ Logger_1.logger.debug(`Could not get update set details: ${error}`);
286
+ return null;
287
+ }
288
+ }
289
+ stopWatching() {
290
+ // Stop all scope watchers
291
+ for (const [scopeName, scopeWatcher] of this.scopeWatchers) {
292
+ Logger_1.logger.info(`Stopping watcher for scope: ${scopeName}`);
293
+ scopeWatcher.watcher.close();
294
+ }
295
+ this.scopeWatchers.clear();
296
+ // Stop update set monitoring
297
+ if (this.updateSetCheckInterval) {
298
+ clearInterval(this.updateSetCheckInterval);
299
+ this.updateSetCheckInterval = null;
300
+ }
301
+ Logger_1.logger.info("All watchers stopped");
302
+ }
303
+ }
304
+ exports.multiScopeWatcher = new MultiScopeWatcherManager();
305
+ function startMultiScopeWatching() {
306
+ return exports.multiScopeWatcher.startWatchingAllScopes();
307
+ }
308
+ function stopMultiScopeWatching() {
309
+ exports.multiScopeWatcher.stopWatching();
310
+ }
311
+ });
@@ -37,15 +37,16 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  if (v !== undefined) module.exports = v;
38
38
  }
39
39
  else if (typeof define === "function" && define.amd) {
40
- define(["require", "exports", "./Logger", "./config", "./FileUtils", "./snClient", "./commands", "path", "fs"], factory);
40
+ define(["require", "exports", "./Logger", "./config", "./snClient", "./commands", "path", "fs"], factory);
41
41
  }
42
42
  })(function (require, exports) {
43
43
  "use strict";
44
+ var __syncRequire = typeof module === "object" && typeof module.exports === "object";
44
45
  Object.defineProperty(exports, "__esModule", { value: true });
45
46
  exports.initScopesCommand = initScopesCommand;
47
+ exports.watchAllScopesCommand = watchAllScopesCommand;
46
48
  const Logger_1 = require("./Logger");
47
49
  const ConfigManager = __importStar(require("./config"));
48
- const fUtils = __importStar(require("./FileUtils"));
49
50
  const snClient_1 = require("./snClient");
50
51
  const commands_1 = require("./commands");
51
52
  const path = __importStar(require("path"));
@@ -53,24 +54,62 @@ var __importStar = (this && this.__importStar) || (function () {
53
54
  const fsp = fs.promises;
54
55
  // Custom function to process manifest with specific source directory
55
56
  async function processManifestForScope(manifest, sourceDirectory, forceWrite = false) {
56
- // Process each table in the manifest
57
- const tables = manifest.tables || {};
58
- const tableNames = Object.keys(tables);
59
- for (const tableName of tableNames) {
60
- const tableRecords = tables[tableName];
61
- const tablePath = path.join(sourceDirectory, tableName);
62
- // Process each record in the table
63
- const recordNames = Object.keys(tableRecords.records || {});
64
- for (const recordName of recordNames) {
65
- const record = tableRecords.records[recordName];
66
- // Process each file in the record
67
- for (const file of record.files || []) {
68
- const filePath = path.join(tablePath, recordName, `${file.name}.${file.type}`);
69
- const fileContent = file.content || "";
70
- // Create the file
71
- await fUtils.writeFileForce(filePath, fileContent);
57
+ var _a;
58
+ try {
59
+ // Ensure the source directory exists
60
+ Logger_1.logger.info(`Creating source directory: ${sourceDirectory}`);
61
+ try {
62
+ await fsp.mkdir(sourceDirectory, { recursive: true });
63
+ Logger_1.logger.info(`Successfully created directory: ${sourceDirectory}`);
64
+ }
65
+ catch (dirError) {
66
+ Logger_1.logger.error(`Failed to create source directory ${sourceDirectory}: ${dirError}`);
67
+ throw dirError;
68
+ }
69
+ // Process each table in the manifest
70
+ const tables = manifest.tables || {};
71
+ const tableNames = Object.keys(tables);
72
+ Logger_1.logger.info(`Processing ${tableNames.length} tables`);
73
+ Logger_1.logger.debug(`Table names: ${tableNames.join(', ')}`);
74
+ for (const tableName of tableNames) {
75
+ const tableRecords = tables[tableName];
76
+ const tablePath = path.join(sourceDirectory, tableName);
77
+ // Process each record in the table
78
+ const recordNames = Object.keys(tableRecords.records || {});
79
+ Logger_1.logger.debug(`Processing ${recordNames.length} records in table ${tableName}`);
80
+ for (const recordName of recordNames) {
81
+ const record = tableRecords.records[recordName];
82
+ // Use the record's name property instead of the key for the directory name
83
+ const recordDirName = record.name || recordName;
84
+ const recordPath = path.join(tablePath, recordDirName);
85
+ Logger_1.logger.debug(`Processing record: ${recordDirName} with ${((_a = record.files) === null || _a === void 0 ? void 0 : _a.length) || 0} files`);
86
+ // Ensure the record directory exists
87
+ await fsp.mkdir(recordPath, { recursive: true });
88
+ // Process each file in the record
89
+ for (const file of record.files || []) {
90
+ const filePath = path.join(recordPath, `${file.name}.${file.type}`);
91
+ const fileContent = file.content || "";
92
+ // Ensure the parent directory exists before writing the file
93
+ const fileDir = path.dirname(filePath);
94
+ Logger_1.logger.debug(`Creating directory: ${fileDir}`);
95
+ await fsp.mkdir(fileDir, { recursive: true });
96
+ // Create the file
97
+ Logger_1.logger.debug(`Writing file: ${filePath}`);
98
+ try {
99
+ await fsp.writeFile(filePath, fileContent, 'utf8');
100
+ }
101
+ catch (writeError) {
102
+ Logger_1.logger.error(`Failed to write file ${filePath}: ${writeError}`);
103
+ throw writeError;
104
+ }
105
+ }
72
106
  }
73
107
  }
108
+ Logger_1.logger.info(`Successfully processed files for ${sourceDirectory}`);
109
+ }
110
+ catch (error) {
111
+ Logger_1.logger.error(`Error in processManifestForScope: ${error}`);
112
+ throw error;
74
113
  }
75
114
  }
76
115
  async function processScope(scopeName, scopeConfig) {
@@ -106,6 +145,7 @@ var __importStar = (this && this.__importStar) || (function () {
106
145
  const manifest = await (0, snClient_1.unwrapSNResponse)(client.getManifest(scopeName, config, true));
107
146
  // Process the manifest to create local files in the correct directory
108
147
  Logger_1.logger.info(`Processing manifest and creating local files for ${scopeName}...`);
148
+ Logger_1.logger.info(`Manifest has ${Object.keys((manifest === null || manifest === void 0 ? void 0 : manifest.tables) || {}).length} tables`);
109
149
  await processManifestForScope(manifest, sourceDirectory, true);
110
150
  // Create the scope-specific manifest structure
111
151
  const scopeManifest = {
@@ -180,11 +220,36 @@ var __importStar = (this && this.__importStar) || (function () {
180
220
  }
181
221
  Logger_1.logger.info(`Manifest written to: ${manifestPath}`);
182
222
  Logger_1.logger.info("\nAll scope files have been downloaded to their respective source directories.");
183
- Logger_1.logger.success("\nYou can now use 'npx sinc dev' to start development mode!");
223
+ Logger_1.logger.success("\nYou can now use 'npx sinc watchAllScopes' to start development mode!");
184
224
  }
185
225
  catch (e) {
186
226
  Logger_1.logger.error("Error initializing scopes: " + e);
187
227
  throw e;
188
228
  }
189
229
  }
230
+ async function watchAllScopesCommand(args) {
231
+ (0, commands_1.setLogLevel)(args);
232
+ try {
233
+ // First check if we have environment variables set
234
+ if (!process.env.SN_USER || !process.env.SN_PASSWORD || !process.env.SN_INSTANCE) {
235
+ Logger_1.logger.error("Missing ServiceNow credentials. Please ensure SN_USER, SN_PASSWORD, and SN_INSTANCE are set in your .env file");
236
+ throw new Error("ServiceNow credentials not configured");
237
+ }
238
+ // Import and start the multi-scope watcher
239
+ const { startMultiScopeWatching } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./MultiScopeWatcher"))) : new Promise((resolve_1, reject_1) => { require(["./MultiScopeWatcher"], resolve_1, reject_1); }).then(__importStar));
240
+ // Start watching all scopes
241
+ await startMultiScopeWatching();
242
+ // Keep the process running
243
+ process.on("SIGINT", async () => {
244
+ Logger_1.logger.info("\nStopping multi-scope watch...");
245
+ const { stopMultiScopeWatching } = await (__syncRequire ? Promise.resolve().then(() => __importStar(require("./MultiScopeWatcher"))) : new Promise((resolve_2, reject_2) => { require(["./MultiScopeWatcher"], resolve_2, reject_2); }).then(__importStar));
246
+ stopMultiScopeWatching();
247
+ process.exit(0);
248
+ });
249
+ }
250
+ catch (error) {
251
+ Logger_1.logger.error("Failed to start multi-scope watch: " + error);
252
+ throw error;
253
+ }
254
+ }
190
255
  });
package/dist/commander.js CHANGED
@@ -61,6 +61,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
61
61
  })
62
62
  .command("init", "Provisions an initial project for you", sharedOptions, commands_1.initCommand)
63
63
  .command("initScopes", "Provisions an initial project for the scopes defined in the config", sharedOptions, allScopesCommands_1.initScopesCommand)
64
+ .command("watchAllScopes", "Watch all scopes for file changes and display update set status", sharedOptions, allScopesCommands_1.watchAllScopesCommand)
64
65
  .command("build", "Build application files locally", (cmdArgs) => {
65
66
  cmdArgs.options({
66
67
  ...sharedOptions,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tenonhq/sincronia-core",
3
- "version": "0.0.19",
3
+ "version": "0.0.22",
4
4
  "description": "Next-gen file syncer",
5
5
  "license": "GPL-3.0",
6
6
  "main": "./dist/index.js",