skedyul 0.1.36 → 0.1.38

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/dist/.build-stamp CHANGED
@@ -1 +1 @@
1
- 1768203723348
1
+ 1768437850820
package/dist/config.d.ts CHANGED
@@ -23,11 +23,37 @@ export interface AppModelDefinition {
23
23
  /** Description of what this model represents */
24
24
  description?: string;
25
25
  }
26
+ /**
27
+ * Context passed to the install handler when a user installs the app.
28
+ */
29
+ export interface InstallHandlerContext {
30
+ /** Environment variables from preInstall.env filled by the user */
31
+ env: Record<string, string>;
32
+ /** Workplace information */
33
+ workplace: {
34
+ id: string;
35
+ subdomain: string;
36
+ };
37
+ }
38
+ /**
39
+ * Result returned by the install handler.
40
+ */
41
+ export interface InstallHandlerResult {
42
+ /** Additional environment variables to add to the installation */
43
+ env?: Record<string, string>;
44
+ /** Optional OAuth redirect URL - if provided, user is redirected before install completes */
45
+ redirect?: string;
46
+ }
47
+ /**
48
+ * Install handler function type.
49
+ */
50
+ export type InstallHandler = (ctx: InstallHandlerContext) => Promise<InstallHandlerResult>;
26
51
  export interface InstallConfig {
27
52
  /**
28
53
  * Per-install environment variables.
29
54
  * These are configured by the user when installing the app.
30
55
  * Values are stored per-installation and can differ between installs.
56
+ * @deprecated Use preInstall.env and postInstall.env instead
31
57
  */
32
58
  env?: EnvSchema;
33
59
  /**
@@ -35,6 +61,35 @@ export interface InstallConfig {
35
61
  * Users will map these to their CRM models during installation.
36
62
  */
37
63
  appModels?: AppModelDefinition[];
64
+ /**
65
+ * Install handler - called when user clicks install.
66
+ * Use dynamic import: handler: import('./src/install')
67
+ */
68
+ handler?: Promise<{
69
+ default: InstallHandler;
70
+ }>;
71
+ }
72
+ /**
73
+ * Pre-install configuration.
74
+ * Variables collected BEFORE the app is installed (e.g., API keys, credentials).
75
+ */
76
+ export interface PreInstallConfig {
77
+ /**
78
+ * Environment variables required before installation.
79
+ * User must provide these values during the install flow.
80
+ */
81
+ env?: EnvSchema;
82
+ }
83
+ /**
84
+ * Post-install configuration.
85
+ * Variables that can be configured AFTER the app is installed.
86
+ */
87
+ export interface PostInstallConfig {
88
+ /**
89
+ * Environment variables configurable after installation.
90
+ * These appear in the Settings page of the installed app.
91
+ */
92
+ env?: EnvSchema;
38
93
  }
