nango 0.23.30 → 0.24.0

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/sync.js CHANGED
@@ -14,31 +14,210 @@ import parser from '@babel/parser';
14
14
  import traverse from '@babel/traverse';
15
15
  import promptly from 'promptly';
16
16
  import { loadSimplifiedConfig, cloudHost, stagingHost, SyncType, syncRunService, nangoConfigFile, checkForIntegrationFile } from '@nangohq/shared';
17
- import { hostport, port, httpsAgent, verifyNecessaryFiles, getConnection, NANGO_INTEGRATIONS_LOCATION, buildInterfaces, enrichHeaders, getNangoRootPath, printDebug } from './utils.js';
17
+ import { hostport, port, httpsAgent, verifyNecessaryFiles, getConnection, NANGO_INTEGRATIONS_LOCATION, NANGO_INTEGRATIONS_NAME, buildInterfaces, enrichHeaders, getNangoRootPath, getProviderBySyncName, printDebug } from './utils.js';
18
18
  const __filename = fileURLToPath(import.meta.url);
19
19
  const __dirname = dirname(__filename);
20
20
  dotenv.config();
21
21
  const TYPES_FILE_NAME = 'models.ts';
22
22
  const NangoSyncTypesFileLocation = 'dist/nango-sync.d.ts';
23
23
  const exampleSyncName = 'github-issue-example';
