@auxx/sdk 0.0.12 → 0.0.14
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/lib/api/api.js +3 -1
- package/lib/api/schemas.js +4 -0
- package/lib/auth/auth.js +3 -0
- package/lib/build/server/find-tool-server-modules.js +279 -0
- package/lib/build/server/find-workflow-block-server-modules.js +10 -2
- package/lib/build/server/generate-server-entry.js +46 -1
- package/lib/build/server/zod-to-provider-tool-schema.js +42 -0
- package/lib/client/workflow/index.d.ts +1 -1
- package/lib/client/workflow/index.d.ts.map +1 -1
- package/lib/commands/build/validate-typescript.js +33 -2
- package/lib/commands/build.js +3 -26
- package/lib/commands/dev/bundle-javascript.js +17 -1
- package/lib/commands/dev/prepare-build-context.js +11 -2
- package/lib/commands/dev/server-builder.js +2 -1
- package/lib/commands/dev/upload.js +5 -1
- package/lib/commands/dev.js +4 -1
- package/lib/commands/version/create/bundle-javascript.js +10 -0
- package/lib/commands/version/create.js +40 -3
- package/lib/constants/app-fields-files.js +1 -0
- package/lib/env-loader.js +17 -1
- package/lib/env.js +1 -0
- package/lib/root/app.d.ts +7 -2
- package/lib/root/app.d.ts.map +1 -1
- package/lib/root/fields/define-field.d.ts +67 -0
- package/lib/root/fields/define-field.d.ts.map +1 -0
- package/lib/root/fields/define-field.js +21 -0
- package/lib/root/fields/field-types.d.ts +47 -0
- package/lib/root/fields/field-types.d.ts.map +1 -0
- package/lib/root/fields/field-types.js +25 -0
- package/lib/root/fields/index.d.ts +3 -0
- package/lib/root/fields/index.d.ts.map +1 -0
- package/lib/root/fields/index.js +2 -0
- package/lib/root/index.d.ts +5 -2
- package/lib/root/index.d.ts.map +1 -1
- package/lib/root/index.js +3 -1
- package/lib/root/tools/define-tool.d.ts +4 -0
- package/lib/root/tools/define-tool.d.ts.map +1 -0
- package/lib/root/tools/define-tool.js +21 -0
- package/lib/root/tools/index.d.ts +5 -0
- package/lib/root/tools/index.d.ts.map +1 -0
- package/lib/root/tools/index.js +3 -0
- package/lib/root/tools/refs.d.ts +9 -0
- package/lib/root/tools/refs.d.ts.map +1 -0
- package/lib/root/tools/refs.js +4 -0
- package/lib/root/tools/types.d.ts +91 -0
- package/lib/root/tools/types.d.ts.map +1 -0
- package/lib/root/tools/types.js +1 -0
- package/lib/root/workflow/types.d.ts +28 -14
- package/lib/root/workflow/types.d.ts.map +1 -1
- package/lib/root/workflow/types.js +3 -0
- package/lib/root/workflow/utils.d.ts +4 -4
- package/lib/root/workflow/utils.d.ts.map +1 -1
- package/lib/runtime/workflow.js +19 -2
- package/lib/server/connections.d.ts +5 -0
- package/lib/server/connections.d.ts.map +1 -1
- package/lib/server/entities.d.ts +44 -0
- package/lib/server/entities.d.ts.map +1 -0
- package/lib/server/entities.js +3 -0
- package/lib/server/index.d.ts +2 -0
- package/lib/server/index.d.ts.map +1 -1
- package/lib/server/storage.d.ts +30 -3
- package/lib/server/storage.d.ts.map +1 -1
- package/lib/shared/errors.d.ts +34 -0
- package/lib/shared/errors.d.ts.map +1 -1
- package/lib/shared/errors.js +56 -0
- package/lib/shared/index.d.ts +1 -1
- package/lib/shared/index.d.ts.map +1 -1
- package/lib/shared/index.js +1 -1
- package/lib/util/add-auxx-hidden-directory-to-ts-config.js +6 -2
- package/lib/util/compile-and-extract-catalog.js +318 -0
- package/lib/util/ensure-app-fields-types.js +26 -0
- package/lib/util/generate-app-fields-types.js +63 -0
- package/lib/util/warn-if-app-type-annotated.js +9 -0
- package/package.json +9 -1
- package/template/src/events/connection-added.event.ts +17 -2
- package/template/tsconfig.json +1 -1
package/lib/api/api.js
CHANGED
|
@@ -123,7 +123,7 @@ class ApiImpl {
|
|
|
123
123
|
}
|
|
124
124
|
return complete(result.value);
|
|
125
125
|
}
|
|
126
|
-
async createDeployment({ appId, clientBundleSha, serverBundleSha, deploymentType, settingsSchema, targetOrganizationId, environmentVariables, version, metadata, }) {
|
|
126
|
+
async createDeployment({ appId, clientBundleSha, serverBundleSha, deploymentType, settingsSchema, catalog, targetOrganizationId, environmentVariables, version, metadata, publish, }) {
|
|
127
127
|
const result = await this.fetcher.post({
|
|
128
128
|
path: `/api/v1/apps/${appId}/deployments`,
|
|
129
129
|
body: {
|
|
@@ -131,10 +131,12 @@ class ApiImpl {
|
|
|
131
131
|
serverBundleSha,
|
|
132
132
|
deploymentType,
|
|
133
133
|
settingsSchema,
|
|
134
|
+
catalog,
|
|
134
135
|
targetOrganizationId,
|
|
135
136
|
environmentVariables,
|
|
136
137
|
version,
|
|
137
138
|
metadata,
|
|
139
|
+
publish,
|
|
138
140
|
},
|
|
139
141
|
schema: createDeploymentResponseSchema,
|
|
140
142
|
});
|
package/lib/api/schemas.js
CHANGED
|
@@ -38,6 +38,7 @@ const appDataSchema = z.object({
|
|
|
38
38
|
avatarId: z.string().nullable().optional(),
|
|
39
39
|
avatarUrl: z.string().nullable().optional(),
|
|
40
40
|
category: z.string().nullable().optional(),
|
|
41
|
+
verified: z.boolean().optional(),
|
|
41
42
|
createdAt: z.string().or(z.date()),
|
|
42
43
|
updatedAt: z.string().or(z.date()),
|
|
43
44
|
});
|
|
@@ -68,6 +69,9 @@ export const confirmBundlesResponseSchema = z.object({
|
|
|
68
69
|
export const createDeploymentResponseSchema = z.object({
|
|
69
70
|
deploymentId: z.string(),
|
|
70
71
|
version: z.string().nullable(),
|
|
72
|
+
status: z.string().optional(),
|
|
73
|
+
publishError: z.string().optional(),
|
|
74
|
+
unchanged: z.boolean().optional(),
|
|
71
75
|
});
|
|
72
76
|
export const deploymentSchema = z.object({
|
|
73
77
|
id: z.string(),
|
package/lib/auth/auth.js
CHANGED
|
@@ -14,6 +14,9 @@ class Authenticator {
|
|
|
14
14
|
isRefreshingToken = false;
|
|
15
15
|
refreshTimeout = null;
|
|
16
16
|
async ensureAuthed() {
|
|
17
|
+
if (process.env.AUXX_API_KEY) {
|
|
18
|
+
return { success: true, value: process.env.AUXX_API_KEY };
|
|
19
|
+
}
|
|
17
20
|
const existingTokenResult = await getKeychain().load();
|
|
18
21
|
if (isError(existingTokenResult)) {
|
|
19
22
|
return this.promptToAuthenticate();
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { parse } from '@typescript-eslint/parser';
|
|
3
|
+
import { analyze } from '@typescript-eslint/scope-manager';
|
|
4
|
+
import { walk } from 'zimmerframe';
|
|
5
|
+
import { complete, errored } from '../../errors.js';
|
|
6
|
+
import { getAppEntryPoint } from '../../util/get-app-entry-point.js';
|
|
7
|
+
function checkPath(path, doesModuleExist) {
|
|
8
|
+
return doesModuleExist(path) ? path : null;
|
|
9
|
+
}
|
|
10
|
+
function resolvePathWithExtension(path, doesModuleExist) {
|
|
11
|
+
return (checkPath(path + '.ts', doesModuleExist) ||
|
|
12
|
+
checkPath(path + '.tsx', doesModuleExist) ||
|
|
13
|
+
checkPath(path + '.js', doesModuleExist));
|
|
14
|
+
}
|
|
15
|
+
function resolveAbsolutePath(sourcePath, currPath) {
|
|
16
|
+
if (sourcePath.startsWith('.')) {
|
|
17
|
+
const currDir = currPath.split('/').slice(0, -1).join('/');
|
|
18
|
+
const combinedPath = currDir + '/' + sourcePath;
|
|
19
|
+
const parts = combinedPath.split('/');
|
|
20
|
+
const resolvedParts = [];
|
|
21
|
+
for (const part of parts) {
|
|
22
|
+
if (part === '..') {
|
|
23
|
+
resolvedParts.pop();
|
|
24
|
+
}
|
|
25
|
+
else if (part !== '.') {
|
|
26
|
+
resolvedParts.push(part);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return resolvedParts.join('/');
|
|
30
|
+
}
|
|
31
|
+
return sourcePath;
|
|
32
|
+
}
|
|
33
|
+
function unwrapTypeAnnotations(node) {
|
|
34
|
+
while (node) {
|
|
35
|
+
if (node.type === 'TSSatisfiesExpression' || node.type === 'TSAsExpression') {
|
|
36
|
+
node = node.expression;
|
|
37
|
+
}
|
|
38
|
+
else if (node.type === 'TSTypeAssertion') {
|
|
39
|
+
node = node.expression;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return node;
|
|
46
|
+
}
|
|
47
|
+
function resolveIdentifierToValue(node, scope) {
|
|
48
|
+
const variable = scope.set.get(node.name);
|
|
49
|
+
if (!variable) {
|
|
50
|
+
throw new Error(`Unable to find variable ${node.name} in scope`);
|
|
51
|
+
}
|
|
52
|
+
if (variable.defs.length !== 1) {
|
|
53
|
+
throw new Error(`Expected exactly one definition for variable ${node.name}, found ${variable.defs.length}`);
|
|
54
|
+
}
|
|
55
|
+
const def = variable.defs[0];
|
|
56
|
+
if (!def)
|
|
57
|
+
return null;
|
|
58
|
+
if (def.node.type === 'VariableDeclarator')
|
|
59
|
+
return def.node.init;
|
|
60
|
+
if (def.type === 'ImportBinding')
|
|
61
|
+
return def;
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function loadModule(sourcePath, currPath, helpers) {
|
|
65
|
+
const absolutePath = resolveAbsolutePath(sourcePath, currPath);
|
|
66
|
+
const fullPath = resolvePathWithExtension(absolutePath, helpers.doesModuleExist);
|
|
67
|
+
if (!fullPath) {
|
|
68
|
+
throw new Error(`Unable to resolve path for module ${sourcePath} from ${currPath}`);
|
|
69
|
+
}
|
|
70
|
+
if (helpers.modules.has(fullPath)) {
|
|
71
|
+
return helpers.modules.get(fullPath);
|
|
72
|
+
}
|
|
73
|
+
const content = helpers.getModuleSource(fullPath);
|
|
74
|
+
const ast = parse(content, { range: true, jsx: true });
|
|
75
|
+
const scopeManager = analyze(ast, { sourceType: 'module' });
|
|
76
|
+
const moduleScope = scopeManager.acquire(ast, true);
|
|
77
|
+
const namedExports = new Map();
|
|
78
|
+
const module = { content, ast, scope: moduleScope, namedExports, path: fullPath };
|
|
79
|
+
helpers.modules.set(fullPath, module);
|
|
80
|
+
walk(ast, null, {
|
|
81
|
+
ExportNamedDeclaration(node) {
|
|
82
|
+
if (node.declaration?.type === 'VariableDeclaration' &&
|
|
83
|
+
node.declaration.declarations.length === 1 &&
|
|
84
|
+
node.declaration.declarations[0].type === 'VariableDeclarator' &&
|
|
85
|
+
node.declaration.declarations[0].id.type === 'Identifier') {
|
|
86
|
+
const declaration = node.declaration.declarations[0];
|
|
87
|
+
namedExports.set(declaration.id.name, declaration.init);
|
|
88
|
+
}
|
|
89
|
+
if (node?.specifiers && moduleScope) {
|
|
90
|
+
for (const specifier of node.specifiers) {
|
|
91
|
+
if (specifier.type === 'ExportSpecifier' &&
|
|
92
|
+
specifier.exported.type === 'Identifier' &&
|
|
93
|
+
specifier.local.type === 'Identifier') {
|
|
94
|
+
if (node.source !== null) {
|
|
95
|
+
namedExports.set(specifier.exported.name, node);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const resolved = resolveIdentifierToValue(specifier.local, moduleScope);
|
|
99
|
+
if (resolved)
|
|
100
|
+
namedExports.set(specifier.exported.name, resolved);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
ExportDefaultDeclaration(node) {
|
|
107
|
+
if (node.declaration) {
|
|
108
|
+
if (node.declaration.type === 'FunctionDeclaration' ||
|
|
109
|
+
node.declaration.type === 'ArrowFunctionExpression' ||
|
|
110
|
+
node.declaration.type === 'FunctionExpression') {
|
|
111
|
+
namedExports.set('default', node.declaration);
|
|
112
|
+
}
|
|
113
|
+
else if (node.declaration.type === 'Identifier' && moduleScope) {
|
|
114
|
+
const resolved = resolveIdentifierToValue(node.declaration, moduleScope);
|
|
115
|
+
if (resolved)
|
|
116
|
+
namedExports.set('default', resolved);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
return module;
|
|
122
|
+
}
|
|
123
|
+
function captureExecuteRef(toolId, node, scope, currPath, helpers) {
|
|
124
|
+
let importValue = node.type === 'Identifier' ? resolveIdentifierToValue(node, scope) : node;
|
|
125
|
+
if (!importValue) {
|
|
126
|
+
throw new Error(`Tool '${toolId}': unable to resolve 'execute'`);
|
|
127
|
+
}
|
|
128
|
+
importValue = unwrapTypeAnnotations(importValue);
|
|
129
|
+
const isInlineFunction = importValue.type === 'ArrowFunctionExpression' ||
|
|
130
|
+
importValue.type === 'FunctionExpression' ||
|
|
131
|
+
importValue.type === 'FunctionDeclaration';
|
|
132
|
+
if (isInlineFunction) {
|
|
133
|
+
throw new Error(`Tool '${toolId}': 'execute' must be imported from a separate .server.ts file. ` +
|
|
134
|
+
`Inline server functions are not allowed.`);
|
|
135
|
+
}
|
|
136
|
+
if (importValue.type !== 'ImportBinding' && importValue.type !== 'ExportNamedDeclaration') {
|
|
137
|
+
throw new Error(`Tool '${toolId}': 'execute' must be imported from another file. Found ${importValue.type}.`);
|
|
138
|
+
}
|
|
139
|
+
const importDeclaration = importValue.type === 'ExportNamedDeclaration' ? importValue : importValue.parent;
|
|
140
|
+
const sourcePath = importDeclaration.source.value;
|
|
141
|
+
const isServerFile = sourcePath.endsWith('.server') ||
|
|
142
|
+
sourcePath.endsWith('.server.ts') ||
|
|
143
|
+
sourcePath.endsWith('.server.tsx') ||
|
|
144
|
+
sourcePath.endsWith('.server.js');
|
|
145
|
+
if (!isServerFile) {
|
|
146
|
+
throw new Error(`Tool '${toolId}': 'execute' must be imported from a .server.ts file (got '${sourcePath}').`);
|
|
147
|
+
}
|
|
148
|
+
if (importValue.type === 'ImportBinding') {
|
|
149
|
+
const specifier = importDeclaration.specifiers.find((s) => s.local && s.local.name === importValue.name.name);
|
|
150
|
+
if (specifier && specifier.type !== 'ImportDefaultSpecifier') {
|
|
151
|
+
throw new Error(`Tool '${toolId}': 'execute' must be imported as a default export from '${sourcePath}'.`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
let absolutePath = resolveAbsolutePath(sourcePath, currPath);
|
|
155
|
+
absolutePath = resolvePathWithExtension(absolutePath, helpers.doesModuleExist) || absolutePath;
|
|
156
|
+
return { path: absolutePath, export: 'default' };
|
|
157
|
+
}
|
|
158
|
+
function visitTool(node, scope, result, currPath, helpers) {
|
|
159
|
+
if (node.type === 'Identifier') {
|
|
160
|
+
let targetScope = scope;
|
|
161
|
+
let value = resolveIdentifierToValue(node, scope);
|
|
162
|
+
let targetPath = currPath;
|
|
163
|
+
if (value?.type === 'ImportBinding') {
|
|
164
|
+
const importDeclaration = value.parent;
|
|
165
|
+
const module = loadModule(importDeclaration.source.value, currPath, helpers);
|
|
166
|
+
const local = value.name.name;
|
|
167
|
+
const specifier = importDeclaration.specifiers.find((s) => s.local && s.local.name === local);
|
|
168
|
+
const name = specifier?.imported?.name ?? 'default';
|
|
169
|
+
if (!module.namedExports.has(name)) {
|
|
170
|
+
throw new Error(`Unable to find named export ${name} in module ${importDeclaration.source.value}`);
|
|
171
|
+
}
|
|
172
|
+
value = module.namedExports.get(name) ?? null;
|
|
173
|
+
if (module.scope)
|
|
174
|
+
targetScope = module.scope;
|
|
175
|
+
targetPath = module.path;
|
|
176
|
+
}
|
|
177
|
+
value = value ? unwrapTypeAnnotations(value) : null;
|
|
178
|
+
if (!value) {
|
|
179
|
+
throw new Error(`Tool ${node.name}: expected initializer`);
|
|
180
|
+
}
|
|
181
|
+
if (value.type === 'CallExpression') {
|
|
182
|
+
visitTool(value.arguments[0], targetScope, result, targetPath, helpers);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (value.type !== 'ObjectExpression') {
|
|
186
|
+
throw new Error(`Tool ${node.name}: expected ObjectExpression, got ${value.type}`);
|
|
187
|
+
}
|
|
188
|
+
visitTool(value, targetScope, result, targetPath, helpers);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (node.type === 'CallExpression') {
|
|
192
|
+
visitTool(node.arguments[0], scope, result, currPath, helpers);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (node.type === 'ObjectExpression') {
|
|
196
|
+
let id;
|
|
197
|
+
let execute = null;
|
|
198
|
+
for (const property of node.properties) {
|
|
199
|
+
if (property.type !== 'Property' || property.key.type !== 'Identifier')
|
|
200
|
+
continue;
|
|
201
|
+
const name = property.key.name;
|
|
202
|
+
if (name === 'id') {
|
|
203
|
+
if (property.value.type !== 'Literal' || typeof property.value.value !== 'string') {
|
|
204
|
+
throw new Error(`Tool: 'id' must be a string literal`);
|
|
205
|
+
}
|
|
206
|
+
id = property.value.value;
|
|
207
|
+
}
|
|
208
|
+
else if (name === 'execute') {
|
|
209
|
+
execute = captureExecuteRef(id ?? '<unknown>', property.value, scope, currPath, helpers);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (!id)
|
|
213
|
+
throw new Error(`Tool: missing 'id'`);
|
|
214
|
+
if (!execute)
|
|
215
|
+
throw new Error(`Tool '${id}': missing 'execute'`);
|
|
216
|
+
result.set(id, { execute });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function findProperty(obj, name, scope) {
|
|
220
|
+
const property = obj.properties.find((p) => p.type === 'Property' && p.key.type === 'Identifier' && p.key.name === name);
|
|
221
|
+
if (!property)
|
|
222
|
+
return null;
|
|
223
|
+
let value = property.value;
|
|
224
|
+
if (value.type === 'Identifier') {
|
|
225
|
+
const resolvedValue = resolveIdentifierToValue(value, scope);
|
|
226
|
+
if (resolvedValue && resolvedValue.type !== 'ImportBinding')
|
|
227
|
+
value = resolvedValue;
|
|
228
|
+
}
|
|
229
|
+
return value;
|
|
230
|
+
}
|
|
231
|
+
export function findToolModulesFromSource(source, currPath, helpers) {
|
|
232
|
+
const result = new Map();
|
|
233
|
+
try {
|
|
234
|
+
const ast = parse(source, { range: true, jsx: true });
|
|
235
|
+
const scopeManager = analyze(ast, { sourceType: 'module' });
|
|
236
|
+
const moduleScope = scopeManager.acquire(ast, true);
|
|
237
|
+
if (moduleScope === null) {
|
|
238
|
+
throw new Error('Expected to be able to acquire module scope');
|
|
239
|
+
}
|
|
240
|
+
;
|
|
241
|
+
walk(ast, null, {
|
|
242
|
+
ExportNamedDeclaration(node) {
|
|
243
|
+
if (!node.declaration || node.declaration.type !== 'VariableDeclaration')
|
|
244
|
+
return;
|
|
245
|
+
if (node.declaration.declarations.length !== 1)
|
|
246
|
+
return;
|
|
247
|
+
const declaration = node.declaration.declarations[0];
|
|
248
|
+
if (declaration.id.type !== 'Identifier' || declaration.id.name !== 'app')
|
|
249
|
+
return;
|
|
250
|
+
const appValue = declaration.init;
|
|
251
|
+
if (!appValue || appValue.type !== 'ObjectExpression')
|
|
252
|
+
return;
|
|
253
|
+
const tools = findProperty(appValue, 'tools', moduleScope);
|
|
254
|
+
if (tools?.type !== 'ArrayExpression')
|
|
255
|
+
return;
|
|
256
|
+
for (const element of tools.elements) {
|
|
257
|
+
if (element)
|
|
258
|
+
visitTool(element, moduleScope, result, currPath, helpers);
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
265
|
+
return errored({ code: 'TOOL_RESOLUTION_FAILED', message });
|
|
266
|
+
}
|
|
267
|
+
return complete(result);
|
|
268
|
+
}
|
|
269
|
+
export async function findToolModules(srcDirAbsolute) {
|
|
270
|
+
const appEntryPoint = await getAppEntryPoint(srcDirAbsolute);
|
|
271
|
+
if (!appEntryPoint) {
|
|
272
|
+
return complete(new Map());
|
|
273
|
+
}
|
|
274
|
+
return findToolModulesFromSource(appEntryPoint.content, appEntryPoint.path, {
|
|
275
|
+
getModuleSource: (p) => fs.readFileSync(p, 'utf-8'),
|
|
276
|
+
doesModuleExist: (p) => fs.existsSync(p),
|
|
277
|
+
modules: new Map(),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
@@ -240,12 +240,20 @@ function visitBlock(node, scope, result, currPath, helpers) {
|
|
|
240
240
|
targetPath = module.path;
|
|
241
241
|
}
|
|
242
242
|
value = unwrapTypeAnnotations(value);
|
|
243
|
+
if (value?.type === 'CallExpression') {
|
|
244
|
+
visitBlock(value.arguments[0], targetScope, result, targetPath, helpers);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
243
247
|
if (!value || value.type !== 'ObjectExpression') {
|
|
244
248
|
throw new Error(`Expected variable ${node.name} to have an initializer`);
|
|
245
249
|
}
|
|
246
250
|
visitBlock(value, targetScope, result, targetPath, helpers);
|
|
247
251
|
return;
|
|
248
252
|
}
|
|
253
|
+
if (node.type === 'CallExpression') {
|
|
254
|
+
visitBlock(node.arguments[0], scope, result, currPath, helpers);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
249
257
|
if (node.type === 'ObjectExpression') {
|
|
250
258
|
let id;
|
|
251
259
|
let execute;
|
|
@@ -381,12 +389,12 @@ export function findWorkflowBlockModulesFromSource(source, currPath, helpers) {
|
|
|
381
389
|
const message = error instanceof Error ? error.message : String(error);
|
|
382
390
|
return errored({ code: 'WORKFLOW_BLOCK_RESOLUTION_FAILED', message });
|
|
383
391
|
}
|
|
384
|
-
return complete(result);
|
|
392
|
+
return complete({ blocks: result });
|
|
385
393
|
}
|
|
386
394
|
export async function findWorkflowBlockModules(srcDirAbsolute) {
|
|
387
395
|
const appEntryPoint = await getAppEntryPoint(srcDirAbsolute);
|
|
388
396
|
if (!appEntryPoint) {
|
|
389
|
-
return complete(new Map());
|
|
397
|
+
return complete({ blocks: new Map() });
|
|
390
398
|
}
|
|
391
399
|
const getModuleSource = (path) => {
|
|
392
400
|
return fs.readFileSync(path, 'utf-8');
|
|
@@ -16,7 +16,7 @@ async function findServerFunctionModules(cwd, pattern) {
|
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
export async function generateServerEntry({ appDirAbsolute, srcDirAbsolute, webhooksDirAbsolute, eventDirAbsolute, workflowBlockModules, log, }) {
|
|
19
|
+
export async function generateServerEntry({ appDirAbsolute, srcDirAbsolute, webhooksDirAbsolute, eventDirAbsolute, workflowBlockModules, toolModules = new Map(), log, }) {
|
|
20
20
|
const pathsResult = await combineAsync({
|
|
21
21
|
serverFunctionConcretePaths: findServerFunctionModules(srcDirAbsolute, 'server'),
|
|
22
22
|
webhookConcretePaths: findServerFunctionModules(webhooksDirAbsolute, 'webhook'),
|
|
@@ -105,6 +105,51 @@ export async function generateServerEntry({ appDirAbsolute, srcDirAbsolute, webh
|
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// Tool module registry
|
|
109
|
+
const toolModulesMap = new Map()
|
|
110
|
+
|
|
111
|
+
${[...toolModules.entries()]
|
|
112
|
+
.map(([toolId, handlers]) => `toolModulesMap.set(
|
|
113
|
+
${JSON.stringify(toolId)},
|
|
114
|
+
{
|
|
115
|
+
${[...Object.entries(handlers)]
|
|
116
|
+
.map(([handler, data]) => data
|
|
117
|
+
? `${JSON.stringify(handler)}: {
|
|
118
|
+
module: () => import(${JSON.stringify(path.join(appDirAbsolute, data.path))}),
|
|
119
|
+
export: ${JSON.stringify(data.export)}
|
|
120
|
+
},`
|
|
121
|
+
: '')
|
|
122
|
+
.join('\n')}
|
|
123
|
+
}
|
|
124
|
+
)`)
|
|
125
|
+
.join('\n')}
|
|
126
|
+
|
|
127
|
+
// Build __AUXX_TOOLS__ — the single tool registry read by the unified
|
|
128
|
+
// lambda tool-executor for both agent-surfaced and action-surfaced
|
|
129
|
+
// invocations. Mirrors __AUXX_WORKFLOW_BLOCKS__: the executor reads
|
|
130
|
+
// execute(input, ctx) off this global. See plans/kopilot/agents/triggers/app-surface-implementation-plan.md §5.2.
|
|
131
|
+
const __AUXX_TOOLS__ = {};
|
|
132
|
+
|
|
133
|
+
for (const [toolId, handlers] of toolModulesMap.entries()) {
|
|
134
|
+
__AUXX_TOOLS__[toolId] = {
|
|
135
|
+
execute: async (...args) => {
|
|
136
|
+
const executeHandler = handlers.execute;
|
|
137
|
+
if (!executeHandler) {
|
|
138
|
+
throw new Error(\`No execute handler for tool \${toolId}\`);
|
|
139
|
+
}
|
|
140
|
+
const module = await executeHandler.module();
|
|
141
|
+
const func = module[executeHandler.export];
|
|
142
|
+
if (!func) {
|
|
143
|
+
throw new Error(\`Execute export not found in tool \${toolId}\`);
|
|
144
|
+
}
|
|
145
|
+
if (typeof func !== "function") {
|
|
146
|
+
throw new Error(\`Execute export in tool \${toolId} is not a function\`);
|
|
147
|
+
}
|
|
148
|
+
return await func(...args);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
108
153
|
var stdin_default;
|
|
109
154
|
var stdin_webhooks_default;
|
|
110
155
|
var stdin_events_default;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
export function zodToProviderToolSchema(schema, _provider = 'anthropic') {
|
|
3
|
+
const raw = z.toJSONSchema(schema, { unrepresentable: 'any' });
|
|
4
|
+
delete raw.$schema;
|
|
5
|
+
delete raw.id;
|
|
6
|
+
const refs = [];
|
|
7
|
+
const cleaned = stripAuxxRefAndMineRefs(raw, [], refs);
|
|
8
|
+
return { jsonSchema: cleaned, refs };
|
|
9
|
+
}
|
|
10
|
+
function stripAuxxRefAndMineRefs(node, path, out) {
|
|
11
|
+
if (!node || typeof node !== 'object')
|
|
12
|
+
return node;
|
|
13
|
+
if (Array.isArray(node)) {
|
|
14
|
+
return node.map((entry, i) => stripAuxxRefAndMineRefs(entry, [...path, String(i)], out));
|
|
15
|
+
}
|
|
16
|
+
const obj = { ...node };
|
|
17
|
+
if (obj.auxxRef && typeof obj.auxxRef === 'object') {
|
|
18
|
+
const kind = obj.auxxRef.kind;
|
|
19
|
+
if (typeof kind === 'string') {
|
|
20
|
+
out.push({ path: [...path], kind });
|
|
21
|
+
}
|
|
22
|
+
delete obj.auxxRef;
|
|
23
|
+
}
|
|
24
|
+
if (obj.properties && typeof obj.properties === 'object') {
|
|
25
|
+
const props = obj.properties;
|
|
26
|
+
const cleanedProps = {};
|
|
27
|
+
for (const key of Object.keys(props)) {
|
|
28
|
+
cleanedProps[key] = stripAuxxRefAndMineRefs(props[key], [...path, key], out);
|
|
29
|
+
}
|
|
30
|
+
obj.properties = cleanedProps;
|
|
31
|
+
}
|
|
32
|
+
if (obj.items) {
|
|
33
|
+
obj.items = stripAuxxRefAndMineRefs(obj.items, [...path, '[]'], out);
|
|
34
|
+
}
|
|
35
|
+
if (obj.anyOf) {
|
|
36
|
+
obj.anyOf = obj.anyOf.map((entry) => stripAuxxRefAndMineRefs(entry, path, out));
|
|
37
|
+
}
|
|
38
|
+
if (obj.oneOf) {
|
|
39
|
+
obj.oneOf = obj.oneOf.map((entry) => stripAuxxRefAndMineRefs(entry, path, out));
|
|
40
|
+
}
|
|
41
|
+
return obj;
|
|
42
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { BaseType, Connection, InferWorkflowInput, InferWorkflowOutput, WorkflowBlock, WorkflowCategory, WorkflowExecutionContext, WorkflowOrganization, WorkflowSchema, WorkflowSDK,
|
|
1
|
+
export type { BaseType, Connection, InferWorkflowInput, InferWorkflowOutput, Trigger, WorkflowBlock, WorkflowCategory, WorkflowExecutionContext, WorkflowOrganization, WorkflowSchema, WorkflowSDK, WorkflowUser, } from '../../root/workflow/types.js';
|
|
2
2
|
export * from './components/index.js';
|
|
3
3
|
export * from './hooks/index.js';
|
|
4
4
|
export type { PathTo, PathToField, ValueAtPath } from './types/index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/workflow/index.ts"],"names":[],"mappings":"AASA,YAAY,EACV,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/workflow/index.ts"],"names":[],"mappings":"AASA,YAAY,EACV,QAAQ,EACR,UAAU,EACV,kBAAkB,EAClB,mBAAmB,EACnB,OAAO,EACP,aAAa,EACb,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,YAAY,GACb,MAAM,8BAA8B,CAAA;AAGrC,cAAc,uBAAuB,CAAA;AAErC,cAAc,kBAAkB,CAAA;AAEhC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
1
2
|
import path from 'path';
|
|
2
|
-
import { complete, errored } from '../../errors.js';
|
|
3
|
-
import {
|
|
3
|
+
import { complete, errored, isErrored } from '../../errors.js';
|
|
4
|
+
import { ensureAppFieldsTypes } from '../../util/ensure-app-fields-types.js';
|
|
5
|
+
import { generateAppEnvTypes } from '../../util/generate-app-env-types.js';
|
|
6
|
+
import { hardExit } from '../../util/hard-exit.js';
|
|
7
|
+
import { spinnerify } from '../../util/spinner.js';
|
|
8
|
+
import { getDiagnostics, printTsError, readConfig, typeScriptErrorSchema, } from '../../util/typescript.js';
|
|
4
9
|
export async function validateTypeScript() {
|
|
5
10
|
try {
|
|
6
11
|
const program = await readConfig(path.resolve('tsconfig.json'));
|
|
@@ -22,3 +27,29 @@ export async function validateTypeScript() {
|
|
|
22
27
|
return errored({ code: 'FILE_SYSTEM_ERROR', error });
|
|
23
28
|
}
|
|
24
29
|
}
|
|
30
|
+
export async function validateTypeScriptOrExit() {
|
|
31
|
+
const appEnvTypesResult = await generateAppEnvTypes();
|
|
32
|
+
if (isErrored(appEnvTypesResult)) {
|
|
33
|
+
process.stderr.write(chalk.yellow(`⚠ Could not generate src/auxx-env.d.ts at ${appEnvTypesResult.error.path}. TypeScript image imports may show warnings.\n`));
|
|
34
|
+
}
|
|
35
|
+
else if (appEnvTypesResult.value === 'skipped_unmanaged') {
|
|
36
|
+
process.stderr.write(chalk.yellow('⚠ Skipping src/auxx-env.d.ts generation because the existing file is unmanaged.\n'));
|
|
37
|
+
}
|
|
38
|
+
await ensureAppFieldsTypes();
|
|
39
|
+
const tsResult = await spinnerify('Validating TypeScript...', 'TypeScript validation passed', validateTypeScript);
|
|
40
|
+
if (isErrored(tsResult)) {
|
|
41
|
+
if (tsResult.error.code === 'VALIDATE_TYPE_SCRIPT_ERROR') {
|
|
42
|
+
process.stdout.write('\n');
|
|
43
|
+
process.stderr.write(chalk.red(`✖ Found ${tsResult.error.errors.length} TypeScript error(s):\n`));
|
|
44
|
+
const errorsToShow = tsResult.error.errors.slice(0, 10);
|
|
45
|
+
for (const error of errorsToShow) {
|
|
46
|
+
printTsError(error);
|
|
47
|
+
}
|
|
48
|
+
if (tsResult.error.errors.length > 10) {
|
|
49
|
+
process.stderr.write(chalk.yellow(`\n ... and ${tsResult.error.errors.length - 10} more error(s)\n`));
|
|
50
|
+
}
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
hardExit(`TypeScript validation failed: ${tsResult.error.error}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
package/lib/commands/build.js
CHANGED
|
@@ -2,12 +2,11 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { isErrored } from '../errors.js';
|
|
4
4
|
import { ensureAppEntryPoint } from '../util/ensure-app-entry-point.js';
|
|
5
|
-
import { printJsError
|
|
6
|
-
import { generateAppEnvTypes } from '../util/generate-app-env-types.js';
|
|
5
|
+
import { printJsError } from '../util/error-reporting.js';
|
|
7
6
|
import { hardExit } from '../util/hard-exit.js';
|
|
8
7
|
import { spinnerify } from '../util/spinner.js';
|
|
9
8
|
import { buildJavaScript } from './build/build-javascript.js';
|
|
10
|
-
import {
|
|
9
|
+
import { validateTypeScriptOrExit } from './build/validate-typescript.js';
|
|
11
10
|
export const build = new Command('build')
|
|
12
11
|
.description('Build your Auxx app for production')
|
|
13
12
|
.action(async () => {
|
|
@@ -17,29 +16,7 @@ export const build = new Command('build')
|
|
|
17
16
|
hardExit(`Could not find app entry point at ${entryPointResult.error}\n` +
|
|
18
17
|
` Make sure you have a src/index.ts file in your project.`);
|
|
19
18
|
}
|
|
20
|
-
|
|
21
|
-
if (isErrored(appEnvTypesResult)) {
|
|
22
|
-
process.stderr.write(chalk.yellow(`⚠ Could not generate src/auxx-env.d.ts at ${appEnvTypesResult.error.path}. TypeScript image imports may show warnings.\n`));
|
|
23
|
-
}
|
|
24
|
-
else if (appEnvTypesResult.value === 'skipped_unmanaged') {
|
|
25
|
-
process.stderr.write(chalk.yellow('⚠ Skipping src/auxx-env.d.ts generation because the existing file is unmanaged.\n'));
|
|
26
|
-
}
|
|
27
|
-
const tsResult = await spinnerify('Validating TypeScript...', 'TypeScript validation passed', validateTypeScript);
|
|
28
|
-
if (isErrored(tsResult)) {
|
|
29
|
-
if (tsResult.error.code === 'VALIDATE_TYPESCRIPT_ERROR') {
|
|
30
|
-
process.stdout.write('\n');
|
|
31
|
-
process.stderr.write(chalk.red(`✖ Found ${tsResult.error.errors.length} TypeScript error(s):\n`));
|
|
32
|
-
const errorsToShow = tsResult.error.errors.slice(0, 10);
|
|
33
|
-
for (const error of errorsToShow) {
|
|
34
|
-
await printTsError(error);
|
|
35
|
-
}
|
|
36
|
-
if (tsResult.error.errors.length > 10) {
|
|
37
|
-
process.stderr.write(chalk.yellow(`\n ... and ${tsResult.error.errors.length - 10} more error(s)\n`));
|
|
38
|
-
}
|
|
39
|
-
process.exit(1);
|
|
40
|
-
}
|
|
41
|
-
hardExit('TypeScript validation failed: ' + tsResult.error.error.message);
|
|
42
|
-
}
|
|
19
|
+
await validateTypeScriptOrExit();
|
|
43
20
|
const buildResult = await spinnerify('Building JavaScript...', 'JavaScript build completed', buildJavaScript);
|
|
44
21
|
if (isErrored(buildResult)) {
|
|
45
22
|
if (buildResult.error.code === 'BUILD_JAVASCRIPT_ERROR') {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
1
2
|
import chokidar from 'chokidar';
|
|
2
3
|
import { complete, isComplete, isErrored } from '../../errors.js';
|
|
4
|
+
import { compileAndExtractCatalog, } from '../../util/compile-and-extract-catalog.js';
|
|
3
5
|
import { compileAndExtractSettingsSchema } from '../../util/compile-and-extract-settings.js';
|
|
4
6
|
import { prepareBuildContext } from './prepare-build-context.js';
|
|
5
7
|
export function bundleJavaScript(onSuccess, onError) {
|
|
@@ -39,7 +41,21 @@ export function bundleJavaScript(onSuccess, onError) {
|
|
|
39
41
|
}
|
|
40
42
|
const results = bundleResults.value;
|
|
41
43
|
const settingsSchema = await compileAndExtractSettingsSchema();
|
|
42
|
-
await
|
|
44
|
+
const catalogResult = await compileAndExtractCatalog();
|
|
45
|
+
let catalog;
|
|
46
|
+
if (isErrored(catalogResult)) {
|
|
47
|
+
const err = catalogResult.error;
|
|
48
|
+
const detail = 'error' in err && err.error instanceof Error
|
|
49
|
+
? `\n ${err.error.message}`
|
|
50
|
+
: 'message' in err
|
|
51
|
+
? `\n ${err.message}`
|
|
52
|
+
: '';
|
|
53
|
+
process.stderr.write(chalk.yellow(`⚠ Catalog extraction failed (${err.code}) — deployment will ship with no catalog${detail}\n`));
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
catalog = catalogResult.value;
|
|
57
|
+
}
|
|
58
|
+
await onSuccess?.([results.client.outputFiles[0].text, results.server.outputFiles[0].text], settingsSchema, catalog);
|
|
43
59
|
isBuilding = false;
|
|
44
60
|
if (buildQueued && !isDisposing) {
|
|
45
61
|
buildQueued = false;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { findToolModules } from '../../build/server/find-tool-server-modules.js';
|
|
3
4
|
import { findWorkflowBlockModules } from '../../build/server/find-workflow-block-server-modules.js';
|
|
4
5
|
import { combine, combineAsync, complete, isComplete, isErrored, map, } from '../../errors.js';
|
|
5
6
|
import { ClientBuilder } from './client-builder.js';
|
|
@@ -41,10 +42,15 @@ export async function prepareBuildContext(mode) {
|
|
|
41
42
|
if (isErrored(workflowBlockModulesResult)) {
|
|
42
43
|
return workflowBlockModulesResult;
|
|
43
44
|
}
|
|
44
|
-
const
|
|
45
|
+
const toolModulesResult = await findToolModules(srcDir);
|
|
46
|
+
if (isErrored(toolModulesResult)) {
|
|
47
|
+
return toolModulesResult;
|
|
48
|
+
}
|
|
49
|
+
const { blocks: workflowBlockModules } = workflowBlockModulesResult.value;
|
|
50
|
+
const toolModules = toolModulesResult.value;
|
|
45
51
|
return combineAsync({
|
|
46
52
|
client: client.rebuild({ workflowBlockModules }),
|
|
47
|
-
server: server.rebuild({ workflowBlockModules }),
|
|
53
|
+
server: server.rebuild({ workflowBlockModules, toolModules }),
|
|
48
54
|
});
|
|
49
55
|
},
|
|
50
56
|
dispose: async (timeoutMs) => {
|
|
@@ -86,5 +92,8 @@ export function printBuildContextError(error) {
|
|
|
86
92
|
case 'WORKFLOW_BLOCK_RESOLUTION_FAILED':
|
|
87
93
|
process.stderr.write(`${chalk.red('✖ ')}Failed to build workflow block(s): ${error.message}\n`);
|
|
88
94
|
break;
|
|
95
|
+
case 'TOOL_RESOLUTION_FAILED':
|
|
96
|
+
process.stderr.write(`${chalk.red('✖ ')}Failed to resolve tool(s): ${error.message}\n`);
|
|
97
|
+
break;
|
|
89
98
|
}
|
|
90
99
|
}
|
|
@@ -42,13 +42,14 @@ export class ServerBuilder {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
async rebuild({ workflowBlockModules, }) {
|
|
45
|
+
async rebuild({ workflowBlockModules, toolModules, }) {
|
|
46
46
|
const jsResult = await generateServerEntry({
|
|
47
47
|
appDirAbsolute: path.resolve(this._directories.app),
|
|
48
48
|
srcDirAbsolute: path.resolve(this._directories.src),
|
|
49
49
|
webhooksDirAbsolute: path.resolve(this._directories.webhooks),
|
|
50
50
|
eventDirAbsolute: path.resolve(this._directories.events),
|
|
51
51
|
workflowBlockModules,
|
|
52
|
+
toolModules: toolModules ?? new Map(),
|
|
52
53
|
log: console.log,
|
|
53
54
|
});
|
|
54
55
|
if (isErrored(jsResult)) {
|