nango 0.40.1 → 0.40.3
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/cli.d.ts +3 -3
- package/dist/cli.js +49 -93
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +0 -1
- package/dist/constants.js.map +1 -1
- package/dist/index.js +15 -10
- package/dist/index.js.map +1 -1
- package/dist/services/compile.service.d.ts +5 -6
- package/dist/services/compile.service.js +40 -51
- package/dist/services/compile.service.js.map +1 -1
- package/dist/services/compile.service.unit.test.js +3 -3
- package/dist/services/compile.service.unit.test.js.map +1 -1
- package/dist/services/config.service.d.ts +16 -7
- package/dist/services/config.service.js +84 -54
- package/dist/services/config.service.js.map +1 -1
- package/dist/services/config.service.unit.test.d.ts +1 -0
- package/dist/services/config.service.unit.test.js +147 -0
- package/dist/services/config.service.unit.test.js.map +1 -0
- package/dist/services/deploy.service.d.ts +3 -3
- package/dist/services/deploy.service.js +76 -66
- package/dist/services/deploy.service.js.map +1 -1
- package/dist/services/dryrun.service.js +10 -10
- package/dist/services/dryrun.service.js.map +1 -1
- package/dist/services/migration.service.js +23 -26
- package/dist/services/migration.service.js.map +1 -1
- package/dist/services/model.service.d.ts +38 -11
- package/dist/services/model.service.js +129 -174
- package/dist/services/model.service.js.map +1 -1
- package/dist/services/model.service.unit.test.d.ts +1 -0
- package/dist/services/model.service.unit.test.js +138 -0
- package/dist/services/model.service.unit.test.js.map +1 -0
- package/dist/services/parser.service.d.ts +1 -2
- package/dist/services/parser.service.js +3 -4
- package/dist/services/parser.service.js.map +1 -1
- package/dist/services/verification.service.d.ts +1 -1
- package/dist/services/verification.service.js +11 -11
- package/dist/services/verification.service.js.map +1 -1
- package/dist/sync.unit.cli-test.js +65 -143
- package/dist/sync.unit.cli-test.js.map +1 -1
- package/dist/templates/action.ejs +2 -47
- package/dist/templates/sync.ejs +1 -4
- package/dist/utils/layoutMode.d.ts +7 -0
- package/dist/utils/layoutMode.js +41 -0
- package/dist/utils/layoutMode.js.map +1 -0
- package/dist/utils.d.ts +0 -3
- package/dist/utils.js +4 -127
- package/dist/utils.js.map +1 -1
- package/lib/nango.yaml.schema.v2.json +183 -178
- package/package.json +7 -6
- package/dist/nango-sync.d.ts +0 -299
|
@@ -4,12 +4,11 @@ import * as tsNode from 'ts-node';
|
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { build } from 'tsup';
|
|
7
|
-
import {
|
|
8
|
-
import configService from './config.service.js';
|
|
7
|
+
import { localFileService } from '@nangohq/shared';
|
|
9
8
|
import { getNangoRootPath, printDebug } from '../utils.js';
|
|
10
|
-
import
|
|
9
|
+
import { loadYamlAndGeneratedModel } from './model.service.js';
|
|
11
10
|
import parserService from './parser.service.js';
|
|
12
|
-
import {
|
|
11
|
+
import { getProviderConfigurationFromPath } from '@nangohq/nango-yaml';
|
|
13
12
|
const ALLOWED_IMPORTS = ['url', 'crypto', 'zod', 'node:url', 'node:crypto'];
|
|
14
13
|
export async function compileAllFiles({ debug, fullPath, scriptName, providerConfigKey, type }) {
|
|
15
14
|
const tsconfig = fs.readFileSync(`${getNangoRootPath()}/tsconfig.dev.json`, 'utf8');
|
|
@@ -20,12 +19,11 @@ export async function compileAllFiles({ debug, fullPath, scriptName, providerCon
|
|
|
20
19
|
}
|
|
21
20
|
fs.mkdirSync(distDir);
|
|
22
21
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
22
|
+
const res = loadYamlAndGeneratedModel({ fullPath, debug });
|
|
23
|
+
if (!res.success) {
|
|
24
|
+
return false;
|
|
27
25
|
}
|
|
28
|
-
|
|
26
|
+
const parsed = res.response;
|
|
29
27
|
const compilerOptions = JSON.parse(tsconfig).compilerOptions;
|
|
30
28
|
const compiler = tsNode.create({
|
|
31
29
|
skipProject: true, // when installed locally we don't want ts-node to pick up the package tsconfig.json file
|
|
@@ -34,22 +32,16 @@ export async function compileAllFiles({ debug, fullPath, scriptName, providerCon
|
|
|
34
32
|
if (debug) {
|
|
35
33
|
printDebug(`Compiler options: ${JSON.stringify(compilerOptions, null, 2)}`);
|
|
36
34
|
}
|
|
37
|
-
const { success: loadSuccess, error, response: config } = await configService.load(fullPath, debug);
|
|
38
|
-
if (!loadSuccess || !config) {
|
|
39
|
-
console.log(chalk.red(error?.message));
|
|
40
|
-
throw new Error('Error loading config');
|
|
41
|
-
}
|
|
42
35
|
let scriptDirectory;
|
|
43
36
|
if (scriptName && providerConfigKey && type) {
|
|
44
37
|
scriptDirectory = localFileService.resolveTsFileLocation({ scriptName, providerConfigKey, type }).replace(fullPath, '');
|
|
45
38
|
console.log(chalk.green(`Compiling ${scriptName}.ts in ${fullPath}${scriptDirectory}`));
|
|
46
39
|
}
|
|
47
|
-
const integrationFiles = listFilesToCompile({ scriptName, fullPath, scriptDirectory,
|
|
40
|
+
const integrationFiles = listFilesToCompile({ scriptName, fullPath, scriptDirectory, parsed, debug });
|
|
48
41
|
let success = true;
|
|
49
|
-
const modelNames = configService.getModelNames(config);
|
|
50
42
|
for (const file of integrationFiles) {
|
|
51
43
|
try {
|
|
52
|
-
const completed = await compile({ fullPath, file,
|
|
44
|
+
const completed = await compile({ fullPath, file, parsed, compiler, debug });
|
|
53
45
|
if (!completed) {
|
|
54
46
|
if (scriptName && file.inputPath.includes(scriptName)) {
|
|
55
47
|
success = false;
|
|
@@ -64,7 +56,7 @@ export async function compileAllFiles({ debug, fullPath, scriptName, providerCon
|
|
|
64
56
|
}
|
|
65
57
|
return success;
|
|
66
58
|
}
|
|
67
|
-
export async function compileSingleFile({ fullPath, file,
|
|
59
|
+
export async function compileSingleFile({ fullPath, file, parsed, tsconfig, debug = false }) {
|
|
68
60
|
try {
|
|
69
61
|
const compiler = tsNode.create({
|
|
70
62
|
skipProject: true, // when installed locally we don't want ts-node to pick up the package tsconfig.json file
|
|
@@ -73,8 +65,7 @@ export async function compileSingleFile({ fullPath, file, config, modelNames, ts
|
|
|
73
65
|
const result = await compile({
|
|
74
66
|
fullPath,
|
|
75
67
|
file,
|
|
76
|
-
|
|
77
|
-
modelNames,
|
|
68
|
+
parsed,
|
|
78
69
|
compiler,
|
|
79
70
|
debug
|
|
80
71
|
});
|
|
@@ -86,10 +77,10 @@ export async function compileSingleFile({ fullPath, file, config, modelNames, ts
|
|
|
86
77
|
return false;
|
|
87
78
|
}
|
|
88
79
|
}
|
|
89
|
-
function compileImportedFile({ fullPath, filePath, compiler,
|
|
80
|
+
function compileImportedFile({ fullPath, filePath, compiler, parsed, type }) {
|
|
90
81
|
let finalResult = true;
|
|
91
82
|
const importedFiles = parserService.getImportedFiles(filePath);
|
|
92
|
-
if (!parserService.callsAreUsedCorrectly(filePath, type,
|
|
83
|
+
if (!parserService.callsAreUsedCorrectly(filePath, type, Array.from(parsed.models.keys()))) {
|
|
93
84
|
return false;
|
|
94
85
|
}
|
|
95
86
|
for (const importedFile of importedFiles) {
|
|
@@ -120,18 +111,18 @@ function compileImportedFile({ fullPath, filePath, compiler, type, modelNames })
|
|
|
120
111
|
}
|
|
121
112
|
compiler.compile(fs.readFileSync(importedFilePathWithExtension, 'utf8'), importedFilePathWithExtension);
|
|
122
113
|
console.log(chalk.green(`Compiled "${importedFilePathWithExtension}" successfully`));
|
|
123
|
-
finalResult = compileImportedFile({ fullPath, filePath: importedFilePathWithExtension, compiler, type,
|
|
114
|
+
finalResult = compileImportedFile({ fullPath, filePath: importedFilePathWithExtension, compiler, type, parsed });
|
|
124
115
|
}
|
|
125
116
|
return finalResult;
|
|
126
117
|
}
|
|
127
|
-
async function compile({ fullPath, file,
|
|
128
|
-
const providerConfiguration =
|
|
118
|
+
async function compile({ fullPath, file, parsed, compiler, debug = false }) {
|
|
119
|
+
const providerConfiguration = getProviderConfigurationFromPath({ filePath: file.inputPath, parsed });
|
|
129
120
|
if (!providerConfiguration) {
|
|
130
121
|
return false;
|
|
131
122
|
}
|
|
132
123
|
const syncConfig = [...providerConfiguration.syncs, ...providerConfiguration.actions].find((sync) => sync.name === file.baseName);
|
|
133
|
-
const type = syncConfig?.type ||
|
|
134
|
-
const success = compileImportedFile({ fullPath, filePath: file.inputPath, compiler, type,
|
|
124
|
+
const type = syncConfig?.type || 'sync';
|
|
125
|
+
const success = compileImportedFile({ fullPath, filePath: file.inputPath, compiler, type, parsed });
|
|
135
126
|
if (!success) {
|
|
136
127
|
return false;
|
|
137
128
|
}
|
|
@@ -172,7 +163,7 @@ export function getFileToCompile({ fullPath, filePath }) {
|
|
|
172
163
|
baseName
|
|
173
164
|
};
|
|
174
165
|
}
|
|
175
|
-
export function listFilesToCompile({ fullPath, scriptDirectory, scriptName,
|
|
166
|
+
export function listFilesToCompile({ fullPath, scriptDirectory, scriptName, parsed, debug }) {
|
|
176
167
|
let files = [];
|
|
177
168
|
if (scriptName) {
|
|
178
169
|
if (debug) {
|
|
@@ -186,30 +177,28 @@ export function listFilesToCompile({ fullPath, scriptDirectory, scriptName, conf
|
|
|
186
177
|
if (files.length === 1 && debug) {
|
|
187
178
|
printDebug(`No files found in the root: ${fullPath}`);
|
|
188
179
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
files
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
printDebug(`Found nested sync files in ${syncPath}`);
|
|
203
|
-
}
|
|
204
|
-
if (glob.sync(`${fullPath}/${actionPath}/*.ts`).length > 0) {
|
|
205
|
-
printDebug(`Found nested action files in ${actionPath}`);
|
|
206
|
-
}
|
|
207
|
-
if (glob.sync(`${fullPath}/${postConnectionPath}/*.ts`).length > 0) {
|
|
208
|
-
printDebug(`Found nested post connection script files in ${postConnectionPath}`);
|
|
209
|
-
}
|
|
180
|
+
parsed.integrations.forEach((integration) => {
|
|
181
|
+
const syncPath = `${integration.providerConfigKey}/syncs`;
|
|
182
|
+
const actionPath = `${integration.providerConfigKey}/actions`;
|
|
183
|
+
const postConnectionPath = `${integration.providerConfigKey}/post-connection-scripts`;
|
|
184
|
+
files = [
|
|
185
|
+
...files,
|
|
186
|
+
...glob.sync(`${fullPath}/${syncPath}/*.ts`),
|
|
187
|
+
...glob.sync(`${fullPath}/${actionPath}/*.ts`),
|
|
188
|
+
...glob.sync(`${fullPath}/${postConnectionPath}/*.ts`)
|
|
189
|
+
];
|
|
190
|
+
if (debug) {
|
|
191
|
+
if (glob.sync(`${fullPath}/${syncPath}/*.ts`).length > 0) {
|
|
192
|
+
printDebug(`Found nested sync files in ${syncPath}`);
|
|
210
193
|
}
|
|
211
|
-
|
|
212
|
-
|
|
194
|
+
if (glob.sync(`${fullPath}/${actionPath}/*.ts`).length > 0) {
|
|
195
|
+
printDebug(`Found nested action files in ${actionPath}`);
|
|
196
|
+
}
|
|
197
|
+
if (glob.sync(`${fullPath}/${postConnectionPath}/*.ts`).length > 0) {
|
|
198
|
+
printDebug(`Found nested post connection script files in ${postConnectionPath}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
});
|
|
213
202
|
}
|
|
214
203
|
return files.map((filePath) => {
|
|
215
204
|
return getFileToCompile({ fullPath, filePath });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.service.js","sourceRoot":"","sources":["../../lib/services/compile.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC;AAClC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"compile.service.js","sourceRoot":"","sources":["../../lib/services/compile.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
5
5
|
const thisFolder = path.dirname(fileURLToPath(import.meta.url));
|
|
6
6
|
describe('listFiles', () => {
|
|
7
7
|
it('should list files with glob', () => {
|
|
8
|
-
const files = listFilesToCompile({ fullPath: thisFolder,
|
|
8
|
+
const files = listFilesToCompile({ fullPath: thisFolder, parsed: { integrations: [], models: new Map(), yamlVersion: 'v2' } });
|
|
9
9
|
expect(files.length).toBeGreaterThan(1);
|
|
10
10
|
expect(files[0]).toStrictEqual({
|
|
11
11
|
baseName: 'verification.service',
|
|
@@ -14,7 +14,7 @@ describe('listFiles', () => {
|
|
|
14
14
|
});
|
|
15
15
|
});
|
|
16
16
|
it('should list files with syncName', () => {
|
|
17
|
-
const files = listFilesToCompile({ scriptName: 'compile.service', scriptDirectory: '', fullPath: thisFolder,
|
|
17
|
+
const files = listFilesToCompile({ scriptName: 'compile.service', scriptDirectory: '', fullPath: thisFolder, parsed: {} });
|
|
18
18
|
expect(files.length).toBe(1);
|
|
19
19
|
expect(files[0]).toStrictEqual({
|
|
20
20
|
baseName: 'compile.service',
|
|
@@ -24,7 +24,7 @@ describe('listFiles', () => {
|
|
|
24
24
|
});
|
|
25
25
|
it('should list files in subdirectory', () => {
|
|
26
26
|
const parent = path.join(thisFolder, '..');
|
|
27
|
-
const files = listFilesToCompile({ scriptName: 'compile.service', fullPath: parent, scriptDirectory: 'services',
|
|
27
|
+
const files = listFilesToCompile({ scriptName: 'compile.service', fullPath: parent, scriptDirectory: 'services', parsed: {} });
|
|
28
28
|
expect(files.length).toBe(1);
|
|
29
29
|
expect(files[0]).toStrictEqual({
|
|
30
30
|
baseName: 'compile.service',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.service.unit.test.js","sourceRoot":"","sources":["../../lib/services/compile.service.unit.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"compile.service.unit.test.js","sourceRoot":"","sources":["../../lib/services/compile.service.unit.test.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEhE,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACvB,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACnC,MAAM,KAAK,GAAG,kBAAkB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAC/H,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YAC3B,QAAQ,EAAE,sBAAsB;YAChC,SAAS,EAAE,GAAG,UAAU,0BAA0B;YAClD,UAAU,EAAE,GAAG,UAAU,+BAA+B;SAC3D,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACvC,MAAM,KAAK,GAAG,kBAAkB,CAAC,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,EAAqB,EAAE,CAAC,CAAC;QAC9I,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YAC3B,QAAQ,EAAE,iBAAiB;YAC3B,SAAS,EAAE,GAAG,UAAU,qBAAqB;YAC7C,UAAU,EAAE,GAAG,UAAU,0BAA0B;SACtD,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QACzC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,kBAAkB,CAAC,EAAE,UAAU,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,EAAE,EAAqB,EAAE,CAAC,CAAC;QAClJ,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YAC3B,QAAQ,EAAE,iBAAiB;YAC3B,SAAS,EAAE,GAAG,MAAM,8BAA8B;YAClD,UAAU,EAAE,GAAG,MAAM,0BAA0B;SAClD,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QACxC,MAAM,IAAI,GAAG,gBAAgB,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QAC/E,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC;YACvB,QAAQ,EAAE,QAAQ;YAClB,SAAS,EAAE,WAAW;YACtB,UAAU,EAAE,GAAG,UAAU,iBAAiB;SAC7C,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import type { NangoYamlParsed } from '@nangohq/types';
|
|
2
|
+
import type { ServiceResponse } from '@nangohq/shared';
|
|
3
|
+
export interface ValidationMessage {
|
|
4
|
+
msg: string;
|
|
5
|
+
path?: string;
|
|
6
|
+
code?: string | undefined;
|
|
7
|
+
params?: Record<string, any> | undefined;
|
|
6
8
|
}
|
|
7
|
-
declare
|
|
8
|
-
|
|
9
|
+
export declare function load(fullPath: string, debug?: boolean): ServiceResponse<NangoYamlParsed>;
|
|
10
|
+
/**
|
|
11
|
+
* Output validation errors to console
|
|
12
|
+
*/
|
|
13
|
+
export declare function validateAndOutput(yaml: any): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Use AJV to validate a nango.yaml against json schema
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateYaml(yaml: any): ValidationMessage[];
|
|
@@ -2,71 +2,101 @@ import fs from 'fs';
|
|
|
2
2
|
import Ajv from 'ajv';
|
|
3
3
|
import addErrors from 'ajv-errors';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
-
import { loadLocalNangoConfig, loadStandardConfig, nangoConfigFile, determineVersion, NangoError } from '@nangohq/shared';
|
|
6
5
|
import { getNangoRootPath, printDebug } from '../utils.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
import { NangoError } from '@nangohq/shared';
|
|
7
|
+
import { determineVersion, loadNangoYaml } from '@nangohq/nango-yaml';
|
|
8
|
+
export function load(fullPath, debug = false) {
|
|
9
|
+
if (debug) {
|
|
10
|
+
printDebug(`Loading ${fullPath}`);
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const parser = loadNangoYaml({ fullPath });
|
|
14
|
+
if (debug) {
|
|
15
|
+
printDebug(`Config file found`);
|
|
12
16
|
}
|
|
13
|
-
const
|
|
14
|
-
if (!
|
|
15
|
-
return { success: false, error:
|
|
17
|
+
const valid = validateAndOutput(parser.raw);
|
|
18
|
+
if (!valid) {
|
|
19
|
+
return { success: false, error: new NangoError('failed_to_parse_nango_yaml'), response: null };
|
|
16
20
|
}
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
|
|
21
|
+
parser.parse();
|
|
22
|
+
if (parser.errors.length > 0) {
|
|
23
|
+
for (const error of parser.errors) {
|
|
24
|
+
console.log(chalk.underline(chalk.white(error.path)));
|
|
25
|
+
console.log(` ${chalk.red('error')} ${error.message}${error.code ? chalk.dim(` [${error.code}]`) : ''}`);
|
|
26
|
+
console.log('');
|
|
27
|
+
}
|
|
28
|
+
return { success: false, error: new NangoError('failed_to_parse_nango_yaml'), response: null };
|
|
20
29
|
}
|
|
21
|
-
if (
|
|
22
|
-
|
|
30
|
+
if (parser.warnings.length > 0) {
|
|
31
|
+
parser.warnings.forEach((warn) => {
|
|
32
|
+
console.log(chalk.underline(chalk.white(warn.path)));
|
|
33
|
+
console.log(`${chalk.yellow(warn.message)} [${warn.code}]`);
|
|
34
|
+
console.log('');
|
|
35
|
+
});
|
|
23
36
|
}
|
|
24
|
-
return { success: true, error: null, response:
|
|
37
|
+
return { success: true, error: null, response: parser.parsed };
|
|
25
38
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const syncs = config.syncs || [];
|
|
29
|
-
const actions = config.actions || [];
|
|
30
|
-
const allSyncs = [...syncs, ...actions];
|
|
31
|
-
const models = allSyncs.reduce((acc, sync) => {
|
|
32
|
-
const models = sync.models || [];
|
|
33
|
-
const names = models.map((model) => model.name);
|
|
34
|
-
return [...acc, ...names];
|
|
35
|
-
}, []);
|
|
36
|
-
return [...acc, ...models];
|
|
37
|
-
}, []);
|
|
38
|
-
return modelNames;
|
|
39
|
+
catch {
|
|
40
|
+
return { success: false, error: new NangoError('error_loading_nango_config'), response: null };
|
|
39
41
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Output validation errors to console
|
|
45
|
+
*/
|
|
46
|
+
export function validateAndOutput(yaml) {
|
|
47
|
+
const errors = validateYaml(yaml);
|
|
48
|
+
if (errors.length <= 0) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
const messages = [];
|
|
52
|
+
for (const error of errors) {
|
|
53
|
+
if (error.path) {
|
|
54
|
+
messages.push(chalk.underline(chalk.white(error.path.substring(1).split('/').join(' > '))));
|
|
45
55
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
messages.push(` ${chalk.red('error')} ${error.msg}${error.code ? chalk.dim(` [${error.code}]`) : ''}`);
|
|
57
|
+
if (error.params) {
|
|
58
|
+
for (const [key, val] of Object.entries(error.params)) {
|
|
59
|
+
messages.push(chalk.dim(` ${key}: ${val}`));
|
|
60
|
+
}
|
|
49
61
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
messages.push('');
|
|
63
|
+
}
|
|
64
|
+
console.log(`${chalk.red(`nango.yaml validation failed`)}\n\n${messages.join('\n')}`);
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Use AJV to validate a nango.yaml against json schema
|
|
69
|
+
*/
|
|
70
|
+
export function validateYaml(yaml) {
|
|
71
|
+
const ajv = new Ajv({ allErrors: true });
|
|
72
|
+
addErrors(ajv);
|
|
73
|
+
if (!yaml || !('integrations' in yaml)) {
|
|
74
|
+
return [
|
|
75
|
+
{
|
|
76
|
+
msg: 'Invalid file format, you should have at least an `integrations` property at the root level. Check our documentation https://docs.nango.dev/reference/integration-configuration'
|
|
62
77
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
const version = determineVersion(yaml);
|
|
81
|
+
const validationFile = version === 'v1' ? 'nango.yaml.schema.v1.json' : 'nango.yaml.schema.v2.json';
|
|
82
|
+
const schema = fs.readFileSync(`${getNangoRootPath()}/lib/${validationFile}`, 'utf8');
|
|
83
|
+
const validate = ajv.compile(JSON.parse(schema));
|
|
84
|
+
if (validate(yaml)) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
const messages = [];
|
|
88
|
+
for (const error of validate.errors) {
|
|
89
|
+
if (!error.message || error.message === ' ') {
|
|
90
|
+
continue;
|
|
66
91
|
}
|
|
67
|
-
|
|
92
|
+
const code = error.keyword !== 'errorMessage' ? error.keyword : undefined;
|
|
93
|
+
messages.push({
|
|
94
|
+
msg: error.message,
|
|
95
|
+
path: error.instancePath,
|
|
96
|
+
code,
|
|
97
|
+
params: error.params && Object.keys(error.params).length > 0 && !('errors' in error.params) ? error.params : undefined
|
|
98
|
+
});
|
|
68
99
|
}
|
|
100
|
+
return messages;
|
|
69
101
|
}
|
|
70
|
-
const configService = new ConfigService();
|
|
71
|
-
export default configService;
|
|
72
102
|
//# sourceMappingURL=config.service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.service.js","sourceRoot":"","sources":["../../lib/services/config.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"config.service.js","sourceRoot":"","sources":["../../lib/services/config.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import yaml from 'js-yaml';
|
|
3
|
+
import stripAnsi from 'strip-ansi';
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { load, validateYaml } from './config.service';
|
|
6
|
+
import { NangoError } from '@nangohq/shared';
|
|
7
|
+
describe('load', () => {
|
|
8
|
+
// Not the best but until we have a logger it will work
|
|
9
|
+
const consoleMock = vi.spyOn(console, 'log').mockImplementation(() => undefined);
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
consoleMock.mockReset();
|
|
12
|
+
});
|
|
13
|
+
it('should parse a nango.yaml file that is version 1 as expected', () => {
|
|
14
|
+
const { response: parsed } = load(path.resolve(__dirname, `../../fixtures/nango-yaml/v1/valid`));
|
|
15
|
+
expect(parsed).toMatchSnapshot();
|
|
16
|
+
expect(parsed).not.toBeNull();
|
|
17
|
+
});
|
|
18
|
+
it('should parse a nango.yaml file that is version 2 as expected', () => {
|
|
19
|
+
const { response: parsed } = load(path.resolve(__dirname, `../../fixtures/nango-yaml/v2/valid`));
|
|
20
|
+
expect(parsed).toMatchSnapshot();
|
|
21
|
+
expect(parsed).not.toBeNull();
|
|
22
|
+
});
|
|
23
|
+
it('should throw a validation error on a nango.yaml file that is not formatted correctly -- missing endpoint', () => {
|
|
24
|
+
const acc = [];
|
|
25
|
+
consoleMock.mockImplementation((m) => acc.push(stripAnsi(m)));
|
|
26
|
+
const { response: parsed, error } = load(path.resolve(__dirname, `../../fixtures/nango-yaml/v2/invalid.1`));
|
|
27
|
+
expect(parsed).toBeNull();
|
|
28
|
+
expect(error).toBeDefined();
|
|
29
|
+
expect(error).toStrictEqual(new NangoError('failed_to_parse_nango_yaml'));
|
|
30
|
+
expect(acc.join('')).toContain('An endpoint property is required to specify how to retrieve the data from the sync');
|
|
31
|
+
});
|
|
32
|
+
it('should throw a validation error on a nango.yaml file that is not formatted correctly -- webhook subscriptions are not allowed in an action', () => {
|
|
33
|
+
const acc = [];
|
|
34
|
+
consoleMock.mockImplementation((m) => acc.push(stripAnsi(m)));
|
|
35
|
+
const { response: parsed, error } = load(path.resolve(__dirname, `../../fixtures/nango-yaml/v2/invalid.2`));
|
|
36
|
+
expect(parsed).toBeNull();
|
|
37
|
+
expect(error).toBeDefined();
|
|
38
|
+
expect(error).toStrictEqual(new NangoError('failed_to_parse_nango_yaml'));
|
|
39
|
+
expect(acc.join('')).toContain('additionalProperty: webhook-subscription');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('validate', () => {
|
|
43
|
+
it('should validate empty yaml', () => {
|
|
44
|
+
const res = validateYaml(yaml.load(``));
|
|
45
|
+
expect(res).toStrictEqual([
|
|
46
|
+
{
|
|
47
|
+
msg: 'Invalid file format, you should have at least an `integrations` property at the root level. Check our documentation https://docs.nango.dev/reference/integration-configuration'
|
|
48
|
+
}
|
|
49
|
+
]);
|
|
50
|
+
});
|
|
51
|
+
it('should require sync to be object', () => {
|
|
52
|
+
const res = validateYaml(yaml.load(`
|
|
53
|
+
integrations:
|
|
54
|
+
test:
|
|
55
|
+
syncs:
|
|
56
|
+
foobar:
|
|
57
|
+
`));
|
|
58
|
+
expect(res).toStrictEqual([
|
|
59
|
+
{
|
|
60
|
+
code: 'type',
|
|
61
|
+
msg: 'must be object',
|
|
62
|
+
params: { type: 'object' },
|
|
63
|
+
path: '/integrations/test/syncs/foobar'
|
|
64
|
+
}
|
|
65
|
+
]);
|
|
66
|
+
});
|
|
67
|
+
it('should require some fields in sync', () => {
|
|
68
|
+
const res = validateYaml(yaml.load(`
|
|
69
|
+
integrations:
|
|
70
|
+
test:
|
|
71
|
+
syncs:
|
|
72
|
+
foobar:
|
|
73
|
+
input: boolean
|
|
74
|
+
runs: every day
|
|
75
|
+
`));
|
|
76
|
+
expect(res).toMatchObject([
|
|
77
|
+
{
|
|
78
|
+
msg: 'An endpoint property is required to specify how to retrieve the data from the sync.',
|
|
79
|
+
path: '/integrations/test/syncs/foobar'
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
msg: 'An output property is required to specify what is the outcome of the sync.',
|
|
83
|
+
path: '/integrations/test/syncs/foobar'
|
|
84
|
+
}
|
|
85
|
+
]);
|
|
86
|
+
});
|
|
87
|
+
it('should disallow extra properties', () => {
|
|
88
|
+
const res = validateYaml(yaml.load(`
|
|
89
|
+
integrations:
|
|
90
|
+
test:
|
|
91
|
+
syncs:
|
|
92
|
+
foobar:
|
|
93
|
+
runs: every day
|
|
94
|
+
endpoint: GET /test
|
|
95
|
+
output: boolean
|
|
96
|
+
iinput: boolean
|
|
97
|
+
`));
|
|
98
|
+
expect(res).toStrictEqual([
|
|
99
|
+
{
|
|
100
|
+
code: 'additionalProperties',
|
|
101
|
+
msg: 'must NOT have additional properties',
|
|
102
|
+
params: { additionalProperty: 'iinput' },
|
|
103
|
+
path: '/integrations/test/syncs/foobar'
|
|
104
|
+
}
|
|
105
|
+
]);
|
|
106
|
+
});
|
|
107
|
+
it('should enforce endpoint format', () => {
|
|
108
|
+
const res = validateYaml(yaml.load(`
|
|
109
|
+
integrations:
|
|
110
|
+
test:
|
|
111
|
+
syncs:
|
|
112
|
+
foobar:
|
|
113
|
+
runs: every day
|
|
114
|
+
endpoint: /te df /+-st
|
|
115
|
+
output: boolean
|
|
116
|
+
`));
|
|
117
|
+
expect(res).toMatchObject([
|
|
118
|
+
{
|
|
119
|
+
msg: 'endpoint must be a URL (or an array of URLs) with an HTTP verb, i.e: "GET /tickets/ticket"',
|
|
120
|
+
path: '/integrations/test/syncs/foobar/endpoint'
|
|
121
|
+
}
|
|
122
|
+
]);
|
|
123
|
+
});
|
|
124
|
+
it('should prevent incorrect HTTP verb for sync endpoint ', () => {
|
|
125
|
+
const res = validateYaml(yaml.load(`
|
|
126
|
+
integrations:
|
|
127
|
+
test:
|
|
128
|
+
sync:
|
|
129
|
+
foobar:
|
|
130
|
+
endpoint: DELETE /test
|
|
131
|
+
output: boolean
|
|
132
|
+
`));
|
|
133
|
+
expect(res).toMatchObject([]);
|
|
134
|
+
});
|
|
135
|
+
it('should allow endpoint format for action', () => {
|
|
136
|
+
const res = validateYaml(yaml.load(`
|
|
137
|
+
integrations:
|
|
138
|
+
test:
|
|
139
|
+
actions:
|
|
140
|
+
foobar:
|
|
141
|
+
endpoint: DELETE /test
|
|
142
|
+
output: boolean
|
|
143
|
+
`));
|
|
144
|
+
expect(res).toMatchObject([]);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=config.service.unit.test.js.map
|