39
94
  export interface AppFieldVisibility {
40
95
  /** Show in data/detail view */
@@ -70,6 +125,71 @@ export interface ChannelToolBindings {
70
125
  /** Tool name for sending messages on this channel */
71
126
  send_message: string;
72
127
  }
128
+ /** Scope of a model: INTERNAL (app-owned) or SHARED (user-mapped) */
129
+ export type ResourceScope = 'INTERNAL' | 'SHARED';
130
+ /** Model dependency reference */
131
+ export interface ModelDependency {
132
+ /** Handle of the model being depended upon */
133
+ model: string;
134
+ /** Specific fields required (undefined = all fields) */
135
+ fields?: string[];
136
+ }
137
+ /** Channel dependency reference */
138
+ export interface ChannelDependency {
139
+ /** Handle of the channel being depended upon */
140
+ channel: string;
141
+ }
142
+ /** Workflow dependency reference */
143
+ export interface WorkflowDependency {
144
+ /** Handle of the workflow being depended upon */
145
+ workflow: string;
146
+ }
147
+ /** Union of all resource dependency types */
148
+ export type ResourceDependency = ModelDependency | ChannelDependency | WorkflowDependency;
149
+ /** Field definition for unified models (works for INTERNAL and SHARED) */
150
+ export interface ModelFieldDefinition {
151
+ /** Field handle (unique within model) */
152
+ handle: string;
153
+ /** Display label */
154
+ label: string;
155
+ /** Data type (required for INTERNAL, optional for SHARED) */
156
+ type?: InternalFieldDataType;
157
+ /** Field definition handle for SHARED fields */
158
+ definitionHandle?: string;
159
+ /** Whether field is required */
160
+ required?: boolean;
161
+ /** Whether field must be unique */
162
+ unique?: boolean;
163
+ /** Whether this is a system field */
164
+ system?: boolean;
165
+ /** Whether field holds a list of values */
166
+ isList?: boolean;
167
+ /** Default value */
168
+ defaultValue?: {
169
+ value: unknown;
170
+ };
171
+ /** Field description */
172
+ description?: string;
173
+ /** Visibility settings (for SHARED fields) */
174
+ visibility?: AppFieldVisibility;
175
+ }
176
+ /** Unified model definition (supports both INTERNAL and SHARED) */
177
+ export interface ModelDefinition {
178
+ /** Model handle (unique within app) */
179
+ handle: string;
180
+ /** Display name */
181
+ name: string;
182
+ /** Plural display name */
183
+ namePlural?: string;
184
+ /** Resource scope: INTERNAL (app creates) or SHARED (user maps) */
185
+ scope: ResourceScope;
186
+ /** Label template for display (required for INTERNAL) */
187
+ labelTemplate?: string;
188
+ /** Model description */
189
+ description?: string;
190
+ /** Field definitions */
191
+ fields: ModelFieldDefinition[];
192
+ }
73
193
  export type ChannelIdentifierType = 'DEDICATED_PHONE' | 'TEXT' | 'EMAIL';
74
194
  export interface ChannelIdentifierValue {
75
195
  /** Type of identifier */
@@ -87,12 +207,16 @@ export interface CommunicationChannelDefinition {
87
207
  /** Tool bindings for this channel */
88
208
  tools: ChannelToolBindings;
89
209
  /** How the channel identifier is configured */
90
- identifierValue: ChannelIdentifierValue;
210
+ identifierValue?: ChannelIdentifierValue;
91
211
  /** Fields to add to contacts when using this channel */
92
212
  appFields?: AppFieldDefinition[];
93
213
  /** Additional settings UI */
94
214
  settings?: unknown[];
215
+ /** Typed dependencies - models, fields this channel requires */
216
+ requires?: ResourceDependency[];
95
217
  }
218
+ /** Alias for channel definition (new naming) */
219
+ export type ChannelDefinition = CommunicationChannelDefinition;
96
220
  export interface WorkflowActionInput {
97
221
  /** Input key */
98
222
  key: string;
@@ -125,6 +249,8 @@ export interface WorkflowDefinition {
125
249
  label?: string;
126
250
  /** Workflow handle/key (optional when path is provided, inferred from YAML) */
127
251
  handle?: string;
252
+ /** Typed dependencies - channels, models this workflow requires */
253
+ requires?: ResourceDependency[];
128
254
  /** Actions in this workflow */
129
255
  actions: WorkflowAction[];
130
256
  }
@@ -228,39 +354,69 @@ export interface SkedyulConfig {
228
354
  /**
229
355
  * Install-time configuration.
230
356
  * Defines what users need to configure when installing the app.
357
+ * @deprecated Use preInstall and postInstall instead
231
358
  */
232
359
  install?: InstallConfig;
233
360
  /**
234
- * Communication channels this app provides.
235
- * Defines how the app can send/receive messages.
361
+ * Pre-install configuration.
362
+ * Environment variables collected BEFORE the app is installed.
363
+ * User must provide these values (e.g., API keys) during the install flow.
236
364
  */
237
- communicationChannels?: CommunicationChannelDefinition[];
365
+ preInstall?: PreInstallConfig;
238
366
  /**
239
- * Workflows this app provides.
240
- * Can reference channels via channelHandle.
367
+ * Post-install configuration.
368
+ * Environment variables that can be configured AFTER the app is installed.
369
+ * These appear in the Settings page of the installed app.
241
370
  */
242
- workflows?: WorkflowDefinition[];
371
+ postInstall?: PostInstallConfig;
243
372
  /**
244
- * Internal models owned by this app.
245
- * These models are created and managed by the app, not by users.
246
- * Data is stored in the standard Model/Field/Instance tables but
247
- * linked to the AppVersion for ownership tracking.
373
+ * Unified model definitions (INTERNAL + SHARED).
374
+ * INTERNAL models are created and managed by the app.
375
+ * SHARED models map to user's existing models.
248
376
  *
249
377
  * @example
250
378
  * ```typescript
251
- * internalModels: [
379
+ * models: [
252
380
  * {
253
- * handle: 'dedicated_phone_number',
254
- * name: 'Dedicated Phone Number',
255
- * namePlural: 'Dedicated Phone Numbers',
381
+ * handle: 'phone_number',
382
+ * name: 'Phone Number',
383
+ * scope: 'INTERNAL',
256
384
  * labelTemplate: '{{phone}}',
257
385
  * fields: [
258
- * { handle: 'phone', label: 'Phone Number', type: 'TEXT', required: true, unique: true },
386
+ * { handle: 'phone', label: 'Phone Number', type: 'STRING', required: true },
387
+ * ],
388
+ * },
389
+ * {
390
+ * handle: 'contact',
391
+ * name: 'Contact',
392
+ * scope: 'SHARED',
393
+ * fields: [
394
+ * { handle: 'phone', label: 'Phone', definitionHandle: 'phone', required: true },
259
395
  * ],
260
396
  * },
261
397
  * ]
262
398
  * ```
263
399
  */
400
+ models?: ModelDefinition[];
401
+ /**
402
+ * Communication channels this app provides (new syntax).
403
+ * Uses typed `requires` for dependencies.
404
+ */
405
+ channels?: ChannelDefinition[];
406
+ /**
407
+ * Communication channels this app provides (legacy syntax).
408
+ * @deprecated Use `channels` instead
409
+ */
410
+ communicationChannels?: CommunicationChannelDefinition[];
411
+ /**
412
+ * Workflows this app provides.
413
+ * Can reference channels via `requires: [{ channel: 'sms' }]`.
414
+ */
415
+ workflows?: WorkflowDefinition[];
416
+ /**
417
+ * Internal models owned by this app.
418
+ * @deprecated Use `models` with `scope: 'INTERNAL'` instead
419
+ */
264
420
  internalModels?: InternalModelDefinition[];
265
421
  }
266
422
  /**
@@ -288,13 +444,21 @@ export interface SerializableSkedyulConfig {
288
444
  workflowsPath?: string;
289
445
  /** Global/version-level environment variable schema */
290
446
  env?: EnvSchema;
291
- /** Install-time configuration */
447
+ /** Install-time configuration @deprecated Use preInstall and postInstall */
292
448
  install?: InstallConfig;
293
- /** Communication channels this app provides */
449
+ /** Pre-install configuration (env vars required before install) */
450
+ preInstall?: PreInstallConfig;
451
+ /** Post-install configuration (env vars configurable after install) */
452
+ postInstall?: PostInstallConfig;
453
+ /** Unified model definitions (INTERNAL + SHARED) */
454
+ models?: ModelDefinition[];
455
+ /** Communication channels (new syntax) */
456
+ channels?: ChannelDefinition[];
457
+ /** Communication channels (legacy) @deprecated */
294
458
  communicationChannels?: CommunicationChannelDefinition[];
295
459
  /** Workflows this app provides */
296
460
  workflows?: WorkflowDefinition[];
297
- /** Internal models owned by this app */
461
+ /** Internal models @deprecated Use models with scope: INTERNAL */
298
462
  internalModels?: InternalModelDefinition[];
299
463
  }
300
464
  /**
@@ -339,12 +503,19 @@ export declare function validateConfig(config: SkedyulConfig): {
339
503
  };
340
504
  /**
341
505
  * Get all required install env keys from a config
506
+ * @deprecated Use getRequiredPreInstallEnvKeys instead
342
507
  */
343
508
  export declare function getRequiredInstallEnvKeys(config: SkedyulConfig): string[];
509
+ /**
510
+ * Get all required pre-install env keys from a config
511
+ */
512
+ export declare function getRequiredPreInstallEnvKeys(config: SkedyulConfig): string[];
344
513
  /**
345
514
  * Get all env keys (both global and install) from a config
346
515
  */
347
516
  export declare function getAllEnvKeys(config: SkedyulConfig): {
348
517
  global: string[];
349
518
  install: string[];
519
+ preInstall: string[];
520
+ postInstall: string[];
350
521
  };
package/dist/config.js CHANGED
@@ -38,6 +38,7 @@ exports.defineConfig = defineConfig;
38
38
  exports.loadConfig = loadConfig;
39
39
  exports.validateConfig = validateConfig;
40
40
  exports.getRequiredInstallEnvKeys = getRequiredInstallEnvKeys;
41
+ exports.getRequiredPreInstallEnvKeys = getRequiredPreInstallEnvKeys;
41
42
  exports.getAllEnvKeys = getAllEnvKeys;
42
43
  const fs = __importStar(require("fs"));
43
44
  const path = __importStar(require("path"));
@@ -184,7 +185,7 @@ function validateConfig(config) {
184
185
  }
185
186
  }
186
187
  }
