@vertesia/common 1.6.0-dev.20260923.085325Z → 1.6.0-dev.20261008.064737Z
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/lib/access-control-values.d.ts +2 -2
- package/lib/access-control-values.d.ts.map +1 -1
- package/lib/access-control-values.js +2 -2
- package/lib/access-control-values.js.map +1 -1
- package/lib/access-control.d.ts +7 -8
- package/lib/access-control.d.ts.map +1 -1
- package/lib/access-control.js +5 -0
- package/lib/access-control.js.map +1 -1
- package/lib/analytics.d.ts +6 -7
- package/lib/analytics.d.ts.map +1 -1
- package/lib/api-contract/components.generated.json +2553 -1046
- package/lib/api-contract/engine.d.ts +65 -0
- package/lib/api-contract/engine.d.ts.map +1 -0
- package/lib/api-contract/engine.js +569 -0
- package/lib/api-contract/engine.js.map +1 -0
- package/lib/api-contract/index.d.ts +21 -182
- package/lib/api-contract/index.d.ts.map +1 -1
- package/lib/api-contract/index.js +13 -551
- package/lib/api-contract/index.js.map +1 -1
- package/lib/api-schemas/access-control.d.ts +33 -10
- package/lib/api-schemas/access-control.d.ts.map +1 -1
- package/lib/api-schemas/access-control.js +7 -6
- package/lib/api-schemas/access-control.js.map +1 -1
- package/lib/api-schemas/account.d.ts +5 -9
- package/lib/api-schemas/account.d.ts.map +1 -1
- package/lib/api-schemas/account.js +0 -7
- package/lib/api-schemas/account.js.map +1 -1
- package/lib/api-schemas/agent-budget.d.ts +15 -0
- package/lib/api-schemas/agent-budget.d.ts.map +1 -0
- package/lib/api-schemas/agent-budget.js +55 -0
- package/lib/api-schemas/agent-budget.js.map +1 -0
- package/lib/api-schemas/agent-runs.d.ts +1525 -100
- package/lib/api-schemas/agent-runs.d.ts.map +1 -1
- package/lib/api-schemas/agent-runs.js +60 -28
- package/lib/api-schemas/agent-runs.js.map +1 -1
- package/lib/api-schemas/apikey.d.ts +11 -10
- package/lib/api-schemas/apikey.d.ts.map +1 -1
- package/lib/api-schemas/apikey.js.map +1 -1
- package/lib/api-schemas/app-lifecycle.d.ts +13 -0
- package/lib/api-schemas/app-lifecycle.d.ts.map +1 -1
- package/lib/api-schemas/app-lifecycle.js +4 -0
- package/lib/api-schemas/app-lifecycle.js.map +1 -1
- package/lib/api-schemas/app-runtime.d.ts +1821 -108
- package/lib/api-schemas/app-runtime.d.ts.map +1 -1
- package/lib/api-schemas/audit-trail.d.ts +275 -0
- package/lib/api-schemas/audit-trail.d.ts.map +1 -1
- package/lib/api-schemas/audit-trail.js +156 -1
- package/lib/api-schemas/audit-trail.js.map +1 -1
- package/lib/api-schemas/content.d.ts +665 -30
- package/lib/api-schemas/content.d.ts.map +1 -1
- package/lib/api-schemas/content.js +47 -0
- package/lib/api-schemas/content.js.map +1 -1
- package/lib/api-schemas/cost-analytics.d.ts +19 -0
- package/lib/api-schemas/cost-analytics.d.ts.map +1 -1
- package/lib/api-schemas/cost-analytics.js +38 -2
- package/lib/api-schemas/cost-analytics.js.map +1 -1
- package/lib/api-schemas/document-processing.d.ts +381 -18
- package/lib/api-schemas/document-processing.d.ts.map +1 -1
- package/lib/api-schemas/environment.d.ts +0 -5
- package/lib/api-schemas/environment.d.ts.map +1 -1
- package/lib/api-schemas/environment.js +0 -1
- package/lib/api-schemas/environment.js.map +1 -1
- package/lib/api-schemas/events.d.ts +1143 -54
- package/lib/api-schemas/events.d.ts.map +1 -1
- package/lib/api-schemas/group.d.ts +2 -1
- package/lib/api-schemas/group.d.ts.map +1 -1
- package/lib/api-schemas/group.js.map +1 -1
- package/lib/api-schemas/index.d.ts +2 -0
- package/lib/api-schemas/index.d.ts.map +1 -1
- package/lib/api-schemas/index.js +2 -0
- package/lib/api-schemas/index.js.map +1 -1
- package/lib/api-schemas/inference-profile.d.ts +5017 -0
- package/lib/api-schemas/inference-profile.d.ts.map +1 -0
- package/lib/api-schemas/inference-profile.js +135 -0
- package/lib/api-schemas/inference-profile.js.map +1 -0
- package/lib/api-schemas/integrations.d.ts +6 -6
- package/lib/api-schemas/interaction.d.ts +34391 -703
- package/lib/api-schemas/interaction.d.ts.map +1 -1
- package/lib/api-schemas/interaction.js +34 -1
- package/lib/api-schemas/interaction.js.map +1 -1
- package/lib/api-schemas/invites.d.ts +10 -9
- package/lib/api-schemas/invites.d.ts.map +1 -1
- package/lib/api-schemas/invites.js.map +1 -1
- package/lib/api-schemas/process.d.ts +653 -34
- package/lib/api-schemas/process.d.ts.map +1 -1
- package/lib/api-schemas/process.js +66 -0
- package/lib/api-schemas/process.js.map +1 -1
- package/lib/api-schemas/project-configuration.d.ts +1323 -62
- package/lib/api-schemas/project-configuration.d.ts.map +1 -1
- package/lib/api-schemas/project-configuration.js +15 -1
- package/lib/api-schemas/project-configuration.js.map +1 -1
- package/lib/api-schemas/project.d.ts +2031 -116
- package/lib/api-schemas/project.d.ts.map +1 -1
- package/lib/api-schemas/project.js +9 -1
- package/lib/api-schemas/project.js.map +1 -1
- package/lib/api-schemas/quota.d.ts +7 -6
- package/lib/api-schemas/quota.d.ts.map +1 -1
- package/lib/api-schemas/quota.js.map +1 -1
- package/lib/api-schemas/registry.d.ts +28171 -36096
- package/lib/api-schemas/registry.d.ts.map +1 -1
- package/lib/api-schemas/registry.js +77 -30
- package/lib/api-schemas/registry.js.map +1 -1
- package/lib/api-schemas/run-budget.d.ts +16 -0
- package/lib/api-schemas/run-budget.d.ts.map +1 -0
- package/lib/api-schemas/run-budget.js +22 -0
- package/lib/api-schemas/run-budget.js.map +1 -0
- package/lib/api-schemas/secrets.d.ts +0 -71
- package/lib/api-schemas/secrets.d.ts.map +1 -1
- package/lib/api-schemas/secrets.js +0 -73
- package/lib/api-schemas/secrets.js.map +1 -1
- package/lib/api-schemas/store.d.ts +6388 -338
- package/lib/api-schemas/store.d.ts.map +1 -1
- package/lib/api-schemas/store.js +11 -0
- package/lib/api-schemas/store.js.map +1 -1
- package/lib/api-schemas/user.d.ts +9 -8
- package/lib/api-schemas/user.d.ts.map +1 -1
- package/lib/api-schemas/user.js.map +1 -1
- package/lib/api-schemas/view-execution.d.ts +8 -0
- package/lib/api-schemas/view-execution.d.ts.map +1 -1
- package/lib/api-schemas/views.d.ts +14 -0
- package/lib/api-schemas/views.d.ts.map +1 -1
- package/lib/api-schemas/workflow-runs.d.ts +335 -12
- package/lib/api-schemas/workflow-runs.d.ts.map +1 -1
- package/lib/api-schemas/workflow-runs.js +2 -0
- package/lib/api-schemas/workflow-runs.js.map +1 -1
- package/lib/apikey.d.ts +30 -25
- package/lib/apikey.d.ts.map +1 -1
- package/lib/apikey.js.map +1 -1
- package/lib/apps.d.ts +116 -121
- package/lib/apps.d.ts.map +1 -1
- package/lib/apps.js.map +1 -1
- package/lib/audit-trail.d.ts +30 -19
- package/lib/audit-trail.d.ts.map +1 -1
- package/lib/audit-trail.js +6 -0
- package/lib/audit-trail.js.map +1 -1
- package/lib/browser-credentials.d.ts +11 -12
- package/lib/browser-credentials.d.ts.map +1 -1
- package/lib/common.d.ts +17 -24
- package/lib/common.d.ts.map +1 -1
- package/lib/content-query.d.ts +3 -4
- package/lib/content-query.d.ts.map +1 -1
- package/lib/cost-analytics.d.ts +13 -21
- package/lib/cost-analytics.d.ts.map +1 -1
- package/lib/cost-analytics.js +0 -7
- package/lib/cost-analytics.js.map +1 -1
- package/lib/data-platform.d.ts +79 -88
- package/lib/data-platform.d.ts.map +1 -1
- package/lib/data-platform.js.map +1 -1
- package/lib/delegation.d.ts +4 -5
- package/lib/delegation.d.ts.map +1 -1
- package/lib/email.d.ts +15 -17
- package/lib/email.d.ts.map +1 -1
- package/lib/email.js.map +1 -1
- package/lib/embeddings.d.ts +25 -26
- package/lib/embeddings.d.ts.map +1 -1
- package/lib/environment.d.ts +16 -17
- package/lib/environment.d.ts.map +1 -1
- package/lib/environment.js.map +1 -1
- package/lib/facets.d.ts +3 -4
- package/lib/facets.d.ts.map +1 -1
- package/lib/group.d.ts +6 -7
- package/lib/group.d.ts.map +1 -1
- package/lib/group.js.map +1 -1
- package/lib/index.d.ts +3 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/inference-profile.d.ts +17 -0
- package/lib/inference-profile.d.ts.map +1 -0
- package/lib/inference-profile.js +2 -0
- package/lib/inference-profile.js.map +1 -0
- package/lib/integrations.d.ts +19 -20
- package/lib/integrations.d.ts.map +1 -1
- package/lib/integrations.js.map +1 -1
- package/lib/interaction.d.ts +68 -73
- package/lib/interaction.d.ts.map +1 -1
- package/lib/interaction.js.map +1 -1
- package/lib/meters.d.ts +4 -5
- package/lib/meters.d.ts.map +1 -1
- package/lib/oauth-server.d.ts +40 -41
- package/lib/oauth-server.d.ts.map +1 -1
- package/lib/oauth.d.ts +9 -10
- package/lib/oauth.d.ts.map +1 -1
- package/lib/payload.d.ts +11 -14
- package/lib/payload.d.ts.map +1 -1
- package/lib/pending-asks.d.ts +8 -13
- package/lib/pending-asks.d.ts.map +1 -1
- package/lib/pending-asks.js +0 -4
- package/lib/pending-asks.js.map +1 -1
- package/lib/platform-event.d.ts +48 -71
- package/lib/platform-event.d.ts.map +1 -1
- package/lib/platform-event.js.map +1 -1
- package/lib/principal-context.d.ts +3 -3
- package/lib/principal-context.d.ts.map +1 -1
- package/lib/project.d.ts +42 -43
- package/lib/project.d.ts.map +1 -1
- package/lib/project.js.map +1 -1
- package/lib/prompt.d.ts +14 -16
- package/lib/prompt.d.ts.map +1 -1
- package/lib/prompt.js.map +1 -1
- package/lib/query.d.ts +10 -13
- package/lib/query.d.ts.map +1 -1
- package/lib/rate-limiter.d.ts +7 -11
- package/lib/rate-limiter.d.ts.map +1 -1
- package/lib/refs.d.ts +2 -3
- package/lib/refs.d.ts.map +1 -1
- package/lib/refs.js.map +1 -1
- package/lib/roles/types.d.ts +5 -6
- package/lib/roles/types.d.ts.map +1 -1
- package/lib/roles/types.js.map +1 -1
- package/lib/run-budget.d.ts +4 -0
- package/lib/run-budget.d.ts.map +1 -0
- package/lib/run-budget.js +2 -0
- package/lib/run-budget.js.map +1 -0
- package/lib/runs.d.ts +9 -10
- package/lib/runs.d.ts.map +1 -1
- package/lib/secrets.d.ts +10 -21
- package/lib/secrets.d.ts.map +1 -1
- package/lib/store/agent-approval.d.ts +4 -5
- package/lib/store/agent-approval.d.ts.map +1 -1
- package/lib/store/agent-approval.js.map +1 -1
- package/lib/store/agent-run.d.ts +50 -52
- package/lib/store/agent-run.d.ts.map +1 -1
- package/lib/store/agent-run.js.map +1 -1
- package/lib/store/collections.d.ts +11 -12
- package/lib/store/collections.d.ts.map +1 -1
- package/lib/store/collections.js.map +1 -1
- package/lib/store/conversation-state.d.ts +14 -8
- package/lib/store/conversation-state.d.ts.map +1 -1
- package/lib/store/doc-analyzer.d.ts +7 -8
- package/lib/store/doc-analyzer.d.ts.map +1 -1
- package/lib/store/dsl-workflow.d.ts +10 -12
- package/lib/store/dsl-workflow.d.ts.map +1 -1
- package/lib/store/dsl-workflow.js.map +1 -1
- package/lib/store/duration.d.ts +12 -0
- package/lib/store/duration.d.ts.map +1 -0
- package/lib/store/duration.js +2 -0
- package/lib/store/duration.js.map +1 -0
- package/lib/store/grounded-extraction.d.ts +6 -7
- package/lib/store/grounded-extraction.d.ts.map +1 -1
- package/lib/store/intake-policy-schema.generated.d.ts.map +1 -1
- package/lib/store/intake-policy-schema.generated.js +143 -2
- package/lib/store/intake-policy-schema.generated.js.map +1 -1
- package/lib/store/process.d.ts +70 -69
- package/lib/store/process.d.ts.map +1 -1
- package/lib/store/process.js.map +1 -1
- package/lib/store/rendering.d.ts +6 -12
- package/lib/store/rendering.d.ts.map +1 -1
- package/lib/store/rendering.js +0 -5
- package/lib/store/rendering.js.map +1 -1
- package/lib/store/signals.d.ts +43 -0
- package/lib/store/signals.d.ts.map +1 -1
- package/lib/store/signals.js +6 -1
- package/lib/store/signals.js.map +1 -1
- package/lib/store/store.d.ts +92 -91
- package/lib/store/store.d.ts.map +1 -1
- package/lib/store/store.js.map +1 -1
- package/lib/store/task.d.ts +10 -14
- package/lib/store/task.d.ts.map +1 -1
- package/lib/store/workflow.d.ts +35 -41
- package/lib/store/workflow.d.ts.map +1 -1
- package/lib/store/workflow.js.map +1 -1
- package/lib/sts-token-types.d.ts +14 -19
- package/lib/sts-token-types.d.ts.map +1 -1
- package/lib/tools.d.ts +12 -13
- package/lib/tools.d.ts.map +1 -1
- package/lib/transient-tokens.d.ts +3 -3
- package/lib/transient-tokens.d.ts.map +1 -1
- package/lib/user.d.ts +16 -20
- package/lib/user.d.ts.map +1 -1
- package/lib/user.js.map +1 -1
- package/lib/vertesia-common.js +2 -2
- package/lib/vertesia-common.js.map +1 -1
- package/lib/views.d.ts +61 -64
- package/lib/views.d.ts.map +1 -1
- package/lib/views.js.map +1 -1
- package/lib/wire-types.generated.d.ts +11227 -0
- package/lib/wire-types.generated.d.ts.map +1 -0
- package/lib/wire-types.generated.js +4 -0
- package/lib/wire-types.generated.js.map +1 -0
- package/lib/workflow-analytics.d.ts +21 -19
- package/lib/workflow-analytics.d.ts.map +1 -1
- package/lib/workflow-analytics.js +2 -2
- package/lib/workflow-analytics.js.map +1 -1
- package/package.json +16 -11
- package/src/access-control-values.ts +2 -2
- package/src/access-control.ts +7 -15
- package/src/analytics.ts +6 -13
- package/src/api-contract/components.generated.json +2553 -1046
- package/src/api-contract/engine.ts +641 -0
- package/src/api-contract/index.ts +30 -661
- package/src/api-schemas/access-control.ts +18 -16
- package/src/api-schemas/account.ts +5 -12
- package/src/api-schemas/agent-budget.ts +60 -0
- package/src/api-schemas/agent-runs.ts +63 -27
- package/src/api-schemas/apikey.ts +11 -10
- package/src/api-schemas/app-lifecycle.ts +5 -0
- package/src/api-schemas/audit-trail.ts +175 -1
- package/src/api-schemas/content.ts +55 -0
- package/src/api-schemas/cost-analytics.ts +42 -2
- package/src/api-schemas/environment.ts +0 -1
- package/src/api-schemas/group.ts +2 -1
- package/src/api-schemas/index.ts +2 -0
- package/src/api-schemas/inference-profile.ts +151 -0
- package/src/api-schemas/interaction.ts +40 -1
- package/src/api-schemas/invites.ts +10 -9
- package/src/api-schemas/process.ts +78 -2
- package/src/api-schemas/project-configuration.ts +19 -1
- package/src/api-schemas/project.ts +19 -10
- package/src/api-schemas/quota.ts +7 -6
- package/src/api-schemas/registry.ts +164 -62
- package/src/api-schemas/run-budget.ts +23 -0
- package/src/api-schemas/secrets.ts +0 -84
- package/src/api-schemas/store.ts +12 -0
- package/src/api-schemas/user.ts +9 -8
- package/src/api-schemas/workflow-runs.ts +2 -0
- package/src/apikey.ts +30 -39
- package/src/apps.ts +116 -239
- package/src/audit-trail.ts +37 -35
- package/src/browser-credentials.ts +11 -23
- package/src/common.ts +17 -37
- package/src/content-query.ts +3 -4
- package/src/cost-analytics.ts +13 -35
- package/src/data-platform.ts +79 -168
- package/src/delegation.ts +4 -9
- package/src/email.ts +15 -29
- package/src/embeddings.ts +25 -51
- package/src/environment.ts +16 -33
- package/src/facets.ts +3 -4
- package/src/group.ts +6 -13
- package/src/index.ts +23 -0
- package/src/inference-profile.ts +20 -0
- package/src/integrations.ts +21 -41
- package/src/interaction.ts +68 -137
- package/src/meters.ts +4 -9
- package/src/oauth-server.ts +40 -81
- package/src/oauth.ts +9 -19
- package/src/payload.ts +11 -25
- package/src/pending-asks.ts +8 -22
- package/src/platform-event.ts +48 -122
- package/src/principal-context.ts +3 -3
- package/src/project.ts +43 -86
- package/src/prompt.ts +14 -31
- package/src/query.ts +10 -20
- package/src/rate-limiter.ts +7 -19
- package/src/refs.ts +2 -3
- package/src/roles/types.ts +5 -11
- package/src/run-budget.ts +4 -0
- package/src/runs.ts +9 -19
- package/src/secrets.ts +10 -42
- package/src/store/agent-approval.ts +4 -9
- package/src/store/agent-run.ts +53 -99
- package/src/store/collections.ts +11 -23
- package/src/store/conversation-state.ts +15 -15
- package/src/store/doc-analyzer.ts +7 -15
- package/src/store/dsl-workflow.ts +10 -23
- package/src/store/duration.ts +45 -0
- package/src/store/grounded-extraction.ts +6 -13
- package/src/store/intake-policy-schema.generated.ts +148 -2
- package/src/store/process.ts +70 -140
- package/src/store/rendering.ts +6 -19
- package/src/store/signals.ts +48 -0
- package/src/store/store.ts +92 -181
- package/src/store/task.ts +10 -24
- package/src/store/workflow.ts +35 -71
- package/src/sts-token-types.ts +14 -33
- package/src/tools.ts +12 -25
- package/src/transient-tokens.ts +3 -3
- package/src/user.ts +16 -40
- package/src/views.ts +61 -125
- package/src/wire-types.generated.ts +11888 -0
- package/src/workflow-analytics.ts +21 -19
- package/src/agent-resources.test.ts +0 -89
- package/src/api-contract/components.contract.test.ts +0 -99
- package/src/api-schemas/access-control.contract.test.ts +0 -209
- package/src/api-schemas/account-apikey.test.ts +0 -60
- package/src/api-schemas/account.contract.test.ts +0 -319
- package/src/api-schemas/adapter-edge-cases.test.ts +0 -499
- package/src/api-schemas/agent-communication.contract.test.ts +0 -90
- package/src/api-schemas/agent-history.contract.test.ts +0 -42
- package/src/api-schemas/agent-runs.contract.test.ts +0 -240
- package/src/api-schemas/api-discriminators.test.ts +0 -185
- package/src/api-schemas/apikey.contract.test.ts +0 -270
- package/src/api-schemas/app-delete-summary.contract.test.ts +0 -67
- package/src/api-schemas/bulk-operation.contract.test.ts +0 -39
- package/src/api-schemas/bundle-isolation.test.ts +0 -44
- package/src/api-schemas/commands.contract.test.ts +0 -51
- package/src/api-schemas/cost-analytics.contract.test.ts +0 -64
- package/src/api-schemas/dashboard.contract.test.ts +0 -138
- package/src/api-schemas/data-store.contract.test.ts +0 -97
- package/src/api-schemas/document-processing.contract.test.ts +0 -76
- package/src/api-schemas/emit-json-schema.test.ts +0 -36
- package/src/api-schemas/environment.contract.test.ts +0 -202
- package/src/api-schemas/group.contract.test.ts +0 -205
- package/src/api-schemas/indexing.contract.test.ts +0 -122
- package/src/api-schemas/interaction.contract.test.ts +0 -307
- package/src/api-schemas/invites.contract.test.ts +0 -268
- package/src/api-schemas/llumiverse.contract.test.ts +0 -179
- package/src/api-schemas/mcp-api-key.contract.test.ts +0 -125
- package/src/api-schemas/oauth.contract.test.ts +0 -181
- package/src/api-schemas/parameters.test.ts +0 -402
- package/src/api-schemas/process.contract.test.ts +0 -115
- package/src/api-schemas/project.contract.test.ts +0 -472
- package/src/api-schemas/pruning-limits.test.ts +0 -189
- package/src/api-schemas/quota.contract.test.ts +0 -147
- package/src/api-schemas/registry-groups.test.ts +0 -99
- package/src/api-schemas/response-pruning.test.ts +0 -260
- package/src/api-schemas/store.contract.test.ts +0 -378
- package/src/api-schemas/sts.contract.test.ts +0 -112
- package/src/api-schemas/user.contract.test.ts +0 -197
- package/src/api-schemas/views.contract.test.ts +0 -112
- package/src/api-schemas/zeno-response-contracts.test.ts +0 -380
- package/src/apps.test.ts +0 -89
- package/src/oauth-scopes.test.ts +0 -15
- package/src/roles.test.ts +0 -33
- package/src/schema-for-extraction.test.ts +0 -191
- package/src/store/agent-approval.test.ts +0 -18
- package/src/store/content-type-editing.test.ts +0 -17
- package/src/store/ms.d.ts +0 -42
- package/src/store/schedule.test.ts +0 -59
- package/src/store/workflow.test.ts +0 -640
- package/src/versions.test.ts +0 -13
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
import { Ajv2020 } from 'ajv/dist/2020.js';
|
|
2
|
-
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import {
|
|
4
|
-
type ApiKey,
|
|
5
|
-
type ApiKeyArray,
|
|
6
|
-
type ApiKeyReadResponse,
|
|
7
|
-
ApiKeyTypes,
|
|
8
|
-
type ApiKeyWithValue,
|
|
9
|
-
type CreateApiKeyPayload,
|
|
10
|
-
type UpdateApiKeyPayload,
|
|
11
|
-
} from '../apikey.js';
|
|
12
|
-
import { type ProjectRef, SystemRoles } from '../project.js';
|
|
13
|
-
import type { JsonObject } from './adapter.js';
|
|
14
|
-
import type { ProjectRefArrayFromSchema } from './apikey.js';
|
|
15
|
-
import { ApiSchemaComponents, apiComponentRef, validateApiRequest, validateApiResponse } from './registry.js';
|
|
16
|
-
|
|
17
|
-
/** Exact type identity — `extends` in both directions is too weak (any/unknown slip through). */
|
|
18
|
-
type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
|
|
19
|
-
function assertType<T extends true>(_ok: T): void {}
|
|
20
|
-
|
|
21
|
-
function compile(name: string) {
|
|
22
|
-
const ajv = new Ajv2020({ strictSchema: false, allErrors: true });
|
|
23
|
-
ajv.addSchema({ $id: 'vertesia://openapi', components: { schemas: ApiSchemaComponents } });
|
|
24
|
-
return ajv.compile({ $ref: `vertesia://openapi${apiComponentRef(name as never)}` });
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const VALID_PROJECT_REF = {
|
|
28
|
-
id: '69d4762f24d3048c99149d0b',
|
|
29
|
-
name: 'Research',
|
|
30
|
-
account: '68b1779130afe5403a1589ba',
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const VALID_KEY = {
|
|
34
|
-
id: '68b1779130afe5403a1589bc',
|
|
35
|
-
name: 'CI',
|
|
36
|
-
type: ApiKeyTypes.secret,
|
|
37
|
-
role: SystemRoles.developer,
|
|
38
|
-
account: '68b1779130afe5403a1589ba',
|
|
39
|
-
project: VALID_PROJECT_REF,
|
|
40
|
-
enabled: true,
|
|
41
|
-
created_by: 'ada@acme.test',
|
|
42
|
-
updated_by: 'ada@acme.test',
|
|
43
|
-
created_at: '2026-01-01T00:00:00.000Z',
|
|
44
|
-
updated_at: '2026-01-02T00:00:00.000Z',
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
describe('gate 1 — the schema is the single source of truth for the public API key types', () => {
|
|
48
|
-
it('publishes the exact schema-derived type, not a hand-written twin', () => {
|
|
49
|
-
assertType<Equals<ApiKeyArray, ApiKey[]>>(true);
|
|
50
|
-
assertType<Equals<ProjectRefArrayFromSchema, ProjectRef[]>>(true);
|
|
51
|
-
expect(true).toBe(true);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('types the timestamps as strings, which is what the document always published', () => {
|
|
55
|
-
// The hand-written `ApiKey` said `Date` for all three. JSON has no date type and the
|
|
56
|
-
// component has always declared `format: date-time`, so the old declaration described the
|
|
57
|
-
// Mongoose document, not the response — the same correction `User` and `UserGroup` needed.
|
|
58
|
-
assertType<Equals<ApiKey['created_at'], string>>(true);
|
|
59
|
-
assertType<Equals<ApiKey['updated_at'], string>>(true);
|
|
60
|
-
assertType<Equals<ApiKey['expires_at'], string | undefined>>(true);
|
|
61
|
-
expect(true).toBe(true);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('keeps the secret off the base type and derives the two shapes that carry it', () => {
|
|
65
|
-
// `value` is absent from `ApiKey` entirely, so a handler cannot leak a secret by returning
|
|
66
|
-
// the wrong shape — it has to name a component that declares one.
|
|
67
|
-
assertType<Equals<Extract<keyof ApiKey, 'value'>, never>>(true);
|
|
68
|
-
// Creation always returns the secret; the single-key read returns it only when asked for it
|
|
69
|
-
// AND permitted, which is why the two cannot share a component.
|
|
70
|
-
assertType<Equals<ApiKeyWithValue['value'], string>>(true);
|
|
71
|
-
assertType<Equals<ApiKeyReadResponse['value'], string | undefined>>(true);
|
|
72
|
-
// Everything else is inherited rather than restated.
|
|
73
|
-
assertType<Equals<ApiKeyWithValue['project'], ApiKey['project']>>(true);
|
|
74
|
-
assertType<Equals<ApiKeyReadResponse['role'], ApiKey['role']>>(true);
|
|
75
|
-
expect(true).toBe(true);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('gives create and update the different payloads the two operations actually have', () => {
|
|
79
|
-
// Both pick from `ApiKeySchema`, so a field's type and documentation keep one home; what
|
|
80
|
-
// differs is requiredness and which fields are writable at all — the only two things a write
|
|
81
|
-
// payload legitimately changes about a field it shares.
|
|
82
|
-
// Compared against `ApiKey`, not against the enums directly: the claim is that the payloads
|
|
83
|
-
// are PICKED from the key, so the identity that matters is with the field they came from.
|
|
84
|
-
assertType<Equals<CreateApiKeyPayload['name'], ApiKey['name']>>(true);
|
|
85
|
-
assertType<Equals<CreateApiKeyPayload['role'], ApiKey['role']>>(true);
|
|
86
|
-
assertType<Equals<CreateApiKeyPayload['type'], ApiKey['type'] | undefined>>(true);
|
|
87
|
-
assertType<Equals<CreateApiKeyPayload['expires_at'], ApiKey['expires_at']>>(true);
|
|
88
|
-
assertType<Equals<UpdateApiKeyPayload['name'], ApiKey['name'] | undefined>>(true);
|
|
89
|
-
assertType<Equals<UpdateApiKeyPayload['role'], ApiKey['role'] | undefined>>(true);
|
|
90
|
-
assertType<Equals<UpdateApiKeyPayload['enabled'], ApiKey['enabled'] | undefined>>(true);
|
|
91
|
-
// `name` and `role` are required on create and optional on update — the only difference a
|
|
92
|
-
// write payload legitimately introduces.
|
|
93
|
-
assertType<Equals<CreateApiKeyPayload['name'], string>>(true);
|
|
94
|
-
assertType<Equals<UpdateApiKeyPayload['name'], string | undefined>>(true);
|
|
95
|
-
|
|
96
|
-
// What the picks leave out is the whitelist, and it is now an explicit list rather than a
|
|
97
|
-
// consequence of `Partial<ApiKey>`: the server-owned fields are unreachable from either.
|
|
98
|
-
assertType<Equals<Extract<keyof CreateApiKeyPayload, 'id' | 'account' | 'maskedValue'>, never>>(true);
|
|
99
|
-
assertType<Equals<Extract<keyof CreateApiKeyPayload, 'created_at' | 'enabled' | 'project'>, never>>(true);
|
|
100
|
-
// `type` and `expires_at` are immutable after creation, so update cannot name them.
|
|
101
|
-
assertType<Equals<Extract<keyof UpdateApiKeyPayload, 'type' | 'expires_at'>, never>>(true);
|
|
102
|
-
expect(true).toBe(true);
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
describe('gate 2 — the published components match the closure the types come from', () => {
|
|
107
|
-
it('publishes the single-member key type as a const, not a one-member enum', () => {
|
|
108
|
-
// Both validate identically; only one is byte-identical to what the TypeScript scanner
|
|
109
|
-
// emitted, and slots that have not converted still derive this component — the generator
|
|
110
|
-
// fails the build if the two definitions disagree.
|
|
111
|
-
expect(ApiSchemaComponents.ApiKeyTypes).toEqual({ type: 'string', const: 'sk' });
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('keeps ProjectRef and SystemRoles as shared components rather than inlining them', () => {
|
|
115
|
-
const props = ApiSchemaComponents.ApiKey.properties as Record<string, JsonObject>;
|
|
116
|
-
expect(props.project).toEqual({ $ref: '#/components/schemas/ProjectRef' });
|
|
117
|
-
expect(props.role).toEqual({ $ref: '#/components/schemas/SystemRoles' });
|
|
118
|
-
expect(props.type).toEqual({ $ref: '#/components/schemas/ApiKeyTypes' });
|
|
119
|
-
expect(ApiSchemaComponents.SystemRoles.enum).toContain('content_superadmin');
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('tightens the API key timestamps to date-time, unlike the ACE ones', () => {
|
|
123
|
-
// Safe here in a way it was not for an access control entry: every one of these is written
|
|
124
|
-
// by the server. `expires_at` too — it is computed from a TTL, never copied out of a payload.
|
|
125
|
-
const props = ApiSchemaComponents.ApiKey.properties as Record<string, JsonObject>;
|
|
126
|
-
expect(props.created_at).toEqual({ type: 'string', format: 'date-time' });
|
|
127
|
-
expect(props.updated_at).toEqual({ type: 'string', format: 'date-time' });
|
|
128
|
-
expect(props.expires_at).toEqual({ type: 'string', format: 'date-time' });
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('does not declare value on the base component', () => {
|
|
132
|
-
expect(Object.keys(ApiSchemaComponents.ApiKey.properties as JsonObject)).not.toContain('value');
|
|
133
|
-
expect(ApiSchemaComponents.ApiKey.additionalProperties).toBe(false);
|
|
134
|
-
expect((ApiSchemaComponents.ApiKeyWithValue.required as string[]) ?? []).toContain('value');
|
|
135
|
-
expect((ApiSchemaComponents.ApiKeyReadResponse.required as string[]) ?? []).not.toContain('value');
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('publishes ProjectRef closed, with the documentation the list endpoints rely on', () => {
|
|
139
|
-
const props = ApiSchemaComponents.ProjectRef.properties as Record<string, JsonObject>;
|
|
140
|
-
expect(ApiSchemaComponents.ProjectRef.additionalProperties).toBe(false);
|
|
141
|
-
expect(props.restricted.description).toContain('org admin or owner');
|
|
142
|
-
expect(ApiSchemaComponents.ProjectRef.required).toEqual(['id', 'name', 'account']);
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
describe('gate 3 — AJV validates the same canonical objects that are published', () => {
|
|
147
|
-
it('accepts a minimal key and rejects a missing required field', () => {
|
|
148
|
-
const validate = compile('ApiKey');
|
|
149
|
-
expect(validate(VALID_KEY)).toBe(true);
|
|
150
|
-
const { project: _dropped, ...incomplete } = VALID_KEY;
|
|
151
|
-
expect(validate(incomplete)).toBe(false);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('rejects a base key response that carries a secret', () => {
|
|
155
|
-
// The point of splitting the components: a handler that returns the wrong one is caught at
|
|
156
|
-
// the boundary rather than shipping the secret.
|
|
157
|
-
expect(compile('ApiKey')({ ...VALID_KEY, value: 'sk-live-abcdef' })).toBe(false);
|
|
158
|
-
expect(compile('ApiKeyWithValue')({ ...VALID_KEY, value: 'sk-live-abcdef' })).toBe(true);
|
|
159
|
-
expect(compile('ApiKeyReadResponse')({ ...VALID_KEY, value: 'sk-live-abcdef' })).toBe(true);
|
|
160
|
-
expect(compile('ApiKeyReadResponse')(VALID_KEY)).toBe(true);
|
|
161
|
-
// ...and one that omits it where it is promised.
|
|
162
|
-
expect(compile('ApiKeyWithValue')(VALID_KEY)).toBe(false);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it('rejects a Date where the contract declares a date-time string', () => {
|
|
166
|
-
// What `jsonDoc()` produced before `toApiKeyResponse` existed: `toJSON()` leaves `Date`
|
|
167
|
-
// objects in place, and only `JSON.stringify` converts them — after the enforcer has run.
|
|
168
|
-
// A `Date` fails on `type: string` alone, so this holds with or without format assertion.
|
|
169
|
-
expect(compile('ApiKey')({ ...VALID_KEY, created_at: new Date('2026-01-01T00:00:00.000Z') })).toBe(false);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it('enforces the date-time format through the registry validator, which is what registers formats', () => {
|
|
173
|
-
// The local `compile()` above deliberately does NOT add ajv-formats — it exists to check the
|
|
174
|
-
// published SHAPE. `format` is only asserted by the production validator, so a malformed
|
|
175
|
-
// timestamp has to be checked there or the assertion would pass vacuously.
|
|
176
|
-
expect(validateApiResponse('ApiKey', { ...VALID_KEY, created_at: 'last tuesday' }).valid).toBe(false);
|
|
177
|
-
expect(validateApiResponse('ApiKey', VALID_KEY).valid).toBe(true);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('rejects the internal fields a serialized document would have leaked', () => {
|
|
181
|
-
const validate = compile('ApiKey');
|
|
182
|
-
expect(validate({ ...VALID_KEY, _id: 'deadbeef' })).toBe(false);
|
|
183
|
-
expect(validate({ ...VALID_KEY, hashed_value: 'deadbeef' })).toBe(false);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('constrains the key type and the role to their catalogs', () => {
|
|
187
|
-
const validate = compile('ApiKey');
|
|
188
|
-
expect(validate({ ...VALID_KEY, type: 'pk' })).toBe(false);
|
|
189
|
-
expect(validate({ ...VALID_KEY, role: 'superuser' })).toBe(false);
|
|
190
|
-
expect(validate({ ...VALID_KEY, role: SystemRoles.content_superadmin })).toBe(true);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('requires name and role on a create, which the handler needed and the payload never said', () => {
|
|
194
|
-
const validate = compile('CreateApiKeyPayload');
|
|
195
|
-
expect(validate({ name: 'CI', role: SystemRoles.reader })).toBe(true);
|
|
196
|
-
expect(validate({ name: 'CI', role: SystemRoles.reader, type: 'sk', expires_at: '2030-01-01T00:00:00Z' })).toBe(
|
|
197
|
-
true,
|
|
198
|
-
);
|
|
199
|
-
// `role` is `required: true` on the Mongoose schema: this used to be accepted here and fail
|
|
200
|
-
// inside `ApiKeyModel.create`, which the endpoint reported as a 500.
|
|
201
|
-
expect(validate({ name: 'CI' })).toBe(false);
|
|
202
|
-
// `name` is required by the published `ApiKey` component, so a key created without one could
|
|
203
|
-
// not produce a conforming response.
|
|
204
|
-
expect(validate({ role: SystemRoles.reader })).toBe(false);
|
|
205
|
-
expect(validate({})).toBe(false);
|
|
206
|
-
// Server-owned fields are no longer declared, so sending one is now an error rather than
|
|
207
|
-
// silently ignored.
|
|
208
|
-
expect(validate({ name: 'CI', role: SystemRoles.reader, id: 'x' })).toBe(false);
|
|
209
|
-
expect(validate({ name: 'CI', role: SystemRoles.reader, enabled: true })).toBe(false);
|
|
210
|
-
expect(validate({ name: 'CI', role: SystemRoles.reader, project: VALID_PROJECT_REF })).toBe(false);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it('accepts a partial update and rejects the fields creation owns', () => {
|
|
214
|
-
const validate = compile('UpdateApiKeyPayload');
|
|
215
|
-
expect(validate({})).toBe(true);
|
|
216
|
-
expect(validate({ enabled: false })).toBe(true);
|
|
217
|
-
expect(validate({ name: 'CI', role: SystemRoles.reader, enabled: true })).toBe(true);
|
|
218
|
-
expect(validate({ role: 'superuser' })).toBe(false);
|
|
219
|
-
// Immutable after creation.
|
|
220
|
-
expect(validate({ type: 'sk' })).toBe(false);
|
|
221
|
-
expect(validate({ expires_at: '2030-01-01T00:00:00Z' })).toBe(false);
|
|
222
|
-
expect(validate({ rogue_field: 1 })).toBe(false);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('validates the two query components the scanner expands into parameters', () => {
|
|
226
|
-
expect(compile('ApiKeyListQuery')({ level: 'project' })).toBe(true);
|
|
227
|
-
expect(compile('ApiKeyListQuery')({})).toBe(true);
|
|
228
|
-
expect(compile('ApiKeyListQuery')({ level: 'organization' })).toBe(false);
|
|
229
|
-
expect(compile('ApiKeyReadQuery')({ withValue: true })).toBe(true);
|
|
230
|
-
expect(compile('ApiKeyReadQuery')({ withValue: 'yes' })).toBe(false);
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
describe('gate 4 — runtime enforcement uses the published components', () => {
|
|
235
|
-
it('checks every member of a listing against the same key component', () => {
|
|
236
|
-
expect(validateApiResponse('ApiKeyArray', [VALID_KEY, VALID_KEY]).valid).toBe(true);
|
|
237
|
-
expect(validateApiResponse('ApiKeyArray', []).valid).toBe(true);
|
|
238
|
-
// One key in the listing still carrying its secret is exactly what the fail-closed boundary
|
|
239
|
-
// in `toApiKeyResponse` exists to make impossible.
|
|
240
|
-
expect(validateApiResponse('ApiKeyArray', [VALID_KEY, { ...VALID_KEY, value: 'sk-leak' }]).valid).toBe(false);
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it('rejects an undeclared payload field without removing it', () => {
|
|
244
|
-
const payload: Record<string, unknown> = { name: 'CI', role: SystemRoles.reader, rogue_field: 42 };
|
|
245
|
-
const result = validateApiRequest('CreateApiKeyPayload', payload);
|
|
246
|
-
expect(result.valid).toBe(false);
|
|
247
|
-
expect(payload.rogue_field).toBe(42);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it('hands back the component type on the valid branch', () => {
|
|
251
|
-
const result = validateApiResponse('ApiKey', VALID_KEY);
|
|
252
|
-
expect(result.valid).toBe(true);
|
|
253
|
-
if (result.valid) {
|
|
254
|
-
assertType<Equals<typeof result.data, ApiKey>>(true);
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it('checks the shared project listing against the ref component', () => {
|
|
259
|
-
expect(validateApiResponse('ProjectRefArray', [VALID_PROJECT_REF]).valid).toBe(true);
|
|
260
|
-
expect(validateApiResponse('ProjectRefArray', [{ ...VALID_PROJECT_REF, restricted: true }]).valid).toBe(true);
|
|
261
|
-
expect(validateApiResponse('ProjectRefArray', [{ id: 'p1', name: 'Research' }]).valid).toBe(false);
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it('checks the two single-field responses the key endpoints publish', () => {
|
|
265
|
-
expect(validateApiResponse('AuthTokenResponse', { token: 'ey...' }).valid).toBe(true);
|
|
266
|
-
expect(validateApiResponse('AuthTokenResponse', { token: 'ey...', refresh: 'x' }).valid).toBe(false);
|
|
267
|
-
expect(validateApiResponse('DeleteOperationResult', { acknowledged: true, deletedCount: 1 }).valid).toBe(true);
|
|
268
|
-
expect(validateApiResponse('DeleteOperationResult', { acknowledged: true }).valid).toBe(false);
|
|
269
|
-
});
|
|
270
|
-
});
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { AppDeleteSummary } from '../apps.js';
|
|
3
|
-
import { AppDeleteSummarySchema } from './app-lifecycle.js';
|
|
4
|
-
import { validateApiResponse } from './registry.js';
|
|
5
|
-
|
|
6
|
-
/** Exact type identity — `extends` in both directions is too weak (any/unknown slip through). */
|
|
7
|
-
type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
|
|
8
|
-
function assertType<T extends true>(_ok: T): void {}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* `DeleteApp` published `CountResult` while returning this shape. Response validation therefore
|
|
12
|
-
* reported a missing `count` and every field below as unexpected — and where the check fails closed
|
|
13
|
-
* (local development) that surfaced as a 500 raised AFTER the app had already been deleted, which is
|
|
14
|
-
* the worst possible moment for it. These assertions pin the component to what the handler builds.
|
|
15
|
-
*/
|
|
16
|
-
const REAL_SUMMARY: AppDeleteSummary = {
|
|
17
|
-
confirmed: true,
|
|
18
|
-
app_id: '68b1779130afe5403a1589bc',
|
|
19
|
-
app_name: 'acme-app',
|
|
20
|
-
versions: 2,
|
|
21
|
-
installations: 1,
|
|
22
|
-
storage_prefix: 'apps/acme-app',
|
|
23
|
-
deleted: true,
|
|
24
|
-
warnings: [],
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
describe('AppDeleteSummary — as the DeleteApp response is validated', () => {
|
|
28
|
-
it('accepts what the handler returns after a confirmed delete', () => {
|
|
29
|
-
expect(validateApiResponse('AppDeleteSummary', REAL_SUMMARY).valid).toBe(true);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('accepts the dry-run preview, which is the same shape with deleted: false', () => {
|
|
33
|
-
const preview = { ...REAL_SUMMARY, confirmed: false, deleted: false };
|
|
34
|
-
expect(validateApiResponse('AppDeleteSummary', preview).valid).toBe(true);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('accepts a git-backed app, whose summary carries the repo URL', () => {
|
|
38
|
-
const withRepo = { ...REAL_SUMMARY, git_repo_url: 'https://git.example.com/acme/acme-app.git' };
|
|
39
|
-
expect(validateApiResponse('AppDeleteSummary', withRepo).valid).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('accepts the warnings a partially-degraded cascade collects', () => {
|
|
43
|
-
const warned = {
|
|
44
|
-
...REAL_SUMMARY,
|
|
45
|
-
warnings: ['git repo delete failed: 502', 'version cleanup failed: timeout'],
|
|
46
|
-
};
|
|
47
|
-
expect(validateApiResponse('AppDeleteSummary', warned).valid).toBe(true);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('is NOT interchangeable with CountResult, the component this endpoint used to publish', () => {
|
|
51
|
-
// The regression in one line: neither validates as the other, so the mismatch was total.
|
|
52
|
-
expect(validateApiResponse('CountResult', REAL_SUMMARY).valid).toBe(false);
|
|
53
|
-
expect(validateApiResponse('AppDeleteSummary', { count: 1 }).valid).toBe(false);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('rejects an undeclared field, so the component cannot silently drift from the handler', () => {
|
|
57
|
-
expect(validateApiResponse('AppDeleteSummary', { ...REAL_SUMMARY, secrets_purged: 3 }).valid).toBe(false);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('keeps the public type derived from the schema rather than hand-written beside it', () => {
|
|
61
|
-
assertType<Equals<AppDeleteSummary, ReturnType<typeof AppDeleteSummarySchema.parse>>>(true);
|
|
62
|
-
// Every field the handler always sets is required; only git_repo_url is optional.
|
|
63
|
-
expect(AppDeleteSummarySchema.safeParse({ ...REAL_SUMMARY, warnings: undefined }).success).toBe(false);
|
|
64
|
-
const { git_repo_url: _omitted, ...withoutRepo } = { ...REAL_SUMMARY, git_repo_url: 'https://x' };
|
|
65
|
-
expect(AppDeleteSummarySchema.safeParse(withoutRepo).success).toBe(true);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { BulkOperationPayload, BulkOperationResponse } from '../common.js';
|
|
3
|
-
import type { BulkOperationPayloadSchema, BulkOperationResponseSchema } from './bulk-operation.js';
|
|
4
|
-
import { validateApiRequest, validateApiResponse } from './registry.js';
|
|
5
|
-
|
|
6
|
-
type Equals<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
|
|
7
|
-
function assertType<T extends true>(_value: T): void {}
|
|
8
|
-
|
|
9
|
-
describe('bulk-operation API contract', () => {
|
|
10
|
-
it('derives the public request and response types from the schemas', () => {
|
|
11
|
-
assertType<Equals<BulkOperationPayload, typeof BulkOperationPayloadSchema._output>>(true);
|
|
12
|
-
assertType<Equals<BulkOperationResponse, typeof BulkOperationResponseSchema._output>>(true);
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('validates the exact published request component', () => {
|
|
16
|
-
const valid = { name: 'change_type', ids: ['object-1'], params: { type: 'invoice' } };
|
|
17
|
-
expect(validateApiRequest('BulkOperationPayload', valid).valid).toBe(true);
|
|
18
|
-
expect(validateApiRequest('BulkOperationPayload', { ...valid, extra: true }).valid).toBe(false);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('enforces the response branch selected by operation', () => {
|
|
22
|
-
expect(
|
|
23
|
-
validateApiResponse('BulkOperationResponse', {
|
|
24
|
-
operation: 'delete',
|
|
25
|
-
status: 'completed',
|
|
26
|
-
deleted: 2,
|
|
27
|
-
failed: [],
|
|
28
|
-
}).valid,
|
|
29
|
-
).toBe(true);
|
|
30
|
-
expect(
|
|
31
|
-
validateApiResponse('BulkOperationResponse', {
|
|
32
|
-
operation: 'delete',
|
|
33
|
-
status: 'completed',
|
|
34
|
-
updated: 2,
|
|
35
|
-
failed: [],
|
|
36
|
-
}).valid,
|
|
37
|
-
).toBe(false);
|
|
38
|
-
});
|
|
39
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { gzipSync } from 'node:zlib';
|
|
3
|
-
import { describe, expect, it } from 'vitest';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Keep schema-authoring code out of the common browser bundle and public root entry.
|
|
7
|
-
* Build outputs are required; Turbo builds this package before running its tests.
|
|
8
|
-
* Client packaging is tested by the client package.
|
|
9
|
-
*/
|
|
10
|
-
const path = (relative: string) => new URL(relative, import.meta.url).pathname;
|
|
11
|
-
|
|
12
|
-
const COMMON_BUNDLE = path('../../lib/vertesia-common.js');
|
|
13
|
-
const COMMON_ENTRY = path('../../lib/index.js');
|
|
14
|
-
/** Markers that prove a runtime schema import leaked into a browser artifact. */
|
|
15
|
-
const FORBIDDEN = ['zod', '_zod', 'ZodObject', 'api-schemas', 'toOpenApiComponents', 'ApiSchemaComponents'];
|
|
16
|
-
|
|
17
|
-
/** Headroom over the current ~34 KB gzip; pulling zod in would add roughly 60 KB. */
|
|
18
|
-
const MAX_COMMON_GZIP_BYTES = 45 * 1024;
|
|
19
|
-
|
|
20
|
-
function expectNoSchemaRuntime(file: string, label: string): void {
|
|
21
|
-
const contents = readFileSync(file, 'utf8');
|
|
22
|
-
for (const marker of FORBIDDEN) {
|
|
23
|
-
expect(contents, `${label} must not contain '${marker}'`).not.toContain(marker);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
describe('@vertesia/common runtime schema isolation', () => {
|
|
28
|
-
it('does not runtime-reference the api-schemas subpath from the root entry', () => {
|
|
29
|
-
expect(readFileSync(COMMON_ENTRY, 'utf8')).not.toContain('api-schemas');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('contains no zod import or implementation code', () => {
|
|
33
|
-
expectNoSchemaRuntime(COMMON_BUNDLE, 'common browser bundle');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('stays within its gzip budget', () => {
|
|
37
|
-
const gzipped = gzipSync(readFileSync(COMMON_BUNDLE)).byteLength;
|
|
38
|
-
expect(
|
|
39
|
-
gzipped,
|
|
40
|
-
`common browser bundle grew to ${(gzipped / 1024).toFixed(1)} KB gzip — check whether a ` +
|
|
41
|
-
'runtime schema export leaked into the root barrel',
|
|
42
|
-
).toBeLessThan(MAX_COMMON_GZIP_BYTES);
|
|
43
|
-
});
|
|
44
|
-
});
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { validateApiRequest, validateApiResponse } from './registry.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* The migration-command contracts, pinned where converting them changed what the document says.
|
|
6
|
-
*
|
|
7
|
-
* Both changes are widenings — every request and response that was valid before is still valid — but
|
|
8
|
-
* both are visible in the generated clients, so each one is asserted here rather than described in a
|
|
9
|
-
* commit message.
|
|
10
|
-
*/
|
|
11
|
-
describe('RunMigrationPayload', () => {
|
|
12
|
-
it('accepts the params object migrations are actually invoked with', () => {
|
|
13
|
-
// The shape from `migrate-agent-runs`' own usage comment. The published component declared
|
|
14
|
-
// only `force`, so enforcing it closed would have rejected this.
|
|
15
|
-
expect(
|
|
16
|
-
validateApiRequest('RunMigrationPayload', {
|
|
17
|
-
force: true,
|
|
18
|
-
params: { tenantId: 'abc123_def456', since: '2025-01-01' },
|
|
19
|
-
}),
|
|
20
|
-
).toMatchObject({ valid: true });
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('still accepts the bare force body, and an empty one', () => {
|
|
24
|
-
expect(validateApiRequest('RunMigrationPayload', { force: true }).valid).toBe(true);
|
|
25
|
-
expect(validateApiRequest('RunMigrationPayload', {}).valid).toBe(true);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('rejects an undeclared sibling of params, so the body stays closed', () => {
|
|
29
|
-
// `params` is freeform INSIDE; that is not the same as the body being open. A typo like
|
|
30
|
-
// `parms` has to fail rather than be silently dropped on the floor by the migration.
|
|
31
|
-
const result = validateApiRequest('RunMigrationPayload', { parms: { tenantId: 'x' } });
|
|
32
|
-
expect(result.valid).toBe(false);
|
|
33
|
-
expect(result.valid === false && result.errors.join('; ')).toContain('additional properties');
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
describe('MigrationListResponse', () => {
|
|
38
|
-
it('validates the shape the handler returns', () => {
|
|
39
|
-
expect(
|
|
40
|
-
validateApiResponse('MigrationListResponse', { migrations: [{ name: 'migrate-agent-runs' }] }),
|
|
41
|
-
).toMatchObject({ valid: true });
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('rejects a response that is no longer the listing', () => {
|
|
45
|
-
// The point of giving the component a body: as `z.unknown()` every one of these passed, so
|
|
46
|
-
// the endpoint was wired to the enforcer while validating nothing at all.
|
|
47
|
-
expect(validateApiResponse('MigrationListResponse', { migrations: ['a'] }).valid).toBe(false);
|
|
48
|
-
expect(validateApiResponse('MigrationListResponse', { migration: [] }).valid).toBe(false);
|
|
49
|
-
expect(validateApiResponse('MigrationListResponse', ['migrate-agent-runs']).valid).toBe(false);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { describe, expect, expectTypeOf, it } from 'vitest';
|
|
2
|
-
import type {
|
|
3
|
-
CostAnalyticsQuery,
|
|
4
|
-
CostAnalyticsResponse,
|
|
5
|
-
CostRunPriceQuery,
|
|
6
|
-
ModelPriceComparisonResponse,
|
|
7
|
-
} from '../cost-analytics.js';
|
|
8
|
-
import type {
|
|
9
|
-
CostAnalyticsQuerySchema,
|
|
10
|
-
CostAnalyticsResponseSchema,
|
|
11
|
-
CostRunPriceQuerySchema,
|
|
12
|
-
ModelPriceComparisonResponseSchema,
|
|
13
|
-
} from './cost-analytics.js';
|
|
14
|
-
import { ApiSchemaComponents, validateApiRequest, validateApiResponse } from './registry.js';
|
|
15
|
-
|
|
16
|
-
describe('cost analytics API contracts', () => {
|
|
17
|
-
it('derives the public types from the runtime schemas', () => {
|
|
18
|
-
expectTypeOf<CostAnalyticsQuery>().toEqualTypeOf<import('zod').z.infer<typeof CostAnalyticsQuerySchema>>();
|
|
19
|
-
expectTypeOf<CostAnalyticsResponse>().toEqualTypeOf<
|
|
20
|
-
import('zod').z.infer<typeof CostAnalyticsResponseSchema>
|
|
21
|
-
>();
|
|
22
|
-
expectTypeOf<CostRunPriceQuery>().toEqualTypeOf<import('zod').z.infer<typeof CostRunPriceQuerySchema>>();
|
|
23
|
-
expectTypeOf<ModelPriceComparisonResponse>().toEqualTypeOf<
|
|
24
|
-
import('zod').z.infer<typeof ModelPriceComparisonResponseSchema>
|
|
25
|
-
>();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('accepts string and epoch time boundaries', () => {
|
|
29
|
-
expect(validateApiRequest('CostAnalyticsQuery', { from: '2026-08-01T00:00:00Z' }).valid).toBe(true);
|
|
30
|
-
expect(validateApiRequest('CostAnalyticsQuery', { from: 1_786_060_800_000 }).valid).toBe(true);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('rejects undeclared request fields through the published component', () => {
|
|
34
|
-
expect(validateApiRequest('CostRunPriceQuery', { run_id: 'run-1', hidden_filter: true }).valid).toBe(false);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('validates the published model-price response', () => {
|
|
38
|
-
const response: ModelPriceComparisonResponse = {
|
|
39
|
-
prices: [
|
|
40
|
-
{
|
|
41
|
-
model: 'gpt-5',
|
|
42
|
-
source: 'model_pricing_daily',
|
|
43
|
-
input_list_price_per_m_tokens: 1.25,
|
|
44
|
-
},
|
|
45
|
-
],
|
|
46
|
-
effective_range: { from: '2026-08-01', to: '2026-08-02' },
|
|
47
|
-
};
|
|
48
|
-
expect(validateApiResponse('ModelPriceComparisonResponse', response).valid).toBe(true);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('registers the complete cost analytics closure', () => {
|
|
52
|
-
for (const name of [
|
|
53
|
-
'CostAnalyticsQuery',
|
|
54
|
-
'CostRunPriceQuery',
|
|
55
|
-
'CostModelPricesQuery',
|
|
56
|
-
'CostExportQuery',
|
|
57
|
-
'CostAnalyticsResponse',
|
|
58
|
-
'ModelPriceComparisonResponse',
|
|
59
|
-
'CostRunPriceResponse',
|
|
60
|
-
]) {
|
|
61
|
-
expect(ApiSchemaComponents[name]).toBeDefined();
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
});
|