skedyul 0.3.20 → 1.0.2
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 +97 -6
- package/dist/.build-stamp +1 -1
- package/dist/cli/commands/invoke.js +123 -0
- package/dist/cli/utils/config.js +6 -1
- package/dist/config/types/model.d.ts +3 -2
- package/dist/config/types/page.d.ts +13 -1
- package/dist/core/client.d.ts +31 -0
- package/dist/core/client.js +25 -52
- package/dist/index.d.ts +1 -1
- package/dist/schemas.d.ts +5 -5
- package/dist/schemas.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
The official Node.js SDK for building Skedyul integration apps. This package provides everything you need to create MCP (Model Context Protocol) servers, handle webhooks, manage lifecycle events, and interact with the Skedyul platform.
|
|
4
4
|
|
|
5
|
+
## Version 1.0.0
|
|
6
|
+
|
|
7
|
+
This release introduces a modular, file-based configuration system with improved type safety and developer experience.
|
|
8
|
+
|
|
5
9
|
## Features
|
|
6
10
|
|
|
7
11
|
- **MCP Server**: Build tools that AI agents can invoke via the Model Context Protocol
|
|
@@ -9,6 +13,7 @@ The official Node.js SDK for building Skedyul integration apps. This package pro
|
|
|
9
13
|
- **Lifecycle Hooks**: Handle app installation, provisioning, and cleanup
|
|
10
14
|
- **Core API Client**: Interact with Skedyul resources (workplaces, channels, instances)
|
|
11
15
|
- **CLI**: Develop and test locally with hot-reload and tunneling
|
|
16
|
+
- **Modular Config**: File-based configuration with auto-discovery patterns
|
|
12
17
|
|
|
13
18
|
## Installation
|
|
14
19
|
|
|
@@ -25,17 +30,76 @@ pnpm add skedyul
|
|
|
25
30
|
```ts
|
|
26
31
|
// skedyul.config.ts
|
|
27
32
|
import { defineConfig } from 'skedyul'
|
|
33
|
+
import pkg from './package.json'
|
|
28
34
|
|
|
29
35
|
export default defineConfig({
|
|
30
|
-
name: '
|
|
31
|
-
version:
|
|
36
|
+
name: 'My Integration',
|
|
37
|
+
version: pkg.version,
|
|
38
|
+
description: 'Description of what this app does',
|
|
32
39
|
computeLayer: 'serverless',
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
|
|
41
|
+
tools: import('./src/registries'),
|
|
42
|
+
webhooks: import('./src/registries'),
|
|
43
|
+
provision: import('./provision'),
|
|
35
44
|
})
|
|
36
45
|
```
|
|
37
46
|
|
|
38
|
-
### 2. Define
|
|
47
|
+
### 2. Define your provision config
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
// provision.ts
|
|
51
|
+
import type { ProvisionConfig } from 'skedyul'
|
|
52
|
+
|
|
53
|
+
import env from './env'
|
|
54
|
+
import { models, relationships } from './crm'
|
|
55
|
+
import * as channels from './channels'
|
|
56
|
+
import * as pages from './pages'
|
|
57
|
+
import navigation from './pages/navigation'
|
|
58
|
+
|
|
59
|
+
const config: ProvisionConfig = {
|
|
60
|
+
env,
|
|
61
|
+
navigation,
|
|
62
|
+
models: Object.values(models),
|
|
63
|
+
channels: Object.values(channels),
|
|
64
|
+
pages: Object.values(pages),
|
|
65
|
+
relationships,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default config
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 3. Define a model
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// crm/models/contact.ts
|
|
75
|
+
import { defineModel } from 'skedyul'
|
|
76
|
+
|
|
77
|
+
export default defineModel({
|
|
78
|
+
handle: 'contact',
|
|
79
|
+
label: 'Contact',
|
|
80
|
+
labelPlural: 'Contacts',
|
|
81
|
+
scope: 'shared',
|
|
82
|
+
|
|
83
|
+
fields: [
|
|
84
|
+
{
|
|
85
|
+
handle: 'name',
|
|
86
|
+
label: 'Name',
|
|
87
|
+
type: 'string',
|
|
88
|
+
required: true,
|
|
89
|
+
owner: 'workplace',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
handle: 'email',
|
|
93
|
+
label: 'Email',
|
|
94
|
+
type: 'string',
|
|
95
|
+
required: false,
|
|
96
|
+
owner: 'workplace',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 4. Define a tool
|
|
39
103
|
|
|
40
104
|
```ts
|
|
41
105
|
// src/tools/hello.ts
|
|
@@ -65,7 +129,7 @@ export const helloTool: ToolDefinition<Input, Output> = {
|
|
|
65
129
|
}
|
|
66
130
|
```
|
|
67
131
|
|
|
68
|
-
###
|
|
132
|
+
### 5. Start the server
|
|
69
133
|
|
|
70
134
|
```ts
|
|
71
135
|
// src/server.ts
|
|
@@ -95,6 +159,33 @@ await mcpServer.listen(3000)
|
|
|
95
159
|
| [Configuration](./docs/configuration.md) | skedyul.config.ts reference |
|
|
96
160
|
| [Errors](./docs/errors.md) | Error types and handling patterns |
|
|
97
161
|
|
|
162
|
+
## Project Structure
|
|
163
|
+
|
|
164
|
+
The recommended project structure uses modular, file-based configuration:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
my-app/
|
|
168
|
+
├── skedyul.config.ts # App metadata + imports
|
|
169
|
+
├── provision.ts # Aggregates all modular configs
|
|
170
|
+
├── env.ts # Environment variables
|
|
171
|
+
├── crm/
|
|
172
|
+
│ ├── index.ts # Re-exports models + relationships
|
|
173
|
+
│ ├── relationships.ts # Model relationships
|
|
174
|
+
│ └── models/
|
|
175
|
+
│ ├── index.ts
|
|
176
|
+
│ └── contact.ts
|
|
177
|
+
├── channels/
|
|
178
|
+
│ ├── index.ts
|
|
179
|
+
│ └── phone.ts
|
|
180
|
+
├── pages/
|
|
181
|
+
│ ├── index.ts
|
|
182
|
+
│ ├── navigation.ts # Root navigation
|
|
183
|
+
│ └── settings/
|
|
184
|
+
│ └── page.ts
|
|
185
|
+
└── src/
|
|
186
|
+
└── registries.ts # Tools and webhooks
|
|
187
|
+
```
|
|
188
|
+
|
|
98
189
|
## Server Modes
|
|
99
190
|
|
|
100
191
|
### Dedicated (Docker/ECS)
|
package/dist/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1771999780767
|
|
@@ -42,6 +42,101 @@ const logger_1 = require("../../server/logger");
|
|
|
42
42
|
const auth_1 = require("../utils/auth");
|
|
43
43
|
const link_1 = require("../utils/link");
|
|
44
44
|
const config_1 = require("../utils/config");
|
|
45
|
+
const client_1 = require("../../core/client");
|
|
46
|
+
/**
|
|
47
|
+
* Simple MIME type lookup based on file extension.
|
|
48
|
+
*/
|
|
49
|
+
function getMimeType(filePath) {
|
|
50
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
51
|
+
const mimeTypes = {
|
|
52
|
+
'.pdf': 'application/pdf',
|
|
53
|
+
'.jpg': 'image/jpeg',
|
|
54
|
+
'.jpeg': 'image/jpeg',
|
|
55
|
+
'.png': 'image/png',
|
|
56
|
+
'.gif': 'image/gif',
|
|
57
|
+
'.webp': 'image/webp',
|
|
58
|
+
'.svg': 'image/svg+xml',
|
|
59
|
+
'.txt': 'text/plain',
|
|
60
|
+
'.html': 'text/html',
|
|
61
|
+
'.htm': 'text/html',
|
|
62
|
+
'.css': 'text/css',
|
|
63
|
+
'.js': 'application/javascript',
|
|
64
|
+
'.json': 'application/json',
|
|
65
|
+
'.xml': 'application/xml',
|
|
66
|
+
'.csv': 'text/csv',
|
|
67
|
+
'.doc': 'application/msword',
|
|
68
|
+
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
69
|
+
'.xls': 'application/vnd.ms-excel',
|
|
70
|
+
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
71
|
+
'.zip': 'application/zip',
|
|
72
|
+
'.mp3': 'audio/mpeg',
|
|
73
|
+
'.mp4': 'video/mp4',
|
|
74
|
+
'.wav': 'audio/wav',
|
|
75
|
+
};
|
|
76
|
+
return mimeTypes[ext] || 'application/octet-stream';
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Upload a local file and return its file ID.
|
|
80
|
+
*/
|
|
81
|
+
async function uploadLocalFile(filePath) {
|
|
82
|
+
const absolutePath = path.resolve(filePath);
|
|
83
|
+
if (!fs.existsSync(absolutePath)) {
|
|
84
|
+
throw new Error(`File not found: ${absolutePath}`);
|
|
85
|
+
}
|
|
86
|
+
const content = fs.readFileSync(absolutePath);
|
|
87
|
+
const fileName = path.basename(absolutePath);
|
|
88
|
+
const mimeType = getMimeType(absolutePath);
|
|
89
|
+
console.error(`Uploading file: ${fileName} (${mimeType}, ${content.length} bytes)...`);
|
|
90
|
+
const result = await client_1.file.upload({
|
|
91
|
+
content,
|
|
92
|
+
name: fileName,
|
|
93
|
+
mimeType,
|
|
94
|
+
});
|
|
95
|
+
console.error(`Uploaded: ${fileName} -> ${result.id}`);
|
|
96
|
+
return result.id;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Process upload templates in args object.
|
|
100
|
+
* Recursively scans all string values and replaces {{upload:/path/to/file}} patterns
|
|
101
|
+
* with the uploaded file ID.
|
|
102
|
+
*/
|
|
103
|
+
async function processUploadTemplates(args) {
|
|
104
|
+
const result = {};
|
|
105
|
+
for (const [key, value] of Object.entries(args)) {
|
|
106
|
+
if (typeof value === 'string') {
|
|
107
|
+
const match = value.match(/^\{\{upload:(.+)\}\}$/);
|
|
108
|
+
if (match) {
|
|
109
|
+
const filePath = match[1];
|
|
110
|
+
const fileId = await uploadLocalFile(filePath);
|
|
111
|
+
result[key] = fileId;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
result[key] = value;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (Array.isArray(value)) {
|
|
118
|
+
result[key] = await Promise.all(value.map(async (item) => {
|
|
119
|
+
if (typeof item === 'string') {
|
|
120
|
+
const match = item.match(/^\{\{upload:(.+)\}\}$/);
|
|
121
|
+
if (match) {
|
|
122
|
+
return await uploadLocalFile(match[1]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
else if (item && typeof item === 'object') {
|
|
126
|
+
return await processUploadTemplates(item);
|
|
127
|
+
}
|
|
128
|
+
return item;
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
else if (value && typeof value === 'object') {
|
|
132
|
+
result[key] = await processUploadTemplates(value);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
result[key] = value;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
45
140
|
/**
|
|
46
141
|
* Find available linked workplaces from .skedyul/links/
|
|
47
142
|
*/
|
|
@@ -73,6 +168,7 @@ Arguments:
|
|
|
73
168
|
Options:
|
|
74
169
|
--registry, -r Path to the registry file (default: auto-detected)
|
|
75
170
|
--args, -a JSON string of arguments to pass to the tool
|
|
171
|
+
Supports {{upload:/path/to/file}} syntax for file uploads
|
|
76
172
|
--env, -e Set environment variable (can be used multiple times)
|
|
77
173
|
Format: --env KEY=VALUE
|
|
78
174
|
--env-file Load environment variables from a file (e.g., .env.local)
|
|
@@ -83,6 +179,10 @@ Workplace Options:
|
|
|
83
179
|
--workplace, -w Workplace subdomain (auto-detected if only one is linked)
|
|
84
180
|
Loads env vars from .skedyul/env/{workplace}.env
|
|
85
181
|
|
|
182
|
+
File Upload Syntax:
|
|
183
|
+
Use {{upload:/path/to/file}} in any string field within --args to automatically
|
|
184
|
+
upload a local file and replace the template with the uploaded file ID.
|
|
185
|
+
|
|
86
186
|
Examples:
|
|
87
187
|
# Basic invocation (auto-detects workspace if only one is linked)
|
|
88
188
|
skedyul dev invoke appointment_types_list
|
|
@@ -93,6 +193,14 @@ Examples:
|
|
|
93
193
|
# With arguments
|
|
94
194
|
skedyul dev invoke create_booking --args '{"date": "2024-01-15"}'
|
|
95
195
|
|
|
196
|
+
# With file upload (uploads file and injects file_id)
|
|
197
|
+
skedyul dev invoke parse_lab_report \\
|
|
198
|
+
--args '{"file_id": "{{upload:/path/to/report.pdf}}"}'
|
|
199
|
+
|
|
200
|
+
# Multiple file uploads in one command
|
|
201
|
+
skedyul dev invoke process_documents \\
|
|
202
|
+
--args '{"doc": "{{upload:./doc.pdf}}", "image": "{{upload:./photo.jpg}}"}'
|
|
203
|
+
|
|
96
204
|
# With inline environment variables
|
|
97
205
|
skedyul dev invoke api_call \\
|
|
98
206
|
--args '{"endpoint": "/users"}' \\
|
|
@@ -209,12 +317,27 @@ async function invokeCommand(args) {
|
|
|
209
317
|
const tokenResponse = await (0, auth_1.callCliApi)({ serverUrl: linkConfig.serverUrl, token: credentials.token }, '/token', { appInstallationId: linkConfig.appInstallationId });
|
|
210
318
|
workplaceToken = tokenResponse.token;
|
|
211
319
|
env.SKEDYUL_API_TOKEN = workplaceToken;
|
|
320
|
+
// Configure the skedyul client for file uploads
|
|
321
|
+
(0, client_1.configure)({
|
|
322
|
+
baseUrl: linkConfig.serverUrl,
|
|
323
|
+
apiToken: workplaceToken,
|
|
324
|
+
});
|
|
212
325
|
}
|
|
213
326
|
catch (error) {
|
|
214
327
|
console.error(`Failed to get API token: ${error instanceof Error ? error.message : String(error)}`);
|
|
215
328
|
process.exit(1);
|
|
216
329
|
}
|
|
217
330
|
}
|
|
331
|
+
// Process upload templates in args (e.g., {{upload:/path/to/file}})
|
|
332
|
+
if (isLinked) {
|
|
333
|
+
try {
|
|
334
|
+
toolArgs = await processUploadTemplates(toolArgs);
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
console.error(`Error processing file uploads: ${error instanceof Error ? error.message : String(error)}`);
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
218
341
|
// Check for estimate mode
|
|
219
342
|
const estimateMode = Boolean(flags.estimate);
|
|
220
343
|
// Load registry
|
package/dist/cli/utils/config.js
CHANGED
|
@@ -90,9 +90,14 @@ function parseConfigFromSource(configPath) {
|
|
|
90
90
|
}
|
|
91
91
|
// Fallback: try to extract handle from config file (top-level only)
|
|
92
92
|
if (!handle) {
|
|
93
|
-
const handleMatch = content.match(/^\s
|
|
93
|
+
const handleMatch = content.match(/^\s{0,2}handle\s*:\s*['"`]([^'"`]+)['"`]/m);
|
|
94
94
|
handle = handleMatch?.[1] ?? null;
|
|
95
95
|
}
|
|
96
|
+
// If handle was found in config, prefer it over package.json derived handle
|
|
97
|
+
const configHandleMatch = content.match(/^\s{0,2}handle\s*:\s*['"`]([^'"`]+)['"`]/m);
|
|
98
|
+
if (configHandleMatch?.[1]) {
|
|
99
|
+
handle = configHandleMatch[1];
|
|
100
|
+
}
|
|
96
101
|
if (!handle && !nameMatch) {
|
|
97
102
|
return null;
|
|
98
103
|
}
|
|
@@ -10,7 +10,8 @@ import type { ResourceDependency } from './resource';
|
|
|
10
10
|
/**
|
|
11
11
|
* Field data types (lowercase).
|
|
12
12
|
* - 'string': Short text (single line)
|
|
13
|
-
* - '
|
|
13
|
+
* - 'long_string': Long text (multi-line, stored as text in DB)
|
|
14
|
+
* - 'text': Alias for long_string
|
|
14
15
|
* - 'number': Numeric value
|
|
15
16
|
* - 'boolean': True/false
|
|
16
17
|
* - 'date': Date only (no time)
|
|
@@ -21,7 +22,7 @@ import type { ResourceDependency } from './resource';
|
|
|
21
22
|
* - 'relation': Reference to another model
|
|
22
23
|
* - 'object': JSON object
|
|
23
24
|
*/
|
|
24
|
-
export type FieldType = 'string' | 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'time' | 'file' | 'image' | 'relation' | 'object';
|
|
25
|
+
export type FieldType = 'string' | 'long_string' | 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'time' | 'file' | 'image' | 'relation' | 'object';
|
|
25
26
|
/**
|
|
26
27
|
* Relationship cardinality between models.
|
|
27
28
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Pages define the UI screens for an app, including their
|
|
5
5
|
* layout, data context, and navigation.
|
|
6
6
|
*/
|
|
7
|
-
import type { BaseDefinition } from './base';
|
|
7
|
+
import type { BaseDefinition, StructuredFilter } from './base';
|
|
8
8
|
import type { ContextDefinition } from './context';
|
|
9
9
|
import type { ActionDefinition, BlockDefinition } from './form';
|
|
10
10
|
import type { NavigationConfig } from './navigation';
|
|
@@ -14,6 +14,16 @@ import type { NavigationConfig } from './navigation';
|
|
|
14
14
|
* - 'list': Shows multiple records (e.g., /phone-numbers)
|
|
15
15
|
*/
|
|
16
16
|
export type PageType = 'instance' | 'list';
|
|
17
|
+
/**
|
|
18
|
+
* Page filter for list pages.
|
|
19
|
+
* Defines which model and optional filter criteria to use.
|
|
20
|
+
*/
|
|
21
|
+
export interface PageFilter {
|
|
22
|
+
/** Model handle to filter */
|
|
23
|
+
model: string;
|
|
24
|
+
/** Optional filter criteria */
|
|
25
|
+
where?: StructuredFilter;
|
|
26
|
+
}
|
|
17
27
|
/**
|
|
18
28
|
* Page definition.
|
|
19
29
|
*/
|
|
@@ -37,4 +47,6 @@ export interface PageDefinition extends BaseDefinition {
|
|
|
37
47
|
actions?: ActionDefinition[];
|
|
38
48
|
/** Context data to load for Liquid templates */
|
|
39
49
|
context?: ContextDefinition;
|
|
50
|
+
/** Filter for list pages - defines which model instances to show */
|
|
51
|
+
filter?: PageFilter;
|
|
40
52
|
}
|
package/dist/core/client.d.ts
CHANGED
|
@@ -382,6 +382,21 @@ export interface FileUrlResponse {
|
|
|
382
382
|
/** ISO timestamp when the URL expires */
|
|
383
383
|
expiresAt: string;
|
|
384
384
|
}
|
|
385
|
+
/**
|
|
386
|
+
* Response from file.get
|
|
387
|
+
*/
|
|
388
|
+
export interface FileInfo {
|
|
389
|
+
/** File ID (fl_xxx format) */
|
|
390
|
+
id: string;
|
|
391
|
+
/** Original filename */
|
|
392
|
+
name: string;
|
|
393
|
+
/** MIME type of the file */
|
|
394
|
+
mimeType: string;
|
|
395
|
+
/** File size in bytes */
|
|
396
|
+
size: number;
|
|
397
|
+
/** ISO timestamp when the file was created */
|
|
398
|
+
createdAt: string;
|
|
399
|
+
}
|
|
385
400
|
/**
|
|
386
401
|
* Parameters for file.upload
|
|
387
402
|
*/
|
|
@@ -405,6 +420,22 @@ export interface FileUploadResult {
|
|
|
405
420
|
url: string | null;
|
|
406
421
|
}
|
|
407
422
|
export declare const file: {
|
|
423
|
+
/**
|
|
424
|
+
* Get file metadata by ID.
|
|
425
|
+
*
|
|
426
|
+
* Returns file information including name, mimeType, and size.
|
|
427
|
+
* Files are validated to ensure they belong to the requesting app installation.
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* ```ts
|
|
431
|
+
* // Get file info
|
|
432
|
+
* const fileInfo = await file.get('fl_abc123')
|
|
433
|
+
* console.log(fileInfo.name) // 'document.pdf'
|
|
434
|
+
* console.log(fileInfo.mimeType) // 'application/pdf'
|
|
435
|
+
* console.log(fileInfo.size) // 12345
|
|
436
|
+
* ```
|
|
437
|
+
*/
|
|
438
|
+
get(fileId: string): Promise<FileInfo>;
|
|
408
439
|
/**
|
|
409
440
|
* Get a temporary download URL for an app-scoped file.
|
|
410
441
|
*
|
package/dist/core/client.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.runWithConfig = runWithConfig;
|
|
|
5
5
|
exports.configure = configure;
|
|
6
6
|
exports.getConfig = getConfig;
|
|
7
7
|
const async_hooks_1 = require("async_hooks");
|
|
8
|
+
const v4_1 = require("zod/v4");
|
|
8
9
|
/**
|
|
9
10
|
* AsyncLocalStorage for request-scoped configuration.
|
|
10
11
|
* This allows each request to have its own config without affecting other concurrent requests.
|
|
@@ -406,6 +407,27 @@ exports.token = {
|
|
|
406
407
|
},
|
|
407
408
|
};
|
|
408
409
|
exports.file = {
|
|
410
|
+
/**
|
|
411
|
+
* Get file metadata by ID.
|
|
412
|
+
*
|
|
413
|
+
* Returns file information including name, mimeType, and size.
|
|
414
|
+
* Files are validated to ensure they belong to the requesting app installation.
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* ```ts
|
|
418
|
+
* // Get file info
|
|
419
|
+
* const fileInfo = await file.get('fl_abc123')
|
|
420
|
+
* console.log(fileInfo.name) // 'document.pdf'
|
|
421
|
+
* console.log(fileInfo.mimeType) // 'application/pdf'
|
|
422
|
+
* console.log(fileInfo.size) // 12345
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
425
|
+
async get(fileId) {
|
|
426
|
+
const { data } = await callCore('file.get', {
|
|
427
|
+
fileId,
|
|
428
|
+
});
|
|
429
|
+
return data;
|
|
430
|
+
},
|
|
409
431
|
/**
|
|
410
432
|
* Get a temporary download URL for an app-scoped file.
|
|
411
433
|
*
|
|
@@ -642,60 +664,11 @@ exports.contactAssociationLink = {
|
|
|
642
664
|
},
|
|
643
665
|
};
|
|
644
666
|
/**
|
|
645
|
-
* Convert a Zod schema to JSON Schema format for transport.
|
|
646
|
-
*
|
|
667
|
+
* Convert a Zod schema to JSON Schema format for transport using Zod's built-in conversion.
|
|
668
|
+
* Uses z.toJSONSchema() from Zod 4 for accurate schema conversion.
|
|
647
669
|
*/
|
|
648
670
|
function zodSchemaToJsonSchema(schema) {
|
|
649
|
-
|
|
650
|
-
// For now, we'll pass the schema description and let the server handle it
|
|
651
|
-
const jsonSchema = schema._def;
|
|
652
|
-
// Basic type mapping
|
|
653
|
-
if (jsonSchema?.typeName === 'ZodString') {
|
|
654
|
-
return { type: 'string' };
|
|
655
|
-
}
|
|
656
|
-
if (jsonSchema?.typeName === 'ZodNumber') {
|
|
657
|
-
return { type: 'number' };
|
|
658
|
-
}
|
|
659
|
-
if (jsonSchema?.typeName === 'ZodBoolean') {
|
|
660
|
-
return { type: 'boolean' };
|
|
661
|
-
}
|
|
662
|
-
if (jsonSchema?.typeName === 'ZodArray') {
|
|
663
|
-
const arrayDef = jsonSchema;
|
|
664
|
-
return {
|
|
665
|
-
type: 'array',
|
|
666
|
-
items: arrayDef.type ? zodSchemaToJsonSchema(arrayDef.type) : {},
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
if (jsonSchema?.typeName === 'ZodObject') {
|
|
670
|
-
const objectDef = jsonSchema;
|
|
671
|
-
const shape = objectDef.shape?.() ?? {};
|
|
672
|
-
const properties = {};
|
|
673
|
-
const required = [];
|
|
674
|
-
for (const [key, value] of Object.entries(shape)) {
|
|
675
|
-
properties[key] = zodSchemaToJsonSchema(value);
|
|
676
|
-
// Check if field is required (not optional/nullable)
|
|
677
|
-
const valueDef = value._def;
|
|
678
|
-
if (valueDef?.typeName !== 'ZodOptional' && valueDef?.typeName !== 'ZodNullable') {
|
|
679
|
-
required.push(key);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
return {
|
|
683
|
-
type: 'object',
|
|
684
|
-
properties,
|
|
685
|
-
required: required.length > 0 ? required : undefined,
|
|
686
|
-
};
|
|
687
|
-
}
|
|
688
|
-
if (jsonSchema?.typeName === 'ZodNullable' || jsonSchema?.typeName === 'ZodOptional') {
|
|
689
|
-
const innerDef = jsonSchema;
|
|
690
|
-
const inner = innerDef.innerType ? zodSchemaToJsonSchema(innerDef.innerType) : {};
|
|
691
|
-
return { ...inner, nullable: true };
|
|
692
|
-
}
|
|
693
|
-
if (jsonSchema?.typeName === 'ZodEnum') {
|
|
694
|
-
const enumDef = jsonSchema;
|
|
695
|
-
return { type: 'string', enum: enumDef.values };
|
|
696
|
-
}
|
|
697
|
-
// Fallback: return empty object schema
|
|
698
|
-
return { type: 'object' };
|
|
671
|
+
return v4_1.z.toJSONSchema(schema);
|
|
699
672
|
}
|
|
700
673
|
exports.ai = {
|
|
701
674
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { InstallError, MissingRequiredFieldError, AuthenticationError, InvalidCo
|
|
|
8
8
|
export type { InstallErrorCode } from './errors';
|
|
9
9
|
export { z };
|
|
10
10
|
export { workplace, communicationChannel, instance, token, file, webhook, resource, contactAssociationLink, ai, configure, getConfig, runWithConfig, } from './core/client';
|
|
11
|
-
export type { InstanceContext, InstanceData, InstanceMeta, InstancePagination, InstanceListResult, InstanceListArgs, FileUrlResponse, FileUploadParams, FileUploadResult, WebhookCreateResult, WebhookListItem, WebhookDeleteByNameOptions, WebhookListOptions, ResourceLinkParams, ResourceLinkResult, ContactAssociationLinkCreateParams, ContactAssociationLinkCreateResult, AITextContent, AIFileContent, AIImageContent, AIMessageContent, AIMessage, GenerateObjectOptions, GenerateObjectResult, } from './core/client';
|
|
11
|
+
export type { InstanceContext, InstanceData, InstanceMeta, InstancePagination, InstanceListResult, InstanceListArgs, FileInfo, FileUrlResponse, FileUploadParams, FileUploadResult, WebhookCreateResult, WebhookListItem, WebhookDeleteByNameOptions, WebhookListOptions, ResourceLinkParams, ResourceLinkResult, ContactAssociationLinkCreateParams, ContactAssociationLinkCreateResult, AITextContent, AIFileContent, AIImageContent, AIMessageContent, AIMessage, GenerateObjectOptions, GenerateObjectResult, } from './core/client';
|
|
12
12
|
export { createContextLogger } from './server/logger';
|
|
13
13
|
export type { ContextLogger } from './server/logger';
|
|
14
14
|
declare const _default: {
|
package/dist/schemas.d.ts
CHANGED
|
@@ -1833,7 +1833,7 @@ export declare const ListBlockDefinitionSchema: z.ZodObject<{
|
|
|
1833
1833
|
}, z.core.$strip>;
|
|
1834
1834
|
/** Model mapper block definition - for mapping SHARED models to workspace models */
|
|
1835
1835
|
export declare const ModelMapperBlockDefinitionSchema: z.ZodObject<{
|
|
1836
|
-
type: z.ZodLiteral<"
|
|
1836
|
+
type: z.ZodLiteral<"model_mapper">;
|
|
1837
1837
|
model: z.ZodString;
|
|
1838
1838
|
}, z.core.$strip>;
|
|
1839
1839
|
/** Union of all block types */
|
|
@@ -2210,7 +2210,7 @@ export declare const PageBlockDefinitionSchema: z.ZodUnion<readonly [z.ZodObject
|
|
|
2210
2210
|
icon: z.ZodOptional<z.ZodString>;
|
|
2211
2211
|
emptyMessage: z.ZodOptional<z.ZodString>;
|
|
2212
2212
|
}, z.core.$strip>, z.ZodObject<{
|
|
2213
|
-
type: z.ZodLiteral<"
|
|
2213
|
+
type: z.ZodLiteral<"model_mapper">;
|
|
2214
2214
|
model: z.ZodString;
|
|
2215
2215
|
}, z.core.$strip>]>;
|
|
2216
2216
|
/** Mode for context data fetching */
|
|
@@ -2714,7 +2714,7 @@ export declare const PageDefinitionSchema: z.ZodObject<{
|
|
|
2714
2714
|
icon: z.ZodOptional<z.ZodString>;
|
|
2715
2715
|
emptyMessage: z.ZodOptional<z.ZodString>;
|
|
2716
2716
|
}, z.core.$strip>, z.ZodObject<{
|
|
2717
|
-
type: z.ZodLiteral<"
|
|
2717
|
+
type: z.ZodLiteral<"model_mapper">;
|
|
2718
2718
|
model: z.ZodString;
|
|
2719
2719
|
}, z.core.$strip>]>>;
|
|
2720
2720
|
actions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -3505,7 +3505,7 @@ export declare const ProvisionConfigSchema: z.ZodObject<{
|
|
|
3505
3505
|
icon: z.ZodOptional<z.ZodString>;
|
|
3506
3506
|
emptyMessage: z.ZodOptional<z.ZodString>;
|
|
3507
3507
|
}, z.core.$strip>, z.ZodObject<{
|
|
3508
|
-
type: z.ZodLiteral<"
|
|
3508
|
+
type: z.ZodLiteral<"model_mapper">;
|
|
3509
3509
|
model: z.ZodString;
|
|
3510
3510
|
}, z.core.$strip>]>>;
|
|
3511
3511
|
actions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -4143,7 +4143,7 @@ export declare const SkedyulConfigSchema: z.ZodObject<{
|
|
|
4143
4143
|
icon: z.ZodOptional<z.ZodString>;
|
|
4144
4144
|
emptyMessage: z.ZodOptional<z.ZodString>;
|
|
4145
4145
|
}, z.core.$strip>, z.ZodObject<{
|
|
4146
|
-
type: z.ZodLiteral<"
|
|
4146
|
+
type: z.ZodLiteral<"model_mapper">;
|
|
4147
4147
|
model: z.ZodString;
|
|
4148
4148
|
}, z.core.$strip>]>>;
|
|
4149
4149
|
actions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
package/dist/schemas.js
CHANGED
|
@@ -545,7 +545,7 @@ exports.ListBlockDefinitionSchema = v4_1.z.object({
|
|
|
545
545
|
});
|
|
546
546
|
/** Model mapper block definition - for mapping SHARED models to workspace models */
|
|
547
547
|
exports.ModelMapperBlockDefinitionSchema = v4_1.z.object({
|
|
548
|
-
type: v4_1.z.literal('
|
|
548
|
+
type: v4_1.z.literal('model_mapper'),
|
|
549
549
|
/** The SHARED model handle from install config (e.g., "client", "patient") */
|
|
550
550
|
model: v4_1.z.string(),
|
|
551
551
|
});
|