187
- // Validate install.env schema
188
+ // Validate install.env schema (deprecated)
188
189
  if (config.install?.env) {
189
190
  for (const [key, def] of Object.entries(config.install.env)) {
190
191
  if (!def.label) {
@@ -195,6 +196,28 @@ function validateConfig(config) {
195
196
  }
196
197
  }
197
198
  }
199
+ // Validate preInstall.env schema
200
+ if (config.preInstall?.env) {
201
+ for (const [key, def] of Object.entries(config.preInstall.env)) {
202
+ if (!def.label) {
203
+ errors.push(`preInstall.env.${key}: Missing required field 'label'`);
204
+ }
205
+ if (def.visibility && !['visible', 'encrypted'].includes(def.visibility)) {
206
+ errors.push(`preInstall.env.${key}: Invalid visibility '${def.visibility}'`);
207
+ }
208
+ }
209
+ }
210
+ // Validate postInstall.env schema
211
+ if (config.postInstall?.env) {
212
+ for (const [key, def] of Object.entries(config.postInstall.env)) {
213
+ if (!def.label) {
214
+ errors.push(`postInstall.env.${key}: Missing required field 'label'`);
215
+ }
216
+ if (def.visibility && !['visible', 'encrypted'].includes(def.visibility)) {
217
+ errors.push(`postInstall.env.${key}: Invalid visibility '${def.visibility}'`);
218
+ }
219
+ }
220
+ }
198
221
  // Validate appModels
199
222
  if (config.install?.appModels) {
200
223
  for (let i = 0; i < config.install.appModels.length; i++) {
@@ -293,6 +316,7 @@ function validateConfig(config) {
293
316
  }
294
317
  /**
295
318
  * Get all required install env keys from a config
319
+ * @deprecated Use getRequiredPreInstallEnvKeys instead
296
320
  */
297
321
  function getRequiredInstallEnvKeys(config) {
298
322
  if (!config.install?.env)
@@ -301,6 +325,16 @@ function getRequiredInstallEnvKeys(config) {
301
325
  .filter(([, def]) => def.required)
302
326
  .map(([key]) => key);
303
327
  }
328
+ /**
329
+ * Get all required pre-install env keys from a config
330
+ */
331
+ function getRequiredPreInstallEnvKeys(config) {
332
+ if (!config.preInstall?.env)
333
+ return [];
334
+ return Object.entries(config.preInstall.env)
335
+ .filter(([, def]) => def.required)
336
+ .map(([key]) => key);
337
+ }
304
338
  /**
305
339
  * Get all env keys (both global and install) from a config
306
340
  */
@@ -308,5 +342,7 @@ function getAllEnvKeys(config) {
308
342
  return {
309
343
  global: config.env ? Object.keys(config.env) : [],
310
344
  install: config.install?.env ? Object.keys(config.install.env) : [],
345
+ preInstall: config.preInstall?.env ? Object.keys(config.preInstall.env) : [],
346
+ postInstall: config.postInstall?.env ? Object.keys(config.postInstall.env) : [],
311
347
  };
312
348
  }
package/dist/index.d.ts CHANGED
@@ -3,4 +3,4 @@ export * from './schemas';
3
3
  export { server } from './server';
4
4
  export { workplace, communicationChannel, configure, getConfig } from './core/client';
5
5
  export { defineConfig, loadConfig, validateConfig, getRequiredInstallEnvKeys, getAllEnvKeys, CONFIG_FILE_NAMES, } from './config';
6
- export type { SkedyulConfig, SerializableSkedyulConfig, EnvVariableDefinition, EnvSchema, EnvVisibility, InstallConfig, AppModelDefinition, ComputeLayerType, AppFieldVisibility, AppFieldDefinition, ChannelToolBindings, ChannelIdentifierType, ChannelIdentifierValue, CommunicationChannelDefinition, WorkflowActionInput, WorkflowAction, WorkflowDefinition, } from './config';
6
+ export type { SkedyulConfig, SerializableSkedyulConfig, EnvVariableDefinition, EnvSchema, EnvVisibility, InstallConfig, AppModelDefinition, ComputeLayerType, InstallHandlerContext, InstallHandlerResult, InstallHandler, PreInstallConfig, PostInstallConfig, AppFieldVisibility, AppFieldDefinition, ChannelToolBindings, ChannelIdentifierType, ChannelIdentifierValue, CommunicationChannelDefinition, WorkflowActionInput, WorkflowAction, WorkflowDefinition, } from './config';
package/dist/schemas.d.ts CHANGED
@@ -116,6 +116,49 @@ export declare const ChannelIdentifierValueSchema: z.ZodObject<{
116
116
  }>;
117
117
  definitionHandle: z.ZodString;
118
118
  }, z.core.$strip>;
119
+ /**
120
+ * Schema for resource scope.
121
+ * INTERNAL: App owns this resource, auto-created when feature is provisioned
122
+ * SHARED: Maps to user's existing resource, requires user selection
123
+ */
124
+ export declare const ResourceScopeSchema: z.ZodEnum<{
125
+ INTERNAL: "INTERNAL";
126
+ SHARED: "SHARED";
127
+ }>;
128
+ /**
129
+ * Schema for a model dependency reference.
130
+ * Used in `requires` arrays to specify model dependencies.
131
+ */
132
+ export declare const ModelDependencySchema: z.ZodObject<{
133
+ model: z.ZodString;
134
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
135
+ }, z.core.$strip>;
136
+ /**
137
+ * Schema for a channel dependency reference.
138
+ * Used in `requires` arrays to specify channel dependencies.
139
+ */
140
+ export declare const ChannelDependencySchema: z.ZodObject<{
141
+ channel: z.ZodString;
142
+ }, z.core.$strip>;
143
+ /**
144
+ * Schema for a workflow dependency reference.
145
+ * Used in `requires` arrays to specify workflow dependencies.
146
+ */
147
+ export declare const WorkflowDependencySchema: z.ZodObject<{
148
+ workflow: z.ZodString;
149
+ }, z.core.$strip>;
150
+ /**
151
+ * Union schema for all resource dependency types.
152
+ * Used in `requires` arrays on channels, workflows, etc.
153
+ */
154
+ export declare const ResourceDependencySchema: z.ZodUnion<readonly [z.ZodObject<{
155
+ model: z.ZodString;
156
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
157
+ }, z.core.$strip>, z.ZodObject<{
158
+ channel: z.ZodString;
159
+ }, z.core.$strip>, z.ZodObject<{
160
+ workflow: z.ZodString;
161
+ }, z.core.$strip>]>;
119
162
  /**
120
163
  * Schema for communication channel definition.
121
164
  */
@@ -126,14 +169,59 @@ export declare const CommunicationChannelDefinitionSchema: z.ZodObject<{
126
169
  tools: z.ZodObject<{
127
170
  send_message: z.ZodString;
128
171
  }, z.core.$strip>;
129
- identifierValue: z.ZodObject<{
172
+ identifierValue: z.ZodOptional<z.ZodObject<{
130
173
  type: z.ZodEnum<{
131
174
  DEDICATED_PHONE: "DEDICATED_PHONE";
132
175
  TEXT: "TEXT";
133
176
  EMAIL: "EMAIL";
134
177
  }>;
135
178
  definitionHandle: z.ZodString;
179
+ }, z.core.$strip>>;
180
+ appFields: z.ZodOptional<z.ZodArray<z.ZodObject<{
181
+ label: z.ZodString;
182
+ fieldHandle: z.ZodString;
183
+ entityHandle: z.ZodString;
184
+ definitionHandle: z.ZodString;
185
+ required: z.ZodOptional<z.ZodBoolean>;
186
+ system: z.ZodOptional<z.ZodBoolean>;
187
+ unique: z.ZodOptional<z.ZodBoolean>;
188
+ defaultValue: z.ZodOptional<z.ZodObject<{
189
+ value: z.ZodUnknown;
190
+ }, z.core.$strip>>;
191
+ visibility: z.ZodOptional<z.ZodObject<{
192
+ data: z.ZodOptional<z.ZodBoolean>;
193
+ list: z.ZodOptional<z.ZodBoolean>;
194
+ filters: z.ZodOptional<z.ZodBoolean>;
195
+ }, z.core.$strip>>;
196
+ }, z.core.$strip>>>;
197
+ settings: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
198
+ requires: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
199
+ model: z.ZodString;
200
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
201
+ }, z.core.$strip>, z.ZodObject<{
202
+ channel: z.ZodString;
203
+ }, z.core.$strip>, z.ZodObject<{
204
+ workflow: z.ZodString;
205
+ }, z.core.$strip>]>>>;
206
+ }, z.core.$strip>;
207
+ /**
208
+ * Shorter alias for channel definition (used in new config syntax).
209
+ */
210
+ export declare const ChannelDefinitionSchema: z.ZodObject<{
211
+ handle: z.ZodString;
212
+ name: z.ZodString;
213
+ icon: z.ZodOptional<z.ZodString>;
214
+ tools: z.ZodObject<{
215
+ send_message: z.ZodString;
136
216
  }, z.core.$strip>;
217
+ identifierValue: z.ZodOptional<z.ZodObject<{
218
+ type: z.ZodEnum<{
219
+ DEDICATED_PHONE: "DEDICATED_PHONE";
220
+ TEXT: "TEXT";
221
+ EMAIL: "EMAIL";
222
+ }>;
223
+ definitionHandle: z.ZodString;
224
+ }, z.core.$strip>>;
137
225
  appFields: z.ZodOptional<z.ZodArray<z.ZodObject<{
138
226
  label: z.ZodString;
139
227
  fieldHandle: z.ZodString;
@@ -152,6 +240,14 @@ export declare const CommunicationChannelDefinitionSchema: z.ZodObject<{
152
240
  }, z.core.$strip>>;
153
241
  }, z.core.$strip>>>;
154
242
  settings: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
243
+ requires: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
244
+ model: z.ZodString;
245
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
246
+ }, z.core.$strip>, z.ZodObject<{
247
+ channel: z.ZodString;
248
+ }, z.core.$strip>, z.ZodObject<{
249
+ workflow: z.ZodString;
250
+ }, z.core.$strip>]>>>;
155
251
  }, z.core.$strip>;
