@spec2tools/core 0.1.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.
@@ -0,0 +1,368 @@
1
+ import { z } from 'zod';
2
+ import { readFile } from 'fs/promises';
3
+ import { parse as parseYaml } from 'yaml';
4
+ import { UnsupportedSchemaError, SpecLoadError } from './errors.js';
5
+ const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
6
+ /**
7
+ * Fetch and parse an OpenAPI specification from URL or file path
8
+ */
9
+ export async function loadOpenAPISpec(specPath) {
10
+ let content;
11
+ if (specPath.startsWith('http://') || specPath.startsWith('https://')) {
12
+ const response = await fetch(specPath);
13
+ if (!response.ok) {
14
+ throw new SpecLoadError(`HTTP ${response.status}: ${response.statusText}`);
15
+ }
16
+ content = await response.text();
17
+ }
18
+ else {
19
+ try {
20
+ content = await readFile(specPath, 'utf-8');
21
+ }
22
+ catch (error) {
23
+ throw new SpecLoadError(`Cannot read file: ${specPath}`);
24
+ }
25
+ }
26
+ try {
27
+ // Try JSON first, then YAML
28
+ if (specPath.endsWith('.json') || content.trim().startsWith('{')) {
29
+ return JSON.parse(content);
30
+ }
31
+ return parseYaml(content);
32
+ }
33
+ catch (error) {
34
+ throw new SpecLoadError('Invalid JSON or YAML format');
35
+ }
36
+ }
37
+ /**
38
+ * Extract the base URL from the OpenAPI spec
39
+ */
40
+ export function extractBaseUrl(spec) {
41
+ if (spec.servers && spec.servers.length > 0) {
42
+ return spec.servers[0].url.replace(/\/$/, ''); // Remove trailing slash
43
+ }
44
+ throw new SpecLoadError('No server URL defined in OpenAPI spec');
45
+ }
46
+ /**
47
+ * Extract authentication configuration from security schemes
48
+ */
49
+ export function extractAuthConfig(spec) {
50
+ const securitySchemes = spec.components?.securitySchemes;
51
+ const globalSecurity = spec.security;
52
+ if (!securitySchemes || !globalSecurity || globalSecurity.length === 0) {
53
+ return { type: 'none' };
54
+ }
55
+ // Get the first security requirement
56
+ const securityReq = globalSecurity[0];
57
+ const schemeName = Object.keys(securityReq)[0];
58
+ const scheme = securitySchemes[schemeName];
59
+ if (!scheme) {
60
+ return { type: 'none' };
61
+ }
62
+ return parseSecurityScheme(scheme, securityReq[schemeName]);
63
+ }
64
+ function parseSecurityScheme(scheme, scopes) {
65
+ if (scheme.type === 'oauth2') {
66
+ const flow = scheme.flows?.authorizationCode;
67
+ if (!flow) {
68
+ throw new UnsupportedSchemaError('securitySchemes', 'Only OAuth2 authorization code flow is supported');
69
+ }
70
+ return {
71
+ type: 'oauth2',
72
+ authorizationUrl: flow.authorizationUrl,
73
+ tokenUrl: flow.tokenUrl,
74
+ scopes: scopes,
75
+ };
76
+ }
77
+ if (scheme.type === 'apiKey') {
78
+ return {
79
+ type: 'apiKey',
80
+ apiKeyHeader: scheme.name,
81
+ apiKeyIn: scheme.in,
82
+ };
83
+ }
84
+ if (scheme.type === 'http' && scheme.scheme === 'bearer') {
85
+ return { type: 'bearer' };
86
+ }
87
+ return { type: 'none' };
88
+ }
89
+ /**
90
+ * Convert an OpenAPI schema to a Zod schema
91
+ */
92
+ function schemaToZod(schema, path, depth = 0) {
93
+ // Check for unsupported features
94
+ if (schema.anyOf) {
95
+ throw new UnsupportedSchemaError(path, 'anyOf is not supported');
96
+ }
97
+ if (schema.oneOf) {
98
+ throw new UnsupportedSchemaError(path, 'oneOf is not supported');
99
+ }
100
+ if (schema.allOf) {
101
+ throw new UnsupportedSchemaError(path, 'allOf is not supported');
102
+ }
103
+ if (schema.$ref) {
104
+ throw new UnsupportedSchemaError(path, '$ref is not supported');
105
+ }
106
+ // Handle array types
107
+ if (schema.type === 'array') {
108
+ if (!schema.items) {
109
+ throw new UnsupportedSchemaError(path, 'Array without items schema');
110
+ }
111
+ if (schema.items.type === 'object') {
112
+ throw new UnsupportedSchemaError(path, 'Arrays of objects are not supported');
113
+ }
114
+ const itemSchema = schemaToZod(schema.items, `${path}.items`, depth);
115
+ let arraySchema = z.array(itemSchema);
116
+ if (schema.description) {
117
+ arraySchema = arraySchema.describe(schema.description);
118
+ }
119
+ return arraySchema;
120
+ }
121
+ // Handle object types
122
+ if (schema.type === 'object' || schema.properties) {
123
+ if (depth > 1) {
124
+ throw new UnsupportedSchemaError(path, 'Nested objects beyond 1 level are not supported');
125
+ }
126
+ const properties = schema.properties || {};
127
+ const required = schema.required || [];
128
+ const shape = {};
129
+ for (const [propName, propSchema] of Object.entries(properties)) {
130
+ let zodProp = schemaToZod(propSchema, `${path}.${propName}`, depth + 1);
131
+ if (!required.includes(propName)) {
132
+ zodProp = zodProp.optional();
133
+ }
134
+ shape[propName] = zodProp;
135
+ }
136
+ let objSchema = z.object(shape);
137
+ if (schema.description) {
138
+ objSchema = objSchema.describe(schema.description);
139
+ }
140
+ return objSchema;
141
+ }
142
+ // Handle primitive types
143
+ switch (schema.type) {
144
+ case 'string': {
145
+ let strSchema = z.string();
146
+ if (schema.enum) {
147
+ strSchema = z.enum(schema.enum);
148
+ }
149
+ if (schema.description) {
150
+ strSchema = strSchema.describe(schema.description);
151
+ }
152
+ return strSchema;
153
+ }
154
+ case 'number':
155
+ case 'integer': {
156
+ let numSchema = z.number();
157
+ if (schema.description) {
158
+ numSchema = numSchema.describe(schema.description);
159
+ }
160
+ return numSchema;
161
+ }
162
+ case 'boolean': {
163
+ let boolSchema = z.boolean();
164
+ if (schema.description) {
165
+ boolSchema = boolSchema.describe(schema.description);
166
+ }
167
+ return boolSchema;
168
+ }
169
+ default:
170
+ // Default to string for unknown types
171
+ return z.string();
172
+ }
173
+ }
174
+ /**
175
+ * Build parameters schema from path and query parameters
176
+ */
177
+ function buildParametersSchema(parameters, operationId) {
178
+ const shape = {};
179
+ for (const param of parameters) {
180
+ if (param.in !== 'path' && param.in !== 'query') {
181
+ continue; // Skip header and cookie parameters
182
+ }
183
+ let paramSchema;
184
+ if (param.schema) {
185
+ paramSchema = schemaToZod(param.schema, `${operationId}.parameters.${param.name}`, 0);
186
+ }
187
+ else {
188
+ paramSchema = z.string();
189
+ }
190
+ if (param.description) {
191
+ paramSchema = paramSchema.describe(param.description);
192
+ }
193
+ if (!param.required) {
194
+ paramSchema = paramSchema.optional();
195
+ }
196
+ shape[param.name] = paramSchema;
197
+ }
198
+ return shape;
199
+ }
200
+ /**
201
+ * Build request body schema
202
+ */
203
+ function buildRequestBodySchema(operation, operationId) {
204
+ if (!operation.requestBody?.content) {
205
+ return {};
206
+ }
207
+ const jsonContent = operation.requestBody.content['application/json'];
208
+ if (!jsonContent?.schema) {
209
+ return {};
210
+ }
211
+ const schema = jsonContent.schema;
212
+ // Check for file uploads
213
+ if (schema.type === 'string' && schema.format === 'binary') {
214
+ throw new UnsupportedSchemaError(`${operationId}.requestBody`, 'File uploads are not supported');
215
+ }
216
+ // For object schemas, flatten properties into the parameter shape
217
+ if (schema.type === 'object' || schema.properties) {
218
+ const properties = schema.properties || {};
219
+ const required = schema.required || [];
220
+ const shape = {};
221
+ for (const [propName, propSchema] of Object.entries(properties)) {
222
+ // Check for file upload in properties
223
+ if (propSchema.type === 'string' &&
224
+ propSchema.format === 'binary') {
225
+ throw new UnsupportedSchemaError(`${operationId}.requestBody.${propName}`, 'File uploads are not supported');
226
+ }
227
+ let zodProp = schemaToZod(propSchema, `${operationId}.requestBody.${propName}`, 1);
228
+ if (!required.includes(propName)) {
229
+ zodProp = zodProp.optional();
230
+ }
231
+ shape[propName] = zodProp;
232
+ }
233
+ return shape;
234
+ }
235
+ return {};
236
+ }
237
+ /**
238
+ * Generate tool name from operation
239
+ */
240
+ function generateToolName(operation, method, path) {
241
+ if (operation.operationId) {
242
+ return operation.operationId;
243
+ }
244
+ // Generate name from method and path
245
+ const cleanPath = path
246
+ .replace(/[{}]/g, '')
247
+ .replace(/\//g, '_')
248
+ .replace(/^_/, '');
249
+ return `${method.toLowerCase()}_${cleanPath}`;
250
+ }
251
+ /**
252
+ * Parse all operations from the OpenAPI spec and generate tool definitions
253
+ */
254
+ export function parseOperations(spec) {
255
+ const tools = [];
256
+ for (const [path, pathItem] of Object.entries(spec.paths)) {
257
+ // Get path-level parameters
258
+ const pathParameters = pathItem.parameters || [];
259
+ for (const method of HTTP_METHODS) {
260
+ const methodKey = method.toLowerCase();
261
+ const operation = pathItem[methodKey];
262
+ if (!operation) {
263
+ continue;
264
+ }
265
+ const operationId = generateToolName(operation, method, path);
266
+ // Combine path-level and operation-level parameters
267
+ const allParameters = [
268
+ ...pathParameters,
269
+ ...(operation.parameters || []),
270
+ ];
271
+ // Build combined schema from parameters and request body
272
+ const parameterShape = buildParametersSchema(allParameters, operationId);
273
+ const bodyShape = buildRequestBodySchema(operation, operationId);
274
+ const combinedShape = { ...parameterShape, ...bodyShape };
275
+ const parameters = z.object(combinedShape);
276
+ tools.push({
277
+ name: operationId,
278
+ description: operation.summary || operation.description || `${method} ${path}`,
279
+ parameters,
280
+ httpMethod: method,
281
+ path,
282
+ });
283
+ }
284
+ }
285
+ return tools;
286
+ }
287
+ /**
288
+ * Format tool schema for display
289
+ */
290
+ export function formatToolSchema(tool) {
291
+ const shape = tool.parameters.shape;
292
+ const lines = ['{'];
293
+ for (const [key, schema] of Object.entries(shape)) {
294
+ const zodSchema = schema;
295
+ const isOptional = zodSchema.isOptional();
296
+ const description = zodSchema.description;
297
+ let typeStr = getZodTypeString(zodSchema);
298
+ if (isOptional) {
299
+ typeStr += '.optional()';
300
+ }
301
+ if (description) {
302
+ typeStr += `.describe("${description}")`;
303
+ }
304
+ lines.push(` ${key}: ${typeStr},`);
305
+ }
306
+ lines.push('}');
307
+ return lines.join('\n');
308
+ }
309
+ function getZodTypeString(schema) {
310
+ if (schema instanceof z.ZodOptional) {
311
+ return getZodTypeString(schema.unwrap());
312
+ }
313
+ if (schema instanceof z.ZodString) {
314
+ return 'z.string()';
315
+ }
316
+ if (schema instanceof z.ZodNumber) {
317
+ return 'z.number()';
318
+ }
319
+ if (schema instanceof z.ZodBoolean) {
320
+ return 'z.boolean()';
321
+ }
322
+ if (schema instanceof z.ZodEnum) {
323
+ return `z.enum([${schema.options.map((o) => `"${o}"`).join(', ')}])`;
324
+ }
325
+ if (schema instanceof z.ZodArray) {
326
+ return `z.array(${getZodTypeString(schema.element)})`;
327
+ }
328
+ if (schema instanceof z.ZodObject) {
329
+ return 'z.object({...})';
330
+ }
331
+ return 'z.unknown()';
332
+ }
333
+ /**
334
+ * Format tool signature for display
335
+ */
336
+ export function formatToolSignature(tool) {
337
+ const shape = tool.parameters.shape;
338
+ const params = [];
339
+ for (const [key, schema] of Object.entries(shape)) {
340
+ const zodSchema = schema;
341
+ const isOptional = zodSchema.isOptional();
342
+ const typeStr = getSimpleTypeString(zodSchema);
343
+ params.push(`${key}${isOptional ? '?' : ''}: ${typeStr}`);
344
+ }
345
+ return `${tool.name}(${params.join(', ')})`;
346
+ }
347
+ function getSimpleTypeString(schema) {
348
+ if (schema instanceof z.ZodOptional) {
349
+ return getSimpleTypeString(schema.unwrap());
350
+ }
351
+ if (schema instanceof z.ZodString || schema instanceof z.ZodEnum) {
352
+ return 'string';
353
+ }
354
+ if (schema instanceof z.ZodNumber) {
355
+ return 'number';
356
+ }
357
+ if (schema instanceof z.ZodBoolean) {
358
+ return 'boolean';
359
+ }
360
+ if (schema instanceof z.ZodArray) {
361
+ return `${getSimpleTypeString(schema.element)}[]`;
362
+ }
363
+ if (schema instanceof z.ZodObject) {
364
+ return 'object';
365
+ }
366
+ return 'unknown';
367
+ }
368
+ //# sourceMappingURL=openapi-parser.js.map
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ import { Tool, HttpMethod } from './types.js';
3
+ import { AuthManager } from './auth-manager.js';
4
+ interface ToolDefinition {
5
+ name: string;
6
+ description: string;
7
+ parameters: z.ZodObject<z.ZodRawShape>;
8
+ httpMethod: HttpMethod;
9
+ path: string;
10
+ }
11
+ /**
12
+ * Create executable tools from tool definitions
13
+ */
14
+ export declare function createExecutableTools(toolDefs: ToolDefinition[], baseUrl: string, authManager: AuthManager): Tool[];
15
+ /**
16
+ * Execute a tool directly by name
17
+ */
18
+ export declare function executeToolByName(tools: Tool[], toolName: string, params: Record<string, unknown>): Promise<unknown>;
19
+ export {};
20
+ //# sourceMappingURL=tool-executor.d.ts.map
@@ -0,0 +1,149 @@
1
+ import { z } from 'zod';
2
+ import { ToolExecutionError } from './errors.js';
3
+ /**
4
+ * Create executable tools from tool definitions
5
+ */
6
+ export function createExecutableTools(toolDefs, baseUrl, authManager) {
7
+ return toolDefs.map((def) => ({
8
+ ...def,
9
+ execute: createExecutor(def, baseUrl, authManager),
10
+ }));
11
+ }
12
+ /**
13
+ * Create an executor function for a tool
14
+ */
15
+ function createExecutor(tool, baseUrl, authManager) {
16
+ return async (params) => {
17
+ try {
18
+ // Validate parameters
19
+ const validatedParams = tool.parameters.parse(params);
20
+ // Build URL with path parameters replaced
21
+ let url = buildUrl(baseUrl, tool.path, validatedParams);
22
+ // Separate path, query, and body parameters
23
+ const { queryParams, bodyParams } = separateParams(validatedParams, tool.path);
24
+ // Add query parameters
25
+ const urlObj = new URL(url);
26
+ for (const [key, value] of Object.entries(queryParams)) {
27
+ if (value !== undefined) {
28
+ urlObj.searchParams.set(key, String(value));
29
+ }
30
+ }
31
+ // Add auth query params if needed
32
+ const authQueryParams = authManager.getAuthQueryParams();
33
+ for (const [key, value] of Object.entries(authQueryParams)) {
34
+ urlObj.searchParams.set(key, value);
35
+ }
36
+ url = urlObj.toString();
37
+ // Build request options
38
+ const headers = {
39
+ ...authManager.getAuthHeaders(),
40
+ };
41
+ const fetchOptions = {
42
+ method: tool.httpMethod,
43
+ headers,
44
+ };
45
+ // Add body for methods that support it
46
+ if (['POST', 'PUT', 'PATCH'].includes(tool.httpMethod)) {
47
+ if (Object.keys(bodyParams).length > 0) {
48
+ headers['Content-Type'] = 'application/json';
49
+ fetchOptions.body = JSON.stringify(bodyParams);
50
+ }
51
+ }
52
+ fetchOptions.headers = headers;
53
+ // Execute request
54
+ const response = await fetch(url, fetchOptions);
55
+ // Parse response
56
+ const contentType = response.headers.get('content-type') || '';
57
+ let responseData;
58
+ if (contentType.includes('application/json')) {
59
+ responseData = await response.json();
60
+ }
61
+ else {
62
+ responseData = await response.text();
63
+ }
64
+ if (!response.ok) {
65
+ throw new Error(`HTTP ${response.status}: ${JSON.stringify(responseData)}`);
66
+ }
67
+ return responseData;
68
+ }
69
+ catch (error) {
70
+ if (error instanceof z.ZodError) {
71
+ throw new ToolExecutionError(tool.name, new Error(`Invalid parameters: ${error.message}`));
72
+ }
73
+ if (error instanceof ToolExecutionError) {
74
+ throw error;
75
+ }
76
+ throw new ToolExecutionError(tool.name, error instanceof Error ? error : new Error(String(error)));
77
+ }
78
+ };
79
+ }
80
+ /**
81
+ * Build URL with path parameters replaced
82
+ */
83
+ function buildUrl(baseUrl, path, params) {
84
+ let finalPath = path;
85
+ // Replace path parameters
86
+ const pathParamRegex = /\{(\w+)\}/g;
87
+ let match;
88
+ while ((match = pathParamRegex.exec(path)) !== null) {
89
+ const paramName = match[1];
90
+ const paramValue = params[paramName];
91
+ if (paramValue !== undefined) {
92
+ finalPath = finalPath.replace(`{${paramName}}`, encodeURIComponent(String(paramValue)));
93
+ }
94
+ }
95
+ return `${baseUrl}${finalPath}`;
96
+ }
97
+ /**
98
+ * Separate parameters into path, query, and body params
99
+ */
100
+ function separateParams(params, path) {
101
+ const pathParams = {};
102
+ const queryParams = {};
103
+ const bodyParams = {};
104
+ // Extract path parameter names
105
+ const pathParamNames = new Set();
106
+ const pathParamRegex = /\{(\w+)\}/g;
107
+ let match;
108
+ while ((match = pathParamRegex.exec(path)) !== null) {
109
+ pathParamNames.add(match[1]);
110
+ }
111
+ for (const [key, value] of Object.entries(params)) {
112
+ if (pathParamNames.has(key)) {
113
+ pathParams[key] = value;
114
+ }
115
+ else if (isPrimitive(value)) {
116
+ // Primitive values go to query params
117
+ queryParams[key] = value;
118
+ }
119
+ else {
120
+ // Complex values go to body
121
+ bodyParams[key] = value;
122
+ }
123
+ }
124
+ // For simplicity, if there are non-path primitive params,
125
+ // we need to determine if they're query or body based on HTTP method
126
+ // Since we don't have that info here, we'll treat all non-path primitives
127
+ // as potential query params for GET/DELETE, and body params for POST/PUT/PATCH
128
+ // This is handled by the executor which knows the method
129
+ return { pathParams, queryParams, bodyParams };
130
+ }
131
+ /**
132
+ * Check if value is a primitive type
133
+ */
134
+ function isPrimitive(value) {
135
+ return (typeof value === 'string' ||
136
+ typeof value === 'number' ||
137
+ typeof value === 'boolean');
138
+ }
139
+ /**
140
+ * Execute a tool directly by name
141
+ */
142
+ export async function executeToolByName(tools, toolName, params) {
143
+ const tool = tools.find((t) => t.name === toolName);
144
+ if (!tool) {
145
+ throw new Error(`Tool not found: ${toolName}`);
146
+ }
147
+ return tool.execute(params);
148
+ }
149
+ //# sourceMappingURL=tool-executor.js.map
@@ -0,0 +1,117 @@
1
+ import { z } from 'zod';
2
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
3
+ export interface Tool {
4
+ name: string;
5
+ description: string;
6
+ parameters: z.ZodObject<z.ZodRawShape>;
7
+ execute: (params: unknown) => Promise<unknown>;
8
+ httpMethod: HttpMethod;
9
+ path: string;
10
+ }
11
+ export type AuthType = 'oauth2' | 'apiKey' | 'bearer' | 'none';
12
+ export interface AuthConfig {
13
+ type: AuthType;
14
+ authorizationUrl?: string;
15
+ tokenUrl?: string;
16
+ scopes?: string[];
17
+ apiKeyHeader?: string;
18
+ apiKeyIn?: 'header' | 'query';
19
+ }
20
+ export interface Session {
21
+ baseUrl: string;
22
+ tools: Tool[];
23
+ authConfig: AuthConfig;
24
+ accessToken?: string;
25
+ refreshToken?: string;
26
+ }
27
+ export interface OpenAPISpec {
28
+ openapi: string;
29
+ info: {
30
+ title: string;
31
+ version: string;
32
+ description?: string;
33
+ };
34
+ servers?: Array<{
35
+ url: string;
36
+ description?: string;
37
+ }>;
38
+ paths: Record<string, PathItem>;
39
+ components?: {
40
+ schemas?: Record<string, SchemaObject>;
41
+ securitySchemes?: Record<string, SecurityScheme>;
42
+ };
43
+ security?: Array<Record<string, string[]>>;
44
+ }
45
+ export interface PathItem {
46
+ get?: Operation;
47
+ post?: Operation;
48
+ put?: Operation;
49
+ patch?: Operation;
50
+ delete?: Operation;
51
+ parameters?: Parameter[];
52
+ }
53
+ export interface Operation {
54
+ operationId?: string;
55
+ summary?: string;
56
+ description?: string;
57
+ parameters?: Parameter[];
58
+ requestBody?: RequestBody;
59
+ responses?: Record<string, Response>;
60
+ security?: Array<Record<string, string[]>>;
61
+ }
62
+ export interface Parameter {
63
+ name: string;
64
+ in: 'path' | 'query' | 'header' | 'cookie';
65
+ required?: boolean;
66
+ description?: string;
67
+ schema?: SchemaObject;
68
+ }
69
+ export interface RequestBody {
70
+ required?: boolean;
71
+ content?: Record<string, MediaType>;
72
+ description?: string;
73
+ }
74
+ export interface MediaType {
75
+ schema?: SchemaObject;
76
+ }
77
+ export interface Response {
78
+ description: string;
79
+ content?: Record<string, MediaType>;
80
+ }
81
+ export interface SchemaObject {
82
+ type?: string;
83
+ format?: string;
84
+ description?: string;
85
+ required?: string[];
86
+ properties?: Record<string, SchemaObject>;
87
+ items?: SchemaObject;
88
+ enum?: unknown[];
89
+ default?: unknown;
90
+ anyOf?: SchemaObject[];
91
+ oneOf?: SchemaObject[];
92
+ allOf?: SchemaObject[];
93
+ $ref?: string;
94
+ }
95
+ export interface SecurityScheme {
96
+ type: 'oauth2' | 'apiKey' | 'http';
97
+ scheme?: string;
98
+ bearerFormat?: string;
99
+ name?: string;
100
+ in?: 'header' | 'query' | 'cookie';
101
+ flows?: {
102
+ authorizationCode?: {
103
+ authorizationUrl: string;
104
+ tokenUrl: string;
105
+ scopes?: Record<string, string>;
106
+ };
107
+ clientCredentials?: {
108
+ tokenUrl: string;
109
+ scopes?: Record<string, string>;
110
+ };
111
+ implicit?: {
112
+ authorizationUrl: string;
113
+ scopes?: Record<string, string>;
114
+ };
115
+ };
116
+ }
117
+ //# sourceMappingURL=types.d.ts.map
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map