@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.
Files changed (76) hide show
  1. package/lib/api/api.js +3 -1
  2. package/lib/api/schemas.js +4 -0
  3. package/lib/auth/auth.js +3 -0
  4. package/lib/build/server/find-tool-server-modules.js +279 -0
  5. package/lib/build/server/find-workflow-block-server-modules.js +10 -2
  6. package/lib/build/server/generate-server-entry.js +46 -1
  7. package/lib/build/server/zod-to-provider-tool-schema.js +42 -0
  8. package/lib/client/workflow/index.d.ts +1 -1
  9. package/lib/client/workflow/index.d.ts.map +1 -1
  10. package/lib/commands/build/validate-typescript.js +33 -2
  11. package/lib/commands/build.js +3 -26
  12. package/lib/commands/dev/bundle-javascript.js +17 -1
  13. package/lib/commands/dev/prepare-build-context.js +11 -2
  14. package/lib/commands/dev/server-builder.js +2 -1
  15. package/lib/commands/dev/upload.js +5 -1
  16. package/lib/commands/dev.js +4 -1
  17. package/lib/commands/version/create/bundle-javascript.js +10 -0
  18. package/lib/commands/version/create.js +40 -3
  19. package/lib/constants/app-fields-files.js +1 -0
  20. package/lib/env-loader.js +17 -1
  21. package/lib/env.js +1 -0
  22. package/lib/root/app.d.ts +7 -2
  23. package/lib/root/app.d.ts.map +1 -1
  24. package/lib/root/fields/define-field.d.ts +67 -0
  25. package/lib/root/fields/define-field.d.ts.map +1 -0
  26. package/lib/root/fields/define-field.js +21 -0
  27. package/lib/root/fields/field-types.d.ts +47 -0
  28. package/lib/root/fields/field-types.d.ts.map +1 -0
  29. package/lib/root/fields/field-types.js +25 -0
  30. package/lib/root/fields/index.d.ts +3 -0
  31. package/lib/root/fields/index.d.ts.map +1 -0
  32. package/lib/root/fields/index.js +2 -0
  33. package/lib/root/index.d.ts +5 -2
  34. package/lib/root/index.d.ts.map +1 -1
  35. package/lib/root/index.js +3 -1
  36. package/lib/root/tools/define-tool.d.ts +4 -0
  37. package/lib/root/tools/define-tool.d.ts.map +1 -0
  38. package/lib/root/tools/define-tool.js +21 -0
  39. package/lib/root/tools/index.d.ts +5 -0
  40. package/lib/root/tools/index.d.ts.map +1 -0
  41. package/lib/root/tools/index.js +3 -0
  42. package/lib/root/tools/refs.d.ts +9 -0
  43. package/lib/root/tools/refs.d.ts.map +1 -0
  44. package/lib/root/tools/refs.js +4 -0
  45. package/lib/root/tools/types.d.ts +91 -0
  46. package/lib/root/tools/types.d.ts.map +1 -0
  47. package/lib/root/tools/types.js +1 -0
  48. package/lib/root/workflow/types.d.ts +28 -14
  49. package/lib/root/workflow/types.d.ts.map +1 -1
  50. package/lib/root/workflow/types.js +3 -0
  51. package/lib/root/workflow/utils.d.ts +4 -4
  52. package/lib/root/workflow/utils.d.ts.map +1 -1
  53. package/lib/runtime/workflow.js +19 -2
  54. package/lib/server/connections.d.ts +5 -0
  55. package/lib/server/connections.d.ts.map +1 -1
  56. package/lib/server/entities.d.ts +44 -0
  57. package/lib/server/entities.d.ts.map +1 -0
  58. package/lib/server/entities.js +3 -0
  59. package/lib/server/index.d.ts +2 -0
  60. package/lib/server/index.d.ts.map +1 -1
  61. package/lib/server/storage.d.ts +30 -3
  62. package/lib/server/storage.d.ts.map +1 -1
  63. package/lib/shared/errors.d.ts +34 -0
  64. package/lib/shared/errors.d.ts.map +1 -1
  65. package/lib/shared/errors.js +56 -0
  66. package/lib/shared/index.d.ts +1 -1
  67. package/lib/shared/index.d.ts.map +1 -1
  68. package/lib/shared/index.js +1 -1
  69. package/lib/util/add-auxx-hidden-directory-to-ts-config.js +6 -2
  70. package/lib/util/compile-and-extract-catalog.js +318 -0
  71. package/lib/util/ensure-app-fields-types.js +26 -0
  72. package/lib/util/generate-app-fields-types.js +63 -0
  73. package/lib/util/warn-if-app-type-annotated.js +9 -0
  74. package/package.json +9 -1
  75. package/template/src/events/connection-added.event.ts +17 -2
  76. 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
  });
@@ -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, WorkflowTrigger, WorkflowUser, } from '../../root/workflow/types.js';
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,eAAe,EACf,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
+ {"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 { getDiagnostics, readConfig, typeScriptErrorSchema } from '../../util/typescript.js';
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
+ }
@@ -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, printTsError } from '../util/error-reporting.js';
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 { validateTypeScript } from './build/validate-typescript.js';
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
- const appEnvTypesResult = await generateAppEnvTypes();
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 onSuccess?.([results.client.outputFiles[0].text, results.server.outputFiles[0].text], settingsSchema);
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 workflowBlockModules = workflowBlockModulesResult.value;
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)) {