@elevasis/core 0.23.0 → 0.24.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 +4343 -2690
- package/dist/index.js +1101 -156
- package/dist/knowledge/index.d.ts +574 -210
- package/dist/knowledge/index.js +104 -1
- package/dist/organization-model/index.d.ts +4343 -2690
- package/dist/organization-model/index.js +1101 -156
- package/dist/test-utils/index.d.ts +483 -109
- package/dist/test-utils/index.js +904 -144
- package/package.json +3 -3
- package/src/README.md +14 -14
- package/src/__tests__/publish.test.ts +24 -24
- package/src/__tests__/template-core-compatibility.test.ts +9 -12
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +2137 -2093
- package/src/_gen/__tests__/scaffold-contracts.test.ts +30 -30
- package/src/auth/multi-tenancy/credentials/__tests__/encryption.test.ts +217 -217
- package/src/auth/multi-tenancy/credentials/server/encryption.ts +69 -69
- package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +37 -37
- package/src/auth/multi-tenancy/index.ts +26 -26
- package/src/auth/multi-tenancy/invitations/api-schemas.ts +104 -104
- package/src/auth/multi-tenancy/memberships/api-schemas.ts +143 -143
- package/src/auth/multi-tenancy/memberships/index.ts +26 -26
- package/src/auth/multi-tenancy/memberships/membership.ts +130 -130
- package/src/auth/multi-tenancy/organizations/__tests__/api-schemas.test.ts +194 -194
- package/src/auth/multi-tenancy/organizations/api-schemas.ts +136 -136
- package/src/auth/multi-tenancy/permissions.test.ts +42 -42
- package/src/auth/multi-tenancy/permissions.ts +123 -123
- package/src/auth/multi-tenancy/role-management/api-schemas.ts +78 -78
- package/src/auth/multi-tenancy/role-management/index.ts +16 -16
- package/src/auth/multi-tenancy/theme-presets.ts +45 -45
- package/src/auth/multi-tenancy/types.ts +57 -57
- package/src/auth/multi-tenancy/users/api-schemas.ts +165 -165
- package/src/business/README.md +2 -2
- package/src/business/acquisition/activity-events.test.ts +250 -250
- package/src/business/acquisition/activity-events.ts +93 -93
- package/src/business/acquisition/api-schemas.test.ts +1883 -1843
- package/src/business/acquisition/api-schemas.ts +1492 -1497
- package/src/business/acquisition/build-templates.test.ts +240 -240
- package/src/business/acquisition/build-templates.ts +98 -98
- package/src/business/acquisition/crm-next-action.test.ts +262 -262
- package/src/business/acquisition/crm-next-action.ts +220 -220
- package/src/business/acquisition/crm-priority.test.ts +216 -216
- package/src/business/acquisition/crm-priority.ts +349 -349
- package/src/business/acquisition/crm-state-actions.test.ts +153 -153
- package/src/business/acquisition/deal-ownership.test.ts +351 -351
- package/src/business/acquisition/deal-ownership.ts +120 -120
- package/src/business/acquisition/derive-actions.test.ts +129 -104
- package/src/business/acquisition/derive-actions.ts +74 -84
- package/src/business/acquisition/index.ts +171 -170
- package/src/business/acquisition/ontology-validation.ts +309 -0
- package/src/business/acquisition/stateful.ts +30 -30
- package/src/business/acquisition/types.ts +396 -396
- package/src/business/clients/api-schemas.test.ts +115 -115
- package/src/business/clients/api-schemas.ts +158 -158
- package/src/business/clients/index.ts +1 -1
- package/src/business/crm/api-schemas.ts +40 -40
- package/src/business/crm/index.ts +1 -1
- package/src/business/deals/api-schemas.ts +87 -87
- package/src/business/deals/index.ts +1 -1
- package/src/business/index.ts +5 -5
- package/src/business/projects/types.ts +144 -144
- package/src/commands/queue/types/task.ts +15 -15
- package/src/execution/core/runner-types.ts +61 -61
- package/src/execution/core/sse-executions.ts +7 -7
- package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -10
- package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -16
- package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -4
- package/src/execution/engine/agent/core/types.ts +25 -25
- package/src/execution/engine/agent/index.ts +6 -6
- package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -24
- package/src/execution/engine/index.ts +443 -443
- package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +298 -298
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -55
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -107
- package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -48
- package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -99
- package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -1
- package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +363 -363
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.test.ts +162 -162
- package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.test.ts +316 -316
- package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -18
- package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -194
- package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -7
- package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +204 -204
- package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-tools.ts +105 -105
- package/src/execution/engine/tools/integration/server/adapters/google-calendar/google-calendar-adapter.ts +428 -428
- package/src/execution/engine/tools/integration/server/adapters/google-calendar/index.ts +2 -2
- package/src/execution/engine/tools/integration/server/adapters/google-sheets/__tests__/google-sheets.integration.test.ts +261 -261
- package/src/execution/engine/tools/integration/server/adapters/instantly/instantly-tools.ts +1474 -1474
- package/src/execution/engine/tools/integration/server/adapters/millionverifier/millionverifier-tools.ts +103 -103
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.test.ts +88 -88
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +141 -141
- package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +76 -76
- package/src/execution/engine/tools/integration/server/adapters/signature-api/signature-api-tools.ts +182 -182
- package/src/execution/engine/tools/integration/server/adapters/stripe/stripe-tools.ts +310 -310
- package/src/execution/engine/tools/integration/service.test.ts +239 -239
- package/src/execution/engine/tools/integration/service.ts +172 -172
- package/src/execution/engine/tools/integration/tool.ts +255 -255
- package/src/execution/engine/tools/lead-service-types.ts +1005 -1005
- package/src/execution/engine/tools/messages.ts +43 -43
- package/src/execution/engine/tools/platform/acquisition/company-tools.ts +7 -7
- package/src/execution/engine/tools/platform/acquisition/contact-tools.ts +6 -6
- package/src/execution/engine/tools/platform/acquisition/list-tools.ts +6 -6
- package/src/execution/engine/tools/platform/acquisition/types.ts +280 -280
- package/src/execution/engine/tools/platform/email/types.ts +97 -97
- package/src/execution/engine/tools/registry.ts +704 -704
- package/src/execution/engine/tools/tool-maps.ts +831 -831
- package/src/execution/engine/tools/types.ts +234 -234
- package/src/execution/engine/workflow/types.ts +195 -197
- package/src/execution/external/__tests__/api-schemas.test.ts +127 -127
- package/src/execution/external/api-schemas.ts +40 -40
- package/src/execution/external/index.ts +1 -1
- package/src/index.ts +18 -18
- package/src/integrations/credentials/__tests__/api-schemas.test.ts +420 -420
- package/src/integrations/credentials/api-schemas.ts +146 -146
- package/src/integrations/credentials/schemas.ts +200 -200
- package/src/integrations/oauth/__tests__/provider-registry.test.ts +7 -7
- package/src/integrations/oauth/provider-registry.ts +74 -74
- package/src/integrations/oauth/server/credentials.ts +43 -43
- package/src/integrations/webhook-endpoints/__tests__/api-schemas.test.ts +327 -327
- package/src/integrations/webhook-endpoints/api-schemas.ts +103 -103
- package/src/integrations/webhook-endpoints/types.ts +58 -58
- package/src/knowledge/README.md +32 -32
- package/src/knowledge/__tests__/queries.test.ts +626 -535
- package/src/knowledge/format.ts +99 -99
- package/src/knowledge/index.ts +5 -5
- package/src/knowledge/published.ts +5 -5
- package/src/knowledge/queries.ts +269 -218
- package/src/operations/activities/api-schemas.ts +80 -80
- package/src/operations/activities/types.ts +64 -64
- package/src/organization-model/README.md +149 -149
- package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -210
- package/src/organization-model/__tests__/defaults.test.ts +168 -168
- package/src/organization-model/__tests__/domains/actions.test.ts +78 -56
- package/src/organization-model/__tests__/domains/customers.test.ts +299 -299
- package/src/organization-model/__tests__/domains/entities.test.ts +56 -56
- package/src/organization-model/__tests__/domains/goals.test.ts +493 -493
- package/src/organization-model/__tests__/domains/identity.test.ts +280 -280
- package/src/organization-model/__tests__/domains/navigation.test.ts +268 -268
- package/src/organization-model/__tests__/domains/offerings.test.ts +414 -414
- package/src/organization-model/__tests__/domains/policies.test.ts +323 -323
- package/src/organization-model/__tests__/domains/resource-mappings.test.ts +293 -293
- package/src/organization-model/__tests__/domains/resources.test.ts +387 -277
- package/src/organization-model/__tests__/domains/roles.test.ts +463 -463
- package/src/organization-model/__tests__/domains/statuses.test.ts +246 -246
- package/src/organization-model/__tests__/domains/systems.test.ts +209 -209
- package/src/organization-model/__tests__/domains/topology.test.ts +188 -0
- package/src/organization-model/__tests__/flatten-additive-merge.test.ts +362 -361
- package/src/organization-model/__tests__/foundation.test.ts +77 -77
- package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -144
- package/src/organization-model/__tests__/graph.test.ts +1312 -862
- package/src/organization-model/__tests__/icons.test.ts +10 -1
- package/src/organization-model/__tests__/knowledge.test.ts +251 -15
- package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -438
- package/src/organization-model/__tests__/migration-helpers.test.ts +591 -591
- package/src/organization-model/__tests__/prospecting-ssot.test.ts +103 -103
- package/src/organization-model/__tests__/recursive-system-schema.test.ts +535 -506
- package/src/organization-model/__tests__/resolve.test.ts +274 -164
- package/src/organization-model/__tests__/schema.test.ts +844 -301
- package/src/organization-model/__tests__/surface-projection.test.ts +284 -284
- package/src/organization-model/catalogs/lead-gen.ts +144 -144
- package/src/organization-model/content-kinds/config.ts +36 -36
- package/src/organization-model/content-kinds/index.ts +76 -72
- package/src/organization-model/content-kinds/pipeline.ts +68 -68
- package/src/organization-model/content-kinds/registry.ts +44 -44
- package/src/organization-model/content-kinds/status.ts +71 -71
- package/src/organization-model/content-kinds/template.ts +83 -83
- package/src/organization-model/content-kinds/types.ts +117 -117
- package/src/organization-model/contracts.ts +27 -27
- package/src/organization-model/defaults.ts +42 -50
- package/src/organization-model/domains/actions.ts +333 -239
- package/src/organization-model/domains/customers.ts +78 -78
- package/src/organization-model/domains/entities.ts +144 -144
- package/src/organization-model/domains/goals.ts +83 -83
- package/src/organization-model/domains/knowledge.ts +117 -101
- package/src/organization-model/domains/navigation.ts +139 -139
- package/src/organization-model/domains/offerings.ts +71 -71
- package/src/organization-model/domains/policies.ts +102 -102
- package/src/organization-model/domains/projects.ts +14 -14
- package/src/organization-model/domains/prospecting.ts +395 -395
- package/src/organization-model/domains/resources.ts +202 -124
- package/src/organization-model/domains/roles.ts +96 -96
- package/src/organization-model/domains/sales.test.ts +218 -218
- package/src/organization-model/domains/sales.ts +380 -380
- package/src/organization-model/domains/shared.ts +63 -63
- package/src/organization-model/domains/statuses.ts +339 -339
- package/src/organization-model/domains/systems.ts +217 -172
- package/src/organization-model/domains/topology.ts +261 -0
- package/src/organization-model/foundation.ts +75 -75
- package/src/organization-model/graph/build.ts +1043 -867
- package/src/organization-model/graph/index.ts +4 -4
- package/src/organization-model/graph/link.ts +10 -10
- package/src/organization-model/graph/schema.ts +75 -68
- package/src/organization-model/graph/types.ts +71 -64
- package/src/organization-model/helpers.ts +289 -241
- package/src/organization-model/icons.ts +78 -66
- package/src/organization-model/index.ts +128 -125
- package/src/organization-model/migration-helpers.ts +247 -244
- package/src/organization-model/ontology.ts +658 -0
- package/src/organization-model/organization-graph.mdx +110 -90
- package/src/organization-model/organization-model.mdx +225 -213
- package/src/organization-model/published.ts +299 -222
- package/src/organization-model/resolve.ts +146 -91
- package/src/organization-model/schema.ts +818 -659
- package/src/organization-model/surface-projection.ts +212 -212
- package/src/organization-model/types.ts +179 -155
- package/src/platform/api/types.ts +38 -38
- package/src/platform/constants/versions.ts +3 -3
- package/src/platform/index.ts +23 -23
- package/src/platform/registry/__tests__/command-view.test.ts +10 -10
- package/src/platform/registry/__tests__/resource-link.test.ts +35 -35
- package/src/platform/registry/__tests__/resource-registry.integration.test.ts +20 -20
- package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -245
- package/src/platform/registry/__tests__/resource-registry.test.ts +2053 -2053
- package/src/platform/registry/__tests__/validation.test.ts +1444 -1259
- package/src/platform/registry/command-view.ts +10 -10
- package/src/platform/registry/index.ts +103 -103
- package/src/platform/registry/resource-link.ts +32 -32
- package/src/platform/registry/resource-registry.ts +886 -886
- package/src/platform/registry/serialization.ts +295 -295
- package/src/platform/registry/serialized-types.ts +166 -166
- package/src/platform/registry/stats-types.ts +68 -68
- package/src/platform/registry/types.ts +425 -425
- package/src/platform/registry/validation.ts +876 -684
- package/src/platform/utils/__tests__/validation.test.ts +1084 -1084
- package/src/platform/utils/validation.ts +425 -425
- package/src/projects/api-schemas.test.ts +39 -39
- package/src/projects/api-schemas.ts +291 -291
- package/src/reference/_generated/contracts.md +2136 -2093
- package/src/reference/glossary.md +76 -76
- package/src/scaffold-registry/__tests__/index.test.ts +206 -206
- package/src/scaffold-registry/__tests__/schema.test.ts +166 -166
- package/src/scaffold-registry/index.ts +392 -392
- package/src/scaffold-registry/schema.ts +243 -243
- package/src/server.ts +289 -289
- package/src/supabase/database.types.ts +3 -0
- package/src/test-utils/README.md +37 -37
- package/src/test-utils/entities.ts +108 -108
- package/src/test-utils/fixtures/memberships.ts +82 -82
- package/src/test-utils/index.ts +12 -12
- package/src/test-utils/organization-model.ts +65 -65
- package/src/test-utils/published.ts +6 -6
- package/src/test-utils/rls/RLSTestContext.ts +588 -588
- package/src/test-utils/test-utils.test.ts +44 -44
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { PERMISSIONS, PERMISSION_CATALOG, isPermissionKey } from './permissions'
|
|
3
|
-
|
|
4
|
-
describe('permissions catalog', () => {
|
|
5
|
-
const permissionValues = Object.values(PERMISSIONS)
|
|
6
|
-
const catalogKeys = PERMISSION_CATALOG.map((p) => p.key)
|
|
7
|
-
|
|
8
|
-
it('every PERMISSIONS value appears as a key in PERMISSION_CATALOG', () => {
|
|
9
|
-
for (const value of permissionValues) {
|
|
10
|
-
expect(catalogKeys).toContain(value)
|
|
11
|
-
}
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('every PERMISSION_CATALOG key exists as a value in PERMISSIONS', () => {
|
|
15
|
-
for (const key of catalogKeys) {
|
|
16
|
-
expect(permissionValues).toContain(key)
|
|
17
|
-
}
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
it('every catalog entry has a non-empty description and a boolean isOrgGrantable', () => {
|
|
21
|
-
for (const entry of PERMISSION_CATALOG) {
|
|
22
|
-
expect(typeof entry.description).toBe('string')
|
|
23
|
-
expect(entry.description.trim().length).toBeGreaterThan(0)
|
|
24
|
-
expect(typeof entry.isOrgGrantable).toBe('boolean')
|
|
25
|
-
}
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('catalog has no duplicate keys', () => {
|
|
29
|
-
const seen = new Set<string>()
|
|
30
|
-
for (const key of catalogKeys) {
|
|
31
|
-
expect(seen.has(key), `duplicate catalog key: ${key}`).toBe(false)
|
|
32
|
-
seen.add(key)
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('isPermissionKey returns true for every catalog key and false for unknown strings', () => {
|
|
37
|
-
for (const key of catalogKeys) {
|
|
38
|
-
expect(isPermissionKey(key)).toBe(true)
|
|
39
|
-
}
|
|
40
|
-
expect(isPermissionKey('not.a.permission')).toBe(false)
|
|
41
|
-
})
|
|
42
|
-
})
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { PERMISSIONS, PERMISSION_CATALOG, isPermissionKey } from './permissions'
|
|
3
|
+
|
|
4
|
+
describe('permissions catalog', () => {
|
|
5
|
+
const permissionValues = Object.values(PERMISSIONS)
|
|
6
|
+
const catalogKeys = PERMISSION_CATALOG.map((p) => p.key)
|
|
7
|
+
|
|
8
|
+
it('every PERMISSIONS value appears as a key in PERMISSION_CATALOG', () => {
|
|
9
|
+
for (const value of permissionValues) {
|
|
10
|
+
expect(catalogKeys).toContain(value)
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('every PERMISSION_CATALOG key exists as a value in PERMISSIONS', () => {
|
|
15
|
+
for (const key of catalogKeys) {
|
|
16
|
+
expect(permissionValues).toContain(key)
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('every catalog entry has a non-empty description and a boolean isOrgGrantable', () => {
|
|
21
|
+
for (const entry of PERMISSION_CATALOG) {
|
|
22
|
+
expect(typeof entry.description).toBe('string')
|
|
23
|
+
expect(entry.description.trim().length).toBeGreaterThan(0)
|
|
24
|
+
expect(typeof entry.isOrgGrantable).toBe('boolean')
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('catalog has no duplicate keys', () => {
|
|
29
|
+
const seen = new Set<string>()
|
|
30
|
+
for (const key of catalogKeys) {
|
|
31
|
+
expect(seen.has(key), `duplicate catalog key: ${key}`).toBe(false)
|
|
32
|
+
seen.add(key)
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('isPermissionKey returns true for every catalog key and false for unknown strings', () => {
|
|
37
|
+
for (const key of catalogKeys) {
|
|
38
|
+
expect(isPermissionKey(key)).toBe(true)
|
|
39
|
+
}
|
|
40
|
+
expect(isPermissionKey('not.a.permission')).toBe(false)
|
|
41
|
+
})
|
|
42
|
+
})
|
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical permission catalog.
|
|
3
|
-
*
|
|
4
|
-
* Source of truth for the permission keys used by:
|
|
5
|
-
* - RLS policies in Supabase (via has_org_permission(org_id, key))
|
|
6
|
-
* - API middleware (via requireOrganizationPermission(key))
|
|
7
|
-
* - UI hooks (via useOrganizationPermissions().hasPermission(key))
|
|
8
|
-
*
|
|
9
|
-
* The DB table `org_rol_permissions` mirrors this constant. There is no
|
|
10
|
-
* runtime reconciler; parity is enforced two ways:
|
|
11
|
-
* 1. Each migration that adds/removes/modifies a permission must INSERT
|
|
12
|
-
* (or UPDATE / DELETE) the corresponding `org_rol_permissions` row in
|
|
13
|
-
* the same transaction.
|
|
14
|
-
* 2. `apps/api/src/auth/multi-tenancy/__tests__/permissions-catalog-sync.integration.test.ts`
|
|
15
|
-
* asserts the TS catalog and the DB rows agree; CI fails on drift.
|
|
16
|
-
*
|
|
17
|
-
* Adding a permission:
|
|
18
|
-
* 1. Add an entry below.
|
|
19
|
-
* 2. Add a row to the migration (INSERT INTO org_rol_permissions ...) in
|
|
20
|
-
* the same transaction as any policies/grants that reference the key.
|
|
21
|
-
* 3. Reference it in RLS / middleware as needed.
|
|
22
|
-
* 4. Optionally grant it to one or more system roles in org_rol_grants.
|
|
23
|
-
*
|
|
24
|
-
* Removing a permission: follow the deletion runbook — never just delete
|
|
25
|
-
* the entry. Existing role grants and policy references must be cleared first.
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
export const PERMISSIONS = {
|
|
29
|
-
ORG_READ: 'org.read',
|
|
30
|
-
ORG_MANAGE: 'org.manage',
|
|
31
|
-
ORG_DELETE: 'org.delete',
|
|
32
|
-
MEMBERS_MANAGE: 'members.manage',
|
|
33
|
-
ROLES_MANAGE: 'roles.manage',
|
|
34
|
-
SECRETS_MANAGE: 'secrets.manage',
|
|
35
|
-
OPERATIONS_READ: 'operations.read',
|
|
36
|
-
OPERATIONS_MANAGE: 'operations.manage',
|
|
37
|
-
ACQUISITION_MANAGE: 'acquisition.manage',
|
|
38
|
-
PROJECTS_MANAGE: 'projects.manage',
|
|
39
|
-
CLIENTS_MANAGE: 'clients.manage'
|
|
40
|
-
} as const
|
|
41
|
-
|
|
42
|
-
export type PermissionKey = (typeof PERMISSIONS)[keyof typeof PERMISSIONS]
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Static metadata for each permission. Mirrored into org_rol_permissions by
|
|
46
|
-
* a migration `INSERT` in the same transaction as any change to this catalog.
|
|
47
|
-
* is_org_grantable=false means the permission is reserved to system roles
|
|
48
|
-
* only — custom roles cannot include it (privilege-escalation guard).
|
|
49
|
-
*/
|
|
50
|
-
export interface PermissionDescriptor {
|
|
51
|
-
key: PermissionKey
|
|
52
|
-
description: string
|
|
53
|
-
isOrgGrantable: boolean
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export const PERMISSION_CATALOG: readonly PermissionDescriptor[] = [
|
|
57
|
-
{
|
|
58
|
-
key: 'org.read',
|
|
59
|
-
description: 'Read organization profile and listings',
|
|
60
|
-
isOrgGrantable: true
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
key: 'org.manage',
|
|
64
|
-
description: 'Update organization settings',
|
|
65
|
-
isOrgGrantable: false
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
key: 'org.delete',
|
|
69
|
-
description: 'Delete the organization (owner-only)',
|
|
70
|
-
isOrgGrantable: false
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
key: 'members.manage',
|
|
74
|
-
description: 'Invite, remove, and reassign roles for members',
|
|
75
|
-
isOrgGrantable: false
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
key: 'roles.manage',
|
|
79
|
-
description: 'Grant or revoke privileged system roles (owner, admin) within the organization',
|
|
80
|
-
isOrgGrantable: false
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
key: 'secrets.manage',
|
|
84
|
-
description: 'Create, update, and delete API keys and credentials',
|
|
85
|
-
isOrgGrantable: false
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
key: 'operations.read',
|
|
89
|
-
description: 'View executions, sessions, schedules, and command queue',
|
|
90
|
-
isOrgGrantable: true
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
key: 'operations.manage',
|
|
94
|
-
description: 'Run and modify executions, sessions, schedules, queue',
|
|
95
|
-
isOrgGrantable: true
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
key: 'acquisition.manage',
|
|
99
|
-
description:
|
|
100
|
-
'Create, update, and delete acquisition records (acq_companies, acq_contacts, acq_deals, acq_lists*, acq_content*, acquisition storage files)',
|
|
101
|
-
isOrgGrantable: false
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
key: 'projects.manage',
|
|
105
|
-
description: 'Create, update, and delete project records (prj_projects, prj_milestones, prj_tasks, prj_notes)',
|
|
106
|
-
isOrgGrantable: false
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
key: 'clients.manage',
|
|
110
|
-
description: 'Create, update, and delete client hub records (clients, clt_* satellites)',
|
|
111
|
-
isOrgGrantable: false
|
|
112
|
-
}
|
|
113
|
-
] as const
|
|
114
|
-
|
|
115
|
-
const PERMISSION_KEY_SET: ReadonlySet<string> = new Set(PERMISSION_CATALOG.map((p) => p.key))
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Type guard. Use at trust boundaries (request input, third-party data) before
|
|
119
|
-
* passing a string to `has_org_permission` / `requireOrganizationPermission`.
|
|
120
|
-
*/
|
|
121
|
-
export function isPermissionKey(value: unknown): value is PermissionKey {
|
|
122
|
-
return typeof value === 'string' && PERMISSION_KEY_SET.has(value)
|
|
123
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Canonical permission catalog.
|
|
3
|
+
*
|
|
4
|
+
* Source of truth for the permission keys used by:
|
|
5
|
+
* - RLS policies in Supabase (via has_org_permission(org_id, key))
|
|
6
|
+
* - API middleware (via requireOrganizationPermission(key))
|
|
7
|
+
* - UI hooks (via useOrganizationPermissions().hasPermission(key))
|
|
8
|
+
*
|
|
9
|
+
* The DB table `org_rol_permissions` mirrors this constant. There is no
|
|
10
|
+
* runtime reconciler; parity is enforced two ways:
|
|
11
|
+
* 1. Each migration that adds/removes/modifies a permission must INSERT
|
|
12
|
+
* (or UPDATE / DELETE) the corresponding `org_rol_permissions` row in
|
|
13
|
+
* the same transaction.
|
|
14
|
+
* 2. `apps/api/src/auth/multi-tenancy/__tests__/permissions-catalog-sync.integration.test.ts`
|
|
15
|
+
* asserts the TS catalog and the DB rows agree; CI fails on drift.
|
|
16
|
+
*
|
|
17
|
+
* Adding a permission:
|
|
18
|
+
* 1. Add an entry below.
|
|
19
|
+
* 2. Add a row to the migration (INSERT INTO org_rol_permissions ...) in
|
|
20
|
+
* the same transaction as any policies/grants that reference the key.
|
|
21
|
+
* 3. Reference it in RLS / middleware as needed.
|
|
22
|
+
* 4. Optionally grant it to one or more system roles in org_rol_grants.
|
|
23
|
+
*
|
|
24
|
+
* Removing a permission: follow the deletion runbook — never just delete
|
|
25
|
+
* the entry. Existing role grants and policy references must be cleared first.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
export const PERMISSIONS = {
|
|
29
|
+
ORG_READ: 'org.read',
|
|
30
|
+
ORG_MANAGE: 'org.manage',
|
|
31
|
+
ORG_DELETE: 'org.delete',
|
|
32
|
+
MEMBERS_MANAGE: 'members.manage',
|
|
33
|
+
ROLES_MANAGE: 'roles.manage',
|
|
34
|
+
SECRETS_MANAGE: 'secrets.manage',
|
|
35
|
+
OPERATIONS_READ: 'operations.read',
|
|
36
|
+
OPERATIONS_MANAGE: 'operations.manage',
|
|
37
|
+
ACQUISITION_MANAGE: 'acquisition.manage',
|
|
38
|
+
PROJECTS_MANAGE: 'projects.manage',
|
|
39
|
+
CLIENTS_MANAGE: 'clients.manage'
|
|
40
|
+
} as const
|
|
41
|
+
|
|
42
|
+
export type PermissionKey = (typeof PERMISSIONS)[keyof typeof PERMISSIONS]
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Static metadata for each permission. Mirrored into org_rol_permissions by
|
|
46
|
+
* a migration `INSERT` in the same transaction as any change to this catalog.
|
|
47
|
+
* is_org_grantable=false means the permission is reserved to system roles
|
|
48
|
+
* only — custom roles cannot include it (privilege-escalation guard).
|
|
49
|
+
*/
|
|
50
|
+
export interface PermissionDescriptor {
|
|
51
|
+
key: PermissionKey
|
|
52
|
+
description: string
|
|
53
|
+
isOrgGrantable: boolean
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export const PERMISSION_CATALOG: readonly PermissionDescriptor[] = [
|
|
57
|
+
{
|
|
58
|
+
key: 'org.read',
|
|
59
|
+
description: 'Read organization profile and listings',
|
|
60
|
+
isOrgGrantable: true
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: 'org.manage',
|
|
64
|
+
description: 'Update organization settings',
|
|
65
|
+
isOrgGrantable: false
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: 'org.delete',
|
|
69
|
+
description: 'Delete the organization (owner-only)',
|
|
70
|
+
isOrgGrantable: false
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: 'members.manage',
|
|
74
|
+
description: 'Invite, remove, and reassign roles for members',
|
|
75
|
+
isOrgGrantable: false
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: 'roles.manage',
|
|
79
|
+
description: 'Grant or revoke privileged system roles (owner, admin) within the organization',
|
|
80
|
+
isOrgGrantable: false
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
key: 'secrets.manage',
|
|
84
|
+
description: 'Create, update, and delete API keys and credentials',
|
|
85
|
+
isOrgGrantable: false
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
key: 'operations.read',
|
|
89
|
+
description: 'View executions, sessions, schedules, and command queue',
|
|
90
|
+
isOrgGrantable: true
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
key: 'operations.manage',
|
|
94
|
+
description: 'Run and modify executions, sessions, schedules, queue',
|
|
95
|
+
isOrgGrantable: true
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
key: 'acquisition.manage',
|
|
99
|
+
description:
|
|
100
|
+
'Create, update, and delete acquisition records (acq_companies, acq_contacts, acq_deals, acq_lists*, acq_content*, acquisition storage files)',
|
|
101
|
+
isOrgGrantable: false
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
key: 'projects.manage',
|
|
105
|
+
description: 'Create, update, and delete project records (prj_projects, prj_milestones, prj_tasks, prj_notes)',
|
|
106
|
+
isOrgGrantable: false
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
key: 'clients.manage',
|
|
110
|
+
description: 'Create, update, and delete client hub records (clients, clt_* satellites)',
|
|
111
|
+
isOrgGrantable: false
|
|
112
|
+
}
|
|
113
|
+
] as const
|
|
114
|
+
|
|
115
|
+
const PERMISSION_KEY_SET: ReadonlySet<string> = new Set(PERMISSION_CATALOG.map((p) => p.key))
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Type guard. Use at trust boundaries (request input, third-party data) before
|
|
119
|
+
* passing a string to `has_org_permission` / `requireOrganizationPermission`.
|
|
120
|
+
*/
|
|
121
|
+
export function isPermissionKey(value: unknown): value is PermissionKey {
|
|
122
|
+
return typeof value === 'string' && PERMISSION_KEY_SET.has(value)
|
|
123
|
+
}
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
|
|
3
|
-
const PermissionKeySchema = z.string().min(1).max(100)
|
|
4
|
-
|
|
5
|
-
export const OrgRoleParamsSchema = z
|
|
6
|
-
.object({
|
|
7
|
-
orgId: z.string().uuid(),
|
|
8
|
-
roleId: z.string().uuid()
|
|
9
|
-
})
|
|
10
|
-
.strict()
|
|
11
|
-
|
|
12
|
-
export const OrgRolesParamsSchema = z
|
|
13
|
-
.object({
|
|
14
|
-
orgId: z.string().uuid()
|
|
15
|
-
})
|
|
16
|
-
.strict()
|
|
17
|
-
|
|
18
|
-
export const MembershipRoleParamsSchema = z
|
|
19
|
-
.object({
|
|
20
|
-
membershipId: z.string().min(1),
|
|
21
|
-
roleId: z.string().uuid()
|
|
22
|
-
})
|
|
23
|
-
.strict()
|
|
24
|
-
|
|
25
|
-
export const MembershipParamsSchema = z
|
|
26
|
-
.object({
|
|
27
|
-
membershipId: z.string().min(1)
|
|
28
|
-
})
|
|
29
|
-
.strict()
|
|
30
|
-
|
|
31
|
-
export const CreateOrgRoleRequestSchema = z
|
|
32
|
-
.object({
|
|
33
|
-
name: z.string().min(1).max(100).trim(),
|
|
34
|
-
slug: z
|
|
35
|
-
.string()
|
|
36
|
-
.min(1)
|
|
37
|
-
.max(100)
|
|
38
|
-
.regex(/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/, 'Role slug must be lowercase letters, numbers, dashes, or underscores'),
|
|
39
|
-
description: z.string().max(500).trim().optional(),
|
|
40
|
-
permissionKeys: z.array(PermissionKeySchema).default([])
|
|
41
|
-
})
|
|
42
|
-
.strict()
|
|
43
|
-
|
|
44
|
-
export const UpdateOrgRoleRequestSchema = z
|
|
45
|
-
.object({
|
|
46
|
-
name: z.string().min(1).max(100).trim().optional(),
|
|
47
|
-
slug: z
|
|
48
|
-
.string()
|
|
49
|
-
.min(1)
|
|
50
|
-
.max(100)
|
|
51
|
-
.regex(/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/, 'Role slug must be lowercase letters, numbers, dashes, or underscores')
|
|
52
|
-
.optional(),
|
|
53
|
-
description: z.string().max(500).trim().nullable().optional(),
|
|
54
|
-
permissionKeys: z.array(PermissionKeySchema).optional()
|
|
55
|
-
})
|
|
56
|
-
.strict()
|
|
57
|
-
.refine(
|
|
58
|
-
(data) =>
|
|
59
|
-
data.name !== undefined ||
|
|
60
|
-
data.slug !== undefined ||
|
|
61
|
-
data.description !== undefined ||
|
|
62
|
-
data.permissionKeys !== undefined,
|
|
63
|
-
{ message: 'At least one field must be provided' }
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
export const AssignMembershipRoleRequestSchema = z
|
|
67
|
-
.object({
|
|
68
|
-
roleId: z.string().uuid()
|
|
69
|
-
})
|
|
70
|
-
.strict()
|
|
71
|
-
|
|
72
|
-
export type OrgRoleParams = z.infer<typeof OrgRoleParamsSchema>
|
|
73
|
-
export type OrgRolesParams = z.infer<typeof OrgRolesParamsSchema>
|
|
74
|
-
export type MembershipRoleParams = z.infer<typeof MembershipRoleParamsSchema>
|
|
75
|
-
export type MembershipParams = z.infer<typeof MembershipParamsSchema>
|
|
76
|
-
export type CreateOrgRoleInput = z.infer<typeof CreateOrgRoleRequestSchema>
|
|
77
|
-
export type UpdateOrgRoleInput = z.infer<typeof UpdateOrgRoleRequestSchema>
|
|
78
|
-
export type AssignMembershipRoleInput = z.infer<typeof AssignMembershipRoleRequestSchema>
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
const PermissionKeySchema = z.string().min(1).max(100)
|
|
4
|
+
|
|
5
|
+
export const OrgRoleParamsSchema = z
|
|
6
|
+
.object({
|
|
7
|
+
orgId: z.string().uuid(),
|
|
8
|
+
roleId: z.string().uuid()
|
|
9
|
+
})
|
|
10
|
+
.strict()
|
|
11
|
+
|
|
12
|
+
export const OrgRolesParamsSchema = z
|
|
13
|
+
.object({
|
|
14
|
+
orgId: z.string().uuid()
|
|
15
|
+
})
|
|
16
|
+
.strict()
|
|
17
|
+
|
|
18
|
+
export const MembershipRoleParamsSchema = z
|
|
19
|
+
.object({
|
|
20
|
+
membershipId: z.string().min(1),
|
|
21
|
+
roleId: z.string().uuid()
|
|
22
|
+
})
|
|
23
|
+
.strict()
|
|
24
|
+
|
|
25
|
+
export const MembershipParamsSchema = z
|
|
26
|
+
.object({
|
|
27
|
+
membershipId: z.string().min(1)
|
|
28
|
+
})
|
|
29
|
+
.strict()
|
|
30
|
+
|
|
31
|
+
export const CreateOrgRoleRequestSchema = z
|
|
32
|
+
.object({
|
|
33
|
+
name: z.string().min(1).max(100).trim(),
|
|
34
|
+
slug: z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1)
|
|
37
|
+
.max(100)
|
|
38
|
+
.regex(/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/, 'Role slug must be lowercase letters, numbers, dashes, or underscores'),
|
|
39
|
+
description: z.string().max(500).trim().optional(),
|
|
40
|
+
permissionKeys: z.array(PermissionKeySchema).default([])
|
|
41
|
+
})
|
|
42
|
+
.strict()
|
|
43
|
+
|
|
44
|
+
export const UpdateOrgRoleRequestSchema = z
|
|
45
|
+
.object({
|
|
46
|
+
name: z.string().min(1).max(100).trim().optional(),
|
|
47
|
+
slug: z
|
|
48
|
+
.string()
|
|
49
|
+
.min(1)
|
|
50
|
+
.max(100)
|
|
51
|
+
.regex(/^[a-z0-9]+(?:[-_][a-z0-9]+)*$/, 'Role slug must be lowercase letters, numbers, dashes, or underscores')
|
|
52
|
+
.optional(),
|
|
53
|
+
description: z.string().max(500).trim().nullable().optional(),
|
|
54
|
+
permissionKeys: z.array(PermissionKeySchema).optional()
|
|
55
|
+
})
|
|
56
|
+
.strict()
|
|
57
|
+
.refine(
|
|
58
|
+
(data) =>
|
|
59
|
+
data.name !== undefined ||
|
|
60
|
+
data.slug !== undefined ||
|
|
61
|
+
data.description !== undefined ||
|
|
62
|
+
data.permissionKeys !== undefined,
|
|
63
|
+
{ message: 'At least one field must be provided' }
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
export const AssignMembershipRoleRequestSchema = z
|
|
67
|
+
.object({
|
|
68
|
+
roleId: z.string().uuid()
|
|
69
|
+
})
|
|
70
|
+
.strict()
|
|
71
|
+
|
|
72
|
+
export type OrgRoleParams = z.infer<typeof OrgRoleParamsSchema>
|
|
73
|
+
export type OrgRolesParams = z.infer<typeof OrgRolesParamsSchema>
|
|
74
|
+
export type MembershipRoleParams = z.infer<typeof MembershipRoleParamsSchema>
|
|
75
|
+
export type MembershipParams = z.infer<typeof MembershipParamsSchema>
|
|
76
|
+
export type CreateOrgRoleInput = z.infer<typeof CreateOrgRoleRequestSchema>
|
|
77
|
+
export type UpdateOrgRoleInput = z.infer<typeof UpdateOrgRoleRequestSchema>
|
|
78
|
+
export type AssignMembershipRoleInput = z.infer<typeof AssignMembershipRoleRequestSchema>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
export {
|
|
2
|
-
AssignMembershipRoleRequestSchema,
|
|
3
|
-
CreateOrgRoleRequestSchema,
|
|
4
|
-
MembershipParamsSchema,
|
|
5
|
-
MembershipRoleParamsSchema,
|
|
6
|
-
OrgRoleParamsSchema,
|
|
7
|
-
OrgRolesParamsSchema,
|
|
8
|
-
UpdateOrgRoleRequestSchema,
|
|
9
|
-
type AssignMembershipRoleInput,
|
|
10
|
-
type CreateOrgRoleInput,
|
|
11
|
-
type MembershipParams,
|
|
12
|
-
type MembershipRoleParams,
|
|
13
|
-
type OrgRoleParams,
|
|
14
|
-
type OrgRolesParams,
|
|
15
|
-
type UpdateOrgRoleInput
|
|
16
|
-
} from './api-schemas'
|
|
1
|
+
export {
|
|
2
|
+
AssignMembershipRoleRequestSchema,
|
|
3
|
+
CreateOrgRoleRequestSchema,
|
|
4
|
+
MembershipParamsSchema,
|
|
5
|
+
MembershipRoleParamsSchema,
|
|
6
|
+
OrgRoleParamsSchema,
|
|
7
|
+
OrgRolesParamsSchema,
|
|
8
|
+
UpdateOrgRoleRequestSchema,
|
|
9
|
+
type AssignMembershipRoleInput,
|
|
10
|
+
type CreateOrgRoleInput,
|
|
11
|
+
type MembershipParams,
|
|
12
|
+
type MembershipRoleParams,
|
|
13
|
+
type OrgRoleParams,
|
|
14
|
+
type OrgRolesParams,
|
|
15
|
+
type UpdateOrgRoleInput
|
|
16
|
+
} from './api-schemas'
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Single source of truth for all active theme preset names.
|
|
5
|
-
*
|
|
6
|
-
* This is the canonical list. To add a preset:
|
|
7
|
-
* 1. Add the name here.
|
|
8
|
-
* 2. Create `packages/ui/src/theme/presets/{name}.ts` exporting `{name}Preset: ThemePreset`.
|
|
9
|
-
* 3. Add to `PRESETS` record in `packages/ui/src/theme/presets/index.ts`.
|
|
10
|
-
* 4. Add to `PresetName` union in `packages/ui/src/theme/presets/types.ts`.
|
|
11
|
-
* 5. Add a card in `apps/command-center/src/features/settings/appearance/components/AppearanceSettings.tsx`.
|
|
12
|
-
*
|
|
13
|
-
* The union type (`ThemePresetName`) and Zod enum (`ThemePresetEnum`) are derived
|
|
14
|
-
* automatically — no other files need updating.
|
|
15
|
-
*/
|
|
16
|
-
export const THEME_PRESETS = [
|
|
17
|
-
'default',
|
|
18
|
-
'tactical',
|
|
19
|
-
'regal',
|
|
20
|
-
'cyber-volt',
|
|
21
|
-
'aurora',
|
|
22
|
-
'rose-gold',
|
|
23
|
-
'midnight',
|
|
24
|
-
'titanium',
|
|
25
|
-
'canopy',
|
|
26
|
-
'slate',
|
|
27
|
-
'cyber-strike',
|
|
28
|
-
'cyber-chrome',
|
|
29
|
-
'cyber-void',
|
|
30
|
-
'nirvana',
|
|
31
|
-
'wave',
|
|
32
|
-
'synapse',
|
|
33
|
-
'cortex',
|
|
34
|
-
'helios',
|
|
35
|
-
'graphite',
|
|
36
|
-
'quarry'
|
|
37
|
-
] as const satisfies readonly string[]
|
|
38
|
-
|
|
39
|
-
export type ThemePresetName = (typeof THEME_PRESETS)[number]
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Zod enum derived from THEME_PRESETS.
|
|
43
|
-
* Use `.catch('default')` at write-path callsites to tolerate stale/unknown values.
|
|
44
|
-
*/
|
|
45
|
-
export const ThemePresetEnum = z.enum(THEME_PRESETS)
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Single source of truth for all active theme preset names.
|
|
5
|
+
*
|
|
6
|
+
* This is the canonical list. To add a preset:
|
|
7
|
+
* 1. Add the name here.
|
|
8
|
+
* 2. Create `packages/ui/src/theme/presets/{name}.ts` exporting `{name}Preset: ThemePreset`.
|
|
9
|
+
* 3. Add to `PRESETS` record in `packages/ui/src/theme/presets/index.ts`.
|
|
10
|
+
* 4. Add to `PresetName` union in `packages/ui/src/theme/presets/types.ts`.
|
|
11
|
+
* 5. Add a card in `apps/command-center/src/features/settings/appearance/components/AppearanceSettings.tsx`.
|
|
12
|
+
*
|
|
13
|
+
* The union type (`ThemePresetName`) and Zod enum (`ThemePresetEnum`) are derived
|
|
14
|
+
* automatically — no other files need updating.
|
|
15
|
+
*/
|
|
16
|
+
export const THEME_PRESETS = [
|
|
17
|
+
'default',
|
|
18
|
+
'tactical',
|
|
19
|
+
'regal',
|
|
20
|
+
'cyber-volt',
|
|
21
|
+
'aurora',
|
|
22
|
+
'rose-gold',
|
|
23
|
+
'midnight',
|
|
24
|
+
'titanium',
|
|
25
|
+
'canopy',
|
|
26
|
+
'slate',
|
|
27
|
+
'cyber-strike',
|
|
28
|
+
'cyber-chrome',
|
|
29
|
+
'cyber-void',
|
|
30
|
+
'nirvana',
|
|
31
|
+
'wave',
|
|
32
|
+
'synapse',
|
|
33
|
+
'cortex',
|
|
34
|
+
'helios',
|
|
35
|
+
'graphite',
|
|
36
|
+
'quarry'
|
|
37
|
+
] as const satisfies readonly string[]
|
|
38
|
+
|
|
39
|
+
export type ThemePresetName = (typeof THEME_PRESETS)[number]
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Zod enum derived from THEME_PRESETS.
|
|
43
|
+
* Use `.catch('default')` at write-path callsites to tolerate stale/unknown values.
|
|
44
|
+
*/
|
|
45
|
+
export const ThemePresetEnum = z.enum(THEME_PRESETS)
|