24
- const createModelFile = (notify = false) => {
24
+ export const version = (debug) => {
25
+ if (debug) {
26
+ printDebug('Looking up the version first for a local path first then globally');
27
+ }
28
+ const packageJson = JSON.parse(fs.readFileSync(path.resolve(getNangoRootPath(debug), 'package.json'), 'utf8'));
29
+ const dockerComposeYaml = fs.readFileSync(path.resolve(getNangoRootPath(), 'docker/docker-compose.yaml'), 'utf8');
30
+ const dockerCompose = yaml.load(dockerComposeYaml);
31
+ const nangoServerImage = dockerCompose.services['nango-server'].image;
32
+ const nangoWorkerImage = dockerCompose.services['nango-worker'].image;
33
+ const nangoServerVersion = nangoServerImage.split(':').pop();
34
+ const nangoWorkerVersion = nangoWorkerImage.split(':').pop();
35
+ console.log(chalk.green('Nango Server version:'), nangoServerVersion);
36
+ console.log(chalk.green('Nango Worker version:'), nangoWorkerVersion);
37
+ console.log(chalk.green('Nango CLI version:'), packageJson.version);
38
+ };
39
+ /**
40
+ * Init
41
+ * If we're not currently in the nango-integrations directory create one
42
+ * and create an example nango.yaml file
43
+ */
44
+ export const init = (debug = false) => {
45
+ const data = {
46
+ integrations: {
47
+ 'demo-github-integration': {
48
+ [exampleSyncName]: {
49
+ runs: 'every half hour',
50
+ returns: ['GithubIssue']
51
+ }
52
+ }
53
+ },
54
+ models: {
55
+ GithubIssue: {
56
+ id: 'integer',
57
+ owner: 'string',
58
+ repo: 'string',
59
+ issue_number: 'number',
60
+ title: 'string',
61
+ author: 'string',
62
+ author_id: 'string',
63
+ state: 'string',
64
+ date_created: 'date',
65
+ date_last_modified: 'date',
66
+ body: 'string'
67
+ }
68
+ }
69
+ };
70
+ const yamlData = yaml.dump(data);
71
+ // if currently in the nango-integrations directory then don't create another one
25
72
  const cwd = process.cwd();
26
- const configContents = fs.readFileSync(path.resolve(cwd, `${NANGO_INTEGRATIONS_LOCATION}/${nangoConfigFile}`), 'utf8');
73
+ const currentDirectorySplit = cwd.split('/');
74
+ const currentDirectory = currentDirectorySplit[currentDirectorySplit.length - 1];
75
+ let dirExists = false;
76
+ let inParentDirectory = true;
77
+ if (currentDirectory === NANGO_INTEGRATIONS_NAME) {
78
+ dirExists = true;
79
+ inParentDirectory = false;
80
+ if (debug) {
81
+ printDebug(`Currently in the ${NANGO_INTEGRATIONS_NAME} directory so the directory will not be created`);
82
+ }
83
+ }
84
+ if (fs.existsSync(`./${NANGO_INTEGRATIONS_NAME}`)) {
85
+ dirExists = true;
86
+ console.log(chalk.red(`The ${NANGO_INTEGRATIONS_NAME} directory already exists. You should run commands from within this directory`));
87
+ }
88
+ if (!dirExists) {
89
+ if (debug) {
90
+ printDebug(`Creating the nango integrations directory at ./${NANGO_INTEGRATIONS_NAME}`);
91
+ }
92
+ fs.mkdirSync(`./${NANGO_INTEGRATIONS_NAME}`);
93
+ }
94
+ const configFileLocation = inParentDirectory ? `./${NANGO_INTEGRATIONS_NAME}/${nangoConfigFile}` : `./${nangoConfigFile}`;
95
+ if (!fs.existsSync(configFileLocation)) {
96
+ if (debug) {
97
+ printDebug(`Creating the ${nangoConfigFile} file at ${configFileLocation}`);
98
+ }
99
+ fs.writeFileSync(configFileLocation, yamlData);
100
+ }
101
+ else {
102
+ if (debug) {
103
+ printDebug(`Nango config file already exists at ${configFileLocation} so not creating a new one`);
104
+ }
105
+ }
106
+ const envFileLocation = inParentDirectory ? `./${NANGO_INTEGRATIONS_NAME}/.env` : './.env';
107
+ if (!fs.existsSync(envFileLocation)) {
108
+ if (debug) {
109
+ printDebug(`Creating the .env file at ${envFileLocation}`);
110
+ }
111
+ fs.writeFileSync(envFileLocation, `# Authenticates the CLI (get the keys in the dashboard's Projects Settings).
112
+ #NANGO_SECRET_KEY_DEV=xxxx-xxx-xxxx
113
+ #NANGO_SECRET_KEY_PROD=xxxx-xxx-xxxx
114
+
115
+ # Nango's instance URL (OSS: change to http://localhost:3003 or your instance URL).
116
+ NANGO_HOSTPORT=https://api.nango.dev # Default value
117
+
118
+ # How to handle CLI upgrades ("prompt", "auto" or "ignore").
119
+ NANGO_CLI_UPGRADE_MODE=prompt # Default value
120
+
121
+ # Whether to prompt before deployments.
122
+ NANGO_DEPLOY_AUTO_CONFIRM=false # Default value`);
123
+ }
124
+ else {
125
+ if (debug) {
126
+ printDebug(`.env file already exists at ${envFileLocation} so not creating a new one`);
127
+ }
128
+ }
129
+ console.log(chalk.green(`Nango integrations initialized!`));
130
+ };
131
+ export const generate = async (debug = false) => {
132
+ const templateContents = fs.readFileSync(path.resolve(__dirname, './integration.ejs'), 'utf8');
133
+ const githubExampleTemplateContents = fs.readFileSync(path.resolve(__dirname, './integration.github.ejs'), 'utf8');
134
+ const configContents = fs.readFileSync(`./${nangoConfigFile}`, 'utf8');
27
135
  const configData = yaml.load(configContents);
136
+ const { integrations } = configData;
28
137
  const { models } = configData;
29
- const interfaceDefinitions = buildInterfaces(models);
138
+ const interfaceDefinitions = buildInterfaces(models, debug);
30
139
  fs.writeFileSync(`${NANGO_INTEGRATIONS_LOCATION}/${TYPES_FILE_NAME}`, interfaceDefinitions.join('\n'));
140
+ if (debug) {
141
+ printDebug(`Interfaces from the ${nangoConfigFile} file written to ${TYPES_FILE_NAME}`);
142
+ }
31
143
  // insert NangoSync types to the bottom of the file
32
144
  const typesContent = fs.readFileSync(`${getNangoRootPath()}/${NangoSyncTypesFileLocation}`, 'utf8');
33
145
  fs.writeFileSync(`${NANGO_INTEGRATIONS_LOCATION}/${TYPES_FILE_NAME}`, typesContent, { flag: 'a' });
146
+ if (debug) {
147
+ printDebug(`NangoSync types written to ${TYPES_FILE_NAME}`);
148
+ }
149
+ const allSyncNames = {};
150
+ for (let i = 0; i < Object.keys(integrations).length; i++) {
151
+ const providerConfigKey = Object.keys(integrations)[i];
152
+ if (debug) {
153
+ printDebug(`Generating ${providerConfigKey} integrations`);
154
+ }
155
+ const syncObject = integrations[providerConfigKey];
156
+ const syncNames = Object.keys(syncObject);
157
+ for (let k = 0; k < syncNames.length; k++) {
158
+ const syncName = syncNames[k];
159
+ if (allSyncNames[syncName] === undefined) {
160
+ allSyncNames[syncName] = true;
161
+ }
162
+ else {
163
+ console.log(chalk.red(`The sync name ${syncName} is duplicated in the ${nangoConfigFile} file. All sync names must be unique.`));
164
+ process.exit(1);
165
+ }
166
+ if (debug) {
167
+ printDebug(`Generating ${syncName} integration`);
168
+ }
169
+ const syncData = syncObject[syncName];
170
+ const { returns: models } = syncData;
171
+ const syncNameCamel = syncName
172
+ .split('-')
173
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
174
+ .join('');
175
+ const ejsTeamplateContents = syncName === exampleSyncName ? githubExampleTemplateContents : templateContents;
176
+ const rendered = ejs.render(ejsTeamplateContents, {
177
+ syncName: syncNameCamel,
178
+ interfaceFileName: TYPES_FILE_NAME.replace('.ts', ''),
179
+ interfaceNames: models.map((model) => {
180
+ const singularModel = model?.charAt(model.length - 1) === 's' ? model.slice(0, -1) : model;
181
+ return `${singularModel.charAt(0).toUpperCase()}${singularModel.slice(1)}`;
182
+ }),
183
+ mappings: models.map((model) => {
184
+ const singularModel = model.charAt(model.length - 1) === 's' ? model.slice(0, -1) : model;
185
+ return {
186
+ name: model,
187
+ type: `${singularModel.charAt(0).toUpperCase()}${singularModel.slice(1)}`
188
+ };
189
+ })
190
+ });
191
+ if (!fs.existsSync(`${NANGO_INTEGRATIONS_LOCATION}/${syncName}.ts`)) {
192
+ fs.writeFileSync(`${NANGO_INTEGRATIONS_LOCATION}/${syncName}.ts`, rendered);
193
+ if (debug) {
194
+ printDebug(`Created ${syncName}.ts file`);
195
+ }
196
+ }
197
+ else {
198
+ if (debug) {
199
+ printDebug(`${syncName}.ts file already exists, so will not overwrite it.`);
200
+ }
201
+ }
202
+ }
203
+ }
204
+ console.log(chalk.green(`Integration files have been created`));
205
+ };
206
+ const createModelFile = (notify = false) => {
207
+ const configContents = fs.readFileSync(`./${nangoConfigFile}`, 'utf8');
208
+ const configData = yaml.load(configContents);
209
+ const { models } = configData;
210
+ const interfaceDefinitions = buildInterfaces(models);
211
+ fs.writeFileSync(`./${TYPES_FILE_NAME}`, interfaceDefinitions.join('\n'));
212
+ // insert NangoSync types to the bottom of the file
213
+ const typesContent = fs.readFileSync(`${getNangoRootPath()}/${NangoSyncTypesFileLocation}`, 'utf8');
214
+ fs.writeFileSync(`./${TYPES_FILE_NAME}`, typesContent, { flag: 'a' });
34
215
  if (notify) {
35
- const rawNangoIntegrationLocation = NANGO_INTEGRATIONS_LOCATION.replace('./', '');
36
- console.log(chalk.green(`${rawNangoIntegrationLocation}/${nangoConfigFile} was updated. The interface file (${rawNangoIntegrationLocation}/${TYPES_FILE_NAME}) was updated to reflect the updated config`));
216
+ console.log(chalk.green(`The ${nangoConfigFile} was updated. The interface file (${TYPES_FILE_NAME}) was updated to reflect the updated config`));
37
217
  }
38
218
  };
39
219
  const getConfig = async (debug = false) => {
40
- const cwd = process.cwd();
41
- const config = await loadSimplifiedConfig(path.resolve(cwd, NANGO_INTEGRATIONS_LOCATION));
220
+ const config = await loadSimplifiedConfig('./');
42
221
  if (!config) {
43
222
  throw new Error(`Error loading the ${nangoConfigFile} file`);
44
223
  }
@@ -47,21 +226,40 @@ const getConfig = async (debug = false) => {
47
226
  }
48
227
  return config;
49
228
  };
50
- export const deploy = async (options, debug = false) => {
51
- const { env, version, sync: optionalSyncName, secretKey, host, autoConfirm } = options;
52
- await verifyNecessaryFiles(autoConfirm);
53
- if (host) {
229
+ async function parseSecretKey(environment, debug = false) {
230
+ if (process.env['NANGO_SECRET_KEY_PROD'] && environment === 'prod') {
54
231
  if (debug) {
55
- printDebug(`Global host flag is set, setting NANGO_HOSTPORT to ${host}.`);
232
+ printDebug(`Environment is set to prod, setting NANGO_SECRET_KEY to NANGO_SECRET_KEY_PROD.`);
56
233
  }
57
- process.env['NANGO_HOSTPORT'] = host;
234
+ process.env['NANGO_SECRET_KEY'] = process.env['NANGO_SECRET_KEY_PROD'];
58
235
  }
59
- if (secretKey) {
236
+ if (process.env['NANGO_SECRET_KEY_DEV'] && environment === 'dev') {
60
237
  if (debug) {
61
- printDebug(`Global secretKey flag is set, setting NANGO_SECRET_KEY.`);
238
+ printDebug(`Environment is set to dev, setting NANGO_SECRET_KEY to NANGO_SECRET_KEY_DEV.`);
239
+ }
240
+ process.env['NANGO_SECRET_KEY'] = process.env['NANGO_SECRET_KEY_DEV'];
241
+ }
242
+ if (!process.env['NANGO_SECRET_KEY']) {
243
+ console.log(chalk.red(`NANGO_SECRET_KEY environment variable is not set. Please set it now`));
244
+ try {
245
+ const secretKey = await promptly.prompt('Secret Key: ');
246
+ if (secretKey) {
247
+ process.env['NANGO_SECRET_KEY'] = secretKey;
248
+ }
249
+ else {
250
+ return;
251
+ }
252
+ }
253
+ catch (error) {
254
+ console.log('Error occurred while trying to prompt for secret key:', error);
255
+ process.exit(1);
62
256
  }
63
- process.env['NANGO_SECRET_KEY'] = secretKey;
64
257
  }
258
+ }
259
+ export const deploy = async (options, environment, debug = false) => {
260
+ const { env, version, sync: optionalSyncName, autoConfirm } = options;
261
+ await verifyNecessaryFiles(autoConfirm);
262
+ await parseSecretKey(environment, debug);
65
263
  if (!process.env['NANGO_HOSTPORT']) {
66
264
  switch (env) {
67
265
  case 'local':
@@ -77,26 +275,10 @@ export const deploy = async (options, debug = false) => {
77
275
  }
78
276
  if (debug) {
79
277
  printDebug(`NANGO_HOSTPORT is set to ${process.env['NANGO_HOSTPORT']}.`);
80
- }
81
- if (process.env['NANGO_HOSTPORT'] !== `http://localhost:${port}` && !process.env['NANGO_SECRET_KEY']) {
82
- console.log(chalk.red(`NANGO_SECRET_KEY environment variable is not set. Please set it now`));
83
- try {
84
- const secretKey = await promptly.prompt('Secret Key: ');
85
- if (secretKey) {
86
- process.env['NANGO_SECRET_KEY'] = secretKey;
87
- }
88
- else {
89
- return;
90
- }
91
- }
92
- catch (error) {
93
- console.log('Error occurred while trying to prompt for secret key:', error);
94
- process.exit(1);
95
- }
278
+ printDebug(`Environment is set to ${environment}`);
96
279
  }
97
280
  tsc(debug);
98
281
  const config = await getConfig(debug);
99
- const cwd = process.cwd();
100
282
  const postData = [];
101
283
  for (const integration of config) {
102
284
  const { providerConfigKey } = integration;
@@ -106,7 +288,7 @@ export const deploy = async (options, debug = false) => {
106
288
  }
107
289
  for (const sync of syncs) {
108
290
  const { name: syncName, runs, returns: models, models: model_schema } = sync;
109
- const { path: integrationFilePath, result: integrationFileResult } = checkForIntegrationFile(syncName, path.resolve(cwd, `${NANGO_INTEGRATIONS_LOCATION}`));
291
+ const { path: integrationFilePath, result: integrationFileResult } = checkForIntegrationFile(syncName, './');
110
292
  if (!integrationFileResult) {
111
293
  console.log(chalk.red(`No integration file found for ${syncName} at ${integrationFilePath}. Skipping...`));
112
294
  continue;
@@ -131,7 +313,7 @@ export const deploy = async (options, debug = false) => {
131
313
  console.log(chalk.red(`No syncs found to deploy. Please make sure your integration files compiled successfully and exist in your dist directory`));
132
314
  return;
133
315
  }
134
- if (!process.env['NANGO_DEPLOY_AUTO_CONFIRM'] && !autoConfirm) {
316
+ if (process.env['NANGO_DEPLOY_AUTO_CONFIRM'] !== 'true' && !autoConfirm) {
135
317
  const confirmationUrl = process.env['NANGO_HOSTPORT'] + `/sync/deploy/confirmation`;
136
318
  try {
137
319
  const response = await axios.post(confirmationUrl, { syncs: postData, reconcile: false, debug }, { headers: enrichHeaders(), httpsAgent: httpsAgent() });
@@ -209,198 +391,36 @@ async function deploySyncs(url, body) {
209
391
  process.exit(1);
210
392
  });
211
393
  }
212
- export const version = (debug) => {
213
- if (debug) {
214
- printDebug('Looking up the version first for a local path first then globally');
215
- }
216
- const packageJson = JSON.parse(fs.readFileSync(path.resolve(getNangoRootPath(debug), 'package.json'), 'utf8'));
217
- const dockerComposeYaml = fs.readFileSync(path.resolve(getNangoRootPath(), 'docker/docker-compose.yaml'), 'utf8');
218
- const dockerCompose = yaml.load(dockerComposeYaml);
219
- const nangoServerImage = dockerCompose.services['nango-server'].image;
220
- const nangoWorkerImage = dockerCompose.services['nango-worker'].image;
221
- const nangoServerVersion = nangoServerImage.split(':').pop();
222
- const nangoWorkerVersion = nangoWorkerImage.split(':').pop();
223
- console.log(chalk.green('Nango Server version:'), nangoServerVersion);
224
- console.log(chalk.green('Nango Worker version:'), nangoWorkerVersion);
225
- console.log(chalk.green('Nango CLI version:'), packageJson.version);
226
- };
227
- export const init = (debug = false) => {
228
- const data = {
229
- integrations: {
230
- github: {
231
- [exampleSyncName]: {
232
- runs: 'every half hour',
233
- returns: ['GithubIssue']
234
- }
235
- }
236
- },
237
- models: {
238
- GithubIssue: {
239
- id: 'integer',
240
- owner: 'string',
241
- repo: 'string',
242
- issue_number: 'number',
243
- title: 'string',
244
- author: 'string',
245
- author_id: 'string',
246
- state: 'string',
247
- date_created: 'date',
248
- date_last_modified: 'date',
249
- body: 'string'
250
- }
251
- }
252
- };
253
- const yamlData = yaml.dump(data);
254
- if (!fs.existsSync(NANGO_INTEGRATIONS_LOCATION)) {
255
- if (debug) {
256
- printDebug('Creating the nango integrations directory');
257
- }
258
- fs.mkdirSync(NANGO_INTEGRATIONS_LOCATION);
259
- }
260
- else {
261
- if (debug) {
262
- printDebug('Nango integrations directory already exists');
263
- }
264
- }
265
- if (!fs.existsSync(`${NANGO_INTEGRATIONS_LOCATION}/${nangoConfigFile}`)) {
266
- if (debug) {
267
- printDebug(`Creating the ${nangoConfigFile} file}`);
268
- }
269
- fs.writeFileSync(`${NANGO_INTEGRATIONS_LOCATION}/${nangoConfigFile}`, yamlData);
270
- }
271
- else {
272
- if (debug) {
273
- printDebug('Nango config file already exists');
274
- }
275
- }
276
- // check if a .env file exists and if not create it with some default content
277
- if (!fs.existsSync('.env')) {
278
- if (debug) {
279
- printDebug('Creating the .env file');
280
- }
281
- fs.writeFileSync('.env', `#NANGO_HOSTPORT=https://api-staging.nango.dev
282
- #NANGO_AUTO_UPGRADE=true # set to true to automatically upgrade to the latest version of nango
283
- #NANGO_NO_PROMPT_FOR_UPGRADE=true # set to true to not prompt for upgrade
284
- #NANGO_DEPLOY_AUTO_CONFIRM=true # set to true to automatically confirm deployment without prompting
285
- #NANGO_SECRET_KEY=xxxx-xxx-xxxx # required if deploying to cloud
286
- #NANGO_INTEGRATIONS_LOCATION=use-this-to-override-where-the-nango-integrations-directory-goes
287
- #NANGO_PORT=use-this-to-override-the-default-3003
288
- #NANGO_DB_PORT=use-this-to-override-the-default-5432`);
289
- }
290
- else {
394
+ export const dryRun = async (options, environment, debug = false) => {
395
+ let syncName, connectionId, suppliedLastSyncDate;
396
+ await parseSecretKey(environment, debug);
397
+ if (!process.env['NANGO_HOSTPORT']) {
291
398
  if (debug) {
292
- printDebug('.env file already exists');
399
+ printDebug(`NANGO_HOSTPORT is not set. Setting the default to ${hostport}`);
293
400
  }
401
+ process.env['NANGO_HOSTPORT'] = hostport;
294
402
  }
295
- console.log(chalk.green(`Nango integrations initialized!`));
296
- };
297
- export const generate = async (debug = false) => {
298
- const templateContents = fs.readFileSync(path.resolve(__dirname, './integration.ejs'), 'utf8');
299
- const githubExampleTemplateContents = fs.readFileSync(path.resolve(__dirname, './integration.github.ejs'), 'utf8');
300
- const cwd = process.cwd();
301
- const configContents = fs.readFileSync(path.resolve(cwd, `${NANGO_INTEGRATIONS_LOCATION}/${nangoConfigFile}`), 'utf8');
302
- const configData = yaml.load(configContents);
303
- const { integrations } = configData;
304
- const { models } = configData;
305
- const interfaceDefinitions = buildInterfaces(models);
306
- fs.writeFileSync(`${NANGO_INTEGRATIONS_LOCATION}/${TYPES_FILE_NAME}`, interfaceDefinitions.join('\n'));
307
- if (debug) {
308
- printDebug(`Interfaces from the ${nangoConfigFile} file written to ${TYPES_FILE_NAME}`);
309
- }
310
- // insert NangoSync types to the bottom of the file
311
- const typesContent = fs.readFileSync(`${getNangoRootPath()}/${NangoSyncTypesFileLocation}`, 'utf8');
312
- fs.writeFileSync(`${NANGO_INTEGRATIONS_LOCATION}/${TYPES_FILE_NAME}`, typesContent, { flag: 'a' });
313
403
  if (debug) {
314
- printDebug(`NangoSync types written to ${TYPES_FILE_NAME}`);
315
- }
316
- for (let i = 0; i < Object.keys(integrations).length; i++) {
317
- const providerConfigKey = Object.keys(integrations)[i];
318
- if (debug) {
319
- printDebug(`Generating ${providerConfigKey} integrations`);
320
- }
321
- const syncObject = integrations[providerConfigKey];
322
- const syncNames = Object.keys(syncObject);
323
- for (let k = 0; k < syncNames.length; k++) {
324
- const syncName = syncNames[k];
325
- if (debug) {
326
- printDebug(`Generating ${syncName} integration`);
327
- }
328
- const syncData = syncObject[syncName];
329
- const { returns: models } = syncData;
330
- const syncNameCamel = syncName
331
- .split('-')
332
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
333
- .join('');
334
- const ejsTeamplateContents = syncName === exampleSyncName ? githubExampleTemplateContents : templateContents;
335
- const rendered = ejs.render(ejsTeamplateContents, {
336
- syncName: syncNameCamel,
337
- interfaceFileName: TYPES_FILE_NAME.replace('.ts', ''),
338
- interfaceNames: models.map((model) => {
339
- const singularModel = model?.charAt(model.length - 1) === 's' ? model.slice(0, -1) : model;
340
- return `${singularModel.charAt(0).toUpperCase()}${singularModel.slice(1)}`;
341
- }),
342
- mappings: models.map((model) => {
343
- const singularModel = model.charAt(model.length - 1) === 's' ? model.slice(0, -1) : model;
344
- return {
345
- name: model,
346
- type: `${singularModel.charAt(0).toUpperCase()}${singularModel.slice(1)}`
347
- };
348
- })
349
- });
350
- if (!fs.existsSync(`${NANGO_INTEGRATIONS_LOCATION}/${syncName}.ts`)) {
351
- fs.writeFileSync(`${NANGO_INTEGRATIONS_LOCATION}/${syncName}.ts`, rendered);
352
- if (debug) {
353
- printDebug(`Created ${syncName}.ts file`);
354
- }
355
- }
356
- else {
357
- if (debug) {
358
- printDebug(`${syncName}.ts file already exists, so will not overwrite it.`);
359
- }
360
- }
361
- }
362
- }
363
- console.log(chalk.green(`Integration files have been created`));
364
- };
365
- export const run = async (args, options, debug = false) => {
366
- let syncName, providerConfigKey, connectionId, suppliedLastSyncDate, host, secretKey;
367
- if (args.length > 0) {
368
- [syncName, providerConfigKey, connectionId, suppliedLastSyncDate] = args;
404
+ printDebug(`NANGO_HOSTPORT is set to ${process.env['NANGO_HOSTPORT']}`);
369
405
  }
370
406
  if (Object.keys(options).length > 0) {
371
- ({ sync: syncName, provider: providerConfigKey, connection: connectionId, lastSyncDate: suppliedLastSyncDate, host, secretKey } = options);
407
+ ({ sync: syncName, connectionId, lastSyncDate: suppliedLastSyncDate } = options);
372
408
  }
373
409
  if (!syncName) {
374
410
  console.log(chalk.red('Sync name is required'));
375
411
  return;
376
412
  }
377
- if (!providerConfigKey) {
378
- console.log(chalk.red('Provider config key is required'));
379
- return;
380
- }
381
413
  if (!connectionId) {
382
414
  console.log(chalk.red('Connection id is required'));
383
415
  return;
384
416
  }
385
- if (debug) {
386
- if (host) {
387
- printDebug(`Host value is set to ${host}. This will override the value in the .env file`);
388
- }
389
- }
390
- if (host) {
391
- process.env['NANGO_HOSTPORT'] = host;
392
- }
393
- if (secretKey) {
394
- process.env['NANGO_SECRET_KEY'] = secretKey;
395
- }
396
- if (!process.env['NANGO_HOSTPORT']) {
397
- if (debug) {
398
- printDebug(`NANGO_HOSTPORT is not set. Setting the default to ${hostport}`);
399
- }
400
- process.env['NANGO_HOSTPORT'] = hostport;
417
+ const providerConfigKey = await getProviderBySyncName({ syncName }, debug);
418
+ if (!providerConfigKey) {
419
+ console.log(chalk.red(`Provider config key not found, please check that the provider exists for this sync name: ${syncName}`));
420
+ return;
401
421
  }
402
422
  if (debug) {
403
- printDebug(`NANGO_HOSTPORT is set to ${process.env['NANGO_HOSTPORT']}`);
423
+ printDebug(`Provider config key found to be ${providerConfigKey}`);
404
424
  }
405
425
  const nangoConnection = (await getConnection(providerConfigKey, connectionId, {
406
426
  'Nango-Is-Sync': true,
@@ -410,6 +430,9 @@ export const run = async (args, options, debug = false) => {
410
430
  console.log(chalk.red('Connection not found'));
411
431
  return;
412
432
  }
433
+ if (debug) {
434
+ printDebug(`Connection found with ${JSON.stringify(nangoConnection, null, 2)}`);
435
+ }
413
436
  if (process.env['NANGO_HOSTPORT'] === cloudHost || process.env['NANGO_HOSTPORT'] === stagingHost) {
414
437
  process.env['NANGO_CLOUD'] = 'true';
415
438
  }
@@ -420,13 +443,12 @@ export const run = async (args, options, debug = false) => {
420
443
  }
421
444
  lastSyncDate = new Date(suppliedLastSyncDate);
422
445
  }
423
- const cwd = process.cwd();
424
446
  const syncRun = new syncRunService({
425
447
  writeToDb: false,
426
448
  nangoConnection,
427
449
  syncName,
428
450
  syncType: SyncType.INITIAL,
429
- loadLocation: path.resolve(cwd, `${NANGO_INTEGRATIONS_LOCATION}`),
451
+ loadLocation: './',
430
452
  debug
431
453
  });
432
454
  try {
@@ -440,38 +462,35 @@ export const run = async (args, options, debug = false) => {
440
462
  }
441
463
  };
442
464
  export const tsc = (debug = false) => {
443
- const cwd = process.cwd();
444
465
  const tsconfig = fs.readFileSync(`${getNangoRootPath()}/tsconfig.dev.json`, 'utf8');
445
- const distDir = path.resolve(cwd, `${NANGO_INTEGRATIONS_LOCATION}/dist`);
466
+ const distDir = './dist';
446
467
  if (!fs.existsSync(distDir)) {
447
468
  if (debug) {
448
469
  printDebug(`Creating ${distDir} directory`);
449
470
  }
450
471
  fs.mkdirSync(distDir);
451
472
  }
452
- if (!fs.existsSync(`${NANGO_INTEGRATIONS_LOCATION}/${TYPES_FILE_NAME}`)) {
473
+ if (!fs.existsSync(`./${TYPES_FILE_NAME}`)) {
453
474
  if (debug) {
454
475
  printDebug(`Creating ${TYPES_FILE_NAME} file`);
455
476
  }
456
477
  createModelFile();
457
478
  }
458
- const rawNangoIntegrationLocation = NANGO_INTEGRATIONS_LOCATION.replace('./', '');
459
479
  const compiler = tsNode.create({
460
480
  compilerOptions: JSON.parse(tsconfig).compilerOptions
461
481
  });
462
482
  if (debug) {
463
483
  printDebug(`Compiler options: ${JSON.stringify(JSON.parse(tsconfig).compilerOptions, null, 2)}`);
464
484
  }
465
- const integrationFiles = glob.sync(path.resolve(cwd, `${NANGO_INTEGRATIONS_LOCATION}/*.ts`));
485
+ const integrationFiles = glob.sync(`./*.ts`);
466
486
  for (const filePath of integrationFiles) {
467
487
  try {
468
488
  if (!nangoCallsAreAwaited(filePath)) {
469
489
  return;
470
490
  }
471
491
  const result = compiler.compile(fs.readFileSync(filePath, 'utf8'), filePath);
472
- const jsFilePath = path.join(path.dirname(filePath), path.basename(filePath, '.ts') + '.js');
473
- const distJSFilePath = jsFilePath.replace(rawNangoIntegrationLocation, `${rawNangoIntegrationLocation}/dist`);
474
- fs.writeFileSync(distJSFilePath, result);
492
+ const jsFilePath = filePath.replace(/\/[^\/]*$/, `/dist/${path.basename(filePath.replace('.ts', '.js'))}`);
493
+ fs.writeFileSync(jsFilePath, result);
475
494
  console.log(chalk.green(`Compiled "${filePath}" successfully`));
476
495
  }
477
496
  catch (error) {
@@ -504,52 +523,51 @@ const nangoCallsAreAwaited = (filePath) => {
504
523
  return areAwaited;
505
524
  };
506
525
  export const tscWatch = (debug = false) => {
507
- const cwd = process.cwd();
508
526
  const tsconfig = fs.readFileSync(`${getNangoRootPath()}/tsconfig.dev.json`, 'utf8');
509
- const watchPath = [`${NANGO_INTEGRATIONS_LOCATION}/*.ts`, `${NANGO_INTEGRATIONS_LOCATION}/${nangoConfigFile}`];
527
+ const watchPath = [`./*.ts`, `./${nangoConfigFile}`];
510
528
  if (debug) {
511
529
  printDebug(`Watching ${watchPath.join(', ')}`);
512
530
  }
513
- const rawNangoIntegrationLocation = NANGO_INTEGRATIONS_LOCATION.replace('./', '');
514
531
  const watcher = chokidar.watch(watchPath, {
515
532
  ignoreInitial: false,
516
533
  ignored: (filePath) => {
517
- return filePath === `${rawNangoIntegrationLocation}/${TYPES_FILE_NAME}`;
534
+ return filePath === TYPES_FILE_NAME;
518
535
  }
519
536
  });
520
- const distDir = path.resolve(cwd, `${NANGO_INTEGRATIONS_LOCATION}/dist`);
537
+ const distDir = './dist';
521
538
  if (!fs.existsSync(distDir)) {
522
539
  if (debug) {
523
540
  printDebug(`Creating ${distDir} directory`);
524
541
  }
525
542
  fs.mkdirSync(distDir);
526
543
  }
527
- if (!fs.existsSync(`${NANGO_INTEGRATIONS_LOCATION}/${TYPES_FILE_NAME}`)) {
544
+ if (!fs.existsSync(`./${TYPES_FILE_NAME}`)) {
528
545
  if (debug) {
529
546
  printDebug(`Creating ${TYPES_FILE_NAME} file`);
530
547
  }
531
548
  createModelFile();
532
549
  }
533
550
  watcher.on('add', (filePath) => {
534
- if (filePath === `${rawNangoIntegrationLocation}/${nangoConfigFile}`) {
551
+ if (filePath === nangoConfigFile) {
535
552
  return;
536
553
  }
537
554
  compileFile(filePath);
538
555
  });
539
556
  watcher.on('unlink', (filePath) => {
540
- if (filePath === `${rawNangoIntegrationLocation}/${nangoConfigFile}`) {
557
+ if (filePath === nangoConfigFile) {
541
558
  return;
542
559
  }
543
- const jsFilePath = path.join(path.dirname(filePath), path.basename(filePath, '.ts') + '.js');
544
- const distJSFilePath = jsFilePath.replace(rawNangoIntegrationLocation, `${rawNangoIntegrationLocation}/dist`);
545
- fs.unlinkSync(distJSFilePath);
560
+ const jsFilePath = `./dist/${path.basename(filePath.replace('.ts', '.js'))}`;
561
+ fs.unlinkSync(jsFilePath);
546
562
  });
547
563
  watcher.on('change', (filePath) => {
548
- if (filePath === `${rawNangoIntegrationLocation}/${nangoConfigFile}`) {
564
+ if (filePath === nangoConfigFile) {
549
565
  // config file changed, re-compile each ts file
550
- const integrationFiles = glob.sync(path.resolve(cwd, `${NANGO_INTEGRATIONS_LOCATION}/*.ts`));
566
+ const integrationFiles = glob.sync(`./*.ts`);
551
567
  for (const file of integrationFiles) {
552
- compileFile(file);
568
+ // strip the file to just the last part
569
+ const strippedFile = file.replace(/^.*[\\\/]/, '');
570
+ compileFile(strippedFile);
553
571
  }
554
572
  return;
555
573
  }
@@ -564,9 +582,8 @@ export const tscWatch = (debug = false) => {
564
582
  return;
565
583
  }
566
584
  const result = compiler.compile(fs.readFileSync(filePath, 'utf8'), filePath);
567
- const jsFilePath = path.join(path.dirname(filePath), path.basename(filePath, '.ts') + '.js');
568
- const distJSFilePath = jsFilePath.replace(rawNangoIntegrationLocation, `${rawNangoIntegrationLocation}/dist`);
569
- fs.writeFileSync(distJSFilePath, result);
585
+ const jsFilePath = `./dist/${path.basename(filePath.replace('.ts', '.js'))}`;
586
+ fs.writeFileSync(jsFilePath, result);
570
587
  console.log(chalk.green(`Compiled ${filePath} successfully`));
571
588
  }
572
589
  catch (error) {
@@ -577,7 +594,7 @@ export const tscWatch = (debug = false) => {
577
594
  }
578
595
  };
579
596
  export const configWatch = (debug = false) => {
580
- const watchPath = `${NANGO_INTEGRATIONS_LOCATION}/${nangoConfigFile}`;
597
+ const watchPath = `./${nangoConfigFile}`;
581
598
  if (debug) {
582
599
  printDebug(`Watching ${watchPath}`);
583
600
  }