skedyul 0.1.40 → 0.1.42

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
- 1768537680901
1
+ 1768780968695
package/dist/config.d.ts CHANGED
@@ -266,6 +266,93 @@ export interface RelationshipDefinition {
266
266
  /** Target side of the relationship */
267
267
  target: RelationshipLink;
268
268
  }
269
+ /** Page type: INSTANCE shows single record, LIST shows multiple records */
270
+ export type PageType = 'INSTANCE' | 'LIST';
271
+ /** Block types available for pages */
272
+ export type PageBlockType = 'form' | 'spreadsheet' | 'kanban' | 'calendar' | 'link';
273
+ /** Supported field datatypes for page fields */
274
+ export type PageFieldType = 'STRING' | 'FILE' | 'NUMBER' | 'DATE' | 'BOOLEAN' | 'SELECT';
275
+ /** Data source for prepopulating a page field from a model */
276
+ export interface PageFieldSource {
277
+ /** Model handle to pull data from */
278
+ model: string;
279
+ /** Field handle on that model */
280
+ field: string;
281
+ }
282
+ /** Self-contained field definition for page blocks */
283
+ export interface PageFieldDefinition {
284
+ /** Unique handle for this field */
285
+ handle: string;
286
+ /** Field datatype - determines UI component */
287
+ type: PageFieldType;
288
+ /** Display label */
289
+ label: string;
290
+ /** Optional description/help text */
291
+ description?: string;
292
+ /** Whether field is required */
293
+ required?: boolean;
294
+ /** Tool name from registry to call on value change */
295
+ handler?: string;
296
+ /** Data source for prepopulating field value */
297
+ source?: PageFieldSource;
298
+ /** For SELECT type: available options */
299
+ options?: Array<{
300
+ value: string;
301
+ label: string;
302
+ }>;
303
+ /** For FILE type: accepted file extensions */
304
+ accept?: string;
305
+ }
306
+ /** Action button definition for pages */
307
+ export interface PageActionDefinition {
308
+ /** Unique handle for this action */
309
+ handle: string;
310
+ /** Button label */
311
+ label: string;
312
+ /** Tool name from registry to invoke */
313
+ handler: string;
314
+ /** Optional icon (lucide icon name) */
315
+ icon?: string;
316
+ /** Button variant */
317
+ variant?: 'primary' | 'secondary' | 'destructive';
318
+ }
319
+ /** Block definition within a page */
320
+ export interface PageBlockDefinition {
321
+ /** Block type determines the UI component */
322
+ type: PageBlockType;
323
+ /** Block title displayed in UI */
324
+ title?: string;
325
+ /** Self-contained field definitions */
326
+ fields?: PageFieldDefinition[];
327
+ /** Whether the block is read-only (no editing) */
328
+ readonly?: boolean;
329
+ }
330
+ /** Filter for selecting which instance(s) to display on a page */
331
+ export interface PageInstanceFilter {
332
+ /** Model to query instances from */
333
+ model: string;
334
+ /** Filter criteria - supports variable substitution like $appInstallationId */
335
+ where?: Record<string, unknown>;
336
+ }
337
+ /** Page definition for app UI */
338
+ export interface PageDefinition {
339
+ /** Unique handle for the page */
340
+ handle: string;
341
+ /** Page type: INSTANCE (single record) or LIST (multiple records) */
342
+ type: PageType;
343
+ /** Page title displayed in UI */
344
+ title: string;
345
+ /** Optional custom path for navigation */
346
+ path?: string;
347
+ /** Whether to show this page in sidebar navigation (default: true) */
348
+ navigation?: boolean;
349
+ /** Blocks that compose this page */
350
+ blocks: PageBlockDefinition[];
351
+ /** Page-level action buttons */
352
+ actions?: PageActionDefinition[];
353
+ /** Filter to select instance(s) for prepopulating field values */
354
+ filter?: PageInstanceFilter;
355
+ }
269
356
  export type ChannelIdentifierType = 'DEDICATED_PHONE' | 'TEXT' | 'EMAIL';
