next-workflow-builder 0.3.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/README.md +165 -0
- package/dist/chunk-3MSAF2TH.js +438 -0
- package/dist/chunk-5YYA34YV.js +96 -0
- package/dist/chunk-7MUXUHEL.js +66 -0
- package/dist/chunk-BNYDOC3I.js +169 -0
- package/dist/chunk-D44JFQYX.js +546 -0
- package/dist/chunk-DJ7ANVJ3.js +51 -0
- package/dist/chunk-O3I2INCD.js +71 -0
- package/dist/chunk-OQHML4II.js +36 -0
- package/dist/chunk-P3DTV3QS.js +105 -0
- package/dist/chunk-XJ67EFQA.js +1162 -0
- package/dist/chunk-Z3BJJYHM.js +246 -0
- package/dist/client/index.d.ts +32 -0
- package/dist/client/index.js +13700 -0
- package/dist/condition-SFT7Y5YJ.js +29 -0
- package/dist/database-query-GRWP3S3M.js +99 -0
- package/dist/http-request-2HVCXQHK.js +76 -0
- package/dist/next/index.d.ts +42 -0
- package/dist/next/index.js +66 -0
- package/dist/plugins/index.d.ts +113 -0
- package/dist/plugins/index.js +52 -0
- package/dist/server/api/index.d.ts +8 -0
- package/dist/server/api/index.js +2672 -0
- package/dist/server/index.d.ts +2911 -0
- package/dist/server/index.js +60 -0
- package/dist/style-prefixed.css +5167 -0
- package/dist/styles.css +5167 -0
- package/dist/types-BACZx2Ft.d.ts +139 -0
- package/package.json +112 -0
- package/src/scripts/nwb.ts +54 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CODEGEN_REGISTRY_FILE,
|
|
3
|
+
GITIGNORE_FILE,
|
|
4
|
+
LEADING_WHITESPACE_PATTERN,
|
|
5
|
+
OUTPUT_CONFIGS_FILE,
|
|
6
|
+
OUTPUT_FILE,
|
|
7
|
+
PLUGINS_DIR,
|
|
8
|
+
STEP_REGISTRY_FILE,
|
|
9
|
+
SYSTEM_INTEGRATION_TYPES,
|
|
10
|
+
TYPES_FILE
|
|
11
|
+
} from "./chunk-OQHML4II.js";
|
|
12
|
+
import {
|
|
13
|
+
computeActionId,
|
|
14
|
+
getAllIntegrations,
|
|
15
|
+
getIntegrationTypes
|
|
16
|
+
} from "./chunk-Z3BJJYHM.js";
|
|
17
|
+
|
|
18
|
+
// src/plugins/discover.ts
|
|
19
|
+
import { createJiti } from "jiti";
|
|
20
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
21
|
+
import { dirname, join, relative } from "path";
|
|
22
|
+
import ts from "typescript";
|
|
23
|
+
async function formatCode(code) {
|
|
24
|
+
try {
|
|
25
|
+
const prettier = await import("prettier");
|
|
26
|
+
return await prettier.format(code, { parser: "typescript" });
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.warn(" Warning: Failed to format generated code:", error);
|
|
29
|
+
return code;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
var generatedCodegenTemplates = /* @__PURE__ */ new Map();
|
|
33
|
+
function generateIndexFile(plugins) {
|
|
34
|
+
const imports = plugins.map((plugin) => `import "./${plugin}";`).join("\n");
|
|
35
|
+
const content = `/**
|
|
36
|
+
* Plugins Index (Auto-Generated)
|
|
37
|
+
*
|
|
38
|
+
* This file is automatically generated by scripts/discover-plugins.ts
|
|
39
|
+
* DO NOT EDIT MANUALLY - your changes will be overwritten!
|
|
40
|
+
*
|
|
41
|
+
* To add a new integration:
|
|
42
|
+
* 1. Create a new directory in plugins/ (e.g., plugins/my-integration/)
|
|
43
|
+
* 2. Add your plugin files (index.tsx, steps/, codegen/, etc.)
|
|
44
|
+
* 3. Run: pnpm discover-plugins (or it runs automatically on build)
|
|
45
|
+
*
|
|
46
|
+
* To remove an integration:
|
|
47
|
+
* 1. Delete the plugin directory
|
|
48
|
+
* 2. Run: pnpm discover-plugins (or it runs automatically on build)
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
// Side-effect imports: each plugin calls registerIntegration() on import
|
|
52
|
+
${imports || "// No plugins discovered"}
|
|
53
|
+
|
|
54
|
+
// Re-export registry utilities so consuming apps can import from "@/plugins"
|
|
55
|
+
export {
|
|
56
|
+
computeActionId,
|
|
57
|
+
findActionById,
|
|
58
|
+
flattenConfigFields,
|
|
59
|
+
generateAIActionPrompts,
|
|
60
|
+
getActionsByCategory,
|
|
61
|
+
getAllActions,
|
|
62
|
+
getAllDependencies,
|
|
63
|
+
getAllEnvVars,
|
|
64
|
+
getAllIntegrations,
|
|
65
|
+
getCredentialMapping,
|
|
66
|
+
getDependenciesForActions,
|
|
67
|
+
getIntegration,
|
|
68
|
+
getIntegrationLabels,
|
|
69
|
+
getIntegrationTypes,
|
|
70
|
+
getPluginEnvVars,
|
|
71
|
+
getSortedIntegrationTypes,
|
|
72
|
+
isFieldGroup,
|
|
73
|
+
parseActionId,
|
|
74
|
+
registerIntegration,
|
|
75
|
+
} from "next-workflow-builder/plugins";
|
|
76
|
+
|
|
77
|
+
export type {
|
|
78
|
+
ActionConfigField,
|
|
79
|
+
ActionConfigFieldBase,
|
|
80
|
+
ActionConfigFieldGroup,
|
|
81
|
+
ActionWithFullId,
|
|
82
|
+
IntegrationPlugin,
|
|
83
|
+
PluginAction,
|
|
84
|
+
} from "next-workflow-builder/plugins";
|
|
85
|
+
`;
|
|
86
|
+
writeFileSync(OUTPUT_FILE, content, "utf-8");
|
|
87
|
+
}
|
|
88
|
+
async function generateTypesFile() {
|
|
89
|
+
const typesDir = dirname(TYPES_FILE);
|
|
90
|
+
if (!existsSync(typesDir)) {
|
|
91
|
+
mkdirSync(typesDir, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
const pluginTypes = getIntegrationTypes();
|
|
94
|
+
const allTypes = [...pluginTypes, ...SYSTEM_INTEGRATION_TYPES].sort();
|
|
95
|
+
const unionType = allTypes.map((t) => ` | "${t}"`).join("\n");
|
|
96
|
+
const content = `/**
|
|
97
|
+
* Integration Types (Auto-Generated)
|
|
98
|
+
*
|
|
99
|
+
* This file is automatically generated by scripts/discover-plugins.ts
|
|
100
|
+
* DO NOT EDIT MANUALLY - your changes will be overwritten!
|
|
101
|
+
*
|
|
102
|
+
* To add a new integration type:
|
|
103
|
+
* 1. Create a plugin in plugins/ directory, OR
|
|
104
|
+
* 2. Add a system integration to SYSTEM_INTEGRATION_TYPES in discover-plugins.ts
|
|
105
|
+
* 3. Run: pnpm discover-plugins
|
|
106
|
+
*
|
|
107
|
+
* Generated types: ${allTypes.join(", ")}
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
// Integration type union - plugins + system integrations
|
|
111
|
+
export type IntegrationType =
|
|
112
|
+
${unionType};
|
|
113
|
+
|
|
114
|
+
// Generic config type - plugins define their own keys via formFields[].configKey
|
|
115
|
+
export type IntegrationConfig = Record<string, string | undefined>;
|
|
116
|
+
`;
|
|
117
|
+
writeFileSync(TYPES_FILE, content, "utf-8");
|
|
118
|
+
console.log(
|
|
119
|
+
`Generated lib/types/integration.ts with ${allTypes.length} type(s)`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
function generateCodegenRegistry() {
|
|
123
|
+
const entries = Array.from(generatedCodegenTemplates.entries());
|
|
124
|
+
if (entries.length === 0) {
|
|
125
|
+
console.log("No codegen templates generated");
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const templateEntries = entries.map(([actionId, { template }]) => {
|
|
129
|
+
const escapedTemplate = template.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
130
|
+
return ` "${actionId}": \`${escapedTemplate}\`,`;
|
|
131
|
+
}).join("\n\n");
|
|
132
|
+
const content = `/**
|
|
133
|
+
* Codegen Registry (Auto-Generated)
|
|
134
|
+
*
|
|
135
|
+
* This file is automatically generated by scripts/discover-plugins.ts
|
|
136
|
+
* DO NOT EDIT MANUALLY - your changes will be overwritten!
|
|
137
|
+
*
|
|
138
|
+
* Contains auto-generated codegen templates for steps with stepHandler.
|
|
139
|
+
* These templates are used when exporting workflows to standalone projects.
|
|
140
|
+
*
|
|
141
|
+
* Generated templates: ${entries.length}
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Auto-generated codegen templates
|
|
146
|
+
* Maps action IDs to their generated export code templates
|
|
147
|
+
*/
|
|
148
|
+
export const AUTO_GENERATED_TEMPLATES: Record<string, string> = {
|
|
149
|
+
${templateEntries}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get the auto-generated codegen template for an action
|
|
154
|
+
*/
|
|
155
|
+
export function getAutoGeneratedTemplate(actionId: string): string | undefined {
|
|
156
|
+
return AUTO_GENERATED_TEMPLATES[actionId];
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
writeFileSync(CODEGEN_REGISTRY_FILE, content, "utf-8");
|
|
160
|
+
console.log(
|
|
161
|
+
`Generated lib/codegen-registry.ts with ${entries.length} template(s)`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
async function generateStepRegistry() {
|
|
165
|
+
const integrations = getAllIntegrations();
|
|
166
|
+
const stepEntries = [];
|
|
167
|
+
for (const integration of integrations) {
|
|
168
|
+
for (const action of integration.actions) {
|
|
169
|
+
const fullActionId = computeActionId(integration.type, action.slug);
|
|
170
|
+
stepEntries.push({
|
|
171
|
+
actionId: fullActionId,
|
|
172
|
+
label: action.label,
|
|
173
|
+
integration: integration.type,
|
|
174
|
+
stepImportPath: action.stepImportPath,
|
|
175
|
+
stepFunction: action.stepFunction
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const importerEntries = stepEntries.flatMap(({ actionId, integration, stepImportPath, stepFunction }) => {
|
|
180
|
+
return [
|
|
181
|
+
` "${actionId}": {
|
|
182
|
+
importer: () => import("@/plugins/${integration}/steps/${stepImportPath}"),
|
|
183
|
+
stepFunction: "${stepFunction}",
|
|
184
|
+
},`
|
|
185
|
+
];
|
|
186
|
+
}).join("\n");
|
|
187
|
+
const labelEntries = stepEntries.map(({ actionId, label }) => ` "${actionId}": "${label}",`).join("\n");
|
|
188
|
+
const content = `/**
|
|
189
|
+
* Step Registry (Auto-Generated)
|
|
190
|
+
*
|
|
191
|
+
* This file is automatically generated by scripts/discover-plugins.ts
|
|
192
|
+
* DO NOT EDIT MANUALLY - your changes will be overwritten!
|
|
193
|
+
*
|
|
194
|
+
* This registry enables dynamic step imports that are statically analyzable
|
|
195
|
+
* by the bundler. Each action type maps to its step importer function.
|
|
196
|
+
*
|
|
197
|
+
* Generated entries: ${stepEntries.length}
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
// biome-ignore lint/suspicious/noExplicitAny: Dynamic step module types - step functions take any input
|
|
201
|
+
export type StepFunction = (input: any) => Promise<any>;
|
|
202
|
+
|
|
203
|
+
// Step modules may contain the step function plus other exports (types, constants, etc.)
|
|
204
|
+
// biome-ignore lint/suspicious/noExplicitAny: Dynamic module with mixed exports
|
|
205
|
+
export type StepModule = Record<string, any>;
|
|
206
|
+
|
|
207
|
+
export type StepImporter = {
|
|
208
|
+
importer: () => Promise<StepModule>;
|
|
209
|
+
stepFunction: string;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Plugin step importers - maps action types to their step import functions
|
|
214
|
+
* These imports are statically analyzable by the bundler
|
|
215
|
+
*/
|
|
216
|
+
export const PLUGIN_STEP_IMPORTERS: Record<string, StepImporter> = {
|
|
217
|
+
${importerEntries}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Action labels - maps action IDs to human-readable labels
|
|
222
|
+
* Used for displaying friendly names in the UI (e.g., Runs tab)
|
|
223
|
+
*/
|
|
224
|
+
export const ACTION_LABELS: Record<string, string> = {
|
|
225
|
+
${labelEntries}
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Get a step importer for an action type
|
|
230
|
+
*/
|
|
231
|
+
export function getStepImporter(actionType: string): StepImporter | undefined {
|
|
232
|
+
return PLUGIN_STEP_IMPORTERS[actionType];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get the human-readable label for an action type
|
|
237
|
+
*/
|
|
238
|
+
export function getActionLabel(actionType: string): string | undefined {
|
|
239
|
+
return ACTION_LABELS[actionType];
|
|
240
|
+
}
|
|
241
|
+
`;
|
|
242
|
+
writeFileSync(STEP_REGISTRY_FILE, content, "utf-8");
|
|
243
|
+
console.log(
|
|
244
|
+
`Generated lib/step-registry.ts with ${stepEntries.length} step(s)`
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
async function generateOutputDisplayConfigs() {
|
|
248
|
+
const integrations = getAllIntegrations();
|
|
249
|
+
const outputConfigs = [];
|
|
250
|
+
for (const integration of integrations) {
|
|
251
|
+
for (const action of integration.actions) {
|
|
252
|
+
if (action.outputConfig && action.outputConfig.type !== "component") {
|
|
253
|
+
outputConfigs.push({
|
|
254
|
+
actionId: computeActionId(integration.type, action.slug),
|
|
255
|
+
type: action.outputConfig.type,
|
|
256
|
+
field: action.outputConfig.field
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
const outputConfigEntries = outputConfigs.map(
|
|
262
|
+
({ actionId, type, field }) => ` "${actionId}": { type: "${type}", field: "${field}" },`
|
|
263
|
+
).join("\n");
|
|
264
|
+
const content = `/**
|
|
265
|
+
* Output Display Configs (Auto-Generated)
|
|
266
|
+
*
|
|
267
|
+
* This file is automatically generated by scripts/discover-plugins.ts
|
|
268
|
+
* DO NOT EDIT MANUALLY - your changes will be overwritten!
|
|
269
|
+
*
|
|
270
|
+
* This file is CLIENT-SAFE and can be imported in client components.
|
|
271
|
+
* It maps action IDs to their output display configuration.
|
|
272
|
+
*
|
|
273
|
+
* Generated configs: ${outputConfigs.length}
|
|
274
|
+
*/
|
|
275
|
+
|
|
276
|
+
export type OutputDisplayConfig = {
|
|
277
|
+
type: "image" | "video" | "url";
|
|
278
|
+
field: string;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Output display configs - maps action IDs to their display configuration
|
|
283
|
+
* Used for rendering outputs in the workflow runs panel
|
|
284
|
+
*/
|
|
285
|
+
export const OUTPUT_DISPLAY_CONFIGS: Record<string, OutputDisplayConfig> = {
|
|
286
|
+
${outputConfigEntries}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Get the output display config for an action type
|
|
291
|
+
*/
|
|
292
|
+
export function getOutputDisplayConfig(actionType: string): OutputDisplayConfig | undefined {
|
|
293
|
+
return OUTPUT_DISPLAY_CONFIGS[actionType];
|
|
294
|
+
}
|
|
295
|
+
`;
|
|
296
|
+
writeFileSync(OUTPUT_CONFIGS_FILE, content, "utf-8");
|
|
297
|
+
console.log(
|
|
298
|
+
`Generated lib/output-display-configs.ts with ${outputConfigs.length} config(s)`
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
function shouldIncludeImport(moduleSpec, importText) {
|
|
302
|
+
if (moduleSpec.startsWith("@/") || moduleSpec.startsWith(".")) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
if (importText.includes("server-only")) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
function extractFunctionInfo(node, sourceCode) {
|
|
311
|
+
if (!(node.name && node.body)) {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
const params = node.parameters.map((p) => sourceCode.slice(p.pos, p.end).trim()).join(", ");
|
|
315
|
+
const returnType = node.type ? sourceCode.slice(node.type.pos, node.type.end).trim() : "Promise<unknown>";
|
|
316
|
+
const body = sourceCode.slice(node.body.pos, node.body.end).trim();
|
|
317
|
+
return {
|
|
318
|
+
name: node.name.text,
|
|
319
|
+
params,
|
|
320
|
+
returnType,
|
|
321
|
+
body
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
function createEmptyAnalysis() {
|
|
325
|
+
return {
|
|
326
|
+
hasExportCore: false,
|
|
327
|
+
integrationType: null,
|
|
328
|
+
coreFunction: null,
|
|
329
|
+
inputTypes: [],
|
|
330
|
+
imports: []
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
function processExportedVariable(decl, result) {
|
|
334
|
+
if (!ts.isIdentifier(decl.name)) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const name = decl.name.text;
|
|
338
|
+
const init = decl.initializer;
|
|
339
|
+
if (name === "_integrationType" && init && ts.isStringLiteral(init)) {
|
|
340
|
+
result.integrationType = init.text;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function processVariableStatement(node, result) {
|
|
344
|
+
const isExported = node.modifiers?.some(
|
|
345
|
+
(m) => m.kind === ts.SyntaxKind.ExportKeyword
|
|
346
|
+
);
|
|
347
|
+
if (!isExported) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
for (const decl of node.declarationList.declarations) {
|
|
351
|
+
processExportedVariable(decl, result);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function shouldIncludeType(typeName) {
|
|
355
|
+
return typeName.endsWith("Result") || typeName.endsWith("Credentials") || typeName.endsWith("CoreInput");
|
|
356
|
+
}
|
|
357
|
+
function processTypeAlias(node, sourceCode, result) {
|
|
358
|
+
if (shouldIncludeType(node.name.text)) {
|
|
359
|
+
result.inputTypes.push(sourceCode.slice(node.pos, node.end).trim());
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
function processImportDeclaration(node, sourceCode, result) {
|
|
363
|
+
const spec = node.moduleSpecifier;
|
|
364
|
+
if (!ts.isStringLiteral(spec)) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const importText = sourceCode.slice(node.pos, node.end).trim();
|
|
368
|
+
if (shouldIncludeImport(spec.text, importText)) {
|
|
369
|
+
result.imports.push(importText);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
function processNode(node, sourceCode, result) {
|
|
373
|
+
if (ts.isVariableStatement(node)) {
|
|
374
|
+
processVariableStatement(node, result);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
378
|
+
processTypeAlias(node, sourceCode, result);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
if (ts.isImportDeclaration(node)) {
|
|
382
|
+
processImportDeclaration(node, sourceCode, result);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (ts.isFunctionDeclaration(node) && node.name?.text === "stepHandler") {
|
|
386
|
+
result.hasExportCore = true;
|
|
387
|
+
result.coreFunction = extractFunctionInfo(node, sourceCode);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function analyzeStepFile(filePath) {
|
|
391
|
+
const result = createEmptyAnalysis();
|
|
392
|
+
if (!existsSync(filePath)) {
|
|
393
|
+
return result;
|
|
394
|
+
}
|
|
395
|
+
const sourceCode = readFileSync(filePath, "utf-8");
|
|
396
|
+
const sourceFile = ts.createSourceFile(
|
|
397
|
+
filePath,
|
|
398
|
+
sourceCode,
|
|
399
|
+
ts.ScriptTarget.Latest,
|
|
400
|
+
true
|
|
401
|
+
);
|
|
402
|
+
ts.forEachChild(sourceFile, (node) => {
|
|
403
|
+
processNode(node, sourceCode, result);
|
|
404
|
+
});
|
|
405
|
+
return result;
|
|
406
|
+
}
|
|
407
|
+
async function generateCodegenTemplate(stepFilePath, stepFunctionName) {
|
|
408
|
+
const analysis = analyzeStepFile(stepFilePath);
|
|
409
|
+
if (!(analysis.hasExportCore && analysis.coreFunction)) {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
const { coreFunction, integrationType, inputTypes, imports } = analysis;
|
|
413
|
+
let innerBody = coreFunction.body.trim();
|
|
414
|
+
if (innerBody.startsWith("{")) {
|
|
415
|
+
innerBody = innerBody.slice(1);
|
|
416
|
+
}
|
|
417
|
+
if (innerBody.endsWith("}")) {
|
|
418
|
+
innerBody = innerBody.slice(0, -1);
|
|
419
|
+
}
|
|
420
|
+
innerBody = innerBody.trim();
|
|
421
|
+
const inputType = coreFunction.params.split(",")[0].replace(LEADING_WHITESPACE_PATTERN, "").split(":")[1]?.trim() || "unknown";
|
|
422
|
+
const rawTemplate = `${imports.join("\n")}
|
|
423
|
+
import { fetchCredentials } from './lib/credential-helper';
|
|
424
|
+
|
|
425
|
+
function getErrorMessage(error: unknown): string {
|
|
426
|
+
if (error instanceof Error) return error.message;
|
|
427
|
+
return String(error);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
${inputTypes.join("\n\n")}
|
|
431
|
+
|
|
432
|
+
export async function ${stepFunctionName}(input: ${inputType}): ${coreFunction.returnType} {
|
|
433
|
+
"use step";
|
|
434
|
+
const credentials = await fetchCredentials("${integrationType || "unknown"}");
|
|
435
|
+
${innerBody}
|
|
436
|
+
}`;
|
|
437
|
+
return await formatCode(rawTemplate);
|
|
438
|
+
}
|
|
439
|
+
async function processStepFilesForCodegen() {
|
|
440
|
+
const integrations = getAllIntegrations();
|
|
441
|
+
for (const integration of integrations) {
|
|
442
|
+
for (const action of integration.actions) {
|
|
443
|
+
const stepFilePath = join(
|
|
444
|
+
PLUGINS_DIR,
|
|
445
|
+
integration.type,
|
|
446
|
+
"steps",
|
|
447
|
+
`${action.stepImportPath}.ts`
|
|
448
|
+
);
|
|
449
|
+
const template = await generateCodegenTemplate(
|
|
450
|
+
stepFilePath,
|
|
451
|
+
action.stepFunction
|
|
452
|
+
);
|
|
453
|
+
if (template) {
|
|
454
|
+
const actionId = computeActionId(integration.type, action.slug);
|
|
455
|
+
generatedCodegenTemplates.set(actionId, {
|
|
456
|
+
template,
|
|
457
|
+
integrationType: integration.type
|
|
458
|
+
});
|
|
459
|
+
console.log(` Generated codegen template for ${actionId}`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function ensureGitignore() {
|
|
465
|
+
const SECTION_HEADER = "\n# Auto-generated by discover-plugins";
|
|
466
|
+
const filesToIgnore = [
|
|
467
|
+
TYPES_FILE,
|
|
468
|
+
CODEGEN_REGISTRY_FILE,
|
|
469
|
+
STEP_REGISTRY_FILE,
|
|
470
|
+
OUTPUT_CONFIGS_FILE,
|
|
471
|
+
OUTPUT_FILE
|
|
472
|
+
];
|
|
473
|
+
const relativePaths = filesToIgnore.map((file) => relative(process.cwd(), file));
|
|
474
|
+
let content = "";
|
|
475
|
+
if (existsSync(GITIGNORE_FILE)) {
|
|
476
|
+
content = readFileSync(GITIGNORE_FILE, "utf-8");
|
|
477
|
+
}
|
|
478
|
+
const existingLines = new Set(content.split("\n").map((line) => line.trim()));
|
|
479
|
+
const newEntries = relativePaths.filter((entry) => !existingLines.has(entry));
|
|
480
|
+
if (newEntries.length > 0) {
|
|
481
|
+
let textToAppend = "";
|
|
482
|
+
if (content.length > 0 && !content.endsWith("\n")) {
|
|
483
|
+
textToAppend += "\n";
|
|
484
|
+
}
|
|
485
|
+
if (!content.includes(SECTION_HEADER)) {
|
|
486
|
+
textToAppend += `${SECTION_HEADER}
|
|
487
|
+
`;
|
|
488
|
+
}
|
|
489
|
+
textToAppend += newEntries.join("\n") + "\n";
|
|
490
|
+
writeFileSync(GITIGNORE_FILE, content + textToAppend, "utf-8");
|
|
491
|
+
console.log(`Updated .gitignore with ${newEntries.length} new file(s).`);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
async function discoverPlugins() {
|
|
495
|
+
console.log("Discovering plugins...");
|
|
496
|
+
const entries = readdirSync(PLUGINS_DIR);
|
|
497
|
+
const plugins = entries.filter((entry) => {
|
|
498
|
+
if (entry.startsWith("_") || entry.startsWith(".") || entry === "index.ts" || entry === "registry.ts") {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
const fullPath = join(PLUGINS_DIR, entry);
|
|
502
|
+
try {
|
|
503
|
+
return statSync(fullPath).isDirectory();
|
|
504
|
+
} catch {
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
}).sort();
|
|
508
|
+
if (plugins.length === 0) {
|
|
509
|
+
console.log("No plugins found in plugins/ directory");
|
|
510
|
+
} else {
|
|
511
|
+
console.log(`Found ${plugins.length} plugin(s):`);
|
|
512
|
+
for (const plugin of plugins) {
|
|
513
|
+
console.log(` - ${plugin}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
ensureGitignore();
|
|
517
|
+
console.log("Generating plugins/index.ts...");
|
|
518
|
+
generateIndexFile(plugins);
|
|
519
|
+
if (plugins.length > 0) {
|
|
520
|
+
console.log("Registering plugins...\n");
|
|
521
|
+
const jiti = createJiti(import.meta.url, { jsx: true });
|
|
522
|
+
for (const plugin of plugins) {
|
|
523
|
+
try {
|
|
524
|
+
await jiti.import(join(PLUGINS_DIR, plugin));
|
|
525
|
+
console.log(` Registered: ${plugin}`);
|
|
526
|
+
} catch (error) {
|
|
527
|
+
console.warn(` Warning: Failed to import plugin ${plugin}:`, error);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
console.log("Generating lib/types/integration.ts...");
|
|
532
|
+
await generateTypesFile();
|
|
533
|
+
console.log("Generating lib/step-registry.ts...");
|
|
534
|
+
await generateStepRegistry();
|
|
535
|
+
console.log("Generating lib/output-display-configs.ts...");
|
|
536
|
+
await generateOutputDisplayConfigs();
|
|
537
|
+
console.log("\nProcessing step files for codegen templates...");
|
|
538
|
+
await processStepFilesForCodegen();
|
|
539
|
+
console.log("Generating lib/codegen-registry.ts...");
|
|
540
|
+
generateCodegenRegistry();
|
|
541
|
+
console.log("Done! Plugin registry updated.\n");
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
export {
|
|
545
|
+
discoverPlugins
|
|
546
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getIntegrationById
|
|
3
|
+
} from "./chunk-BNYDOC3I.js";
|
|
4
|
+
import {
|
|
5
|
+
getCredentialMapping,
|
|
6
|
+
getIntegration
|
|
7
|
+
} from "./chunk-Z3BJJYHM.js";
|
|
8
|
+
|
|
9
|
+
// src/server/lib/credential-fetcher.ts
|
|
10
|
+
var SYSTEM_CREDENTIAL_MAPPERS = {
|
|
11
|
+
database: (config) => {
|
|
12
|
+
const creds = {};
|
|
13
|
+
if (config.url) {
|
|
14
|
+
creds.DATABASE_URL = config.url;
|
|
15
|
+
}
|
|
16
|
+
return creds;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
function mapIntegrationConfig(integrationType, config) {
|
|
20
|
+
const systemMapper = SYSTEM_CREDENTIAL_MAPPERS[integrationType];
|
|
21
|
+
if (systemMapper) {
|
|
22
|
+
return systemMapper(config);
|
|
23
|
+
}
|
|
24
|
+
const plugin = getIntegration(integrationType);
|
|
25
|
+
if (plugin) {
|
|
26
|
+
return getCredentialMapping(plugin, config);
|
|
27
|
+
}
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
async function fetchCredentials(integrationId) {
|
|
31
|
+
console.log("[Credential Fetcher] Fetching integration:", integrationId);
|
|
32
|
+
const integration = await getIntegrationById(integrationId);
|
|
33
|
+
if (!integration) {
|
|
34
|
+
console.log("[Credential Fetcher] Integration not found");
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
console.log("[Credential Fetcher] Found integration:", integration.type);
|
|
38
|
+
const credentials = mapIntegrationConfig(
|
|
39
|
+
integration.type,
|
|
40
|
+
integration.config
|
|
41
|
+
);
|
|
42
|
+
console.log(
|
|
43
|
+
"[Credential Fetcher] Returning credentials for type:",
|
|
44
|
+
integration.type
|
|
45
|
+
);
|
|
46
|
+
return credentials;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
fetchCredentials
|
|
51
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// src/server/lib/utils.ts
|
|
2
|
+
function getErrorMessage(error) {
|
|
3
|
+
if (error === null || error === void 0) {
|
|
4
|
+
return "Unknown error";
|
|
5
|
+
}
|
|
6
|
+
if (error instanceof Error) {
|
|
7
|
+
if (error.cause && error.cause instanceof Error) {
|
|
8
|
+
return `${error.message}: ${error.cause.message}`;
|
|
9
|
+
}
|
|
10
|
+
return error.message;
|
|
11
|
+
}
|
|
12
|
+
if (typeof error === "string") {
|
|
13
|
+
return error;
|
|
14
|
+
}
|
|
15
|
+
if (typeof error === "object") {
|
|
16
|
+
const obj = error;
|
|
17
|
+
if (typeof obj.message === "string" && obj.message) {
|
|
18
|
+
return obj.message;
|
|
19
|
+
}
|
|
20
|
+
if (obj.responseBody && typeof obj.responseBody === "object") {
|
|
21
|
+
const body = obj.responseBody;
|
|
22
|
+
if (typeof body.error === "string") {
|
|
23
|
+
return body.error;
|
|
24
|
+
}
|
|
25
|
+
if (body.error && typeof body.error === "object" && typeof body.error.message === "string") {
|
|
26
|
+
return body.error.message;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (typeof obj.error === "string" && obj.error) {
|
|
30
|
+
return obj.error;
|
|
31
|
+
}
|
|
32
|
+
if (obj.error && typeof obj.error === "object") {
|
|
33
|
+
const nestedError = obj.error;
|
|
34
|
+
if (typeof nestedError.message === "string") {
|
|
35
|
+
return nestedError.message;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (obj.data && typeof obj.data === "object") {
|
|
39
|
+
const data = obj.data;
|
|
40
|
+
if (typeof data.error === "string") {
|
|
41
|
+
return data.error;
|
|
42
|
+
}
|
|
43
|
+
if (typeof data.message === "string") {
|
|
44
|
+
return data.message;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (typeof obj.reason === "string" && obj.reason) {
|
|
48
|
+
return obj.reason;
|
|
49
|
+
}
|
|
50
|
+
if (typeof obj.statusText === "string" && obj.statusText) {
|
|
51
|
+
const status = typeof obj.status === "number" ? ` (${obj.status})` : "";
|
|
52
|
+
return `${obj.statusText}${status}`;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
const stringified = JSON.stringify(error, null, 0);
|
|
56
|
+
if (stringified && stringified !== "{}" && stringified.length < 500) {
|
|
57
|
+
return stringified;
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
const toString = Object.prototype.toString.call(error);
|
|
62
|
+
if (toString !== "[object Object]") {
|
|
63
|
+
return toString;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return "Unknown error";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
getErrorMessage
|
|
71
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/server/constants.ts
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
var CWD = process.cwd();
|
|
4
|
+
var PLUGINS_DIR = join(CWD, "plugins");
|
|
5
|
+
var LIB_DIR = join(CWD, "lib");
|
|
6
|
+
var OUTPUT_FILE = join(PLUGINS_DIR, "index.ts");
|
|
7
|
+
var TYPES_FILE = join(LIB_DIR, "types", "integration.ts");
|
|
8
|
+
var GITIGNORE_FILE = join(CWD, ".gitignore");
|
|
9
|
+
var STEP_REGISTRY_FILE = join(LIB_DIR, "step-registry.ts");
|
|
10
|
+
var OUTPUT_CONFIGS_FILE = join(LIB_DIR, "output-display-configs.ts");
|
|
11
|
+
var CODEGEN_REGISTRY_FILE = join(LIB_DIR, "codegen-registry.ts");
|
|
12
|
+
var SYSTEM_INTEGRATION_TYPES = ["database"];
|
|
13
|
+
var LEADING_WHITESPACE_PATTERN = /^\s*/;
|
|
14
|
+
var BOILERPLATE_PATH = join(".", "lib", "next-boilerplate");
|
|
15
|
+
var CODEGEN_TEMPLATES_PATH = join(process.cwd(), "lib", "codegen-templates");
|
|
16
|
+
var NON_ALPHANUMERIC_REGEX = /[^a-zA-Z0-9\s]/g;
|
|
17
|
+
var WHITESPACE_SPLIT_REGEX = /\s+/;
|
|
18
|
+
var TEMPLATE_EXPORT_REGEX = /export default `([\s\S]*)`/;
|
|
19
|
+
var IS_PRODUCTION = process.env.NODE_ENV === "production";
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
PLUGINS_DIR,
|
|
23
|
+
OUTPUT_FILE,
|
|
24
|
+
TYPES_FILE,
|
|
25
|
+
GITIGNORE_FILE,
|
|
26
|
+
STEP_REGISTRY_FILE,
|
|
27
|
+
OUTPUT_CONFIGS_FILE,
|
|
28
|
+
CODEGEN_REGISTRY_FILE,
|
|
29
|
+
SYSTEM_INTEGRATION_TYPES,
|
|
30
|
+
LEADING_WHITESPACE_PATTERN,
|
|
31
|
+
BOILERPLATE_PATH,
|
|
32
|
+
CODEGEN_TEMPLATES_PATH,
|
|
33
|
+
NON_ALPHANUMERIC_REGEX,
|
|
34
|
+
WHITESPACE_SPLIT_REGEX,
|
|
35
|
+
TEMPLATE_EXPORT_REGEX
|
|
36
|
+
};
|