@elevasis/core 0.34.1 → 0.35.0
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/auth/index.d.ts +74 -2
- package/dist/auth/index.js +65 -30
- package/dist/index.d.ts +60 -2
- package/dist/index.js +52 -1
- package/dist/knowledge/index.d.ts +12 -0
- package/dist/organization-model/index.d.ts +60 -2
- package/dist/organization-model/index.js +52 -1
- package/dist/test-utils/index.d.ts +12 -0
- package/dist/test-utils/index.js +51 -0
- package/package.json +1 -1
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +69 -30
- package/src/auth/multi-tenancy/index.ts +29 -26
- package/src/auth/multi-tenancy/org-id.test.ts +139 -0
- package/src/auth/multi-tenancy/org-id.ts +112 -0
- package/src/business/acquisition/api-schemas.test.ts +456 -28
- package/src/business/acquisition/ontology-validation.ts +715 -23
- package/src/execution/engine/tools/platform/storage/__tests__/storage.test.ts +997 -998
- package/src/organization-model/__tests__/domains/systems.test.ts +61 -15
- package/src/organization-model/__tests__/domains/topology.test.ts +23 -0
- package/src/organization-model/__tests__/schema.test.ts +112 -0
- package/src/organization-model/domains/systems.ts +44 -0
- package/src/organization-model/domains/topology.ts +18 -1
- package/src/organization-model/published.ts +19 -1
- package/src/organization-model/schema-refinements.ts +23 -0
- package/src/organization-model/types.ts +17 -1
- package/src/platform/constants/versions.ts +1 -1
- package/src/platform/registry/__tests__/validation.test.ts +254 -15
- package/src/platform/registry/index.ts +28 -15
- package/src/platform/registry/validation.ts +180 -2
- package/src/reference/_generated/contracts.md +44 -0
- package/src/supabase/__tests__/helpers.test.ts +92 -51
- package/src/supabase/helpers.ts +40 -20
- package/src/supabase/index.ts +52 -52
|
@@ -992,6 +992,26 @@ var SystemUiSchema = z.object({
|
|
|
992
992
|
icon: IconNameSchema.optional(),
|
|
993
993
|
order: z.number().int().optional()
|
|
994
994
|
});
|
|
995
|
+
var SystemInterfaceKeySchema = ModelIdSchema;
|
|
996
|
+
var SystemInterfaceLifecycleSchema = z.enum(["draft", "active", "disabled", "deprecated", "archived"]).meta({ label: "System interface lifecycle", color: "teal" });
|
|
997
|
+
var SystemInterfaceReadinessProfileSchema = z.string().trim().min(1).max(200).regex(
|
|
998
|
+
/^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*(?:\.[a-z0-9][a-z0-9-]*)?$/,
|
|
999
|
+
'Readiness profiles must use dotted lowercase identifiers (e.g. "sales.lead-gen.api")'
|
|
1000
|
+
);
|
|
1001
|
+
var SystemInterfaceResourceScopeSchema = z.array(ModelIdSchema).default([]);
|
|
1002
|
+
var SystemApiInterfaceSchema = z.object({
|
|
1003
|
+
lifecycle: SystemInterfaceLifecycleSchema.default("active"),
|
|
1004
|
+
readinessProfile: SystemInterfaceReadinessProfileSchema.optional(),
|
|
1005
|
+
/**
|
|
1006
|
+
* Resource ids that participate in this API interface. This scopes readiness
|
|
1007
|
+
* derivation without duplicating authored required/provided contract refs.
|
|
1008
|
+
*/
|
|
1009
|
+
resourceIds: SystemInterfaceResourceScopeSchema.optional()
|
|
1010
|
+
}).strict();
|
|
1011
|
+
var SystemInterfaceRefSchema = z.object({
|
|
1012
|
+
systemPath: SystemPathSchema,
|
|
1013
|
+
interfaceKey: SystemInterfaceKeySchema
|
|
1014
|
+
}).strict();
|
|
995
1015
|
var JsonValueSchema = z.lazy(
|
|
996
1016
|
() => z.union([
|
|
997
1017
|
z.string(),
|
|
@@ -1030,6 +1050,8 @@ var SystemEntrySchema = z.object({
|
|
|
1030
1050
|
policies: z.array(ModelIdSchema.meta({ ref: "policy" })).default([]).optional(),
|
|
1031
1051
|
/** Optional goals this system contributes to. */
|
|
1032
1052
|
drivesGoals: z.array(ModelIdSchema.meta({ ref: "goal" })).default([]).optional(),
|
|
1053
|
+
/** Thin API runtime-boundary marker. Readiness is derived from scoped resources and topology. */
|
|
1054
|
+
apiInterface: SystemApiInterfaceSchema.optional(),
|
|
1033
1055
|
/** @deprecated Use lifecycle. Accepted for one publish cycle. */
|
|
1034
1056
|
status: SystemStatusSchema.optional(),
|
|
1035
1057
|
/** @deprecated Use ui.path. Kept for one-cycle Feature compatibility. */
|
|
@@ -1508,6 +1530,15 @@ var OmTopologyMetadataSchema = z.record(z.string().trim().min(1).max(120), JsonV
|
|
|
1508
1530
|
}
|
|
1509
1531
|
visit(metadata, []);
|
|
1510
1532
|
});
|
|
1533
|
+
var OmTopologySystemInterfaceGrantSchema = z.object({
|
|
1534
|
+
consumer: SystemInterfaceRefSchema,
|
|
1535
|
+
provider: SystemInterfaceRefSchema,
|
|
1536
|
+
resourceIds: z.array(ResourceIdSchema).default([]),
|
|
1537
|
+
ontologyIds: z.array(OntologyIdSchema).default([])
|
|
1538
|
+
}).strict();
|
|
1539
|
+
var OmTopologySystemInterfaceGrantMetadataSchema = z.object({
|
|
1540
|
+
systemInterfaceGrant: OmTopologySystemInterfaceGrantSchema
|
|
1541
|
+
}).strict();
|
|
1511
1542
|
var OmTopologyRelationshipSchema = z.object({
|
|
1512
1543
|
from: OmTopologyNodeRefSchema,
|
|
1513
1544
|
kind: OmTopologyRelationshipKindSchema,
|
|
@@ -2247,6 +2278,26 @@ function refineOrganizationModel(model, ctx) {
|
|
|
2247
2278
|
);
|
|
2248
2279
|
}
|
|
2249
2280
|
});
|
|
2281
|
+
allSystems.forEach(({ path: systemPath, schemaPath, system }) => {
|
|
2282
|
+
system.apiInterface?.resourceIds?.forEach((resourceId, resourceIndex) => {
|
|
2283
|
+
const resource = resourcesById.get(resourceId);
|
|
2284
|
+
if (resource === void 0) {
|
|
2285
|
+
addIssue(
|
|
2286
|
+
ctx,
|
|
2287
|
+
[...schemaPath, "apiInterface", "resourceIds", resourceIndex],
|
|
2288
|
+
`System Interface "${systemPath}/api" scopes unknown resource "${resourceId}"`
|
|
2289
|
+
);
|
|
2290
|
+
return;
|
|
2291
|
+
}
|
|
2292
|
+
if (resource.systemPath !== systemPath) {
|
|
2293
|
+
addIssue(
|
|
2294
|
+
ctx,
|
|
2295
|
+
[...schemaPath, "apiInterface", "resourceIds", resourceIndex],
|
|
2296
|
+
`System Interface "${systemPath}/api" scopes resource "${resourceId}" from system "${resource.systemPath}"`
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
});
|
|
2300
|
+
});
|
|
2250
2301
|
function validateResourceOntologyBinding(resourceId, bindingKey, expectedKind, ids) {
|
|
2251
2302
|
const ontologyIds2 = ids === void 0 ? [] : Array.isArray(ids) ? ids : [ids];
|
|
2252
2303
|
ontologyIds2.forEach((ontologyId, ontologyIndex) => {
|
|
@@ -3406,4 +3457,4 @@ function scaffoldOrganizationModel(model, spec) {
|
|
|
3406
3457
|
return scaffoldKnowledgeNode(model, spec);
|
|
3407
3458
|
}
|
|
3408
3459
|
|
|
3409
|
-
export { ActionIdSchema, ActionInvocationKindSchema, ActionInvocationSchema, ActionRefSchema, ActionSchema, ActionScopeSchema, ActionsDomainSchema, AgentKindSchema, AgentResourceEntrySchema, AgentRoleHolderSchema, ApiEndpointInvocationSchema, CodeReferenceRoleSchema, CodeReferenceSchema, ContractRefSchema, CustomerSegmentSchema, CustomersDomainSchema, DEFAULT_ONTOLOGY_SCOPE, DEFAULT_ORGANIZATION_MODEL, DEFAULT_ORGANIZATION_MODEL_ACTIONS, DEFAULT_ORGANIZATION_MODEL_CUSTOMERS, DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA, DEFAULT_ORGANIZATION_MODEL_GOALS, DEFAULT_ORGANIZATION_MODEL_NAVIGATION, DEFAULT_ORGANIZATION_MODEL_OFFERINGS, DEFAULT_ORGANIZATION_MODEL_POLICIES, DEFAULT_ORGANIZATION_MODEL_RESOURCES, DEFAULT_ORGANIZATION_MODEL_ROLES, DEFAULT_ORGANIZATION_MODEL_STATUSES, DEFAULT_ORGANIZATION_MODEL_SYSTEMS, DEFAULT_ORGANIZATION_MODEL_TOPOLOGY, EntitiesDomainSchema, EntityIdSchema, EntityLinkKindSchema, EntityLinkSchema, EntitySchema, EventDescriptorSchema, EventEmissionDescriptorSchema, EventIdSchema, FirmographicsSchema, GoalsDomainSchema, HumanRoleHolderSchema, IconNameSchema, IntegrationResourceEntrySchema, KNOWLEDGE_FEATURE_ID, KNOWLEDGE_SYSTEM_ID, KeyResultSchema, KnowledgeDomainSchema, KnowledgeLinkSchema, KnowledgeTargetKindSchema, KnowledgeTargetRefSchema, LinkSchema, MONITORING_FEATURE_ID, MONITORING_SYSTEM_ID, McpToolInvocationSchema, NavigationGroupSchema, NodeIdPathSchema, NodeIdStringSchema, OPERATIONS_COMMAND_VIEW_SURFACE_ID, OPERATIONS_FEATURE_ID, OPERATIONS_SYSTEM_ID, ORGANIZATION_MODEL_ICON_TOKENS, ObjectiveSchema, OfferingsDomainSchema, OmTopologyDomainSchema, OmTopologyMetadataSchema, OmTopologyNodeKindSchema, OmTopologyNodeRefSchema, OmTopologyRelationshipKindSchema, OmTopologyRelationshipSchema, OntologyActionTypeSchema, OntologyCatalogTypeSchema, OntologyEventTypeSchema, OntologyGroupSchema, OntologyIdSchema, OntologyInterfaceTypeSchema, OntologyKindSchema, OntologyLinkTypeSchema, OntologyObjectTypeSchema, OntologyScopeSchema, OntologySharedPropertySchema, OntologySurfaceTypeSchema, OntologyValueTypeSchema, OrgKnowledgeKindSchema, OrgKnowledgeNodeSchema, OrganizationModelBuiltinIconTokenSchema, OrganizationModelDomainKeySchema, OrganizationModelDomainMetadataByDomainSchema, OrganizationModelDomainMetadataSchema, OrganizationModelIconTokenSchema, OrganizationModelNavigationSchema, OrganizationModelSchema, PROJECTS_FEATURE_ID, PROJECTS_INDEX_SURFACE_ID, PROJECTS_SYSTEM_ID, PROJECTS_VIEW_ACTION_ID, PROSPECTING_FEATURE_ID, PROSPECTING_LISTS_SURFACE_ID, PROSPECTING_SYSTEM_ID, PoliciesDomainSchema, PolicyApplicabilitySchema, PolicyEffectSchema, PolicyIdSchema, PolicyPredicateSchema, PolicySchema, PolicyTriggerSchema, PricingModelSchema, ProductSchema, ResourceEntrySchema, ResourceGovernanceStatusSchema, ResourceIdSchema, ResourceKindSchema, ResourceOntologyBindingSchema, ResourcesDomainSchema, RoleHolderSchema, RoleHoldersSchema, RoleIdSchema, RoleSchema, RolesDomainSchema, SALES_FEATURE_ID, SALES_PIPELINE_SURFACE_ID, SALES_SYSTEM_ID, SEO_FEATURE_ID, SEO_SYSTEM_ID, SETTINGS_FEATURE_ID, SETTINGS_ROLES_SURFACE_ID, SETTINGS_SYSTEM_ID, ScriptExecutionInvocationSchema, ScriptResourceEntrySchema, ScriptResourceLanguageSchema, ScriptResourceSourceSchema, SidebarNavigationSchema, SidebarNodeSchema, SidebarSectionSchema, SidebarSurfaceTargetsSchema, SlashCommandInvocationSchema, StatusEntrySchema, StatusSemanticClassSchema, StatusesDomainSchema, SurfaceDefinitionSchema, SurfaceTypeSchema, SystemEntrySchema, SystemIdSchema, SystemKindSchema, SystemLifecycleSchema, SystemPathSchema, SystemStatusSchema, SystemUiSchema, SystemsDomainSchema, TeamRoleHolderSchema, TechStackEntrySchema, UiPositionSchema, WorkflowResourceEntrySchema, compileOrganizationOntology, compileTopologyNodeRef, createFoundationOrganizationModel, defineAction, defineActions, defineCustomer, defineCustomers, defineDomainRecord, defineEntities, defineEntity, defineGoal, defineGoals, defineKnowledgeNode, defineKnowledgeNodes, defineOffering, defineOfferings, defineOrganizationModel, definePolicies, definePolicy, defineResource, defineResourceOntology, defineResources, defineRole, defineRoles, defineStatus, defineStatuses, defineSystem, defineSystems, defineTopology, defineTopologyRelationship, findOrganizationActionById, formatOntologyId, getOntologyDiagnostics, getSortedSidebarEntries, isOntologyGraphNodeId, isOntologyTopologyRef, listAllSystems, listResolvedOntologyRecords, ontologyGraphNodeId, ontologyIdFromGraphNodeId, parseContractRef, parseOntologyId, parseTopologyNodeRef, projectOrganizationSurfaces, resolveOrganizationModel, resolveOrganizationModelWithResources, scaffoldOrganizationModel, topologyRef, topologyRelationship, validateOrganizationSurfaceProjection };
|
|
3460
|
+
export { ActionIdSchema, ActionInvocationKindSchema, ActionInvocationSchema, ActionRefSchema, ActionSchema, ActionScopeSchema, ActionsDomainSchema, AgentKindSchema, AgentResourceEntrySchema, AgentRoleHolderSchema, ApiEndpointInvocationSchema, CodeReferenceRoleSchema, CodeReferenceSchema, ContractRefSchema, CustomerSegmentSchema, CustomersDomainSchema, DEFAULT_ONTOLOGY_SCOPE, DEFAULT_ORGANIZATION_MODEL, DEFAULT_ORGANIZATION_MODEL_ACTIONS, DEFAULT_ORGANIZATION_MODEL_CUSTOMERS, DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA, DEFAULT_ORGANIZATION_MODEL_GOALS, DEFAULT_ORGANIZATION_MODEL_NAVIGATION, DEFAULT_ORGANIZATION_MODEL_OFFERINGS, DEFAULT_ORGANIZATION_MODEL_POLICIES, DEFAULT_ORGANIZATION_MODEL_RESOURCES, DEFAULT_ORGANIZATION_MODEL_ROLES, DEFAULT_ORGANIZATION_MODEL_STATUSES, DEFAULT_ORGANIZATION_MODEL_SYSTEMS, DEFAULT_ORGANIZATION_MODEL_TOPOLOGY, EntitiesDomainSchema, EntityIdSchema, EntityLinkKindSchema, EntityLinkSchema, EntitySchema, EventDescriptorSchema, EventEmissionDescriptorSchema, EventIdSchema, FirmographicsSchema, GoalsDomainSchema, HumanRoleHolderSchema, IconNameSchema, IntegrationResourceEntrySchema, KNOWLEDGE_FEATURE_ID, KNOWLEDGE_SYSTEM_ID, KeyResultSchema, KnowledgeDomainSchema, KnowledgeLinkSchema, KnowledgeTargetKindSchema, KnowledgeTargetRefSchema, LinkSchema, MONITORING_FEATURE_ID, MONITORING_SYSTEM_ID, McpToolInvocationSchema, NavigationGroupSchema, NodeIdPathSchema, NodeIdStringSchema, OPERATIONS_COMMAND_VIEW_SURFACE_ID, OPERATIONS_FEATURE_ID, OPERATIONS_SYSTEM_ID, ORGANIZATION_MODEL_ICON_TOKENS, ObjectiveSchema, OfferingsDomainSchema, OmTopologyDomainSchema, OmTopologyMetadataSchema, OmTopologyNodeKindSchema, OmTopologyNodeRefSchema, OmTopologyRelationshipKindSchema, OmTopologyRelationshipSchema, OmTopologySystemInterfaceGrantMetadataSchema, OmTopologySystemInterfaceGrantSchema, OntologyActionTypeSchema, OntologyCatalogTypeSchema, OntologyEventTypeSchema, OntologyGroupSchema, OntologyIdSchema, OntologyInterfaceTypeSchema, OntologyKindSchema, OntologyLinkTypeSchema, OntologyObjectTypeSchema, OntologyScopeSchema, OntologySharedPropertySchema, OntologySurfaceTypeSchema, OntologyValueTypeSchema, OrgKnowledgeKindSchema, OrgKnowledgeNodeSchema, OrganizationModelBuiltinIconTokenSchema, OrganizationModelDomainKeySchema, OrganizationModelDomainMetadataByDomainSchema, OrganizationModelDomainMetadataSchema, OrganizationModelIconTokenSchema, OrganizationModelNavigationSchema, OrganizationModelSchema, PROJECTS_FEATURE_ID, PROJECTS_INDEX_SURFACE_ID, PROJECTS_SYSTEM_ID, PROJECTS_VIEW_ACTION_ID, PROSPECTING_FEATURE_ID, PROSPECTING_LISTS_SURFACE_ID, PROSPECTING_SYSTEM_ID, PoliciesDomainSchema, PolicyApplicabilitySchema, PolicyEffectSchema, PolicyIdSchema, PolicyPredicateSchema, PolicySchema, PolicyTriggerSchema, PricingModelSchema, ProductSchema, ResourceEntrySchema, ResourceGovernanceStatusSchema, ResourceIdSchema, ResourceKindSchema, ResourceOntologyBindingSchema, ResourcesDomainSchema, RoleHolderSchema, RoleHoldersSchema, RoleIdSchema, RoleSchema, RolesDomainSchema, SALES_FEATURE_ID, SALES_PIPELINE_SURFACE_ID, SALES_SYSTEM_ID, SEO_FEATURE_ID, SEO_SYSTEM_ID, SETTINGS_FEATURE_ID, SETTINGS_ROLES_SURFACE_ID, SETTINGS_SYSTEM_ID, ScriptExecutionInvocationSchema, ScriptResourceEntrySchema, ScriptResourceLanguageSchema, ScriptResourceSourceSchema, SidebarNavigationSchema, SidebarNodeSchema, SidebarSectionSchema, SidebarSurfaceTargetsSchema, SlashCommandInvocationSchema, StatusEntrySchema, StatusSemanticClassSchema, StatusesDomainSchema, SurfaceDefinitionSchema, SurfaceTypeSchema, SystemApiInterfaceSchema, SystemEntrySchema, SystemIdSchema, SystemInterfaceKeySchema, SystemInterfaceLifecycleSchema, SystemInterfaceReadinessProfileSchema, SystemInterfaceRefSchema, SystemKindSchema, SystemLifecycleSchema, SystemPathSchema, SystemStatusSchema, SystemUiSchema, SystemsDomainSchema, TeamRoleHolderSchema, TechStackEntrySchema, UiPositionSchema, WorkflowResourceEntrySchema, compileOrganizationOntology, compileTopologyNodeRef, createFoundationOrganizationModel, defineAction, defineActions, defineCustomer, defineCustomers, defineDomainRecord, defineEntities, defineEntity, defineGoal, defineGoals, defineKnowledgeNode, defineKnowledgeNodes, defineOffering, defineOfferings, defineOrganizationModel, definePolicies, definePolicy, defineResource, defineResourceOntology, defineResources, defineRole, defineRoles, defineStatus, defineStatuses, defineSystem, defineSystems, defineTopology, defineTopologyRelationship, findOrganizationActionById, formatOntologyId, getOntologyDiagnostics, getSortedSidebarEntries, isOntologyGraphNodeId, isOntologyTopologyRef, listAllSystems, listResolvedOntologyRecords, ontologyGraphNodeId, ontologyIdFromGraphNodeId, parseContractRef, parseOntologyId, parseTopologyNodeRef, projectOrganizationSurfaces, resolveOrganizationModel, resolveOrganizationModelWithResources, scaffoldOrganizationModel, topologyRef, topologyRelationship, validateOrganizationSurfaceProjection };
|
|
@@ -3739,6 +3739,17 @@ declare const OntologyScopeSchema: z.ZodDefault<z.ZodObject<{
|
|
|
3739
3739
|
}, z.core.$strip>>;
|
|
3740
3740
|
type OntologyScope = z.infer<typeof OntologyScopeSchema>;
|
|
3741
3741
|
|
|
3742
|
+
declare const SystemApiInterfaceSchema: z.ZodObject<{
|
|
3743
|
+
lifecycle: z.ZodDefault<z.ZodEnum<{
|
|
3744
|
+
active: "active";
|
|
3745
|
+
deprecated: "deprecated";
|
|
3746
|
+
draft: "draft";
|
|
3747
|
+
archived: "archived";
|
|
3748
|
+
disabled: "disabled";
|
|
3749
|
+
}>>;
|
|
3750
|
+
readinessProfile: z.ZodOptional<z.ZodString>;
|
|
3751
|
+
resourceIds: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString>>>;
|
|
3752
|
+
}, z.core.$strict>;
|
|
3742
3753
|
type JsonPrimitive = string | number | boolean | null;
|
|
3743
3754
|
type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
3744
3755
|
[key: string]: JsonValue;
|
|
@@ -3767,6 +3778,7 @@ interface SystemEntry {
|
|
|
3767
3778
|
}[];
|
|
3768
3779
|
policies?: string[];
|
|
3769
3780
|
drivesGoals?: string[];
|
|
3781
|
+
apiInterface?: z.infer<typeof SystemApiInterfaceSchema>;
|
|
3770
3782
|
/** @deprecated Use lifecycle. Accepted for one publish cycle. */
|
|
3771
3783
|
status?: 'active' | 'deprecated' | 'archived';
|
|
3772
3784
|
path?: string;
|
package/dist/test-utils/index.js
CHANGED
|
@@ -20318,6 +20318,26 @@ var SystemUiSchema = z.object({
|
|
|
20318
20318
|
icon: IconNameSchema.optional(),
|
|
20319
20319
|
order: z.number().int().optional()
|
|
20320
20320
|
});
|
|
20321
|
+
var SystemInterfaceKeySchema = ModelIdSchema;
|
|
20322
|
+
var SystemInterfaceLifecycleSchema = z.enum(["draft", "active", "disabled", "deprecated", "archived"]).meta({ label: "System interface lifecycle", color: "teal" });
|
|
20323
|
+
var SystemInterfaceReadinessProfileSchema = z.string().trim().min(1).max(200).regex(
|
|
20324
|
+
/^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*(?:\.[a-z0-9][a-z0-9-]*)?$/,
|
|
20325
|
+
'Readiness profiles must use dotted lowercase identifiers (e.g. "sales.lead-gen.api")'
|
|
20326
|
+
);
|
|
20327
|
+
var SystemInterfaceResourceScopeSchema = z.array(ModelIdSchema).default([]);
|
|
20328
|
+
var SystemApiInterfaceSchema = z.object({
|
|
20329
|
+
lifecycle: SystemInterfaceLifecycleSchema.default("active"),
|
|
20330
|
+
readinessProfile: SystemInterfaceReadinessProfileSchema.optional(),
|
|
20331
|
+
/**
|
|
20332
|
+
* Resource ids that participate in this API interface. This scopes readiness
|
|
20333
|
+
* derivation without duplicating authored required/provided contract refs.
|
|
20334
|
+
*/
|
|
20335
|
+
resourceIds: SystemInterfaceResourceScopeSchema.optional()
|
|
20336
|
+
}).strict();
|
|
20337
|
+
var SystemInterfaceRefSchema = z.object({
|
|
20338
|
+
systemPath: SystemPathSchema,
|
|
20339
|
+
interfaceKey: SystemInterfaceKeySchema
|
|
20340
|
+
}).strict();
|
|
20321
20341
|
var JsonValueSchema = z.lazy(
|
|
20322
20342
|
() => z.union([
|
|
20323
20343
|
z.string(),
|
|
@@ -20356,6 +20376,8 @@ var SystemEntrySchema = z.object({
|
|
|
20356
20376
|
policies: z.array(ModelIdSchema.meta({ ref: "policy" })).default([]).optional(),
|
|
20357
20377
|
/** Optional goals this system contributes to. */
|
|
20358
20378
|
drivesGoals: z.array(ModelIdSchema.meta({ ref: "goal" })).default([]).optional(),
|
|
20379
|
+
/** Thin API runtime-boundary marker. Readiness is derived from scoped resources and topology. */
|
|
20380
|
+
apiInterface: SystemApiInterfaceSchema.optional(),
|
|
20359
20381
|
/** @deprecated Use lifecycle. Accepted for one publish cycle. */
|
|
20360
20382
|
status: SystemStatusSchema.optional(),
|
|
20361
20383
|
/** @deprecated Use ui.path. Kept for one-cycle Feature compatibility. */
|
|
@@ -20771,6 +20793,15 @@ var OmTopologyMetadataSchema = z.record(z.string().trim().min(1).max(120), JsonV
|
|
|
20771
20793
|
}
|
|
20772
20794
|
visit(metadata, []);
|
|
20773
20795
|
});
|
|
20796
|
+
var OmTopologySystemInterfaceGrantSchema = z.object({
|
|
20797
|
+
consumer: SystemInterfaceRefSchema,
|
|
20798
|
+
provider: SystemInterfaceRefSchema,
|
|
20799
|
+
resourceIds: z.array(ResourceIdSchema).default([]),
|
|
20800
|
+
ontologyIds: z.array(OntologyIdSchema).default([])
|
|
20801
|
+
}).strict();
|
|
20802
|
+
z.object({
|
|
20803
|
+
systemInterfaceGrant: OmTopologySystemInterfaceGrantSchema
|
|
20804
|
+
}).strict();
|
|
20774
20805
|
var OmTopologyRelationshipSchema = z.object({
|
|
20775
20806
|
from: OmTopologyNodeRefSchema,
|
|
20776
20807
|
kind: OmTopologyRelationshipKindSchema,
|
|
@@ -21398,6 +21429,26 @@ function refineOrganizationModel(model, ctx) {
|
|
|
21398
21429
|
);
|
|
21399
21430
|
}
|
|
21400
21431
|
});
|
|
21432
|
+
allSystems.forEach(({ path: systemPath, schemaPath, system }) => {
|
|
21433
|
+
system.apiInterface?.resourceIds?.forEach((resourceId, resourceIndex) => {
|
|
21434
|
+
const resource = resourcesById.get(resourceId);
|
|
21435
|
+
if (resource === void 0) {
|
|
21436
|
+
addIssue(
|
|
21437
|
+
ctx,
|
|
21438
|
+
[...schemaPath, "apiInterface", "resourceIds", resourceIndex],
|
|
21439
|
+
`System Interface "${systemPath}/api" scopes unknown resource "${resourceId}"`
|
|
21440
|
+
);
|
|
21441
|
+
return;
|
|
21442
|
+
}
|
|
21443
|
+
if (resource.systemPath !== systemPath) {
|
|
21444
|
+
addIssue(
|
|
21445
|
+
ctx,
|
|
21446
|
+
[...schemaPath, "apiInterface", "resourceIds", resourceIndex],
|
|
21447
|
+
`System Interface "${systemPath}/api" scopes resource "${resourceId}" from system "${resource.systemPath}"`
|
|
21448
|
+
);
|
|
21449
|
+
}
|
|
21450
|
+
});
|
|
21451
|
+
});
|
|
21401
21452
|
function validateResourceOntologyBinding(resourceId, bindingKey, expectedKind, ids) {
|
|
21402
21453
|
const ontologyIds2 = ids === void 0 ? [] : Array.isArray(ids) ? ids : [ids];
|
|
21403
21454
|
ontologyIds2.forEach((ontologyId, ontologyIndex) => {
|
package/package.json
CHANGED
|
@@ -303,6 +303,36 @@ export type OrganizationModelSystemKind = z.infer<typeof SystemKindSchema>
|
|
|
303
303
|
export type OrganizationModelSystemLifecycle = z.infer<typeof SystemLifecycleSchema>
|
|
304
304
|
```
|
|
305
305
|
|
|
306
|
+
### `OrganizationModelSystemInterfaceKey`
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
export type OrganizationModelSystemInterfaceKey = z.infer<typeof SystemInterfaceKeySchema>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### `OrganizationModelSystemInterfaceLifecycle`
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
export type OrganizationModelSystemInterfaceLifecycle = z.infer<typeof SystemInterfaceLifecycleSchema>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### `OrganizationModelSystemInterfaceReadinessProfile`
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
export type OrganizationModelSystemInterfaceReadinessProfile = z.infer<typeof SystemInterfaceReadinessProfileSchema>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### `OrganizationModelSystemApiInterface`
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
export type OrganizationModelSystemApiInterface = z.infer<typeof SystemApiInterfaceSchema>
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### `OrganizationModelSystemInterfaceRef`
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
export type OrganizationModelSystemInterfaceRef = z.infer<typeof SystemInterfaceRefSchema>
|
|
334
|
+
```
|
|
335
|
+
|
|
306
336
|
### `OrganizationModelSystemStatus`
|
|
307
337
|
|
|
308
338
|
```typescript
|
|
@@ -466,6 +496,20 @@ export type OrganizationModelTopologyRelationship = z.infer<typeof OmTopologyRel
|
|
|
466
496
|
export type OrganizationModelTopologyMetadata = z.infer<typeof OmTopologyMetadataSchema>
|
|
467
497
|
```
|
|
468
498
|
|
|
499
|
+
### `OrganizationModelTopologySystemInterfaceGrant`
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
export type OrganizationModelTopologySystemInterfaceGrant = z.infer<typeof OmTopologySystemInterfaceGrantSchema>
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### `OrganizationModelTopologySystemInterfaceGrantMetadata`
|
|
506
|
+
|
|
507
|
+
```typescript
|
|
508
|
+
export type OrganizationModelTopologySystemInterfaceGrantMetadata = z.infer<
|
|
509
|
+
typeof OmTopologySystemInterfaceGrantMetadataSchema
|
|
510
|
+
>
|
|
511
|
+
```
|
|
512
|
+
|
|
469
513
|
### `OrganizationModelActions`
|
|
470
514
|
|
|
471
515
|
```typescript
|
|
@@ -1328,38 +1372,33 @@ export interface HumanCheckpointDefinition extends ResourceDefinition {
|
|
|
1328
1372
|
### `DeploymentSpec`
|
|
1329
1373
|
|
|
1330
1374
|
```typescript
|
|
1331
|
-
/**
|
|
1332
|
-
* Organization-specific resource collection
|
|
1333
|
-
*
|
|
1334
|
-
* Complete manifest of all automation resources for an organization.
|
|
1335
|
-
* Used by ResourceRegistry for discovery and Command View for visualization.
|
|
1336
|
-
*/
|
|
1337
|
-
export interface DeploymentSpec {
|
|
1375
|
+
/**
|
|
1376
|
+
* Organization-specific resource collection
|
|
1377
|
+
*
|
|
1378
|
+
* Complete manifest of all automation resources for an organization.
|
|
1379
|
+
* Used by ResourceRegistry for discovery and Command View for visualization.
|
|
1380
|
+
*/
|
|
1381
|
+
export interface DeploymentSpec {
|
|
1338
1382
|
/** Deployment version (semver) */
|
|
1339
1383
|
version: string
|
|
1340
|
-
/** Optional Organization Model
|
|
1341
|
-
organizationModel?:
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
relationships?: ResourceRelationships
|
|
1359
|
-
/** External automation resources (n8n, Make, Zapier, etc.) */
|
|
1360
|
-
externalResources?: ExternalResourceDefinition[]
|
|
1361
|
-
/** Human checkpoint definitions - human decision points in automation */
|
|
1362
|
-
humanCheckpoints?: HumanCheckpointDefinition[]
|
|
1384
|
+
/** Optional full Organization Model snapshot used for OM-code validation and deployment persistence */
|
|
1385
|
+
organizationModel?: OrganizationModel
|
|
1386
|
+
/** Workflow definitions */
|
|
1387
|
+
workflows?: WorkflowDefinition[]
|
|
1388
|
+
/** Agent definitions */
|
|
1389
|
+
agents?: AgentDefinition[]
|
|
1390
|
+
|
|
1391
|
+
// Resource Manifest fields (optional for backwards compatibility)
|
|
1392
|
+
/** Trigger definitions - entry points that initiate executions */
|
|
1393
|
+
triggers?: TriggerDefinition[]
|
|
1394
|
+
/** Integration definitions - external service connections */
|
|
1395
|
+
integrations?: IntegrationDefinition[]
|
|
1396
|
+
/** Explicit relationship declarations between resources */
|
|
1397
|
+
relationships?: ResourceRelationships
|
|
1398
|
+
/** External automation resources (n8n, Make, Zapier, etc.) */
|
|
1399
|
+
externalResources?: ExternalResourceDefinition[]
|
|
1400
|
+
/** Human checkpoint definitions - human decision points in automation */
|
|
1401
|
+
humanCheckpoints?: HumanCheckpointDefinition[]
|
|
1363
1402
|
}
|
|
1364
1403
|
```
|
|
1365
1404
|
|
|
@@ -1,26 +1,29 @@
|
|
|
1
|
-
// Theme preset SSOT (const tuple + derived union + Zod enum)
|
|
2
|
-
export * from './theme-presets'
|
|
3
|
-
|
|
4
|
-
// Config types
|
|
5
|
-
export * from './types'
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
export * from './
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
-
export * from './
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
export * from './
|
|
15
|
-
|
|
16
|
-
//
|
|
17
|
-
export * from './
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
export * from './
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
export * from './
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
export * from './
|
|
1
|
+
// Theme preset SSOT (const tuple + derived union + Zod enum)
|
|
2
|
+
export * from './theme-presets'
|
|
3
|
+
|
|
4
|
+
// Config types
|
|
5
|
+
export * from './types'
|
|
6
|
+
|
|
7
|
+
// Branded organization identifiers (WorkOS id vs Supabase UUID)
|
|
8
|
+
export * from './org-id'
|
|
9
|
+
|
|
10
|
+
// Permission catalog (canonical PERMISSIONS constant + types)
|
|
11
|
+
export * from './permissions'
|
|
12
|
+
|
|
13
|
+
// Role management schemas
|
|
14
|
+
export * from './role-management/index'
|
|
15
|
+
|
|
16
|
+
// Organization types
|
|
17
|
+
export * from './organizations/index'
|
|
18
|
+
|
|
19
|
+
// User types
|
|
20
|
+
export * from './users/index'
|
|
21
|
+
|
|
22
|
+
// Membership types
|
|
23
|
+
export * from './memberships/index'
|
|
24
|
+
|
|
25
|
+
// Invitation types
|
|
26
|
+
export * from './invitations/index'
|
|
27
|
+
|
|
28
|
+
// Credentials types
|
|
29
|
+
export * from './credentials/index'
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
asSupabaseOrgId,
|
|
4
|
+
asWorkOsOrgId,
|
|
5
|
+
asSupabaseOrgIdOrNull,
|
|
6
|
+
asWorkOsOrgIdOrNull,
|
|
7
|
+
brandSupabaseOrgId,
|
|
8
|
+
brandWorkOsOrgId,
|
|
9
|
+
isSupabaseOrgId,
|
|
10
|
+
isWorkOsOrgId,
|
|
11
|
+
type SupabaseOrgId,
|
|
12
|
+
type WorkOsOrgId
|
|
13
|
+
} from './org-id'
|
|
14
|
+
|
|
15
|
+
// Real fixtures pulled from the dev `organizations` table so the format checks
|
|
16
|
+
// exercise production-shaped values, not invented ones.
|
|
17
|
+
const ELEVASIS_UUID = 'f9aa5a56-8c13-4cd1-9161-8827ae7b452b'
|
|
18
|
+
const ELEVASIS_WORKOS = 'org_01K64D59CA5J3PJCWJFQV87PPN'
|
|
19
|
+
const TESTER_UUID = '1b7a6cb2-d73f-44cb-942b-1fa841085ec0'
|
|
20
|
+
const TESTER_WORKOS = 'org_01K4EW076HK9ND7JWPFZKGCNJF'
|
|
21
|
+
// A WorkOS test-org id -- still prefixed `org_`, must be treated as a WorkOS id.
|
|
22
|
+
const TEST_ORG_WORKOS = 'org_test_1776593934703_6gfvsb_l6nyy6'
|
|
23
|
+
const TEST_ORG_UUID = '2ac228f7-a0a1-49f9-920e-8a348f5253d3'
|
|
24
|
+
|
|
25
|
+
describe('org-id brands: runtime validation', () => {
|
|
26
|
+
it('asSupabaseOrgId accepts real Supabase UUIDs and returns the same value', () => {
|
|
27
|
+
expect(asSupabaseOrgId(ELEVASIS_UUID)).toBe(ELEVASIS_UUID)
|
|
28
|
+
expect(asSupabaseOrgId(TESTER_UUID)).toBe(TESTER_UUID)
|
|
29
|
+
expect(asSupabaseOrgId(TEST_ORG_UUID)).toBe(TEST_ORG_UUID)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('asWorkOsOrgId accepts real WorkOS ids (including org_test_*) and returns the same value', () => {
|
|
33
|
+
expect(asWorkOsOrgId(ELEVASIS_WORKOS)).toBe(ELEVASIS_WORKOS)
|
|
34
|
+
expect(asWorkOsOrgId(TESTER_WORKOS)).toBe(TESTER_WORKOS)
|
|
35
|
+
expect(asWorkOsOrgId(TEST_ORG_WORKOS)).toBe(TEST_ORG_WORKOS)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('asSupabaseOrgId throws loudly when handed a WorkOS id (the silent footgun, surfaced)', () => {
|
|
39
|
+
expect(() => asSupabaseOrgId(ELEVASIS_WORKOS)).toThrow(/Supabase organization UUID/)
|
|
40
|
+
expect(() => asSupabaseOrgId(TEST_ORG_WORKOS)).toThrow(/Supabase organization UUID/)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('asWorkOsOrgId throws loudly when handed a Supabase UUID (the reverse footgun)', () => {
|
|
44
|
+
expect(() => asWorkOsOrgId(ELEVASIS_UUID)).toThrow(/WorkOS organization id/)
|
|
45
|
+
expect(() => asWorkOsOrgId(TESTER_UUID)).toThrow(/WorkOS organization id/)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('rejects empty and obviously malformed values', () => {
|
|
49
|
+
expect(() => asSupabaseOrgId('')).toThrow()
|
|
50
|
+
expect(() => asSupabaseOrgId('not-a-uuid')).toThrow()
|
|
51
|
+
expect(() => asWorkOsOrgId('')).toThrow()
|
|
52
|
+
expect(() => asWorkOsOrgId('01K64D59CA5J3PJCWJFQV87PPN')).toThrow() // missing org_ prefix
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('org-id brands: type guards', () => {
|
|
57
|
+
it('isSupabaseOrgId is true only for UUIDs', () => {
|
|
58
|
+
expect(isSupabaseOrgId(ELEVASIS_UUID)).toBe(true)
|
|
59
|
+
expect(isSupabaseOrgId(ELEVASIS_WORKOS)).toBe(false)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('isWorkOsOrgId is true only for org_ prefixed values', () => {
|
|
63
|
+
expect(isWorkOsOrgId(ELEVASIS_WORKOS)).toBe(true)
|
|
64
|
+
expect(isWorkOsOrgId(TEST_ORG_WORKOS)).toBe(true)
|
|
65
|
+
expect(isWorkOsOrgId(ELEVASIS_UUID)).toBe(false)
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
describe('org-id brands: nullable mint helpers', () => {
|
|
70
|
+
it('pass null/undefined through unchanged', () => {
|
|
71
|
+
expect(asSupabaseOrgIdOrNull(null)).toBeNull()
|
|
72
|
+
expect(asSupabaseOrgIdOrNull(undefined)).toBeNull()
|
|
73
|
+
expect(asWorkOsOrgIdOrNull(null)).toBeNull()
|
|
74
|
+
expect(asWorkOsOrgIdOrNull(undefined)).toBeNull()
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('validate non-null values', () => {
|
|
78
|
+
expect(asSupabaseOrgIdOrNull(ELEVASIS_UUID)).toBe(ELEVASIS_UUID)
|
|
79
|
+
expect(asWorkOsOrgIdOrNull(ELEVASIS_WORKOS)).toBe(ELEVASIS_WORKOS)
|
|
80
|
+
expect(() => asSupabaseOrgIdOrNull(ELEVASIS_WORKOS)).toThrow()
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
describe('org-id brands: trusted-source casts', () => {
|
|
85
|
+
it('brand* never throws (trusted values are not re-validated) and preserves the value', () => {
|
|
86
|
+
expect(brandSupabaseOrgId(ELEVASIS_UUID)).toBe(ELEVASIS_UUID)
|
|
87
|
+
expect(brandWorkOsOrgId(ELEVASIS_WORKOS)).toBe(ELEVASIS_WORKOS)
|
|
88
|
+
// Unlike as*, brand* does not validate -- it is the trusted-data path.
|
|
89
|
+
expect(() => brandSupabaseOrgId('anything')).not.toThrow()
|
|
90
|
+
expect(() => brandWorkOsOrgId('anything')).not.toThrow()
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('brand* maps null/undefined to null', () => {
|
|
94
|
+
expect(brandSupabaseOrgId(null)).toBeNull()
|
|
95
|
+
expect(brandSupabaseOrgId(undefined)).toBeNull()
|
|
96
|
+
expect(brandWorkOsOrgId(null)).toBeNull()
|
|
97
|
+
expect(brandWorkOsOrgId(undefined)).toBeNull()
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Compile-time enforcement. These sinks model the real consumers: a Supabase
|
|
103
|
+
* `.eq('organization_id', ...)` helper (needs SupabaseOrgId) and a query-key
|
|
104
|
+
* factory (needs WorkOsOrgId). The `@ts-expect-error` directives are the actual
|
|
105
|
+
* assertions -- if a brand ever fails to block a swap, the directive becomes
|
|
106
|
+
* "unused" and `tsc` (check-types) fails. The sinks are runtime no-ops, so this
|
|
107
|
+
* block executes harmlessly under vitest; the guarantee is verified by the type
|
|
108
|
+
* checker.
|
|
109
|
+
*/
|
|
110
|
+
describe('org-id brands: compile-time swap prevention', () => {
|
|
111
|
+
function expectsSupabaseOrgId(_id: SupabaseOrgId): void {}
|
|
112
|
+
function expectsWorkOsOrgId(_id: WorkOsOrgId): void {}
|
|
113
|
+
|
|
114
|
+
it('accepts correctly-branded ids and keeps string compatibility', () => {
|
|
115
|
+
// Positive: the right brand flows into the right sink.
|
|
116
|
+
expectsSupabaseOrgId(asSupabaseOrgId(ELEVASIS_UUID))
|
|
117
|
+
expectsWorkOsOrgId(asWorkOsOrgId(ELEVASIS_WORKOS))
|
|
118
|
+
|
|
119
|
+
// A branded id is still a string everywhere a plain string is expected.
|
|
120
|
+
const asString: string = asSupabaseOrgId(ELEVASIS_UUID)
|
|
121
|
+
expect(asString).toBe(ELEVASIS_UUID)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('rejects cross-brand and raw-string assignment at compile time', () => {
|
|
125
|
+
// @ts-expect-error WorkOsOrgId must not be usable where a SupabaseOrgId is required.
|
|
126
|
+
expectsSupabaseOrgId(asWorkOsOrgId(ELEVASIS_WORKOS))
|
|
127
|
+
|
|
128
|
+
// @ts-expect-error SupabaseOrgId must not be usable where a WorkOsOrgId is required.
|
|
129
|
+
expectsWorkOsOrgId(asSupabaseOrgId(ELEVASIS_UUID))
|
|
130
|
+
|
|
131
|
+
// @ts-expect-error a raw string cannot reach the sink without minting through the factory.
|
|
132
|
+
expectsSupabaseOrgId(ELEVASIS_UUID)
|
|
133
|
+
|
|
134
|
+
// @ts-expect-error a raw string cannot reach the sink without minting through the factory.
|
|
135
|
+
expectsWorkOsOrgId(ELEVASIS_WORKOS)
|
|
136
|
+
|
|
137
|
+
expect(true).toBe(true)
|
|
138
|
+
})
|
|
139
|
+
})
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branded organization identifiers.
|
|
3
|
+
*
|
|
4
|
+
* Every organization carries TWO distinct ID values that are both plain
|
|
5
|
+
* strings at runtime but mean different things:
|
|
6
|
+
*
|
|
7
|
+
* - WorkOS organization id (`org_...`) -- the auth/JWT identity. Used for API
|
|
8
|
+
* requests, SSE headers, and org-scoped query keys.
|
|
9
|
+
* - Supabase organization id (UUID) -- the database key. Used for
|
|
10
|
+
* `.eq('organization_id', ...)` queries and RLS scoping.
|
|
11
|
+
*
|
|
12
|
+
* They are not interchangeable, yet both are `string` -- so a swap compiles
|
|
13
|
+
* cleanly and fails silently (zero rows on the Supabase side, cross-pollinated
|
|
14
|
+
* cache keys on the API side). These brands make the two non-assignable to one
|
|
15
|
+
* another, turning that silent footgun into a compile error at the sink.
|
|
16
|
+
*
|
|
17
|
+
* Mint a brand only through the `as*` factories below: they are the single
|
|
18
|
+
* validate-and-tag boundary (compile-time brand + runtime format check). The
|
|
19
|
+
* type predicates double as the cast, so no raw `as` cast is needed anywhere.
|
|
20
|
+
*
|
|
21
|
+
* Lives on the published `@repo/core` / `@repo/core/auth` surface so the UI,
|
|
22
|
+
* the API, and the dogfooding `@repo/elevasis-*` packages can all use it.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { UuidSchema } from '../../platform/utils/validation'
|
|
26
|
+
|
|
27
|
+
declare const supabaseOrgIdBrand: unique symbol
|
|
28
|
+
declare const workOsOrgIdBrand: unique symbol
|
|
29
|
+
|
|
30
|
+
/** A Supabase organization id (UUID) -- the database key for RLS-scoped rows. */
|
|
31
|
+
export type SupabaseOrgId = string & { readonly [supabaseOrgIdBrand]: true }
|
|
32
|
+
|
|
33
|
+
/** A WorkOS organization id (`org_...`) -- the auth identity for API/SSE/query keys. */
|
|
34
|
+
export type WorkOsOrgId = string & { readonly [workOsOrgIdBrand]: true }
|
|
35
|
+
|
|
36
|
+
/** WorkOS organization ids are always prefixed with `org_` (incl. `org_test_...`). */
|
|
37
|
+
const WORKOS_ORG_ID_PREFIX = 'org_'
|
|
38
|
+
|
|
39
|
+
/** True when `value` is shaped like a Supabase organization UUID. */
|
|
40
|
+
export function isSupabaseOrgId(value: string): value is SupabaseOrgId {
|
|
41
|
+
return UuidSchema.safeParse(value).success
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** True when `value` is shaped like a WorkOS organization id (`org_...`). */
|
|
45
|
+
export function isWorkOsOrgId(value: string): value is WorkOsOrgId {
|
|
46
|
+
return value.startsWith(WORKOS_ORG_ID_PREFIX)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validate-and-brand a string as a Supabase organization id.
|
|
51
|
+
*
|
|
52
|
+
* @throws {Error} if the value is not a UUID (e.g. a WorkOS `org_...` id leaked in).
|
|
53
|
+
*/
|
|
54
|
+
export function asSupabaseOrgId(value: string): SupabaseOrgId {
|
|
55
|
+
if (!isSupabaseOrgId(value)) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Expected a Supabase organization UUID, received "${value}". ` +
|
|
58
|
+
`A WorkOS org id (org_...) was likely used where the database key is required.`
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
return value
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Validate-and-brand a string as a WorkOS organization id.
|
|
66
|
+
*
|
|
67
|
+
* @throws {Error} if the value is not `org_...` (e.g. a Supabase UUID leaked in).
|
|
68
|
+
*/
|
|
69
|
+
export function asWorkOsOrgId(value: string): WorkOsOrgId {
|
|
70
|
+
if (!isWorkOsOrgId(value)) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Expected a WorkOS organization id (org_...), received "${value}". ` +
|
|
73
|
+
`A Supabase UUID was likely used where the auth identity is required.`
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
return value
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Nullable convenience for mint sites that read `... ?? null` from a membership. */
|
|
80
|
+
export function asSupabaseOrgIdOrNull(value: string | null | undefined): SupabaseOrgId | null {
|
|
81
|
+
return value == null ? null : asSupabaseOrgId(value)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Nullable convenience for mint sites that read `... ?? null` from a membership. */
|
|
85
|
+
export function asWorkOsOrgIdOrNull(value: string | null | undefined): WorkOsOrgId | null {
|
|
86
|
+
return value == null ? null : asWorkOsOrgId(value)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Trusted-source casts (brand WITHOUT validating).
|
|
91
|
+
//
|
|
92
|
+
// Use these when the value is already known to be well-formed -- e.g. an
|
|
93
|
+
// organization id read from our own database/membership API, or a test
|
|
94
|
+
// fixture. They never throw, so they are safe at UI mint points (a provider
|
|
95
|
+
// must not white-screen on data shape) and avoid re-validating trusted DB
|
|
96
|
+
// UUIDs on every render. For UNTRUSTED input (route params, external ids)
|
|
97
|
+
// prefer the validating `as*` factories above, which throw on a bad shape.
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
/** Brand a trusted string as a Supabase organization id without validating. */
|
|
101
|
+
export function brandSupabaseOrgId(value: string): SupabaseOrgId
|
|
102
|
+
export function brandSupabaseOrgId(value: string | null | undefined): SupabaseOrgId | null
|
|
103
|
+
export function brandSupabaseOrgId(value: string | null | undefined): SupabaseOrgId | null {
|
|
104
|
+
return (value ?? null) as SupabaseOrgId | null
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Brand a trusted string as a WorkOS organization id without validating. */
|
|
108
|
+
export function brandWorkOsOrgId(value: string): WorkOsOrgId
|
|
109
|
+
export function brandWorkOsOrgId(value: string | null | undefined): WorkOsOrgId | null
|
|
110
|
+
export function brandWorkOsOrgId(value: string | null | undefined): WorkOsOrgId | null {
|
|
111
|
+
return (value ?? null) as WorkOsOrgId | null
|
|
112
|
+
}
|