156
252
  /**
157
253
  * Schema for workflow action input.
@@ -191,6 +287,14 @@ export declare const WorkflowDefinitionSchema: z.ZodObject<{
191
287
  label: z.ZodOptional<z.ZodString>;
192
288
  handle: z.ZodOptional<z.ZodString>;
193
289
  channelHandle: z.ZodOptional<z.ZodString>;
290
+ requires: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
291
+ model: z.ZodString;
292
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
293
+ }, z.core.$strip>, z.ZodObject<{
294
+ channel: z.ZodString;
295
+ }, z.core.$strip>, z.ZodObject<{
296
+ workflow: z.ZodString;
297
+ }, z.core.$strip>]>>>;
194
298
  actions: z.ZodArray<z.ZodObject<{
195
299
  label: z.ZodString;
196
300
  handle: z.ZodString;
@@ -215,9 +319,106 @@ export declare const ComputeLayerTypeSchema: z.ZodEnum<{
215
319
  serverless: "serverless";
216
320
  }>;
217
321
  /**
218
- * Schema for internal field data types.
322
+ * Schema for field data types.
219
323
  * Matches the DataType enum in the database.
220
324
  */
325
+ export declare const FieldDataTypeSchema: z.ZodEnum<{
326
+ LONG_STRING: "LONG_STRING";
327
+ STRING: "STRING";
328
+ NUMBER: "NUMBER";
329
+ BOOLEAN: "BOOLEAN";
330
+ DATE: "DATE";
331
+ DATE_TIME: "DATE_TIME";
332
+ TIME: "TIME";
333
+ FILE: "FILE";
334
+ IMAGE: "IMAGE";
335
+ RELATION: "RELATION";
336
+ OBJECT: "OBJECT";
337
+ }>;
338
+ /**
339
+ * Schema for a field within a model.
340
+ * Works for both INTERNAL and SHARED models.
341
+ */
342
+ export declare const ModelFieldDefinitionSchema: z.ZodObject<{
343
+ handle: z.ZodString;
344
+ label: z.ZodString;
345
+ type: z.ZodOptional<z.ZodEnum<{
346
+ LONG_STRING: "LONG_STRING";
347
+ STRING: "STRING";
348
+ NUMBER: "NUMBER";
349
+ BOOLEAN: "BOOLEAN";
350
+ DATE: "DATE";
351
+ DATE_TIME: "DATE_TIME";
352
+ TIME: "TIME";
353
+ FILE: "FILE";
354
+ IMAGE: "IMAGE";
355
+ RELATION: "RELATION";
356
+ OBJECT: "OBJECT";
357
+ }>>;
358
+ definitionHandle: z.ZodOptional<z.ZodString>;
359
+ required: z.ZodOptional<z.ZodBoolean>;
360
+ unique: z.ZodOptional<z.ZodBoolean>;
361
+ system: z.ZodOptional<z.ZodBoolean>;
362
+ isList: z.ZodOptional<z.ZodBoolean>;
363
+ defaultValue: z.ZodOptional<z.ZodObject<{
364
+ value: z.ZodUnknown;
365
+ }, z.core.$strip>>;
366
+ description: z.ZodOptional<z.ZodString>;
367
+ visibility: z.ZodOptional<z.ZodObject<{
368
+ data: z.ZodOptional<z.ZodBoolean>;
369
+ list: z.ZodOptional<z.ZodBoolean>;
370
+ filters: z.ZodOptional<z.ZodBoolean>;
371
+ }, z.core.$strip>>;
372
+ }, z.core.$strip>;
373
+ /**
374
+ * Schema for a unified model definition.
375
+ * Supports both INTERNAL (app-owned) and SHARED (user-mapped) models.
376
+ */
377
+ export declare const ModelDefinitionSchema: z.ZodObject<{
378
+ handle: z.ZodString;
379
+ name: z.ZodString;
380
+ namePlural: z.ZodOptional<z.ZodString>;
381
+ scope: z.ZodEnum<{
382
+ INTERNAL: "INTERNAL";
383
+ SHARED: "SHARED";
384
+ }>;
385
+ labelTemplate: z.ZodOptional<z.ZodString>;
386
+ description: z.ZodOptional<z.ZodString>;
387
+ fields: z.ZodArray<z.ZodObject<{
388
+ handle: z.ZodString;
389
+ label: z.ZodString;
390
+ type: z.ZodOptional<z.ZodEnum<{
391
+ LONG_STRING: "LONG_STRING";
392
+ STRING: "STRING";
393
+ NUMBER: "NUMBER";
394
+ BOOLEAN: "BOOLEAN";
395
+ DATE: "DATE";
396
+ DATE_TIME: "DATE_TIME";
397
+ TIME: "TIME";
398
+ FILE: "FILE";
399
+ IMAGE: "IMAGE";
400
+ RELATION: "RELATION";
401
+ OBJECT: "OBJECT";
402
+ }>>;
403
+ definitionHandle: z.ZodOptional<z.ZodString>;
404
+ required: z.ZodOptional<z.ZodBoolean>;
405
+ unique: z.ZodOptional<z.ZodBoolean>;
406
+ system: z.ZodOptional<z.ZodBoolean>;
407
+ isList: z.ZodOptional<z.ZodBoolean>;
408
+ defaultValue: z.ZodOptional<z.ZodObject<{
409
+ value: z.ZodUnknown;
410
+ }, z.core.$strip>>;
411
+ description: z.ZodOptional<z.ZodString>;
412
+ visibility: z.ZodOptional<z.ZodObject<{
413
+ data: z.ZodOptional<z.ZodBoolean>;
414
+ list: z.ZodOptional<z.ZodBoolean>;
415
+ filters: z.ZodOptional<z.ZodBoolean>;
416
+ }, z.core.$strip>>;
417
+ }, z.core.$strip>>;
418
+ }, z.core.$strip>;
419
+ /**
420
+ * @deprecated Use FieldDataTypeSchema instead
421
+ */
221
422
  export declare const InternalFieldDataTypeSchema: z.ZodEnum<{
222
423
  LONG_STRING: "LONG_STRING";
223
424
  STRING: "STRING";
@@ -232,7 +433,7 @@ export declare const InternalFieldDataTypeSchema: z.ZodEnum<{
232
433
  OBJECT: "OBJECT";
233
434
  }>;
234
435
  /**
235
- * Schema for a field within an internal model.
436
+ * @deprecated Use ModelFieldDefinitionSchema instead
236
437
  */
237
438
  export declare const InternalFieldDefinitionSchema: z.ZodObject<{
238
439
  handle: z.ZodString;
@@ -261,7 +462,7 @@ export declare const InternalFieldDefinitionSchema: z.ZodObject<{
261
462
  description: z.ZodOptional<z.ZodString>;
262
463
  }, z.core.$strip>;
263
464
  /**
264
- * Schema for an internal model definition.
465
+ * @deprecated Use ModelDefinitionSchema instead
265
466
  */
266
467
  export declare const InternalModelDefinitionSchema: z.ZodObject<{
267
468
  handle: z.ZodString;
@@ -326,6 +527,19 @@ export declare const SkedyulConfigSchema: z.ZodObject<{
326
527
  description: z.ZodOptional<z.ZodString>;
327
528
  placeholder: z.ZodOptional<z.ZodString>;
328
529
  }, z.core.$strip>>>;
530
+ preInstall: z.ZodOptional<z.ZodObject<{
531
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
532
+ label: z.ZodString;
533
+ required: z.ZodOptional<z.ZodBoolean>;
534
+ visibility: z.ZodOptional<z.ZodEnum<{
535
+ visible: "visible";
536
+ encrypted: "encrypted";
537
+ }>>;
538
+ default: z.ZodOptional<z.ZodString>;
539
+ description: z.ZodOptional<z.ZodString>;
540
+ placeholder: z.ZodOptional<z.ZodString>;
541
+ }, z.core.$strip>>>;
542
+ }, z.core.$strip>>;
329
543
  install: z.ZodOptional<z.ZodObject<{
330
544
  env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
331
545
  label: z.ZodString;
@@ -344,21 +558,118 @@ export declare const SkedyulConfigSchema: z.ZodObject<{
344
558
  description: z.ZodOptional<z.ZodString>;
345
559
  }, z.core.$strip>>>;
346
560
  }, z.core.$strip>>;
347
- communicationChannels: z.ZodOptional<z.ZodArray<z.ZodObject<{
561
+ postInstall: z.ZodOptional<z.ZodObject<{
562
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
563
+ label: z.ZodString;
564
+ required: z.ZodOptional<z.ZodBoolean>;
565
+ visibility: z.ZodOptional<z.ZodEnum<{
566
+ visible: "visible";
567
+ encrypted: "encrypted";
568
+ }>>;
569
+ default: z.ZodOptional<z.ZodString>;
570
+ description: z.ZodOptional<z.ZodString>;
571
+ placeholder: z.ZodOptional<z.ZodString>;
572
+ }, z.core.$strip>>>;
573
+ }, z.core.$strip>>;
574
+ models: z.ZodOptional<z.ZodArray<z.ZodObject<{
575
+ handle: z.ZodString;
576
+ name: z.ZodString;
577
+ namePlural: z.ZodOptional<z.ZodString>;
578
+ scope: z.ZodEnum<{
579
+ INTERNAL: "INTERNAL";
580
+ SHARED: "SHARED";
581
+ }>;
582
+ labelTemplate: z.ZodOptional<z.ZodString>;
583
+ description: z.ZodOptional<z.ZodString>;
584
+ fields: z.ZodArray<z.ZodObject<{
585
+ handle: z.ZodString;
586
+ label: z.ZodString;
587
+ type: z.ZodOptional<z.ZodEnum<{
588
+ LONG_STRING: "LONG_STRING";
589
+ STRING: "STRING";
590
+ NUMBER: "NUMBER";
591
+ BOOLEAN: "BOOLEAN";
592
+ DATE: "DATE";
593
+ DATE_TIME: "DATE_TIME";
594
+ TIME: "TIME";
595
+ FILE: "FILE";
596
+ IMAGE: "IMAGE";
597
+ RELATION: "RELATION";
598
+ OBJECT: "OBJECT";
599
+ }>>;
600
+ definitionHandle: z.ZodOptional<z.ZodString>;
601
+ required: z.ZodOptional<z.ZodBoolean>;
602
+ unique: z.ZodOptional<z.ZodBoolean>;
603
+ system: z.ZodOptional<z.ZodBoolean>;
604
+ isList: z.ZodOptional<z.ZodBoolean>;
605
+ defaultValue: z.ZodOptional<z.ZodObject<{
606
+ value: z.ZodUnknown;
607
+ }, z.core.$strip>>;
608
+ description: z.ZodOptional<z.ZodString>;
609
+ visibility: z.ZodOptional<z.ZodObject<{
610
+ data: z.ZodOptional<z.ZodBoolean>;
611
+ list: z.ZodOptional<z.ZodBoolean>;
612
+ filters: z.ZodOptional<z.ZodBoolean>;
613
+ }, z.core.$strip>>;
614
+ }, z.core.$strip>>;
615
+ }, z.core.$strip>>>;
616
+ channels: z.ZodOptional<z.ZodArray<z.ZodObject<{
348
617
  handle: z.ZodString;
349
618
  name: z.ZodString;
350
619
  icon: z.ZodOptional<z.ZodString>;
351
620
  tools: z.ZodObject<{
352
621
  send_message: z.ZodString;
353
622
  }, z.core.$strip>;
354
- identifierValue: z.ZodObject<{
623
+ identifierValue: z.ZodOptional<z.ZodObject<{
355
624
  type: z.ZodEnum<{
356
625
  DEDICATED_PHONE: "DEDICATED_PHONE";
357
626
  TEXT: "TEXT";
358
627
  EMAIL: "EMAIL";
359
628
  }>;
360
629
  definitionHandle: z.ZodString;
630
+ }, z.core.$strip>>;
631
+ appFields: z.ZodOptional<z.ZodArray<z.ZodObject<{
632
+ label: z.ZodString;
633
+ fieldHandle: z.ZodString;
634
+ entityHandle: z.ZodString;
635
+ definitionHandle: z.ZodString;
636
+ required: z.ZodOptional<z.ZodBoolean>;
637
+ system: z.ZodOptional<z.ZodBoolean>;
638
+ unique: z.ZodOptional<z.ZodBoolean>;
639
+ defaultValue: z.ZodOptional<z.ZodObject<{
640
+ value: z.ZodUnknown;
641
+ }, z.core.$strip>>;
642
+ visibility: z.ZodOptional<z.ZodObject<{
643
+ data: z.ZodOptional<z.ZodBoolean>;
644
+ list: z.ZodOptional<z.ZodBoolean>;
645
+ filters: z.ZodOptional<z.ZodBoolean>;
646
+ }, z.core.$strip>>;
647
+ }, z.core.$strip>>>;
648
+ settings: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
649
+ requires: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
650
+ model: z.ZodString;
651
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
652
+ }, z.core.$strip>, z.ZodObject<{
653
+ channel: z.ZodString;
654
+ }, z.core.$strip>, z.ZodObject<{
655
+ workflow: z.ZodString;
656
+ }, z.core.$strip>]>>>;
657
+ }, z.core.$strip>>>;
658
+ communicationChannels: z.ZodOptional<z.ZodArray<z.ZodObject<{
659
+ handle: z.ZodString;
660
+ name: z.ZodString;
661
+ icon: z.ZodOptional<z.ZodString>;
662
+ tools: z.ZodObject<{
663
+ send_message: z.ZodString;
361
664
  }, z.core.$strip>;
665
+ identifierValue: z.ZodOptional<z.ZodObject<{
666
+ type: z.ZodEnum<{
667
+ DEDICATED_PHONE: "DEDICATED_PHONE";
668
+ TEXT: "TEXT";
669
+ EMAIL: "EMAIL";
670
+ }>;
671
+ definitionHandle: z.ZodString;
672
+ }, z.core.$strip>>;
362
673
  appFields: z.ZodOptional<z.ZodArray<z.ZodObject<{
363
674
  label: z.ZodString;
364
675
  fieldHandle: z.ZodString;
@@ -377,12 +688,28 @@ export declare const SkedyulConfigSchema: z.ZodObject<{
377
688
  }, z.core.$strip>>;
378
689
  }, z.core.$strip>>>;
379
690
  settings: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
691
+ requires: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
692
+ model: z.ZodString;
693
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
694
+ }, z.core.$strip>, z.ZodObject<{
695
+ channel: z.ZodString;
696
+ }, z.core.$strip>, z.ZodObject<{
697
+ workflow: z.ZodString;
698
+ }, z.core.$strip>]>>>;
380
699
  }, z.core.$strip>>>;
