@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.
- package/dist/index.d.ts +69 -159
- package/dist/index.js +324 -613
- package/dist/organization-model/index.d.ts +69 -159
- package/dist/organization-model/index.js +324 -613
- package/dist/test-utils/index.d.ts +192 -45
- package/dist/test-utils/index.js +260 -600
- package/package.json +1 -1
- package/src/__tests__/template-core-compatibility.test.ts +73 -91
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +94 -182
- package/src/auth/multi-tenancy/index.ts +20 -17
- package/src/auth/multi-tenancy/memberships/api-schemas.ts +142 -126
- package/src/auth/multi-tenancy/memberships/index.ts +26 -22
- package/src/auth/multi-tenancy/permissions.test.ts +42 -0
- package/src/auth/multi-tenancy/permissions.ts +104 -0
- package/src/organization-model/README.md +102 -97
- package/src/organization-model/__tests__/defaults.test.ts +19 -6
- package/src/organization-model/__tests__/domains/resource-mappings.test.ts +24 -93
- package/src/organization-model/__tests__/graph.test.ts +82 -894
- package/src/organization-model/__tests__/resolve.test.ts +59 -690
- package/src/organization-model/__tests__/schema.test.ts +83 -407
- package/src/organization-model/contracts.ts +4 -3
- package/src/organization-model/defaults.ts +277 -141
- package/src/organization-model/domains/features.ts +31 -22
- package/src/organization-model/domains/navigation.ts +27 -20
- package/src/organization-model/foundation.ts +42 -54
- package/src/organization-model/graph/build.ts +42 -217
- package/src/organization-model/graph/index.ts +4 -4
- package/src/organization-model/graph/link.ts +10 -0
- package/src/organization-model/graph/schema.ts +21 -16
- package/src/organization-model/graph/types.ts +10 -10
- package/src/organization-model/helpers.ts +74 -0
- package/src/organization-model/index.ts +7 -7
- package/src/organization-model/organization-graph.mdx +89 -272
- package/src/organization-model/organization-model.mdx +152 -320
- package/src/organization-model/published.ts +20 -19
- package/src/organization-model/resolve.ts +8 -33
- package/src/organization-model/schema.ts +63 -205
- package/src/organization-model/types.ts +12 -11
- package/src/platform/constants/versions.ts +3 -3
- package/src/platform/registry/__tests__/command-view.test.ts +6 -5
- package/src/platform/registry/__tests__/resource-link.test.ts +30 -0
- package/src/platform/registry/__tests__/resource-registry.integration.test.ts +15 -15
- package/src/platform/registry/command-view.ts +10 -12
- package/src/platform/registry/index.ts +93 -93
- package/src/platform/registry/resource-link.ts +32 -0
- package/src/platform/registry/resource-registry.ts +917 -876
- package/src/platform/registry/serialization.ts +56 -73
- package/src/platform/registry/serialized-types.ts +17 -12
- package/src/platform/registry/types.ts +14 -43
- package/src/reference/_generated/contracts.md +94 -182
- package/src/reference/glossary.md +71 -105
- package/src/scaffold-registry/__tests__/index.test.ts +125 -1
- package/src/scaffold-registry/__tests__/schema.test.ts +48 -20
- package/src/scaffold-registry/index.ts +236 -188
- package/src/scaffold-registry/schema.ts +47 -22
- package/src/supabase/database.types.ts +2880 -2719
- package/src/test-utils/fixtures/memberships.ts +82 -80
- package/src/platform/registry/domains.ts +0 -165
|
@@ -73,7 +73,7 @@ function ensureResourceNode(
|
|
|
73
73
|
})
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
type CommandViewResource =
|
|
76
|
+
type CommandViewResource =
|
|
77
77
|
| CommandViewData['workflows'][number]
|
|
78
78
|
| CommandViewData['agents'][number]
|
|
79
79
|
| CommandViewData['triggers'][number]
|
|
@@ -87,7 +87,7 @@ function normalizeCommandViewResourceType(
|
|
|
87
87
|
return resourceType === 'human' ? 'human_checkpoint' : resourceType
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
function collectCommandViewResources(commandViewData: CommandViewData): CommandViewResource[] {
|
|
90
|
+
function collectCommandViewResources(commandViewData: CommandViewData): CommandViewResource[] {
|
|
91
91
|
return [
|
|
92
92
|
...commandViewData.workflows,
|
|
93
93
|
...commandViewData.agents,
|
|
@@ -95,8 +95,24 @@ function collectCommandViewResources(commandViewData: CommandViewData): CommandV
|
|
|
95
95
|
...commandViewData.integrations,
|
|
96
96
|
...commandViewData.externalResources,
|
|
97
97
|
...commandViewData.humanCheckpoints
|
|
98
|
-
]
|
|
99
|
-
}
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function pushResourceLinks(
|
|
102
|
+
edges: OrganizationGraphEdge[],
|
|
103
|
+
edgeIds: Set<string>,
|
|
104
|
+
resourceNodeId: string,
|
|
105
|
+
links: CommandViewResource['links'] | undefined
|
|
106
|
+
): void {
|
|
107
|
+
for (const link of links ?? []) {
|
|
108
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
109
|
+
id: edgeId(link.kind, resourceNodeId, link.nodeId),
|
|
110
|
+
kind: link.kind,
|
|
111
|
+
sourceId: resourceNodeId,
|
|
112
|
+
targetId: link.nodeId
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
}
|
|
100
116
|
|
|
101
117
|
export function buildOrganizationGraph(input: BuildOrganizationGraphInput): OrganizationGraph {
|
|
102
118
|
const parsed = BuildOrganizationGraphInputSchema.parse(input)
|
|
@@ -116,34 +132,8 @@ export function buildOrganizationGraph(input: BuildOrganizationGraphInput): Orga
|
|
|
116
132
|
}
|
|
117
133
|
pushUniqueNode(nodes, nodeIds, organizationNode)
|
|
118
134
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
for (const feature of organizationModel.features) {
|
|
122
|
-
featureMap.set(feature.id, feature)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const surfaceMap = new Map<string, (typeof organizationModel.navigation.surfaces)[number]>()
|
|
126
|
-
for (const surface of organizationModel.navigation.surfaces) {
|
|
127
|
-
surfaceMap.set(surface.id, surface)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const entityIds = new Set<string>()
|
|
131
|
-
const capabilityIds = new Set<string>()
|
|
132
|
-
const resourceMappings = [...organizationModel.resourceMappings].sort((a, b) =>
|
|
133
|
-
a.resourceId.localeCompare(b.resourceId)
|
|
134
|
-
)
|
|
135
|
-
for (const resourceMapping of resourceMappings) {
|
|
136
|
-
for (const entityId of resourceMapping.entityIds) {
|
|
137
|
-
entityIds.add(entityId)
|
|
138
|
-
}
|
|
139
|
-
for (const capabilityId of resourceMapping.capabilityIds) {
|
|
140
|
-
capabilityIds.add(capabilityId)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Unified feature loop: creates feature nodes with semantic data (replaces old feature + domain loops)
|
|
145
|
-
for (const feature of [...organizationModel.features].sort((a, b) => a.id.localeCompare(b.id))) {
|
|
146
|
-
const id = nodeId('feature', feature.id)
|
|
135
|
+
for (const feature of [...organizationModel.features].sort((a, b) => a.id.localeCompare(b.id))) {
|
|
136
|
+
const id = nodeId('feature', feature.id)
|
|
147
137
|
pushUniqueNode(nodes, nodeIds, {
|
|
148
138
|
id,
|
|
149
139
|
kind: 'feature',
|
|
@@ -157,173 +147,18 @@ export function buildOrganizationGraph(input: BuildOrganizationGraphInput): Orga
|
|
|
157
147
|
id: edgeId('contains', organizationNode.id, id),
|
|
158
148
|
kind: 'contains',
|
|
159
149
|
sourceId: organizationNode.id,
|
|
160
|
-
targetId: id
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
173
|
-
id: edgeId('references', id, nodeId('surface', surface.id)),
|
|
174
|
-
kind: 'references',
|
|
175
|
-
sourceId: id,
|
|
176
|
-
targetId: nodeId('surface', surface.id)
|
|
177
|
-
})
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
for (const surface of [...organizationModel.navigation.surfaces].sort((a, b) => a.id.localeCompare(b.id))) {
|
|
183
|
-
const id = nodeId('surface', surface.id)
|
|
184
|
-
pushUniqueNode(nodes, nodeIds, {
|
|
185
|
-
id,
|
|
186
|
-
kind: 'surface',
|
|
187
|
-
label: surface.label,
|
|
188
|
-
sourceId: surface.id,
|
|
189
|
-
description: surface.description,
|
|
190
|
-
surfaceType: surface.surfaceType
|
|
191
|
-
})
|
|
192
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
193
|
-
id: edgeId('contains', organizationNode.id, id),
|
|
194
|
-
kind: 'contains',
|
|
195
|
-
sourceId: organizationNode.id,
|
|
196
|
-
targetId: id
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
if (surface.featureId) {
|
|
200
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
201
|
-
id: edgeId('exposes', nodeId('feature', surface.featureId), id),
|
|
202
|
-
kind: 'exposes',
|
|
203
|
-
sourceId: nodeId('feature', surface.featureId),
|
|
204
|
-
targetId: id
|
|
205
|
-
})
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
for (const featureId of surface.featureIds) {
|
|
209
|
-
if (featureMap.has(featureId)) {
|
|
210
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
211
|
-
id: edgeId('references', id, nodeId('feature', featureId)),
|
|
212
|
-
kind: 'references',
|
|
213
|
-
sourceId: id,
|
|
214
|
-
targetId: nodeId('feature', featureId)
|
|
215
|
-
})
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
for (const entityId of surface.entityIds) {
|
|
220
|
-
entityIds.add(entityId)
|
|
221
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
222
|
-
id: edgeId('references', id, nodeId('entity', entityId)),
|
|
223
|
-
kind: 'references',
|
|
224
|
-
sourceId: id,
|
|
225
|
-
targetId: nodeId('entity', entityId)
|
|
226
|
-
})
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
for (const capabilityId of surface.capabilityIds) {
|
|
230
|
-
capabilityIds.add(capabilityId)
|
|
231
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
232
|
-
id: edgeId('references', id, nodeId('capability', capabilityId)),
|
|
233
|
-
kind: 'references',
|
|
234
|
-
sourceId: id,
|
|
235
|
-
targetId: nodeId('capability', capabilityId)
|
|
236
|
-
})
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
for (const entityId of [...entityIds].sort()) {
|
|
241
|
-
pushUniqueNode(nodes, nodeIds, {
|
|
242
|
-
id: nodeId('entity', entityId),
|
|
243
|
-
kind: 'entity',
|
|
244
|
-
label: entityId,
|
|
245
|
-
sourceId: entityId
|
|
246
|
-
})
|
|
247
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
248
|
-
id: edgeId('contains', organizationNode.id, nodeId('entity', entityId)),
|
|
249
|
-
kind: 'contains',
|
|
250
|
-
sourceId: organizationNode.id,
|
|
251
|
-
targetId: nodeId('entity', entityId)
|
|
252
|
-
})
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
for (const capabilityId of [...capabilityIds].sort()) {
|
|
256
|
-
pushUniqueNode(nodes, nodeIds, {
|
|
257
|
-
id: nodeId('capability', capabilityId),
|
|
258
|
-
kind: 'capability',
|
|
259
|
-
label: capabilityId,
|
|
260
|
-
sourceId: capabilityId
|
|
261
|
-
})
|
|
262
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
263
|
-
id: edgeId('contains', organizationNode.id, nodeId('capability', capabilityId)),
|
|
264
|
-
kind: 'contains',
|
|
265
|
-
sourceId: organizationNode.id,
|
|
266
|
-
targetId: nodeId('capability', capabilityId)
|
|
267
|
-
})
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
for (const resourceMapping of resourceMappings) {
|
|
271
|
-
const id = nodeId('resource', resourceMapping.resourceId)
|
|
272
|
-
upsertResourceNode(nodes, nodeIds, resourceNodesById, {
|
|
273
|
-
id,
|
|
274
|
-
kind: 'resource',
|
|
275
|
-
label: resourceMapping.label,
|
|
276
|
-
sourceId: resourceMapping.resourceId,
|
|
277
|
-
description: resourceMapping.description,
|
|
278
|
-
resourceType: resourceMapping.resourceType
|
|
279
|
-
})
|
|
280
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
281
|
-
id: edgeId('contains', organizationNode.id, id),
|
|
282
|
-
kind: 'contains',
|
|
283
|
-
sourceId: organizationNode.id,
|
|
284
|
-
targetId: id
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
for (const featureId of resourceMapping.featureIds) {
|
|
288
|
-
if (featureMap.has(featureId)) {
|
|
289
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
290
|
-
id: edgeId('maps_to', id, nodeId('feature', featureId)),
|
|
291
|
-
kind: 'maps_to',
|
|
292
|
-
sourceId: id,
|
|
293
|
-
targetId: nodeId('feature', featureId)
|
|
294
|
-
})
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
for (const entityId of resourceMapping.entityIds) {
|
|
299
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
300
|
-
id: edgeId('maps_to', id, nodeId('entity', entityId)),
|
|
301
|
-
kind: 'maps_to',
|
|
302
|
-
sourceId: id,
|
|
303
|
-
targetId: nodeId('entity', entityId)
|
|
304
|
-
})
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
for (const surfaceId of resourceMapping.surfaceIds) {
|
|
308
|
-
if (surfaceMap.has(surfaceId)) {
|
|
309
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
310
|
-
id: edgeId('maps_to', id, nodeId('surface', surfaceId)),
|
|
311
|
-
kind: 'maps_to',
|
|
312
|
-
sourceId: id,
|
|
313
|
-
targetId: nodeId('surface', surfaceId)
|
|
314
|
-
})
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
for (const capabilityId of resourceMapping.capabilityIds) {
|
|
319
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
320
|
-
id: edgeId('maps_to', id, nodeId('capability', capabilityId)),
|
|
321
|
-
kind: 'maps_to',
|
|
322
|
-
sourceId: id,
|
|
323
|
-
targetId: nodeId('capability', capabilityId)
|
|
324
|
-
})
|
|
325
|
-
}
|
|
326
|
-
}
|
|
150
|
+
targetId: id
|
|
151
|
+
})
|
|
152
|
+
const parentId = feature.id.includes('.') ? feature.id.slice(0, feature.id.lastIndexOf('.')) : undefined
|
|
153
|
+
if (parentId) {
|
|
154
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
155
|
+
id: edgeId('contains', nodeId('feature', parentId), id),
|
|
156
|
+
kind: 'contains',
|
|
157
|
+
sourceId: nodeId('feature', parentId),
|
|
158
|
+
targetId: id
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
}
|
|
327
162
|
|
|
328
163
|
if (commandViewData) {
|
|
329
164
|
const commandViewResources = collectCommandViewResources(commandViewData).sort((a, b) =>
|
|
@@ -341,24 +176,14 @@ export function buildOrganizationGraph(input: BuildOrganizationGraphInput): Orga
|
|
|
341
176
|
resourceType: normalizeCommandViewResourceType(resource.type)
|
|
342
177
|
})
|
|
343
178
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
pushUniqueEdge(edges, edgeIds, {
|
|
356
|
-
id: edgeId('contains', organizationNode.id, resourceNode.id),
|
|
357
|
-
kind: 'contains',
|
|
358
|
-
sourceId: organizationNode.id,
|
|
359
|
-
targetId: resourceNode.id
|
|
360
|
-
})
|
|
361
|
-
}
|
|
179
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
180
|
+
id: edgeId('contains', organizationNode.id, resourceNode.id),
|
|
181
|
+
kind: 'contains',
|
|
182
|
+
sourceId: organizationNode.id,
|
|
183
|
+
targetId: resourceNode.id
|
|
184
|
+
})
|
|
185
|
+
pushResourceLinks(edges, edgeIds, resourceNode.id, resource.links)
|
|
186
|
+
}
|
|
362
187
|
|
|
363
188
|
for (const relationship of [...commandViewData.edges].sort((a, b) => a.id.localeCompare(b.id))) {
|
|
364
189
|
const sourceNode = ensureResourceNode(nodes, nodeIds, resourceNodesById, relationship.source)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from './types'
|
|
2
|
-
export * from './schema'
|
|
3
|
-
export * from './build'
|
|
4
|
-
|
|
1
|
+
export * from './types'
|
|
2
|
+
export * from './schema'
|
|
3
|
+
export * from './build'
|
|
4
|
+
export * from './link'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { NodeIdStringSchema } from '../domains/features'
|
|
3
|
+
import { OrganizationGraphEdgeKindSchema } from './schema'
|
|
4
|
+
|
|
5
|
+
export const LinkSchema = z.object({
|
|
6
|
+
nodeId: NodeIdStringSchema,
|
|
7
|
+
kind: OrganizationGraphEdgeKindSchema
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export type Link = z.infer<typeof LinkSchema>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
import { DescriptionSchema, LabelSchema
|
|
3
|
-
import {
|
|
4
|
-
import { OrganizationModelSchema } from '../schema'
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { DescriptionSchema, LabelSchema } from '../domains/shared'
|
|
3
|
+
import { OrganizationModelSchema } from '../schema'
|
|
5
4
|
|
|
6
5
|
export const OrganizationGraphNodeKindSchema = z.enum([
|
|
7
6
|
'organization',
|
|
@@ -12,19 +11,25 @@ export const OrganizationGraphNodeKindSchema = z.enum([
|
|
|
12
11
|
'resource'
|
|
13
12
|
])
|
|
14
13
|
|
|
15
|
-
export const OrganizationGraphEdgeKindSchema = z.enum([
|
|
14
|
+
export const OrganizationGraphEdgeKindSchema = z.enum([
|
|
15
|
+
'contains',
|
|
16
|
+
'references',
|
|
17
|
+
'exposes',
|
|
18
|
+
'maps_to',
|
|
19
|
+
'operates-on',
|
|
20
|
+
'uses'
|
|
21
|
+
])
|
|
16
22
|
|
|
17
|
-
export const OrganizationGraphNodeSchema = z.object({
|
|
18
|
-
id: z.string().trim().min(1).max(200),
|
|
19
|
-
kind: OrganizationGraphNodeKindSchema,
|
|
20
|
-
label: LabelSchema,
|
|
21
|
-
sourceId: z.string().trim().min(1).max(255).optional(),
|
|
22
|
-
description: DescriptionSchema.optional(),
|
|
23
|
-
enabled: z.boolean().optional(),
|
|
24
|
-
featureId:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
})
|
|
23
|
+
export const OrganizationGraphNodeSchema = z.object({
|
|
24
|
+
id: z.string().trim().min(1).max(200),
|
|
25
|
+
kind: OrganizationGraphNodeKindSchema,
|
|
26
|
+
label: LabelSchema,
|
|
27
|
+
sourceId: z.string().trim().min(1).max(255).optional(),
|
|
28
|
+
description: DescriptionSchema.optional(),
|
|
29
|
+
enabled: z.boolean().optional(),
|
|
30
|
+
featureId: z.string().trim().min(1).max(100).optional(),
|
|
31
|
+
resourceType: z.enum(['workflow', 'agent', 'trigger', 'integration', 'external', 'human_checkpoint']).optional()
|
|
32
|
+
})
|
|
28
33
|
|
|
29
34
|
export const OrganizationGraphEdgeSchema = z.object({
|
|
30
35
|
id: z.string().trim().min(1).max(250),
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import type { CommandViewData } from '../../platform/registry/command-view'
|
|
2
|
-
import type { OrganizationModel
|
|
3
|
-
import type { RelationshipType } from '../../platform/registry/command-view'
|
|
1
|
+
import type { CommandViewData } from '../../platform/registry/command-view'
|
|
2
|
+
import type { OrganizationModel } from '../types'
|
|
3
|
+
import type { RelationshipType } from '../../platform/registry/command-view'
|
|
4
4
|
|
|
5
5
|
export type OrganizationGraphNodeKind = 'organization' | 'feature' | 'surface' | 'entity' | 'capability' | 'resource'
|
|
6
6
|
|
|
7
|
-
export type OrganizationGraphEdgeKind = 'contains' | 'references' | 'exposes' | 'maps_to'
|
|
7
|
+
export type OrganizationGraphEdgeKind = 'contains' | 'references' | 'exposes' | 'maps_to' | 'operates-on' | 'uses'
|
|
8
|
+
export type { Link } from './link'
|
|
8
9
|
|
|
9
10
|
export interface OrganizationGraphNode {
|
|
10
11
|
id: string
|
|
11
12
|
kind: OrganizationGraphNodeKind
|
|
12
13
|
label: string
|
|
13
14
|
sourceId?: string
|
|
14
|
-
description?: string
|
|
15
|
-
enabled?: boolean
|
|
16
|
-
featureId?: string
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
15
|
+
description?: string
|
|
16
|
+
enabled?: boolean
|
|
17
|
+
featureId?: string
|
|
18
|
+
resourceType?: 'workflow' | 'agent' | 'trigger' | 'integration' | 'external' | 'human_checkpoint'
|
|
19
|
+
}
|
|
20
20
|
|
|
21
21
|
export interface OrganizationGraphEdge {
|
|
22
22
|
id: string
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { OrganizationModelFeature } from './types'
|
|
2
|
+
|
|
3
|
+
export function defaultPathFor(id: string): string {
|
|
4
|
+
return `/${id.replaceAll('.', '/')}`
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function parentIdOf(id: string): string | undefined {
|
|
8
|
+
const index = id.lastIndexOf('.')
|
|
9
|
+
return index === -1 ? undefined : id.slice(0, index)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function findById(features: readonly OrganizationModelFeature[], id: string): OrganizationModelFeature | undefined {
|
|
13
|
+
return features.find((feature) => feature.id === id)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function findByPath(
|
|
17
|
+
features: readonly OrganizationModelFeature[],
|
|
18
|
+
path: string
|
|
19
|
+
): OrganizationModelFeature | undefined {
|
|
20
|
+
return features.find((feature) => (feature.path ?? defaultPathFor(feature.id)) === path)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function childrenOf(
|
|
24
|
+
features: readonly OrganizationModelFeature[],
|
|
25
|
+
id: string
|
|
26
|
+
): OrganizationModelFeature[] {
|
|
27
|
+
const prefix = `${id}.`
|
|
28
|
+
return features.filter((feature) => feature.id.startsWith(prefix) && !feature.id.slice(prefix.length).includes('.'))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function topLevel(features: readonly OrganizationModelFeature[]): OrganizationModelFeature[] {
|
|
32
|
+
return features.filter((feature) => !feature.id.includes('.'))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function ancestorsOf(
|
|
36
|
+
features: readonly OrganizationModelFeature[],
|
|
37
|
+
id: string
|
|
38
|
+
): OrganizationModelFeature[] {
|
|
39
|
+
const segments = id.split('.')
|
|
40
|
+
const ids = segments.map((_, index) => segments.slice(0, index + 1).join('.'))
|
|
41
|
+
return ids.map((ancestorId) => findById(features, ancestorId)).filter((feature): feature is OrganizationModelFeature => Boolean(feature))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function parentOf(
|
|
45
|
+
features: readonly OrganizationModelFeature[],
|
|
46
|
+
id: string
|
|
47
|
+
): OrganizationModelFeature | undefined {
|
|
48
|
+
const parentId = parentIdOf(id)
|
|
49
|
+
return parentId ? findById(features, parentId) : undefined
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function inheritedValue<T>(
|
|
53
|
+
features: readonly OrganizationModelFeature[],
|
|
54
|
+
id: string,
|
|
55
|
+
getValue: (feature: OrganizationModelFeature) => T | undefined
|
|
56
|
+
): T | undefined {
|
|
57
|
+
return ancestorsOf(features, id)
|
|
58
|
+
.slice()
|
|
59
|
+
.reverse()
|
|
60
|
+
.map(getValue)
|
|
61
|
+
.find((value): value is T => value !== undefined)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function uiPositionFor(features: readonly OrganizationModelFeature[], id: string) {
|
|
65
|
+
return inheritedValue(features, id, (feature) => feature.uiPosition)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function requiresAdminFor(features: readonly OrganizationModelFeature[], id: string): boolean {
|
|
69
|
+
return inheritedValue(features, id, (feature) => feature.requiresAdmin) ?? false
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function devOnlyFor(features: readonly OrganizationModelFeature[], id: string): boolean {
|
|
73
|
+
return inheritedValue(features, id, (feature) => feature.devOnly) ?? false
|
|
74
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export * from './schema'
|
|
2
2
|
export * from './types'
|
|
3
3
|
export * from './contracts'
|
|
4
|
-
export * from './defaults'
|
|
5
|
-
export * from './resolve'
|
|
6
|
-
export * from './foundation'
|
|
7
|
-
export * from './
|
|
4
|
+
export * from './defaults'
|
|
5
|
+
export * from './resolve'
|
|
6
|
+
export * from './foundation'
|
|
7
|
+
export * from './helpers'
|
|
8
|
+
export * from './graph'
|
|
8
9
|
export * from './domains/branding'
|
|
9
10
|
export * from './domains/sales'
|
|
10
11
|
export * from './domains/projects'
|
|
11
|
-
export * from './domains/features'
|
|
12
|
-
export * from './domains/prospecting'
|
|
13
|
-
export * from './domains/navigation'
|
|
12
|
+
export * from './domains/features'
|
|
13
|
+
export * from './domains/prospecting'
|