@elevasis/core 0.10.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/index.d.ts +69 -159
  2. package/dist/index.js +324 -613
  3. package/dist/organization-model/index.d.ts +69 -159
  4. package/dist/organization-model/index.js +324 -613
  5. package/dist/test-utils/index.d.ts +192 -45
  6. package/dist/test-utils/index.js +260 -600
  7. package/package.json +1 -1
  8. package/src/__tests__/template-core-compatibility.test.ts +73 -91
  9. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +94 -182
  10. package/src/auth/multi-tenancy/index.ts +20 -17
  11. package/src/auth/multi-tenancy/memberships/api-schemas.ts +142 -126
  12. package/src/auth/multi-tenancy/memberships/index.ts +26 -22
  13. package/src/auth/multi-tenancy/permissions.test.ts +42 -0
  14. package/src/auth/multi-tenancy/permissions.ts +104 -0
  15. package/src/organization-model/README.md +102 -97
  16. package/src/organization-model/__tests__/defaults.test.ts +19 -6
  17. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +24 -93
  18. package/src/organization-model/__tests__/graph.test.ts +82 -894
  19. package/src/organization-model/__tests__/resolve.test.ts +59 -690
  20. package/src/organization-model/__tests__/schema.test.ts +83 -407
  21. package/src/organization-model/contracts.ts +4 -3
  22. package/src/organization-model/defaults.ts +277 -141
  23. package/src/organization-model/domains/features.ts +31 -22
  24. package/src/organization-model/domains/navigation.ts +27 -20
  25. package/src/organization-model/foundation.ts +42 -54
  26. package/src/organization-model/graph/build.ts +42 -217
  27. package/src/organization-model/graph/index.ts +4 -4
  28. package/src/organization-model/graph/link.ts +10 -0
  29. package/src/organization-model/graph/schema.ts +21 -16
  30. package/src/organization-model/graph/types.ts +10 -10
  31. package/src/organization-model/helpers.ts +74 -0
  32. package/src/organization-model/index.ts +7 -7
  33. package/src/organization-model/organization-graph.mdx +89 -272
  34. package/src/organization-model/organization-model.mdx +152 -320
  35. package/src/organization-model/published.ts +20 -19
  36. package/src/organization-model/resolve.ts +8 -33
  37. package/src/organization-model/schema.ts +63 -205
  38. package/src/organization-model/types.ts +12 -11
  39. package/src/platform/constants/versions.ts +3 -3
  40. package/src/platform/registry/__tests__/command-view.test.ts +6 -5
  41. package/src/platform/registry/__tests__/resource-link.test.ts +30 -0
  42. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +15 -15
  43. package/src/platform/registry/command-view.ts +10 -12
  44. package/src/platform/registry/index.ts +93 -93
  45. package/src/platform/registry/resource-link.ts +32 -0
  46. package/src/platform/registry/resource-registry.ts +917 -876
  47. package/src/platform/registry/serialization.ts +56 -73
  48. package/src/platform/registry/serialized-types.ts +17 -12
  49. package/src/platform/registry/types.ts +14 -43
  50. package/src/reference/_generated/contracts.md +94 -182
  51. package/src/reference/glossary.md +71 -105
  52. package/src/scaffold-registry/__tests__/index.test.ts +125 -1
  53. package/src/scaffold-registry/__tests__/schema.test.ts +48 -20
  54. package/src/scaffold-registry/index.ts +236 -188
  55. package/src/scaffold-registry/schema.ts +47 -22
  56. package/src/supabase/database.types.ts +2880 -2719
  57. package/src/test-utils/fixtures/memberships.ts +82 -80
  58. package/src/platform/registry/domains.ts +0 -165
@@ -2404,6 +2404,7 @@ var TEST_MEMBERSHIPS = {
2404
2404
  role_slug: "admin",
2405
2405
  membership_status: "active",
2406
2406
  config: {},
2407
+ effective_permissions: [],
2407
2408
  created_at: "2025-01-01T00:00:00Z",
2408
2409
  updated_at: "2025-01-01T00:00:00Z"
2409
2410
  },
@@ -2415,6 +2416,7 @@ var TEST_MEMBERSHIPS = {
2415
2416
  role_slug: "member",
2416
2417
  membership_status: "active",
2417
2418
  config: {},
2419
+ effective_permissions: [],
2418
2420
  created_at: "2025-01-01T00:00:00Z",
2419
2421
  updated_at: "2025-01-01T00:00:00Z"
2420
2422
  },
@@ -2426,6 +2428,7 @@ var TEST_MEMBERSHIPS = {
2426
2428
  role_slug: "member",
2427
2429
  membership_status: "inactive",
2428
2430
  config: {},
2431
+ effective_permissions: [],
2429
2432
  created_at: "2025-01-01T00:00:00Z",
2430
2433
  updated_at: "2025-01-01T00:00:00Z"
2431
2434
  }