270
357
  export interface ChannelIdentifierValue {
271
358
  /** Type of identifier */
@@ -502,6 +589,36 @@ export interface SkedyulConfig {
502
589
  * ```
503
590
  */
504
591
  relationships?: RelationshipDefinition[];
592
+ /**
593
+ * Pages for internal models.
594
+ * Defines how internal models are displayed in the post-install UI.
595
+ * Each page references a model by handle and can have multiple pages per model.
596
+ *
597
+ * @example
598
+ * ```typescript
599
+ * pages: [
600
+ * {
601
+ * handle: 'compliance_submission',
602
+ * model: 'compliance_record',
603
+ * type: 'INSTANCE',
604
+ * title: 'Submit Compliance Record',
605
+ * blocks: [
606
+ * { type: 'form', title: 'Business Registration', fields: ['file'] },
607
+ * ],
608
+ * },
609
+ * {
610
+ * handle: 'phone_numbers_list',
611
+ * model: 'phone_number',
612
+ * type: 'LIST',
613
+ * title: 'Phone Numbers',
614
+ * blocks: [
615
+ * { type: 'spreadsheet', fields: ['phone', 'forwarding_phone_number'] },
616
+ * ],
617
+ * },
618
+ * ]
619
+ * ```
620
+ */
621
+ pages?: PageDefinition[];
505
622
  /**
506
623
  * Communication channels this app provides (new syntax).
507
624
  * Uses typed `requires` for dependencies.
@@ -556,6 +673,8 @@ export interface SerializableSkedyulConfig {
556
673
  postInstall?: PostInstallConfig;
557
674
  /** Unified model definitions (INTERNAL + SHARED) */
558
675
  models?: ModelDefinition[];
676
+ /** Pages for internal model display */
677
+ pages?: PageDefinition[];
559
678
  /** Communication channels (new syntax) */
560
679
  channels?: ChannelDefinition[];
561
680
  /** Communication channels (legacy) @deprecated */
package/dist/schemas.d.ts CHANGED
@@ -333,8 +333,8 @@ export declare const WorkflowDefinitionSchema: z.ZodObject<{
333
333
  * Schema for compute layer type.
334
334
  */
335
335
  export declare const ComputeLayerTypeSchema: z.ZodEnum<{
336
- dedicated: "dedicated";
337
336
  serverless: "serverless";
337
+ dedicated: "dedicated";
338
338
  }>;
339
339
  /**
340
340
  * Schema for field data types.
@@ -436,6 +436,185 @@ export declare const RelationshipDefinitionSchema: z.ZodObject<{
436
436
  }>>;
437
437
  }, z.core.$strip>;
438
438
  }, z.core.$strip>;
439
+ /**
440
+ * Schema for page type.
441
+ * INSTANCE: Shows a single record (form-like)
442
+ * LIST: Shows multiple records (spreadsheet/table)
443
+ */
444
+ export declare const PageTypeSchema: z.ZodEnum<{
445
+ INSTANCE: "INSTANCE";
446
+ LIST: "LIST";
447
+ }>;
448
+ /**
449
+ * Schema for block type in a page.
450
+ * Matches existing block types in the system.
451
+ */
452
+ export declare const PageBlockTypeSchema: z.ZodEnum<{
453
+ form: "form";
454
+ spreadsheet: "spreadsheet";
455
+ kanban: "kanban";
456
+ calendar: "calendar";
457
+ link: "link";
458
+ }>;
459
+ /** Supported field datatypes for page fields */
460
+ export declare const PageFieldTypeSchema: z.ZodEnum<{
461
+ STRING: "STRING";
462
+ NUMBER: "NUMBER";
463
+ BOOLEAN: "BOOLEAN";
464
+ DATE: "DATE";
465
+ FILE: "FILE";
466
+ SELECT: "SELECT";
467
+ }>;
468
+ /** Data source for prepopulating a page field from a model */
469
+ export declare const PageFieldSourceSchema: z.ZodObject<{
470
+ model: z.ZodString;
471
+ field: z.ZodString;
472
+ }, z.core.$strip>;
473
+ /** Self-contained field definition for page blocks */
474
+ export declare const PageFieldDefinitionSchema: z.ZodObject<{
475
+ handle: z.ZodString;
476
+ type: z.ZodEnum<{
477
+ STRING: "STRING";
478
+ NUMBER: "NUMBER";
479
+ BOOLEAN: "BOOLEAN";
480
+ DATE: "DATE";
481
+ FILE: "FILE";
482
+ SELECT: "SELECT";
483
+ }>;
484
+ label: z.ZodString;
485
+ description: z.ZodOptional<z.ZodString>;
486
+ required: z.ZodOptional<z.ZodBoolean>;
487
+ handler: z.ZodOptional<z.ZodString>;
488
+ source: z.ZodOptional<z.ZodObject<{
489
+ model: z.ZodString;
490
+ field: z.ZodString;
491
+ }, z.core.$strip>>;
492
+ options: z.ZodOptional<z.ZodArray<z.ZodObject<{
493
+ value: z.ZodString;
494
+ label: z.ZodString;
495
+ }, z.core.$strip>>>;
496
+ accept: z.ZodOptional<z.ZodString>;
497
+ }, z.core.$strip>;
498
+ /** Action button definition for pages */
499
+ export declare const PageActionDefinitionSchema: z.ZodObject<{
500
+ handle: z.ZodString;
501
+ label: z.ZodString;
502
+ handler: z.ZodString;
503
+ icon: z.ZodOptional<z.ZodString>;
504
+ variant: z.ZodOptional<z.ZodEnum<{
505
+ primary: "primary";
506
+ secondary: "secondary";
507
+ destructive: "destructive";
508
+ }>>;
509
+ }, z.core.$strip>;
510
+ /**
511
+ * Schema for a block definition within a page.
512
+ * Blocks define the UI components that render model data.
513
+ */
514
+ export declare const PageBlockDefinitionSchema: z.ZodObject<{
515
+ type: z.ZodEnum<{
516
+ form: "form";
517
+ spreadsheet: "spreadsheet";
518
+ kanban: "kanban";
519
+ calendar: "calendar";
520
+ link: "link";
521
+ }>;
522
+ title: z.ZodOptional<z.ZodString>;
523
+ fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
524
+ handle: z.ZodString;
525
+ type: z.ZodEnum<{
526
+ STRING: "STRING";
527
+ NUMBER: "NUMBER";
528
+ BOOLEAN: "BOOLEAN";
529
+ DATE: "DATE";
530
+ FILE: "FILE";
531
+ SELECT: "SELECT";
532
+ }>;
533
+ label: z.ZodString;
534
+ description: z.ZodOptional<z.ZodString>;
535
+ required: z.ZodOptional<z.ZodBoolean>;
536
+ handler: z.ZodOptional<z.ZodString>;
537
+ source: z.ZodOptional<z.ZodObject<{
538
+ model: z.ZodString;
539
+ field: z.ZodString;
540
+ }, z.core.$strip>>;
541
+ options: z.ZodOptional<z.ZodArray<z.ZodObject<{
542
+ value: z.ZodString;
543
+ label: z.ZodString;
544
+ }, z.core.$strip>>>;
545
+ accept: z.ZodOptional<z.ZodString>;
546
+ }, z.core.$strip>>>;
547
+ readonly: z.ZodOptional<z.ZodBoolean>;
548
+ }, z.core.$strip>;
549
+ /** Filter for selecting which instance(s) to display on a page */
550
+ export declare const PageInstanceFilterSchema: z.ZodObject<{
551
+ model: z.ZodString;
552
+ where: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
553
+ }, z.core.$strip>;
554
+ /**
555
+ * Schema for a page definition.
556
+ * Pages define how internal models are displayed in the post-install UI.
557
+ */
558
+ export declare const PageDefinitionSchema: z.ZodObject<{
559
+ handle: z.ZodString;
560
+ type: z.ZodEnum<{
561
+ INSTANCE: "INSTANCE";
562
+ LIST: "LIST";
563
+ }>;
564
+ title: z.ZodString;
565
+ path: z.ZodOptional<z.ZodString>;
566
+ navigation: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
567
+ blocks: z.ZodArray<z.ZodObject<{
568
+ type: z.ZodEnum<{
569
+ form: "form";
570
+ spreadsheet: "spreadsheet";
571
+ kanban: "kanban";
572
+ calendar: "calendar";
573
+ link: "link";
574
+ }>;
575
+ title: z.ZodOptional<z.ZodString>;
576
+ fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
577
+ handle: z.ZodString;
578
+ type: z.ZodEnum<{
579
+ STRING: "STRING";
580
+ NUMBER: "NUMBER";
581
+ BOOLEAN: "BOOLEAN";
582
+ DATE: "DATE";
583
+ FILE: "FILE";
584
+ SELECT: "SELECT";
585
+ }>;
586
+ label: z.ZodString;
587
+ description: z.ZodOptional<z.ZodString>;
588
+ required: z.ZodOptional<z.ZodBoolean>;
589
+ handler: z.ZodOptional<z.ZodString>;
590
+ source: z.ZodOptional<z.ZodObject<{
591
+ model: z.ZodString;
592
+ field: z.ZodString;
593
+ }, z.core.$strip>>;
594
+ options: z.ZodOptional<z.ZodArray<z.ZodObject<{
595
+ value: z.ZodString;
596
+ label: z.ZodString;
597
+ }, z.core.$strip>>>;
598
+ accept: z.ZodOptional<z.ZodString>;
599
+ }, z.core.$strip>>>;
600
+ readonly: z.ZodOptional<z.ZodBoolean>;
601
+ }, z.core.$strip>>;
602
+ actions: z.ZodOptional<z.ZodArray<z.ZodObject<{
603
+ handle: z.ZodString;
604
+ label: z.ZodString;
605
+ handler: z.ZodString;
606
+ icon: z.ZodOptional<z.ZodString>;
607
+ variant: z.ZodOptional<z.ZodEnum<{
608
+ primary: "primary";
609
+ secondary: "secondary";
610
+ destructive: "destructive";
611
+ }>>;
612
+ }, z.core.$strip>>>;
613
+ filter: z.ZodOptional<z.ZodObject<{
614
+ model: z.ZodString;
615
+ where: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
616
+ }, z.core.$strip>>;
617
+ }, z.core.$strip>;
439
618
  /**
440
619
  * Schema for inline field definition (constraints, options, etc.)
441
620
  * This allows defining field behavior without referencing a metafield definition.
@@ -673,8 +852,8 @@ export declare const SkedyulConfigSchema: z.ZodObject<{
673
852
  version: z.ZodOptional<z.ZodString>;
674
853
  description: z.ZodOptional<z.ZodString>;
675
854
  computeLayer: z.ZodOptional<z.ZodEnum<{
676
- dedicated: "dedicated";
677
855
  serverless: "serverless";
856
+ dedicated: "dedicated";
678
857
  }>>;
679
858
  tools: z.ZodOptional<z.ZodUnknown>;
680
859
  webhooks: z.ZodOptional<z.ZodUnknown>;
@@ -837,6 +1016,66 @@ export declare const SkedyulConfigSchema: z.ZodObject<{
837
1016
  }>>;
838
1017
  }, z.core.$strip>;
839
1018
  }, z.core.$strip>>>;
1019
+ pages: z.ZodOptional<z.ZodArray<z.ZodObject<{
1020
+ handle: z.ZodString;
1021
+ type: z.ZodEnum<{
1022
+ INSTANCE: "INSTANCE";
1023
+ LIST: "LIST";
1024
+ }>;
1025
+ title: z.ZodString;
1026
+ path: z.ZodOptional<z.ZodString>;
1027
+ navigation: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1028
+ blocks: z.ZodArray<z.ZodObject<{
1029
+ type: z.ZodEnum<{
1030
+ form: "form";
1031
+ spreadsheet: "spreadsheet";
1032
+ kanban: "kanban";
1033
+ calendar: "calendar";
1034
+ link: "link";
1035
+ }>;
1036
+ title: z.ZodOptional<z.ZodString>;
1037
+ fields: z.ZodOptional<z.ZodArray<z.ZodObject<{
1038
+ handle: z.ZodString;
1039
+ type: z.ZodEnum<{
1040
+ STRING: "STRING";
1041
+ NUMBER: "NUMBER";
1042
+ BOOLEAN: "BOOLEAN";
1043
+ DATE: "DATE";
1044
+ FILE: "FILE";
1045
+ SELECT: "SELECT";
1046
+ }>;
1047
+ label: z.ZodString;
1048
+ description: z.ZodOptional<z.ZodString>;
1049
+ required: z.ZodOptional<z.ZodBoolean>;
1050
+ handler: z.ZodOptional<z.ZodString>;
1051
+ source: z.ZodOptional<z.ZodObject<{
1052
+ model: z.ZodString;
1053
+ field: z.ZodString;
1054
+ }, z.core.$strip>>;
1055
+ options: z.ZodOptional<z.ZodArray<z.ZodObject<{
1056
+ value: z.ZodString;
1057
+ label: z.ZodString;
1058
+ }, z.core.$strip>>>;
1059
+ accept: z.ZodOptional<z.ZodString>;
1060
+ }, z.core.$strip>>>;
1061
+ readonly: z.ZodOptional<z.ZodBoolean>;
1062
+ }, z.core.$strip>>;
1063
+ actions: z.ZodOptional<z.ZodArray<z.ZodObject<{
1064
+ handle: z.ZodString;
1065
+ label: z.ZodString;
1066
+ handler: z.ZodString;
1067
+ icon: z.ZodOptional<z.ZodString>;
1068
+ variant: z.ZodOptional<z.ZodEnum<{
1069
+ primary: "primary";
1070
+ secondary: "secondary";
1071
+ destructive: "destructive";
1072
+ }>>;
1073
+ }, z.core.$strip>>>;
1074
+ filter: z.ZodOptional<z.ZodObject<{
1075
+ model: z.ZodString;
1076
+ where: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1077
+ }, z.core.$strip>>;
1078
+ }, z.core.$strip>>>;
840
1079
  channels: z.ZodOptional<z.ZodArray<z.ZodObject<{
841
1080
  handle: z.ZodString;
842
1081
  name: z.ZodString;
@@ -1013,6 +1252,24 @@ export type OnDeleteBehavior = z.infer<typeof OnDeleteBehaviorSchema>;
1013
1252
  export type RelationshipLink = z.infer<typeof RelationshipLinkSchema>;
1014
1253
  /** Relationship definition */
1015
1254
  export type RelationshipDefinition = z.infer<typeof RelationshipDefinitionSchema>;
1255
+ /** Page type */
1256
+ export type PageType = z.infer<typeof PageTypeSchema>;
1257
+ /** Page block type */
1258
+ export type PageBlockType = z.infer<typeof PageBlockTypeSchema>;
1259
+ /** Page field type */
1260
+ export type PageFieldType = z.infer<typeof PageFieldTypeSchema>;
1261
+ /** Page field source for data binding */
1262
+ export type PageFieldSource = z.infer<typeof PageFieldSourceSchema>;
1263
+ /** Page field definition */
1264
+ export type PageFieldDefinition = z.infer<typeof PageFieldDefinitionSchema>;
1265
+ /** Page action definition */
1266
+ export type PageActionDefinition = z.infer<typeof PageActionDefinitionSchema>;
1267
+ /** Page block definition */
1268
+ export type PageBlockDefinition = z.infer<typeof PageBlockDefinitionSchema>;
1269
+ /** Page instance filter */
1270
+ export type PageInstanceFilter = z.infer<typeof PageInstanceFilterSchema>;
1271
+ /** Page definition */
1272
+ export type PageDefinition = z.infer<typeof PageDefinitionSchema>;
1016
1273
  /** Model dependency reference */
1017
1274
  export type ModelDependency = z.infer<typeof ModelDependencySchema>;
1018
1275
  /** Channel dependency reference */
package/dist/schemas.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SkedyulConfigSchema = exports.InternalModelDefinitionSchema = exports.InternalFieldDefinitionSchema = exports.InternalFieldDataTypeSchema = exports.ModelDefinitionSchema = exports.ModelFieldDefinitionSchema = exports.InlineFieldDefinitionSchema = exports.RelationshipDefinitionSchema = exports.RelationshipLinkSchema = exports.OnDeleteBehaviorSchema = exports.RelationshipCardinalitySchema = exports.FieldOptionSchema = exports.FieldDataTypeSchema = exports.ComputeLayerTypeSchema = exports.WorkflowDefinitionSchema = exports.WorkflowActionSchema = exports.WorkflowActionInputSchema = exports.ChannelDefinitionSchema = exports.CommunicationChannelDefinitionSchema = exports.ResourceDependencySchema = exports.WorkflowDependencySchema = exports.ChannelDependencySchema = exports.ModelDependencySchema = exports.StructuredFilterSchema = exports.FieldOwnerSchema = exports.ResourceScopeSchema = 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.InlineFieldDefinitionSchema = exports.PageDefinitionSchema = exports.PageInstanceFilterSchema = exports.PageBlockDefinitionSchema = exports.PageActionDefinitionSchema = exports.PageFieldDefinitionSchema = exports.PageFieldSourceSchema = exports.PageFieldTypeSchema = exports.PageBlockTypeSchema = exports.PageTypeSchema = exports.RelationshipDefinitionSchema = exports.RelationshipLinkSchema = exports.OnDeleteBehaviorSchema = exports.RelationshipCardinalitySchema = exports.FieldOptionSchema = exports.FieldDataTypeSchema = exports.ComputeLayerTypeSchema = exports.WorkflowDefinitionSchema = exports.WorkflowActionSchema = exports.WorkflowActionInputSchema = exports.ChannelDefinitionSchema = exports.CommunicationChannelDefinitionSchema = exports.ResourceDependencySchema = exports.WorkflowDependencySchema = exports.ChannelDependencySchema = exports.ModelDependencySchema = exports.StructuredFilterSchema = exports.FieldOwnerSchema = 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
5
  exports.isModelDependency = isModelDependency;
6
6
  exports.isChannelDependency = isChannelDependency;
@@ -288,6 +288,119 @@ exports.RelationshipDefinitionSchema = zod_1.z.object({
288
288
  /** Target side of the relationship */
289
289
  target: exports.RelationshipLinkSchema,
290
290
  });
291
+ // ─────────────────────────────────────────────────────────────────────────────
292
+ // Page and Block Schemas
293
+ // ─────────────────────────────────────────────────────────────────────────────
294
+ /**
295
+ * Schema for page type.
296
+ * INSTANCE: Shows a single record (form-like)
297
+ * LIST: Shows multiple records (spreadsheet/table)
298
+ */
299
+ exports.PageTypeSchema = zod_1.z.enum(['INSTANCE', 'LIST']);
300
+ /**
301
+ * Schema for block type in a page.
302
+ * Matches existing block types in the system.
303
+ */
304
+ exports.PageBlockTypeSchema = zod_1.z.enum([
305
+ 'form',
306
+ 'spreadsheet',
307
+ 'kanban',
308
+ 'calendar',
309
+ 'link',
310
+ ]);
311
+ /** Supported field datatypes for page fields */
312
+ exports.PageFieldTypeSchema = zod_1.z.enum([
313
+ 'STRING',
314
+ 'FILE',
315
+ 'NUMBER',
316
+ 'DATE',
317
+ 'BOOLEAN',
318
+ 'SELECT',
319
+ ]);
320
+ /** Data source for prepopulating a page field from a model */
321
+ exports.PageFieldSourceSchema = zod_1.z.object({
322
+ /** Model handle to pull data from */
323
+ model: zod_1.z.string(),
324
+ /** Field handle on that model */
325
+ field: zod_1.z.string(),
326
+ });
327
+ /** Self-contained field definition for page blocks */
328
+ exports.PageFieldDefinitionSchema = zod_1.z.object({
329
+ /** Unique handle for this field */
330
+ handle: zod_1.z.string(),
331
+ /** Field datatype - determines UI component */
332
+ type: exports.PageFieldTypeSchema,
333
+ /** Display label */
334
+ label: zod_1.z.string(),
335
+ /** Optional description/help text */
336
+ description: zod_1.z.string().optional(),
337
+ /** Whether field is required */
338
+ required: zod_1.z.boolean().optional(),
339
+ /** Tool name from registry to call on value change */
340
+ handler: zod_1.z.string().optional(),
341
+ /** Data source for prepopulating field value */
342
+ source: exports.PageFieldSourceSchema.optional(),
343
+ /** For SELECT type: available options */
344
+ options: zod_1.z.array(zod_1.z.object({ value: zod_1.z.string(), label: zod_1.z.string() })).optional(),
345
+ /** For FILE type: accepted file extensions */
346
+ accept: zod_1.z.string().optional(),
347
+ });
348
+ /** Action button definition for pages */
349
+ exports.PageActionDefinitionSchema = zod_1.z.object({
350
+ /** Unique handle for this action */
351
+ handle: zod_1.z.string(),
352
+ /** Button label */
353
+ label: zod_1.z.string(),
354
+ /** Tool name from registry to invoke */
355
+ handler: zod_1.z.string(),
356
+ /** Optional icon (lucide icon name) */
357
+ icon: zod_1.z.string().optional(),
358
+ /** Button variant */
359
+ variant: zod_1.z.enum(['primary', 'secondary', 'destructive']).optional(),
360
+ });
361
+ /**
362
+ * Schema for a block definition within a page.
363
+ * Blocks define the UI components that render model data.
364
+ */
365
+ exports.PageBlockDefinitionSchema = zod_1.z.object({
366
+ /** Block type determines the UI component */
367
+ type: exports.PageBlockTypeSchema,
368
+ /** Block title displayed in UI */
369
+ title: zod_1.z.string().optional(),
370
+ /** Self-contained field definitions */
371
+ fields: zod_1.z.array(exports.PageFieldDefinitionSchema).optional(),
372
+ /** Whether the block is read-only (no editing) */
373
+ readonly: zod_1.z.boolean().optional(),
374
+ });
375
+ /** Filter for selecting which instance(s) to display on a page */
376
+ exports.PageInstanceFilterSchema = zod_1.z.object({
377
+ /** Model to query instances from */
378
+ model: zod_1.z.string(),
379
+ /** Filter criteria - supports variable substitution like $appInstallationId */
380
+ where: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
381
+ });
382
+ /**
383
+ * Schema for a page definition.
384
+ * Pages define how internal models are displayed in the post-install UI.
385
+ */
386
+ exports.PageDefinitionSchema = zod_1.z.object({
387
+ /** Unique handle for the page */
388
+ handle: zod_1.z.string(),
389
+ /** Page type: INSTANCE (single record) or LIST (multiple records) */
390
+ type: exports.PageTypeSchema,
391
+ /** Page title displayed in UI */
392
+ title: zod_1.z.string(),
393
+ /** Optional custom path for navigation */
394
+ path: zod_1.z.string().optional(),
395
+ /** Whether to show this page in sidebar navigation (default: true) */
396
+ navigation: zod_1.z.boolean().optional().default(true),
397
+ /** Blocks that compose this page */
398
+ blocks: zod_1.z.array(exports.PageBlockDefinitionSchema),
399
+ /** Page-level action buttons */
400
+ actions: zod_1.z.array(exports.PageActionDefinitionSchema).optional(),
401
+ /** Filter to select instance(s) for prepopulating field values */
402
+ filter: exports.PageInstanceFilterSchema.optional(),
403
+ });
291
404
  /**
292
405
  * Schema for inline field definition (constraints, options, etc.)
293
406
  * This allows defining field behavior without referencing a metafield definition.
@@ -428,6 +541,8 @@ exports.SkedyulConfigSchema = zod_1.z.object({
428
541
  models: zod_1.z.array(exports.ModelDefinitionSchema).optional(),
429
542
  // Relationships between models
430
543
  relationships: zod_1.z.array(exports.RelationshipDefinitionSchema).optional(),
544
+ // Pages for internal models (displayed in post-install UI)
545
+ pages: zod_1.z.array(exports.PageDefinitionSchema).optional(),
431
546
  // New channel syntax (alias for communicationChannels)
432
547
  channels: zod_1.z.array(exports.ChannelDefinitionSchema).optional(),
433
548
  // Legacy: communication channels (deprecated - use channels)
package/dist/server.js CHANGED
@@ -45,17 +45,6 @@ const z = __importStar(require("zod"));
45
45
  const zod_to_json_schema_1 = require("zod-to-json-schema");
46
46
  const service_1 = require("./core/service");
47
47
  const zodToJsonSchemaLoose = zod_to_json_schema_1.zodToJsonSchema;
48
- let toJsonSchemaCompatFn = null;
49
- try {
50
- // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require
51
- const compat = require('@modelcontextprotocol/sdk/server/zod-json-schema-compat.js');
52
- if (compat?.toJsonSchemaCompat) {
53
- toJsonSchemaCompatFn = compat.toJsonSchemaCompat;
54
- }
55
- }
56
- catch {
57
- toJsonSchemaCompatFn = null;
58
- }
59
48
  function normalizeBilling(billing) {
60
49
  if (!billing || typeof billing.credits !== 'number') {
61
50
  return { credits: 0 };
@@ -66,12 +55,14 @@ function toJsonSchema(schema) {
66
55
  if (!schema)
67
56
  return undefined;
68
57
  try {
69
- if (toJsonSchemaCompatFn) {
70
- return toJsonSchemaCompatFn(schema, {
71
- target: 'jsonSchema7',
72
- pipeStrategy: 'input',
58
+ // Zod v4 has native JSON Schema support via z.toJSONSchema()
59
+ // This is preferred over external libraries for Zod v4 compatibility
60
+ if (typeof z.toJSONSchema === 'function') {
61
+ return z.toJSONSchema(schema, {
62
+ unrepresentable: 'any', // Handle z.date(), z.bigint() etc gracefully
73
63
  });
74
64
  }
65
+ // Fallback to zod-to-json-schema for older Zod versions
75
66
  return zodToJsonSchemaLoose(schema, {
76
67
  target: 'jsonSchema7',
77
68
  $refStrategy: 'none',
package/dist/types.d.ts CHANGED
@@ -1,9 +1,54 @@
1
1
  import type { CoreApiConfig } from './core/types';
2
2
  import type { z } from 'zod';
3
+ import type { PageFieldType } from './schemas';
3
4
  export interface ToolContext {
4
5
  env: Record<string, string | undefined>;
5
6
  mode?: 'execute' | 'estimate';
6
7
  }
8
+ /** Context passed to field change handlers */
9
+ export interface FieldChangeContext extends ToolContext {
10
+ /** Field handle from page definition */
11
+ fieldHandle: string;
12
+ /** Field datatype */
13
+ fieldType: PageFieldType;
14
+ /** Page handle */
15
+ pageHandle: string;
16
+ /** App installation ID */
17
+ appInstallationId: string;
18
+ /** Workplace info */
19
+ workplace: {
20
+ id: string;
21
+ subdomain: string;
22
+ };
23
+ }
24
+ /** Parameters for field change handlers */
25
+ export interface FieldChangeParams<T = unknown> {
26
+ /** The new value */
27
+ value: T;
28
+ /** Previous value if available */
29
+ previousValue?: T;
30
+ /** Handler context */
31
+ context: FieldChangeContext;
32
+ }
33
+ /** Context passed to page action handlers */
34
+ export interface PageActionContext extends ToolContext {
35
+ /** Page handle */
36
+ pageHandle: string;
37
+ /** App installation ID */
38
+ appInstallationId: string;
39
+ /** Workplace info */
40
+ workplace: {
41
+ id: string;
42
+ subdomain: string;
43
+ };
44
+ /** All current field values on the page */
45
+ fieldValues: Record<string, unknown>;
46
+ }
47
+ /** Parameters for page action handlers */
48
+ export interface PageActionParams {
49
+ /** Handler context */
50
+ context: PageActionContext;
51
+ }
7
52
  export interface ToolParams<Input, Output> {
8
53
  input: Input;
9
54
  context: ToolContext;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skedyul",
3
- "version": "0.1.40",
3
+ "version": "0.1.42",
4
4
  "description": "The Skedyul SDK for Node.js",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",