381
700
  workflows: z.ZodOptional<z.ZodArray<z.ZodObject<{
382
701
  path: z.ZodString;
383
702
  label: z.ZodOptional<z.ZodString>;
384
703
  handle: z.ZodOptional<z.ZodString>;
385
704
  channelHandle: z.ZodOptional<z.ZodString>;
705
+ requires: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
706
+ model: z.ZodString;
707
+ fields: z.ZodOptional<z.ZodArray<z.ZodString>>;
708
+ }, z.core.$strip>, z.ZodObject<{
709
+ channel: z.ZodString;
710
+ }, z.core.$strip>, z.ZodObject<{
711
+ workflow: z.ZodString;
712
+ }, z.core.$strip>]>>>;
386
713
  actions: z.ZodArray<z.ZodObject<{
387
714
  label: z.ZodString;
388
715
  handle: z.ZodString;
@@ -441,3 +768,27 @@ export type ParsedSkedyulConfig = z.infer<typeof SkedyulConfigSchema>;
441
768
  * Safely parse a skedyul config, returning null if invalid.
442
769
  */
443
770
  export declare function safeParseConfig(data: unknown): ParsedSkedyulConfig | null;
771
+ /** Resource scope type */
772
+ export type ResourceScope = z.infer<typeof ResourceScopeSchema>;
773
+ /** Model dependency reference */
774
+ export type ModelDependency = z.infer<typeof ModelDependencySchema>;
775
+ /** Channel dependency reference */
776
+ export type ChannelDependency = z.infer<typeof ChannelDependencySchema>;
777
+ /** Workflow dependency reference */
778
+ export type WorkflowDependency = z.infer<typeof WorkflowDependencySchema>;
779
+ /** Union of all resource dependencies */
780
+ export type ResourceDependency = z.infer<typeof ResourceDependencySchema>;
781
+ /** Model field definition */
782
+ export type ModelFieldDefinition = z.infer<typeof ModelFieldDefinitionSchema>;
783
+ /** Unified model definition (INTERNAL or SHARED) */
784
+ export type ModelDefinition = z.infer<typeof ModelDefinitionSchema>;
785
+ /** Channel definition */
786
+ export type ChannelDefinition = z.infer<typeof ChannelDefinitionSchema>;
787
+ /** Workflow definition */
788
+ export type WorkflowDefinition = z.infer<typeof WorkflowDefinitionSchema>;
789
+ /** Check if a dependency is a model dependency */
790
+ export declare function isModelDependency(dep: ResourceDependency): dep is ModelDependency;
791
+ /** Check if a dependency is a channel dependency */
792
+ export declare function isChannelDependency(dep: ResourceDependency): dep is ChannelDependency;
793
+ /** Check if a dependency is a workflow dependency */
794
+ export declare function isWorkflowDependency(dep: ResourceDependency): dep is WorkflowDependency;
package/dist/schemas.js CHANGED
@@ -1,7 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SkedyulConfigSchema = exports.InternalModelDefinitionSchema = exports.InternalFieldDefinitionSchema = exports.InternalFieldDataTypeSchema = exports.ComputeLayerTypeSchema = exports.WorkflowDefinitionSchema = exports.WorkflowActionSchema = exports.WorkflowActionInputSchema = exports.CommunicationChannelDefinitionSchema = exports.ChannelIdentifierValueSchema = exports.ChannelIdentifierTypeSchema = exports.ChannelToolBindingsSchema = exports.AppFieldDefinitionSchema = exports.AppFieldVisibilitySchema = exports.InstallConfigSchema = exports.AppModelDefinitionSchema = exports.EnvSchemaSchema = exports.EnvVariableDefinitionSchema = exports.EnvVisibilitySchema = void 0;
3
+ exports.SkedyulConfigSchema = exports.InternalModelDefinitionSchema = exports.InternalFieldDefinitionSchema = exports.InternalFieldDataTypeSchema = exports.ModelDefinitionSchema = exports.ModelFieldDefinitionSchema = exports.FieldDataTypeSchema = exports.ComputeLayerTypeSchema = exports.WorkflowDefinitionSchema = exports.WorkflowActionSchema = exports.WorkflowActionInputSchema = exports.ChannelDefinitionSchema = exports.CommunicationChannelDefinitionSchema = exports.ResourceDependencySchema = exports.WorkflowDependencySchema = exports.ChannelDependencySchema = exports.ModelDependencySchema = exports.ResourceScopeSchema = exports.ChannelIdentifierValueSchema = exports.ChannelIdentifierTypeSchema = exports.ChannelToolBindingsSchema = exports.AppFieldDefinitionSchema = exports.AppFieldVisibilitySchema = exports.InstallConfigSchema = exports.AppModelDefinitionSchema = exports.EnvSchemaSchema = exports.EnvVariableDefinitionSchema = exports.EnvVisibilitySchema = void 0;
4
4
  exports.safeParseConfig = safeParseConfig;
5
+ exports.isModelDependency = isModelDependency;
6
+ exports.isChannelDependency = isChannelDependency;
7
+ exports.isWorkflowDependency = isWorkflowDependency;
5
8
  const zod_1 = require("zod");
6
9
  // ─────────────────────────────────────────────────────────────────────────────
7
10
  // Zod Schemas for SkedyulConfig
@@ -85,6 +88,52 @@ exports.ChannelIdentifierValueSchema = zod_1.z.object({
85
88
  type: exports.ChannelIdentifierTypeSchema,
86
89
  definitionHandle: zod_1.z.string(),
87
90
  });
91
+ // ─────────────────────────────────────────────────────────────────────────────
92
+ // Resource Scope and Dependency Schemas
93
+ // Unified system for tracking app resources and their dependencies.
94
+ // Must be defined before channel/workflow schemas that use them.
95
+ // ─────────────────────────────────────────────────────────────────────────────
96
+ /**
97
+ * Schema for resource scope.
98
+ * INTERNAL: App owns this resource, auto-created when feature is provisioned
99
+ * SHARED: Maps to user's existing resource, requires user selection
100
+ */
101
+ exports.ResourceScopeSchema = zod_1.z.enum(['INTERNAL', 'SHARED']);
102
+ /**
103
+ * Schema for a model dependency reference.
104
+ * Used in `requires` arrays to specify model dependencies.
105
+ */
106
+ exports.ModelDependencySchema = zod_1.z.object({
107
+ /** Handle of the model being depended upon */
108
+ model: zod_1.z.string(),
109
+ /** Specific fields required (undefined = all fields) */
110
+ fields: zod_1.z.array(zod_1.z.string()).optional(),
111
+ });
112
+ /**
113
+ * Schema for a channel dependency reference.
114
+ * Used in `requires` arrays to specify channel dependencies.
115
+ */
116
+ exports.ChannelDependencySchema = zod_1.z.object({
117
+ /** Handle of the channel being depended upon */
118
+ channel: zod_1.z.string(),
119
+ });
120
+ /**
121
+ * Schema for a workflow dependency reference.
122
+ * Used in `requires` arrays to specify workflow dependencies.
123
+ */
124
+ exports.WorkflowDependencySchema = zod_1.z.object({
125
+ /** Handle of the workflow being depended upon */
126
+ workflow: zod_1.z.string(),
127
+ });
128
+ /**
129
+ * Union schema for all resource dependency types.
130
+ * Used in `requires` arrays on channels, workflows, etc.
131
+ */
132
+ exports.ResourceDependencySchema = zod_1.z.union([
133
+ exports.ModelDependencySchema,
134
+ exports.ChannelDependencySchema,
135
+ exports.WorkflowDependencySchema,
136
+ ]);
88
137
  /**
89
138
  * Schema for communication channel definition.
90
139
  */
@@ -93,10 +142,16 @@ exports.CommunicationChannelDefinitionSchema = zod_1.z.object({
93
142
  name: zod_1.z.string(),
94
143
  icon: zod_1.z.string().optional(),
95
144
  tools: exports.ChannelToolBindingsSchema,
96
- identifierValue: exports.ChannelIdentifierValueSchema,
145
+ identifierValue: exports.ChannelIdentifierValueSchema.optional(),
97
146
  appFields: zod_1.z.array(exports.AppFieldDefinitionSchema).optional(),
98
147
  settings: zod_1.z.array(zod_1.z.unknown()).optional(),
148
+ /** Typed dependencies - models, fields, etc. this channel requires */
149
+ requires: zod_1.z.array(exports.ResourceDependencySchema).optional(),
99
150
  });
151
+ /**
152
+ * Shorter alias for channel definition (used in new config syntax).
153
+ */
154
+ exports.ChannelDefinitionSchema = exports.CommunicationChannelDefinitionSchema;
100
155
  /**
101
156
  * Schema for workflow action input.
102
157
  */
@@ -131,8 +186,10 @@ exports.WorkflowDefinitionSchema = zod_1.z.object({
131
186
  label: zod_1.z.string().optional(),
132
187
  /** Workflow handle/key (optional when path is provided, inferred from YAML) */
133
188
  handle: zod_1.z.string().optional(),
134
- /** Channel handle (optional) */
189
+ /** Channel handle (optional, deprecated - use requires instead) */
135
190
  channelHandle: zod_1.z.string().optional(),
191
+ /** Typed dependencies - channels, models, etc. this workflow requires */
192
+ requires: zod_1.z.array(exports.ResourceDependencySchema).optional(),
136
193
  /** Actions in this workflow */
137
194
  actions: zod_1.z.array(exports.WorkflowActionSchema),
138
195
  });
@@ -141,13 +198,13 @@ exports.WorkflowDefinitionSchema = zod_1.z.object({
141
198
  */
142
199
  exports.ComputeLayerTypeSchema = zod_1.z.enum(['serverless', 'dedicated']);
143
200
  // ─────────────────────────────────────────────────────────────────────────────
144
- // Internal Model Schemas (App-owned models)
201
+ // Model Schemas (Unified INTERNAL + SHARED)
145
202
  // ─────────────────────────────────────────────────────────────────────────────
146
203
  /**
147
- * Schema for internal field data types.
204
+ * Schema for field data types.
148
205
  * Matches the DataType enum in the database.
149
206
  */
150
- exports.InternalFieldDataTypeSchema = zod_1.z.enum([
207
+ exports.FieldDataTypeSchema = zod_1.z.enum([
151
208
  'LONG_STRING',
152
209
  'STRING',
153
210
  'NUMBER',
@@ -161,7 +218,62 @@ exports.InternalFieldDataTypeSchema = zod_1.z.enum([
161
218
  'OBJECT',
162
219
  ]);
163
220
  /**
164
- * Schema for a field within an internal model.
221
+ * Schema for a field within a model.
222
+ * Works for both INTERNAL and SHARED models.
223
+ */
224
+ exports.ModelFieldDefinitionSchema = zod_1.z.object({
225
+ /** Field handle (unique within model) */
226
+ handle: zod_1.z.string(),
227
+ /** Display label */
228
+ label: zod_1.z.string(),
229
+ /** Data type (required for INTERNAL, optional for SHARED) */
230
+ type: exports.FieldDataTypeSchema.optional(),
231
+ /** Field definition handle for SHARED fields */
232
+ definitionHandle: zod_1.z.string().optional(),
233
+ /** Whether field is required */
234
+ required: zod_1.z.boolean().optional(),
235
+ /** Whether field must be unique */
236
+ unique: zod_1.z.boolean().optional(),
237
+ /** Whether this is a system field */
238
+ system: zod_1.z.boolean().optional(),
239
+ /** Whether field holds a list of values */
240
+ isList: zod_1.z.boolean().optional(),
241
+ /** Default value */
242
+ defaultValue: zod_1.z.object({ value: zod_1.z.unknown() }).optional(),
243
+ /** Field description */
244
+ description: zod_1.z.string().optional(),
245
+ /** Visibility settings for SHARED fields */
246
+ visibility: exports.AppFieldVisibilitySchema.optional(),
247
+ });
248
+ /**
249
+ * Schema for a unified model definition.
250
+ * Supports both INTERNAL (app-owned) and SHARED (user-mapped) models.
251
+ */
252
+ exports.ModelDefinitionSchema = zod_1.z.object({
253
+ /** Model handle (unique within app) */
254
+ handle: zod_1.z.string(),
255
+ /** Display name */
256
+ name: zod_1.z.string(),
257
+ /** Plural display name */
258
+ namePlural: zod_1.z.string().optional(),
259
+ /** Resource scope: INTERNAL (app creates) or SHARED (user maps) */
260
+ scope: exports.ResourceScopeSchema,
261
+ /** Label template for display (required for INTERNAL) */
262
+ labelTemplate: zod_1.z.string().optional(),
263
+ /** Model description */
264
+ description: zod_1.z.string().optional(),
265
+ /** Field definitions */
266
+ fields: zod_1.z.array(exports.ModelFieldDefinitionSchema),
267
+ });
268
+ // ─────────────────────────────────────────────────────────────────────────────
269
+ // Legacy Internal Model Schemas (deprecated - use ModelDefinitionSchema)
270
+ // ─────────────────────────────────────────────────────────────────────────────
271
+ /**
272
+ * @deprecated Use FieldDataTypeSchema instead
273
+ */
274
+ exports.InternalFieldDataTypeSchema = exports.FieldDataTypeSchema;
275
+ /**
276
+ * @deprecated Use ModelFieldDefinitionSchema instead
165
277
  */
166
278
  exports.InternalFieldDefinitionSchema = zod_1.z.object({
167
279
  handle: zod_1.z.string(),
@@ -176,7 +288,7 @@ exports.InternalFieldDefinitionSchema = zod_1.z.object({
176
288
  description: zod_1.z.string().optional(),
177
289
  });
178
290
  /**
179
- * Schema for an internal model definition.
291
+ * @deprecated Use ModelDefinitionSchema instead
180
292
  */
181
293
  exports.InternalModelDefinitionSchema = zod_1.z.object({
182
294
  handle: zod_1.z.string(),
@@ -204,9 +316,25 @@ exports.SkedyulConfigSchema = zod_1.z.object({
204
316
  webhooks: zod_1.z.unknown().optional(),
205
317
  workflowsPath: zod_1.z.string().optional(),
206
318
  env: exports.EnvSchemaSchema.optional(),
319
+ preInstall: zod_1.z
320
+ .object({
321
+ env: exports.EnvSchemaSchema.optional(),
322
+ })
323
+ .optional(),
207
324
  install: exports.InstallConfigSchema.optional(),
325
+ postInstall: zod_1.z
326
+ .object({
327
+ env: exports.EnvSchemaSchema.optional(),
328
+ })
329
+ .optional(),
330
+ // New unified model definitions (INTERNAL + SHARED)
331
+ models: zod_1.z.array(exports.ModelDefinitionSchema).optional(),
332
+ // New channel syntax (alias for communicationChannels)
333
+ channels: zod_1.z.array(exports.ChannelDefinitionSchema).optional(),
334
+ // Legacy: communication channels (deprecated - use channels)
208
335
  communicationChannels: zod_1.z.array(exports.CommunicationChannelDefinitionSchema).optional(),
209
336
  workflows: zod_1.z.array(exports.WorkflowDefinitionSchema).optional(),
337
+ // Legacy: internal models only (deprecated - use models with scope: INTERNAL)
210
338
  internalModels: zod_1.z.array(exports.InternalModelDefinitionSchema).optional(),
211
339
  });
212
340
  /**
@@ -216,3 +344,18 @@ function safeParseConfig(data) {
216
344
  const result = exports.SkedyulConfigSchema.safeParse(data);
217
345
  return result.success ? result.data : null;
218
346
  }
347
+ // ─────────────────────────────────────────────────────────────────────────────
348
+ // Dependency Type Guards
349
+ // ─────────────────────────────────────────────────────────────────────────────
350
+ /** Check if a dependency is a model dependency */
351
+ function isModelDependency(dep) {
352
+ return 'model' in dep;
353
+ }
354
+ /** Check if a dependency is a channel dependency */
355
+ function isChannelDependency(dep) {
356
+ return 'channel' in dep;
357
+ }
358
+ /** Check if a dependency is a workflow dependency */
359
+ function isWorkflowDependency(dep) {
360
+ return 'workflow' in dep;
361
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skedyul",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "The Skedyul SDK for Node.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",