@@ -2453,6 +2456,7 @@ function createTestMembership(overrides) {
2453
2456
  role_slug: "member",
2454
2457
  membership_status: "active",
2455
2458
  config: {},
2459
+ effective_permissions: [],
2456
2460
  created_at: "2025-01-01T00:00:00Z",
2457
2461
  updated_at: "2025-01-01T00:00:00Z",
2458
2462
  ...overrides
@@ -19425,7 +19429,7 @@ var TechStackEntrySchema = z.object({
19425
19429
  */
19426
19430
  isSystemOfRecord: z.boolean().default(false)
19427
19431
  });
19428
- var ResourceMappingSchema = DisplayMetadataSchema.extend({
19432
+ DisplayMetadataSchema.extend({
19429
19433
  id: ModelIdSchema,
19430
19434
  resourceId: z.string().trim().min(1).max(255),
19431
19435
  resourceType: z.enum(["workflow", "agent", "trigger", "integration", "external", "human_checkpoint"]),
@@ -19584,17 +19588,20 @@ var DEFAULT_ORGANIZATION_MODEL_PROJECTS = {
19584
19588
  { id: "completed", label: "Completed", order: 9 }
19585
19589
  ]
19586
19590
  };
19591
+ var NodeIdPathSchema = z.string().trim().min(1).max(100).regex(/^([a-z0-9-]+)(\.[a-z0-9-]+)*$/, "Node IDs must be lowercase dotted paths");
19592
+ z.string().trim().min(1).max(200).regex(/^[a-z]+:([a-z0-9-]+)(\.[a-z0-9-]+)*$/, "Node references must use kind:dotted-path");
19593
+ var UiPositionSchema = z.enum(["sidebar-primary", "sidebar-bottom"]);
19587
19594
  var FeatureSchema = z.object({
19588
- id: ModelIdSchema,
19595
+ id: NodeIdPathSchema,
19589
19596
  label: LabelSchema,
19590
19597
  description: DescriptionSchema.optional(),
19591
19598
  enabled: z.boolean().default(true),
19592
- color: ColorTokenSchema.optional(),
19599
+ path: PathSchema.optional(),
19593
19600
  icon: IconNameSchema.optional(),
19594
- entityIds: ReferenceIdsSchema,
19595
- surfaceIds: ReferenceIdsSchema,
19596
- resourceIds: ReferenceIdsSchema,
19597
- capabilityIds: ReferenceIdsSchema
19601
+ color: ColorTokenSchema.optional(),
19602
+ uiPosition: UiPositionSchema.optional(),
19603
+ requiresAdmin: z.boolean().optional(),
19604
+ devOnly: z.boolean().optional()
19598
19605
  });
19599
19606
  var ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
19600
19607
  id: ModelIdSchema,
@@ -19624,22 +19631,6 @@ var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
19624
19631
  { id: "uploaded", label: "Uploaded", order: 4 }
19625
19632
  ]
19626
19633
  };
19627
-
19628
- // src/organization-model/contracts.ts
19629
- var PROJECTS_FEATURE_ID = "projects";
19630
- var PROJECTS_INDEX_SURFACE_ID = "projects.index";
19631
- var PROJECTS_VIEW_CAPABILITY_ID = "delivery.projects.view";
19632
- var SALES_FEATURE_ID = "crm";
19633
- var PROSPECTING_FEATURE_ID = "lead-gen";
19634
- var OPERATIONS_FEATURE_ID = "operations";
19635
- var MONITORING_FEATURE_ID = "monitoring";
19636
- var SETTINGS_FEATURE_ID = "settings";
19637
- var SEO_FEATURE_ID = "seo";
19638
- var SALES_PIPELINE_SURFACE_ID = "crm.pipeline";
19639
- var PROSPECTING_LISTS_SURFACE_ID = "lead-gen.lists";
19640
- var OPERATIONS_ORGANIZATION_GRAPH_SURFACE_ID = "operations.organization-graph";
19641
-
19642
- // src/organization-model/domains/navigation.ts
19643
19634
  var SurfaceTypeSchema = z.enum(["page", "dashboard", "graph", "detail", "list", "settings"]);
19644
19635
  var SurfaceDefinitionSchema = z.object({
19645
19636
  id: ModelIdSchema,
@@ -19648,6 +19639,7 @@ var SurfaceDefinitionSchema = z.object({
19648
19639
  surfaceType: SurfaceTypeSchema,
19649
19640
  description: DescriptionSchema.optional(),
19650
19641
  enabled: z.boolean().default(true),
19642
+ devOnly: z.boolean().optional(),
19651
19643
  icon: IconNameSchema.optional(),
19652
19644
  featureId: ModelIdSchema.optional(),
19653
19645
  featureIds: ReferenceIdsSchema,
@@ -19667,349 +19659,6 @@ var OrganizationModelNavigationSchema = z.object({
19667
19659
  surfaces: z.array(SurfaceDefinitionSchema).default([]),
19668
19660
  groups: z.array(NavigationGroupSchema).default([])
19669
19661
  });
19670
- var DEFAULT_ORGANIZATION_MODEL_NAVIGATION = {
19671
- defaultSurfaceId: "crm.pipeline",
19672
- surfaces: [
19673
- {
19674
- id: "crm.pipeline",
19675
- label: "Pipeline",
19676
- path: "/crm/pipeline",
19677
- surfaceType: "graph",
19678
- enabled: true,
19679
- featureId: "crm",
19680
- featureIds: ["crm"],
19681
- entityIds: ["crm.deal"],
19682
- resourceIds: [],
19683
- capabilityIds: ["crm.pipeline.manage"]
19684
- },
19685
- {
19686
- id: "lead-gen.lists",
19687
- label: "Lists",
19688
- path: "/lead-gen/lists",
19689
- surfaceType: "list",
19690
- enabled: true,
19691
- featureId: "lead-gen",
19692
- featureIds: ["lead-gen"],
19693
- entityIds: ["leadgen.list"],
19694
- resourceIds: [],
19695
- capabilityIds: ["leadgen.lists.manage"]
19696
- },
19697
- {
19698
- id: PROJECTS_INDEX_SURFACE_ID,
19699
- label: "Projects",
19700
- path: "/projects",
19701
- surfaceType: "list",
19702
- enabled: true,
19703
- featureId: PROJECTS_FEATURE_ID,
19704
- featureIds: [PROJECTS_FEATURE_ID],
19705
- entityIds: ["delivery.project"],
19706
- resourceIds: [],
19707
- capabilityIds: [PROJECTS_VIEW_CAPABILITY_ID]
19708
- },
19709
- {
19710
- id: "operations.organization-graph",
19711
- label: "Organization Graph",
19712
- path: "/operations/organization-graph",
19713
- surfaceType: "graph",
19714
- enabled: true,
19715
- featureId: "operations",
19716
- featureIds: ["operations"],
19717
- entityIds: [],
19718
- resourceIds: [],
19719
- capabilityIds: ["operations.organization-graph"]
19720
- },
19721
- {
19722
- id: "operations.command-view",
19723
- label: "Command View",
19724
- path: "/operations/command-view",
19725
- surfaceType: "graph",
19726
- enabled: false,
19727
- featureId: "operations",
19728
- featureIds: ["operations"],
19729
- entityIds: [],
19730
- resourceIds: [],
19731
- capabilityIds: ["operations.command-view"]
19732
- },
19733
- {
19734
- id: "operations.overview",
19735
- label: "Overview",
19736
- path: "/operations",
19737
- surfaceType: "dashboard",
19738
- enabled: true,
19739
- featureId: "operations",
19740
- featureIds: ["operations"],
19741
- entityIds: [],
19742
- resourceIds: [],
19743
- capabilityIds: []
19744
- },
19745
- {
19746
- id: "operations.resources",
19747
- label: "Resources",
19748
- path: "/operations/resources",
19749
- surfaceType: "list",
19750
- enabled: true,
19751
- featureId: "operations",
19752
- featureIds: ["operations"],
19753
- entityIds: [],
19754
- resourceIds: [],
19755
- capabilityIds: []
19756
- },
19757
- {
19758
- id: "operations.command-queue",
19759
- label: "Command Queue",
19760
- path: "/operations/command-queue",
19761
- surfaceType: "list",
19762
- enabled: true,
19763
- featureId: "operations",
19764
- featureIds: ["operations"],
19765
- entityIds: [],
19766
- resourceIds: [],
19767
- capabilityIds: []
19768
- },
19769
- {
19770
- id: "operations.sessions",
19771
- label: "Sessions",
19772
- path: "/operations/sessions",
19773
- surfaceType: "page",
19774
- enabled: false,
19775
- featureId: "operations",
19776
- featureIds: ["operations"],
19777
- entityIds: [],
19778
- resourceIds: [],
19779
- capabilityIds: []
19780
- },
19781
- {
19782
- id: "operations.task-scheduler",
19783
- label: "Task Scheduler",
19784
- path: "/operations/task-scheduler",
19785
- surfaceType: "page",
19786
- enabled: true,
19787
- featureId: "operations",
19788
- featureIds: ["operations"],
19789
- entityIds: [],
19790
- resourceIds: [],
19791
- capabilityIds: []
19792
- },
19793
- {
19794
- id: "monitoring.activity-log",
19795
- label: "Activity Log",
19796
- path: "/monitoring/activity-log",
19797
- surfaceType: "list",
19798
- enabled: true,
19799
- featureId: "monitoring",
19800
- featureIds: ["monitoring"],
19801
- entityIds: [],
19802
- resourceIds: [],
19803
- capabilityIds: []
19804
- },
19805
- {
19806
- id: "monitoring.execution-logs",
19807
- label: "Execution Logs",
19808
- path: "/monitoring/execution-logs",
19809
- surfaceType: "list",
19810
- enabled: true,
19811
- featureId: "monitoring",
19812
- featureIds: ["monitoring"],
19813
- entityIds: [],
19814
- resourceIds: [],
19815
- capabilityIds: []
19816
- },
19817
- {
19818
- id: "monitoring.execution-health",
19819
- label: "Execution Health",
19820
- path: "/monitoring/execution-health",
19821
- surfaceType: "dashboard",
19822
- enabled: true,
19823
- featureId: "monitoring",
19824
- featureIds: ["monitoring"],
19825
- entityIds: [],
19826
- resourceIds: [],
19827
- capabilityIds: []
19828
- },
19829
- {
19830
- id: "monitoring.cost-analytics",
19831
- label: "Cost Analytics",
19832
- path: "/monitoring/cost-analytics",
19833
- surfaceType: "dashboard",
19834
- enabled: false,
19835
- featureId: "monitoring",
19836
- featureIds: ["monitoring"],
19837
- entityIds: [],
19838
- resourceIds: [],
19839
- capabilityIds: []
19840
- },
19841
- {
19842
- id: "monitoring.notifications",
19843
- label: "Notifications",
19844
- path: "/monitoring/notifications",
19845
- surfaceType: "page",
19846
- enabled: true,
19847
- featureId: "monitoring",
19848
- featureIds: ["monitoring"],
19849
- entityIds: [],
19850
- resourceIds: [],
19851
- capabilityIds: []
19852
- },
19853
- {
19854
- id: "submitted-requests.list",
19855
- label: "Submitted Requests",
19856
- path: "/monitoring/requests",
19857
- surfaceType: "list",
19858
- enabled: true,
19859
- featureId: "submitted-requests",
19860
- featureIds: ["submitted-requests"],
19861
- entityIds: ["reported_request"],
19862
- resourceIds: [],
19863
- capabilityIds: []
19864
- },
19865
- {
19866
- id: "submitted-requests.detail",
19867
- label: "Request Detail",
19868
- path: "/monitoring/requests/:requestId",
19869
- surfaceType: "detail",
19870
- enabled: true,
19871
- featureId: "submitted-requests",
19872
- featureIds: ["submitted-requests"],
19873
- entityIds: ["reported_request"],
19874
- resourceIds: [],
19875
- capabilityIds: []
19876
- },
19877
- {
19878
- id: "settings.account",
19879
- label: "Account",
19880
- path: "/settings/account",
19881
- surfaceType: "settings",
19882
- enabled: true,
19883
- featureId: "settings",
19884
- featureIds: ["settings"],
19885
- entityIds: [],
19886
- resourceIds: [],
19887
- capabilityIds: []
19888
- },
19889
- {
19890
- id: "settings.appearance",
19891
- label: "Appearance",
19892
- path: "/settings/appearance",
19893
- surfaceType: "settings",
19894
- enabled: true,
19895
- featureId: "settings",
19896
- featureIds: ["settings"],
19897
- entityIds: [],
19898
- resourceIds: [],
19899
- capabilityIds: []
19900
- },
19901
- {
19902
- id: "settings.organization",
19903
- label: "Organization",
19904
- path: "/settings/organization",
19905
- surfaceType: "settings",
19906
- enabled: true,
19907
- featureId: "settings",
19908
- featureIds: ["settings"],
19909
- entityIds: [],
19910
- resourceIds: [],
19911
- capabilityIds: []
19912
- },
19913
- {
19914
- id: "settings.credentials",
19915
- label: "Credentials",
19916
- path: "/settings/credentials",
19917
- surfaceType: "settings",
19918
- enabled: true,
19919
- featureId: "settings",
19920
- featureIds: ["settings"],
19921
- entityIds: [],
19922
- resourceIds: [],
19923
- capabilityIds: []
19924
- },
19925
- {
19926
- id: "settings.api-keys",
19927
- label: "API Keys",
19928
- path: "/settings/api-keys",
19929
- surfaceType: "settings",
19930
- enabled: true,
19931
- featureId: "settings",
19932
- featureIds: ["settings"],
19933
- entityIds: [],
19934
- resourceIds: [],
19935
- capabilityIds: []
19936
- },
19937
- {
19938
- id: "settings.webhooks",
19939
- label: "Webhooks",
19940
- path: "/settings/webhooks",
19941
- surfaceType: "settings",
19942
- enabled: true,
19943
- featureId: "settings",
19944
- featureIds: ["settings"],
19945
- entityIds: [],
19946
- resourceIds: [],
19947
- capabilityIds: []
19948
- },
19949
- {
19950
- id: "settings.deployments",
19951
- label: "Deployments",
19952
- path: "/settings/deployments",
19953
- surfaceType: "settings",
19954
- enabled: true,
19955
- featureId: "settings",
19956
- featureIds: ["settings"],
19957
- entityIds: [],
19958
- resourceIds: [],
19959
- capabilityIds: []
19960
- }
19961
- ],
19962
- groups: [
19963
- {
19964
- id: "primary-workspace",
19965
- label: "Workspace",
19966
- placement: "primary",
19967
- surfaceIds: ["crm.pipeline", "lead-gen.lists", PROJECTS_INDEX_SURFACE_ID]
19968
- },
19969
- {
19970
- id: "primary-operations",
19971
- label: "Operations",
19972
- placement: "primary",
19973
- surfaceIds: [
19974
- "operations.organization-graph",
19975
- "operations.command-view",
19976
- "operations.overview",
19977
- "operations.resources",
19978
- "operations.command-queue",
19979
- "operations.sessions",
19980
- "operations.task-scheduler"
19981
- ]
19982
- },
19983
- {
19984
- id: "primary-monitoring",
19985
- label: "Monitoring",
19986
- placement: "primary",
19987
- surfaceIds: [
19988
- "monitoring.activity-log",
19989
- "monitoring.execution-logs",
19990
- "monitoring.execution-health",
19991
- "monitoring.cost-analytics",
19992
- "monitoring.notifications",
19993
- "submitted-requests.list",
19994
- "submitted-requests.detail"
19995
- ]
19996
- },
19997
- {
19998
- id: "primary-settings",
19999
- label: "Settings",
20000
- placement: "bottom",
20001
- surfaceIds: [
20002
- "settings.account",
20003
- "settings.appearance",
20004
- "settings.organization",
20005
- "settings.credentials",
20006
- "settings.api-keys",
20007
- "settings.webhooks",
20008
- "settings.deployments"
20009
- ]
20010
- }
20011
- ]
20012
- };
20013
19662
  var BusinessHoursDaySchema = z.object({
20014
19663
  open: z.string().trim().regex(/^\d{2}:\d{2}$/, "Expected HH:MM format"),
20015
19664
  close: z.string().trim().regex(/^\d{2}:\d{2}$/, "Expected HH:MM format")
@@ -20409,7 +20058,7 @@ var OrganizationModelSchemaBase = z.object({
20409
20058
  version: z.literal(1).default(1),
20410
20059
  features: z.array(FeatureSchema).default([]),
20411
20060
  branding: OrganizationModelBrandingSchema,
20412
- navigation: OrganizationModelNavigationSchema,
20061
+ navigation: OrganizationModelNavigationSchema.default({ surfaces: [], groups: [] }),
20413
20062
  sales: OrganizationModelSalesSchema,
20414
20063
  prospecting: OrganizationModelProspectingSchema,
20415
20064
  projects: OrganizationModelProjectsSchema,
@@ -20419,8 +20068,7 @@ var OrganizationModelSchemaBase = z.object({
20419
20068
  roles: RolesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_ROLES),
20420
20069
  goals: GoalsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_GOALS),
20421
20070
  statuses: StatusesDomainSchema.default({ entries: [] }),
20422
- operations: OperationsDomainSchema.default({ entries: [] }),
20423
- resourceMappings: z.array(ResourceMappingSchema).default([])
20071
+ operations: OperationsDomainSchema.default({ entries: [] })
20424
20072
  });
20425
20073
  function addIssue(ctx, path, message) {
20426
20074
  ctx.addIssue({
@@ -20440,123 +20088,39 @@ function collectIds(items, ctx, collectionPath, label) {
20440
20088
  });
20441
20089
  return itemsById;
20442
20090
  }
20091
+ var LEGACY_FEATURE_ALIASES = /* @__PURE__ */ new Map([
20092
+ ["crm", "sales.crm"],
20093
+ ["lead-gen", "sales.lead-gen"],
20094
+ ["submitted-requests", "monitoring.submitted-requests"]
20095
+ ]);
20096
+ function hasFeature(featuresById, featureId) {
20097
+ return featuresById.has(featureId) || featuresById.has(LEGACY_FEATURE_ALIASES.get(featureId) ?? "");
20098
+ }
20443
20099
  var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ctx) => {
20444
20100
  const featuresById = collectIds(model.features, ctx, ["features"], "Feature");
20445
- const surfacesById = collectIds(model.navigation.surfaces, ctx, ["navigation", "surfaces"], "Surface");
20446
- collectIds(model.navigation.groups, ctx, ["navigation", "groups"], "Navigation group");
20447
- collectIds(model.resourceMappings, ctx, ["resourceMappings"], "Resource mapping");
20448
- const resourceMappingsByResourceId = /* @__PURE__ */ new Map();
20449
- model.resourceMappings.forEach((resourceMapping, index2) => {
20450
- if (resourceMappingsByResourceId.has(resourceMapping.resourceId)) {
20451
- addIssue(
20452
- ctx,
20453
- ["resourceMappings", index2, "resourceId"],
20454
- `Resource mapping resourceId "${resourceMapping.resourceId}" must be unique`
20455
- );
20456
- return;
20457
- }
20458
- resourceMappingsByResourceId.set(resourceMapping.resourceId, resourceMapping);
20459
- });
20460
- if (model.navigation.defaultSurfaceId && !surfacesById.has(model.navigation.defaultSurfaceId)) {
20461
- addIssue(
20462
- ctx,
20463
- ["navigation", "defaultSurfaceId"],
20464
- `Default surface "${model.navigation.defaultSurfaceId}" must reference a declared navigation surface`
20465
- );
20466
- }
20467
- model.navigation.groups.forEach((group, groupIndex) => {
20468
- group.surfaceIds.forEach((surfaceId, surfaceIndex) => {
20469
- if (!surfacesById.has(surfaceId)) {
20470
- addIssue(
20471
- ctx,
20472
- ["navigation", "groups", groupIndex, "surfaceIds", surfaceIndex],
20473
- `Navigation group "${group.id}" references unknown surface "${surfaceId}"`
20474
- );
20475
- }
20476
- });
20477
- });
20478
20101
  model.features.forEach((feature, featureIndex) => {
20479
- feature.surfaceIds.forEach((surfaceId, surfaceIndex) => {
20480
- const surface = surfacesById.get(surfaceId);
20481
- if (!surface) {
20482
- addIssue(
20483
- ctx,
20484
- ["features", featureIndex, "surfaceIds", surfaceIndex],
20485
- `Feature "${feature.id}" references unknown surface "${surfaceId}"`
20486
- );
20487
- return;
20488
- }
20489
- if (!surface.featureIds.includes(feature.id)) {
20490
- addIssue(
20491
- ctx,
20492
- ["features", featureIndex, "surfaceIds", surfaceIndex],
20493
- `Feature "${feature.id}" references surface "${surfaceId}" but that surface does not include feature "${feature.id}"`
20494
- );
20495
- }
20496
- });
20497
- feature.resourceIds.forEach((resourceId, resourceIndex) => {
20498
- const resourceMapping = resourceMappingsByResourceId.get(resourceId);
20499
- if (!resourceMapping) {
20500
- addIssue(
20501
- ctx,
20502
- ["features", featureIndex, "resourceIds", resourceIndex],
20503
- `Feature "${feature.id}" references unknown resource "${resourceId}"`
20504
- );
20505
- return;
20102
+ const segments = feature.id.split(".");
20103
+ if (segments.length > 1) {
20104
+ const parentId = segments.slice(0, -1).join(".");
20105
+ if (!featuresById.has(parentId)) {
20106
+ addIssue(ctx, ["features", featureIndex, "id"], `Feature "${feature.id}" references unknown parent "${parentId}"`);
20506
20107
  }
20507
- if (!resourceMapping.featureIds.includes(feature.id)) {
20508
- addIssue(
20509
- ctx,
20510
- ["features", featureIndex, "resourceIds", resourceIndex],
20511
- `Feature "${feature.id}" references resource "${resourceId}" but that resource mapping does not include feature "${feature.id}"`
20512
- );
20513
- }
20514
- });
20515
- });
20516
- model.navigation.surfaces.forEach((surface, surfaceIndex) => {
20517
- if (surface.parentId && !surfacesById.has(surface.parentId)) {
20518
- addIssue(
20519
- ctx,
20520
- ["navigation", "surfaces", surfaceIndex, "parentId"],
20521
- `Surface "${surface.id}" references unknown parent surface "${surface.parentId}"`
20522
- );
20523
20108
  }
20524
- surface.featureIds.forEach((featureId, featureIndex) => {
20525
- const feature = featuresById.get(featureId);
20526
- if (!feature) {
20527
- addIssue(
20528
- ctx,
20529
- ["navigation", "surfaces", surfaceIndex, "featureIds", featureIndex],
20530
- `Surface "${surface.id}" references unknown feature "${featureId}"`
20531
- );
20532
- return;
20533
- }
20534
- if (!feature.surfaceIds.includes(surface.id)) {
20535
- addIssue(
20536
- ctx,
20537
- ["navigation", "surfaces", surfaceIndex, "featureIds", featureIndex],
20538
- `Surface "${surface.id}" references feature "${featureId}" but that feature does not include surface "${surface.id}"`
20539
- );
20540
- }
20541
- });
20542
- surface.resourceIds.forEach((resourceId, resourceIndex) => {
20543
- const resourceMapping = resourceMappingsByResourceId.get(resourceId);
20544
- if (!resourceMapping) {
20545
- addIssue(
20546
- ctx,
20547
- ["navigation", "surfaces", surfaceIndex, "resourceIds", resourceIndex],
20548
- `Surface "${surface.id}" references unknown resource "${resourceId}"`
20549
- );
20550
- return;
20551
- }
20552
- if (!resourceMapping.surfaceIds.includes(surface.id)) {
20109
+ const hasChildren = model.features.some(
20110
+ (candidate) => candidate.id.startsWith(`${feature.id}.`) && candidate.id !== feature.id
20111
+ );
20112
+ if (hasChildren && feature.enabled) {
20113
+ const hasEnabledDescendant = model.features.some(
20114
+ (candidate) => candidate.id.startsWith(`${feature.id}.`) && candidate.enabled
20115
+ );
20116
+ if (!hasEnabledDescendant) {
20553
20117
  addIssue(
20554
20118
  ctx,
20555
- ["navigation", "surfaces", surfaceIndex, "resourceIds", resourceIndex],
20556
- `Surface "${surface.id}" references resource "${resourceId}" but that surface does not include resource "${surface.id}"`
20119
+ ["features", featureIndex, "enabled"],
20120
+ `Feature "${feature.id}" is enabled but has no enabled descendants`
20557
20121
  );
20558
20122
  }
20559
- });
20123
+ }
20560
20124
  });
20561
20125
  const segmentsById = new Map(model.customers.segments.map((seg) => [seg.id, seg]));
20562
20126
  model.offerings.products.forEach((product, productIndex) => {
@@ -20569,7 +20133,7 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
20569
20133
  );
20570
20134
  }
20571
20135
  });
20572
- if (product.deliveryFeatureId !== void 0 && !featuresById.has(product.deliveryFeatureId)) {
20136
+ if (product.deliveryFeatureId !== void 0 && !hasFeature(featuresById, product.deliveryFeatureId)) {
20573
20137
  addIssue(
20574
20138
  ctx,
20575
20139
  ["offerings", "products", productIndex, "deliveryFeatureId"],
@@ -20596,44 +20160,6 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
20596
20160
  );
20597
20161
  }
20598
20162
  });
20599
- model.resourceMappings.forEach((resourceMapping, resourceIndex) => {
20600
- resourceMapping.featureIds.forEach((featureId, featureIndex) => {
20601
- const feature = featuresById.get(featureId);
20602
- if (!feature) {
20603
- addIssue(
20604
- ctx,
20605
- ["resourceMappings", resourceIndex, "featureIds", featureIndex],
20606
- `Resource mapping "${resourceMapping.id}" references unknown feature "${featureId}"`
20607
- );
20608
- return;
20609
- }
20610
- if (!feature.resourceIds.includes(resourceMapping.resourceId)) {
20611
- addIssue(
20612
- ctx,
20613
- ["resourceMappings", resourceIndex, "featureIds", featureIndex],
20614
- `Resource mapping "${resourceMapping.id}" references feature "${featureId}" but that feature does not include resource "${resourceMapping.resourceId}"`
20615
- );
20616
- }
20617
- });
20618
- resourceMapping.surfaceIds.forEach((surfaceId, surfaceIndex) => {
20619
- const surface = surfacesById.get(surfaceId);
20620
- if (!surface) {
20621
- addIssue(
20622
- ctx,
20623
- ["resourceMappings", resourceIndex, "surfaceIds", surfaceIndex],
20624
- `Resource mapping "${resourceMapping.id}" references unknown surface "${surfaceId}"`
20625
- );
20626
- return;
20627
- }
20628
- if (!surface.resourceIds.includes(resourceMapping.resourceId)) {
20629
- addIssue(
20630
- ctx,
20631
- ["resourceMappings", resourceIndex, "surfaceIds", surfaceIndex],
20632
- `Resource mapping "${resourceMapping.id}" references surface "${surfaceId}" but that surface does not include resource "${resourceMapping.resourceId}"`
20633
- );
20634
- }
20635
- });
20636
- });
20637
20163
  });
20638
20164
 
20639
20165
  // src/organization-model/defaults.ts
@@ -20641,110 +20167,262 @@ var DEFAULT_ORGANIZATION_MODEL = {
20641
20167
  version: 1,
20642
20168
  features: [
20643
20169
  {
20644
- id: SALES_FEATURE_ID,
20170
+ id: "dashboard",
20171
+ label: "Dashboard",
20172
+ enabled: true,
20173
+ path: "/",
20174
+ icon: "dashboard",
20175
+ uiPosition: "sidebar-primary"
20176
+ },
20177
+ {
20178
+ id: "sales",
20179
+ label: "Sales",
20180
+ description: "Revenue workflows and customer acquisition",
20181
+ enabled: true,
20182
+ color: "blue",
20183
+ icon: "crm",
20184
+ uiPosition: "sidebar-primary"
20185
+ },
20186
+ {
20187
+ id: "sales.crm",
20645
20188
  label: "CRM",
20646
20189
  description: "Relationship pipeline and deal management",
20647
20190
  enabled: true,
20648
20191
  color: "blue",
20649
- entityIds: ["crm.deal"],
20650
- surfaceIds: [SALES_PIPELINE_SURFACE_ID],
20651
- resourceIds: [],
20652
- capabilityIds: ["crm.pipeline.manage"]
20192
+ icon: "crm",
20193
+ path: "/crm"
20653
20194
  },
20654
20195
  {
20655
- id: PROSPECTING_FEATURE_ID,
20196
+ id: "sales.lead-gen",
20656
20197
  label: "Lead Gen",
20657
20198
  description: "Prospecting, qualification, and outreach preparation",
20658
20199
  enabled: true,
20659
20200
  color: "cyan",
20660
- entityIds: ["leadgen.list", "leadgen.company", "leadgen.contact"],
20661
- surfaceIds: [PROSPECTING_LISTS_SURFACE_ID],
20662
- resourceIds: [],
20663
- capabilityIds: ["leadgen.lists.manage"]
20201
+ icon: "lead-gen",
20202
+ path: "/lead-gen"
20664
20203
  },
20665
20204
  {
20666
- id: PROJECTS_FEATURE_ID,
20205
+ id: "projects",
20667
20206
  label: "Projects",
20668
20207
  description: "Projects, milestones, and client work execution",
20669
20208
  enabled: true,
20670
20209
  color: "orange",
20671
- entityIds: ["delivery.project", "delivery.milestone", "delivery.task"],
20672
- surfaceIds: [PROJECTS_INDEX_SURFACE_ID],
20673
- resourceIds: [],
20674
- capabilityIds: [PROJECTS_VIEW_CAPABILITY_ID]
20210
+ icon: "projects",
20211
+ path: "/projects",
20212
+ uiPosition: "sidebar-primary"
20675
20213
  },
20676
20214
  {
20677
- id: OPERATIONS_FEATURE_ID,
20215
+ id: "operations",
20678
20216
  label: "Operations",
20679
20217
  description: "Operational resources, topology, and orchestration visibility",
20680
20218
  enabled: true,
20681
20219
  color: "violet",
20682
- entityIds: [],
20683
- surfaceIds: [
20684
- OPERATIONS_ORGANIZATION_GRAPH_SURFACE_ID,
20685
- "operations.command-view",
20686
- "operations.overview",
20687
- "operations.resources",
20688
- "operations.command-queue",
20689
- "operations.sessions",
20690
- "operations.task-scheduler"
20691
- ],
20692
- resourceIds: [],
20693
- capabilityIds: ["operations.organization-graph", "operations.command-view"]
20220
+ icon: "operations",
20221
+ uiPosition: "sidebar-primary"
20694
20222
  },
20695
20223
  {
20696
- id: MONITORING_FEATURE_ID,
20224
+ id: "operations.graph",
20225
+ label: "Organization Graph",
20226
+ enabled: true,
20227
+ path: "/operations/organization-graph"
20228
+ },
20229
+ {
20230
+ id: "operations.command-view",
20231
+ label: "Command View",
20232
+ enabled: true,
20233
+ path: "/operations/command-view",
20234
+ devOnly: true
20235
+ },
20236
+ {
20237
+ id: "operations.overview",
20238
+ label: "Overview",
20239
+ enabled: true,
20240
+ path: "/operations"
20241
+ },
20242
+ {
20243
+ id: "operations.resources",
20244
+ label: "Resources",
20245
+ enabled: true,
20246
+ path: "/operations/resources"
20247
+ },
20248
+ {
20249
+ id: "operations.command-queue",
20250
+ label: "Command Queue",
20251
+ enabled: true,
20252
+ path: "/operations/command-queue"
20253
+ },
20254
+ {
20255
+ id: "operations.sessions",
20256
+ label: "Sessions",
20257
+ enabled: false,
20258
+ path: "/operations/sessions"
20259
+ },
20260
+ {
20261
+ id: "operations.task-scheduler",
20262
+ label: "Task Scheduler",
20263
+ enabled: true,
20264
+ path: "/operations/task-scheduler"
20265
+ },
20266
+ {
20267
+ id: "monitoring",
20697
20268
  label: "Monitoring",
20698
20269
  enabled: true,
20699
- entityIds: [],
20700
- surfaceIds: [
20701
- "monitoring.activity-log",
20702
- "monitoring.execution-logs",
20703
- "monitoring.execution-health",
20704
- "monitoring.cost-analytics",
20705
- "monitoring.notifications"
20706
- ],
20707
- resourceIds: [],
20708
- capabilityIds: []
20270
+ uiPosition: "sidebar-primary"
20709
20271
  },
20710
20272
  {
20711
- id: SETTINGS_FEATURE_ID,
20712
- label: "Settings",
20273
+ id: "monitoring.activity-log",
20274
+ label: "Activity Log",
20275
+ enabled: true,
20276
+ path: "/monitoring/activity-log"
20277
+ },
20278
+ {
20279
+ id: "monitoring.execution-logs",
20280
+ label: "Execution Logs",
20281
+ enabled: true,
20282
+ path: "/monitoring/execution-logs"
20283
+ },
20284
+ {
20285
+ id: "monitoring.execution-health",
20286
+ label: "Execution Health",
20713
20287
  enabled: true,
20714
- entityIds: [],
20715
- surfaceIds: [
20716
- "settings.account",
20717
- "settings.appearance",
20718
- "settings.organization",
20719
- "settings.credentials",
20720
- "settings.api-keys",
20721
- "settings.webhooks",
20722
- "settings.deployments"
20723
- ],
20724
- resourceIds: [],
20725
- capabilityIds: []
20288
+ path: "/monitoring/execution-health"
20726
20289
  },
20727
20290
  {
20728
- id: "submitted-requests",
20291
+ id: "monitoring.cost-analytics",
20292
+ label: "Cost Analytics",
20293
+ enabled: false,
20294
+ path: "/monitoring/cost-analytics"
20295
+ },
20296
+ {
20297
+ id: "monitoring.notifications",
20298
+ label: "Notifications",
20299
+ enabled: true,
20300
+ path: "/monitoring/notifications"
20301
+ },
20302
+ {
20303
+ id: "monitoring.submitted-requests",
20729
20304
  label: "Submitted Requests",
20730
20305
  enabled: true,
20731
- entityIds: ["reported_request"],
20732
- surfaceIds: ["submitted-requests.list", "submitted-requests.detail"],
20733
- resourceIds: [],
20734
- capabilityIds: []
20306
+ path: "/monitoring/requests"
20307
+ },
20308
+ {
20309
+ id: "settings",
20310
+ label: "Settings",
20311
+ enabled: true,
20312
+ icon: "settings",
20313
+ uiPosition: "sidebar-bottom"
20314
+ },
20315
+ {
20316
+ id: "settings.account",
20317
+ label: "Account",
20318
+ enabled: true,
20319
+ path: "/settings/account"
20320
+ },
20321
+ {
20322
+ id: "settings.appearance",
20323
+ label: "Appearance",
20324
+ enabled: true,
20325
+ path: "/settings/appearance"
20326
+ },
20327
+ {
20328
+ id: "settings.organization",
20329
+ label: "Organization",
20330
+ enabled: true,
20331
+ path: "/settings/organization"
20332
+ },
20333
+ {
20334
+ id: "settings.credentials",
20335
+ label: "Credentials",
20336
+ enabled: true,
20337
+ path: "/settings/credentials"
20338
+ },
20339
+ {
20340
+ id: "settings.api-keys",
20341
+ label: "API Keys",
20342
+ enabled: true,
20343
+ path: "/settings/api-keys"
20344
+ },
20345
+ {
20346
+ id: "settings.webhooks",
20347
+ label: "Webhooks",
20348
+ enabled: true,
20349
+ path: "/settings/webhooks"
20735
20350
  },
20736
20351
  {
20737
- id: SEO_FEATURE_ID,
20352
+ id: "settings.deployments",
20353
+ label: "Deployments",
20354
+ enabled: true,
20355
+ path: "/settings/deployments"
20356
+ },
20357
+ {
20358
+ id: "admin",
20359
+ label: "Admin",
20360
+ enabled: true,
20361
+ path: "/admin",
20362
+ icon: "settings",
20363
+ uiPosition: "sidebar-bottom",
20364
+ requiresAdmin: true
20365
+ },
20366
+ {
20367
+ id: "admin.system-health",
20368
+ label: "System Health",
20369
+ enabled: true,
20370
+ path: "/admin/system-health"
20371
+ },
20372
+ {
20373
+ id: "admin.organizations",
20374
+ label: "Organizations",
20375
+ enabled: true,
20376
+ path: "/admin/organizations"
20377
+ },
20378
+ {
20379
+ id: "admin.users",
20380
+ label: "Users",
20381
+ enabled: true,
20382
+ path: "/admin/users"
20383
+ },
20384
+ {
20385
+ id: "admin.design-showcase",
20386
+ label: "Design Showcase",
20387
+ enabled: true,
20388
+ path: "/admin/design-showcase"
20389
+ },
20390
+ {
20391
+ id: "admin.debug",
20392
+ label: "Debug",
20393
+ enabled: true,
20394
+ path: "/admin/debug"
20395
+ },
20396
+ {
20397
+ id: "archive",
20398
+ label: "Archive",
20399
+ enabled: true,
20400
+ path: "/archive",
20401
+ icon: "archive",
20402
+ uiPosition: "sidebar-bottom",
20403
+ devOnly: true
20404
+ },
20405
+ {
20406
+ id: "archive.agent-chat",
20407
+ label: "Agent Chat",
20408
+ enabled: true,
20409
+ path: "/archive/agent-chat"
20410
+ },
20411
+ {
20412
+ id: "archive.execution-runner",
20413
+ label: "Execution Runner",
20414
+ enabled: true,
20415
+ path: "/archive/execution-runner"
20416
+ },
20417
+ {
20418
+ id: "seo",
20738
20419
  label: "SEO",
20739
20420
  enabled: false,
20740
- entityIds: [],
20741
- surfaceIds: [],
20742
- resourceIds: [],
20743
- capabilityIds: []
20421
+ path: "/seo"
20744
20422
  }
20745
20423
  ],
20746
20424
  branding: DEFAULT_ORGANIZATION_MODEL_BRANDING,
20747
- navigation: DEFAULT_ORGANIZATION_MODEL_NAVIGATION,
20425
+ navigation: { surfaces: [], groups: [] },
20748
20426
  sales: DEFAULT_ORGANIZATION_MODEL_SALES,
20749
20427
  prospecting: DEFAULT_ORGANIZATION_MODEL_PROSPECTING,
20750
20428
  projects: DEFAULT_ORGANIZATION_MODEL_PROJECTS,
@@ -20754,8 +20432,7 @@ var DEFAULT_ORGANIZATION_MODEL = {
20754
20432
  roles: DEFAULT_ORGANIZATION_MODEL_ROLES,
20755
20433
  goals: DEFAULT_ORGANIZATION_MODEL_GOALS,
20756
20434
  statuses: DEFAULT_ORGANIZATION_MODEL_STATUSES,
20757
- operations: DEFAULT_ORGANIZATION_MODEL_OPERATIONS,
20758
- resourceMappings: []
20435
+ operations: DEFAULT_ORGANIZATION_MODEL_OPERATIONS
20759
20436
  };
20760
20437
 
20761
20438
  // src/organization-model/resolve.ts
@@ -20780,25 +20457,8 @@ function deepMerge2(base, override) {
20780
20457
  }
20781
20458
  return result;
20782
20459
  }
20783
- function normalizeInheritedNavigationGroups(model, override) {
20784
- if (override?.navigation?.surfaces === void 0 || override.navigation.groups !== void 0) {
20785
- return model;
20786
- }
20787
- const validSurfaceIds = new Set(model.navigation.surfaces.map((surface) => surface.id));
20788
- const groups = model.navigation.groups.map((group) => ({
20789
- ...group,
20790
- surfaceIds: group.surfaceIds.filter((surfaceId) => validSurfaceIds.has(surfaceId))
20791
- })).filter((group) => group.surfaceIds.length > 0);
20792
- return {
20793
- ...model,
20794
- navigation: {
20795
- ...model.navigation,
20796
- groups
20797
- }
20798
- };
20799
- }
20800
20460
  function resolveOrganizationModel(override) {
20801
- const merged = normalizeInheritedNavigationGroups(deepMerge2(DEFAULT_ORGANIZATION_MODEL, override), override);
20461
+ const merged = deepMerge2(DEFAULT_ORGANIZATION_MODEL, override);
20802
20462
  return OrganizationModelSchema.parse(merged);
20803
20463
  }
20804
20464