@xtrape/capsule-contracts-node 0.1.0-public-review.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/LICENSE +48 -0
- package/NOTICE +4 -0
- package/README.md +295 -0
- package/dist/index.cjs +271 -0
- package/dist/index.d.cts +2741 -0
- package/dist/index.d.ts +2741 -0
- package/dist/index.js +179 -0
- package/package.json +63 -0
- package/spec/.source +1 -0
- package/spec/enums/audit-actions.json +213 -0
- package/spec/enums/id-prefixes.json +32 -0
- package/spec/enums/status-enums.json +128 -0
- package/spec/errors.json +128 -0
- package/spec/errors.md +166 -0
- package/spec/openapi/opstage-ce-v0.1.yaml +2085 -0
- package/spec/openapi/redocly.yaml +18 -0
package/spec/errors.json
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./errors.schema.json",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"envelope": {
|
|
5
|
+
"shape": {
|
|
6
|
+
"success": false,
|
|
7
|
+
"error": {
|
|
8
|
+
"code": "STRING (one of codes.code)",
|
|
9
|
+
"message": "STRING (human readable English)",
|
|
10
|
+
"details": "OPTIONAL OBJECT (structured; sensitive values must be redacted)"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"rules": [
|
|
14
|
+
"code MUST be one of the codes in this document",
|
|
15
|
+
"code values are stable, uppercase, snake-case strings",
|
|
16
|
+
"message is English; UI MAY translate locally",
|
|
17
|
+
"details is optional and structured; sensitive values MUST be redacted",
|
|
18
|
+
"HTTP status codes are listed alongside each code; backend MUST use the listed status"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"auditMapping": {
|
|
22
|
+
"rule": "When backend emits an error response that should also produce an AuditEvent, it writes result=FAILURE and metadata.errorCode=<code>",
|
|
23
|
+
"example": {
|
|
24
|
+
"result": "FAILURE",
|
|
25
|
+
"metadata": { "errorCode": "AGENT_TOKEN_INVALID" }
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"groups": [
|
|
29
|
+
{
|
|
30
|
+
"name": "generic",
|
|
31
|
+
"title": "Generic Codes",
|
|
32
|
+
"codes": [
|
|
33
|
+
{ "code": "VALIDATION_FAILED", "httpStatus": 422, "meaning": "Request body or query parameters failed Zod validation." },
|
|
34
|
+
{ "code": "UNAUTHORIZED", "httpStatus": 401, "meaning": "No valid session or token." },
|
|
35
|
+
{ "code": "FORBIDDEN", "httpStatus": 403, "meaning": "Authenticated but not allowed (includes CSRF token mismatch)." },
|
|
36
|
+
{ "code": "NOT_FOUND", "httpStatus": 404, "meaning": "Requested resource does not exist or is not visible to the caller." },
|
|
37
|
+
{ "code": "CONFLICT", "httpStatus": 409, "meaning": "State conflict (duplicate resource, idempotency violation)." },
|
|
38
|
+
{ "code": "RATE_LIMITED", "httpStatus": 429, "meaning": "Reserved for future EE/Cloud editions.", "reservedFor": "EE" },
|
|
39
|
+
{ "code": "INTERNAL_ERROR", "httpStatus": 500, "meaning": "Unexpected server error. Use sparingly; prefer specific codes." },
|
|
40
|
+
{ "code": "SERVICE_UNAVAILABLE", "httpStatus": 503, "meaning": "Backend cannot reach a critical dependency (e.g. database)." }
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "authentication",
|
|
45
|
+
"title": "Authentication Codes",
|
|
46
|
+
"codes": [
|
|
47
|
+
{ "code": "LOGIN_FAILED", "httpStatus": 401, "meaning": "Username or password invalid (do not reveal which)." },
|
|
48
|
+
{ "code": "SESSION_EXPIRED", "httpStatus": 401, "meaning": "Session cookie present but expired." },
|
|
49
|
+
{ "code": "SESSION_INVALID", "httpStatus": 401, "meaning": "Session cookie tampered with or session not found." },
|
|
50
|
+
{ "code": "CSRF_TOKEN_MISMATCH", "httpStatus": 403, "meaning": "X-CSRF-Token header missing or does not match server-side session token." }
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "tokens",
|
|
55
|
+
"title": "Token Codes",
|
|
56
|
+
"codes": [
|
|
57
|
+
{ "code": "REGISTRATION_TOKEN_INVALID", "httpStatus": 401, "meaning": "Token does not exist or hash does not match." },
|
|
58
|
+
{ "code": "REGISTRATION_TOKEN_EXPIRED", "httpStatus": 401, "meaning": "Token past expiresAt." },
|
|
59
|
+
{ "code": "REGISTRATION_TOKEN_USED", "httpStatus": 409, "meaning": "Token already consumed." },
|
|
60
|
+
{ "code": "REGISTRATION_TOKEN_REVOKED", "httpStatus": 401, "meaning": "Token revoked by admin." },
|
|
61
|
+
{ "code": "AGENT_TOKEN_INVALID", "httpStatus": 401, "meaning": "Authorization: Bearer header missing or hash mismatch." },
|
|
62
|
+
{ "code": "AGENT_TOKEN_REVOKED", "httpStatus": 401, "meaning": "Agent token has been revoked." },
|
|
63
|
+
{ "code": "AGENT_TOKEN_EXPIRED", "httpStatus": 401, "meaning": "Agent token past expiresAt." }
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"name": "agents",
|
|
68
|
+
"title": "Agent Codes",
|
|
69
|
+
"codes": [
|
|
70
|
+
{ "code": "AGENT_NOT_FOUND", "httpStatus": 404, "meaning": "agentId does not exist." },
|
|
71
|
+
{ "code": "AGENT_DISABLED", "httpStatus": 403, "meaning": "Agent is DISABLED." },
|
|
72
|
+
{ "code": "AGENT_REVOKED", "httpStatus": 403, "meaning": "Agent is REVOKED." },
|
|
73
|
+
{ "code": "AGENT_CODE_TAKEN", "httpStatus": 409, "meaning": "An Agent with this code already exists in the workspace." },
|
|
74
|
+
{ "code": "AGENT_ID_MISMATCH", "httpStatus": 403, "meaning": "Path agentId does not match the Agent that owns the token." }
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "capsuleService",
|
|
79
|
+
"title": "Capsule Service Codes",
|
|
80
|
+
"codes": [
|
|
81
|
+
{ "code": "CAPSULE_SERVICE_NOT_FOUND", "httpStatus": 404, "meaning": "serviceId does not exist." },
|
|
82
|
+
{ "code": "CAPSULE_SERVICE_NOT_OWNED", "httpStatus": 403, "meaning": "Service exists but does not belong to the calling Agent." },
|
|
83
|
+
{ "code": "CAPSULE_SERVICE_MANIFEST_INVALID", "httpStatus": 422, "meaning": "Manifest validation failed (missing required fields, etc.)." },
|
|
84
|
+
{ "code": "CAPSULE_SERVICE_CODE_TAKEN", "httpStatus": 409, "meaning": "Service code conflict in workspace." }
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"name": "actionsAndCommands",
|
|
89
|
+
"title": "Action and Command Codes",
|
|
90
|
+
"codes": [
|
|
91
|
+
{ "code": "ACTION_NOT_FOUND", "httpStatus": 404, "meaning": "Action name not declared on the service manifest." },
|
|
92
|
+
{ "code": "ACTION_DISABLED", "httpStatus": 403, "meaning": "ActionDefinition.enabled = false." },
|
|
93
|
+
{ "code": "ACTION_PAYLOAD_INVALID", "httpStatus": 422, "meaning": "Payload failed inputSchema validation." },
|
|
94
|
+
{ "code": "ACTION_REQUIRES_CONFIRMATION", "httpStatus": 422, "meaning": "Confirmation flag missing for an action with requiresConfirmation = true." },
|
|
95
|
+
{ "code": "COMMAND_NOT_FOUND", "httpStatus": 404, "meaning": "commandId does not exist." },
|
|
96
|
+
{ "code": "COMMAND_NOT_OWNED", "httpStatus": 403, "meaning": "Command exists but is not assigned to the calling Agent." },
|
|
97
|
+
{ "code": "COMMAND_ALREADY_TERMINAL", "httpStatus": 409, "meaning": "Result reported for a Command already in a terminal state." },
|
|
98
|
+
{ "code": "COMMAND_EXPIRED", "httpStatus": 410, "meaning": "Command past expiresAt and cannot be reported." },
|
|
99
|
+
{ "code": "COMMAND_INVALID_TRANSITION", "httpStatus": 409, "meaning": "Attempted a CommandStatus transition that is not allowed." }
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"name": "config",
|
|
104
|
+
"title": "Config Codes (read-only in CE v0.1)",
|
|
105
|
+
"codes": [
|
|
106
|
+
{ "code": "CONFIG_ITEM_NOT_FOUND", "httpStatus": 404, "meaning": "Config key does not exist for the service." },
|
|
107
|
+
{ "code": "CONFIG_EDIT_NOT_SUPPORTED", "httpStatus": 405, "meaning": "CE v0.1 does not support config editing — reserved for EE/Cloud." }
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "system",
|
|
112
|
+
"title": "System Codes",
|
|
113
|
+
"codes": [
|
|
114
|
+
{ "code": "DATABASE_UNAVAILABLE", "httpStatus": 503, "meaning": "Backend cannot reach SQLite database." },
|
|
115
|
+
{ "code": "BOOTSTRAP_FAILED", "httpStatus": 500, "meaning": "Required environment variable missing — surfaced only via startup logs." }
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"reservedForFutureEditions": [
|
|
120
|
+
"TENANT_NOT_FOUND",
|
|
121
|
+
"ORGANIZATION_NOT_FOUND",
|
|
122
|
+
"SUBSCRIPTION_REQUIRED",
|
|
123
|
+
"PERMISSION_DENIED",
|
|
124
|
+
"ROLE_NOT_FOUND",
|
|
125
|
+
"SECRET_NOT_FOUND",
|
|
126
|
+
"LICENSE_INVALID"
|
|
127
|
+
]
|
|
128
|
+
}
|
package/spec/errors.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# CE v0.1 Error Codes
|
|
2
|
+
|
|
3
|
+
- Status: Implementation Contract
|
|
4
|
+
- Edition: CE
|
|
5
|
+
- Priority: Current
|
|
6
|
+
- Audience: backend developers, frontend developers, agent SDK developers, AI coding agents
|
|
7
|
+
|
|
8
|
+
> **This file is rendered from `09-contracts/errors.json` by `09-contracts/tools/render-errors.ts`.**
|
|
9
|
+
> Edit `errors.json` (the SSOT). CI verifies this file is byte-for-byte equal to the rendered output.
|
|
10
|
+
> See ADR 0009 — Contracts Spec and Bindings.
|
|
11
|
+
|
|
12
|
+
This document enumerates the CE v0.1 error codes. Backend, UI, and Agent SDK MUST use only the codes listed here. New codes require a contract update (edit `errors.json`, regenerate this file).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. Error Envelope
|
|
17
|
+
|
|
18
|
+
All error responses use the OpenAPI `ErrorEnvelope` shape:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"success": false,
|
|
23
|
+
"error": {
|
|
24
|
+
"code": "AGENT_NOT_FOUND",
|
|
25
|
+
"message": "Agent not found.",
|
|
26
|
+
"details": {}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Rules:
|
|
32
|
+
|
|
33
|
+
- `code` MUST be one of the codes in this document. Codes are stable, uppercase, snake-case strings.
|
|
34
|
+
- `message` is a human-readable English summary. UI MAY translate it locally.
|
|
35
|
+
- `details` is optional and structured. Sensitive values must be redacted before being placed in `details`.
|
|
36
|
+
- HTTP status codes are listed alongside each code; Backend MUST use the listed status.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 2. Generic Codes
|
|
41
|
+
|
|
42
|
+
| Code | HTTP | Meaning |
|
|
43
|
+
|-----------------------|------|----------------------------------------------------------------------|
|
|
44
|
+
| `VALIDATION_FAILED` | 422 | Request body or query parameters failed Zod validation. |
|
|
45
|
+
| `UNAUTHORIZED` | 401 | No valid session or token. |
|
|
46
|
+
| `FORBIDDEN` | 403 | Authenticated but not allowed (includes CSRF token mismatch). |
|
|
47
|
+
| `NOT_FOUND` | 404 | Requested resource does not exist or is not visible to the caller. |
|
|
48
|
+
| `CONFLICT` | 409 | State conflict (duplicate resource, idempotency violation). |
|
|
49
|
+
| `RATE_LIMITED` | 429 | Reserved for future EE/Cloud editions. |
|
|
50
|
+
| `INTERNAL_ERROR` | 500 | Unexpected server error. Use sparingly; prefer specific codes. |
|
|
51
|
+
| `SERVICE_UNAVAILABLE` | 503 | Backend cannot reach a critical dependency (e.g. database). |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 3. Authentication Codes
|
|
56
|
+
|
|
57
|
+
| Code | HTTP | Meaning |
|
|
58
|
+
|----------------------------|------|--------------------------------------------------------------------|
|
|
59
|
+
| `LOGIN_FAILED` | 401 | Username or password invalid (do not reveal which). |
|
|
60
|
+
| `SESSION_EXPIRED` | 401 | Session cookie present but expired. |
|
|
61
|
+
| `SESSION_INVALID` | 401 | Session cookie tampered with or session not found. |
|
|
62
|
+
| `CSRF_TOKEN_MISMATCH` | 403 | `X-CSRF-Token` header missing or does not match server-side session token. |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 4. Token Codes
|
|
67
|
+
|
|
68
|
+
| Code | HTTP | Meaning |
|
|
69
|
+
|-------------------------------------|------|--------------------------------------------------------------|
|
|
70
|
+
| `REGISTRATION_TOKEN_INVALID` | 401 | Token does not exist or hash does not match. |
|
|
71
|
+
| `REGISTRATION_TOKEN_EXPIRED` | 401 | Token past `expiresAt`. |
|
|
72
|
+
| `REGISTRATION_TOKEN_USED` | 409 | Token already consumed. |
|
|
73
|
+
| `REGISTRATION_TOKEN_REVOKED` | 401 | Token revoked by admin. |
|
|
74
|
+
| `AGENT_TOKEN_INVALID` | 401 | `Authorization: Bearer` header missing or hash mismatch. |
|
|
75
|
+
| `AGENT_TOKEN_REVOKED` | 401 | Agent token has been revoked. |
|
|
76
|
+
| `AGENT_TOKEN_EXPIRED` | 401 | Agent token past `expiresAt`. |
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 5. Agent Codes
|
|
81
|
+
|
|
82
|
+
| Code | HTTP | Meaning |
|
|
83
|
+
|-------------------------------|------|------------------------------------------------------------------|
|
|
84
|
+
| `AGENT_NOT_FOUND` | 404 | `agentId` does not exist. |
|
|
85
|
+
| `AGENT_DISABLED` | 403 | Agent is `DISABLED`. |
|
|
86
|
+
| `AGENT_REVOKED` | 403 | Agent is `REVOKED`. |
|
|
87
|
+
| `AGENT_CODE_TAKEN` | 409 | An Agent with this `code` already exists in the workspace. |
|
|
88
|
+
| `AGENT_ID_MISMATCH` | 403 | Path `agentId` does not match the Agent that owns the token. |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 6. Capsule Service Codes
|
|
93
|
+
|
|
94
|
+
| Code | HTTP | Meaning |
|
|
95
|
+
|-----------------------------------|------|---------------------------------------------------------------|
|
|
96
|
+
| `CAPSULE_SERVICE_NOT_FOUND` | 404 | `serviceId` does not exist. |
|
|
97
|
+
| `CAPSULE_SERVICE_NOT_OWNED` | 403 | Service exists but does not belong to the calling Agent. |
|
|
98
|
+
| `CAPSULE_SERVICE_MANIFEST_INVALID`| 422 | Manifest validation failed (missing required fields, etc.). |
|
|
99
|
+
| `CAPSULE_SERVICE_CODE_TAKEN` | 409 | Service code conflict in workspace. |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 7. Action and Command Codes
|
|
104
|
+
|
|
105
|
+
| Code | HTTP | Meaning |
|
|
106
|
+
|-----------------------------------|------|------------------------------------------------------------------|
|
|
107
|
+
| `ACTION_NOT_FOUND` | 404 | Action name not declared on the service manifest. |
|
|
108
|
+
| `ACTION_DISABLED` | 403 | `ActionDefinition.enabled = false`. |
|
|
109
|
+
| `ACTION_PAYLOAD_INVALID` | 422 | Payload failed `inputSchema` validation. |
|
|
110
|
+
| `ACTION_REQUIRES_CONFIRMATION` | 422 | Confirmation flag missing for an action with `requiresConfirmation = true`. |
|
|
111
|
+
| `COMMAND_NOT_FOUND` | 404 | `commandId` does not exist. |
|
|
112
|
+
| `COMMAND_NOT_OWNED` | 403 | Command exists but is not assigned to the calling Agent. |
|
|
113
|
+
| `COMMAND_ALREADY_TERMINAL` | 409 | Result reported for a Command already in a terminal state. |
|
|
114
|
+
| `COMMAND_EXPIRED` | 410 | Command past `expiresAt` and cannot be reported. |
|
|
115
|
+
| `COMMAND_INVALID_TRANSITION` | 409 | Attempted a CommandStatus transition that is not allowed. |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 8. Config Codes (read-only in CE v0.1)
|
|
120
|
+
|
|
121
|
+
| Code | HTTP | Meaning |
|
|
122
|
+
|----------------------------|------|-------------------------------------------------------------------|
|
|
123
|
+
| `CONFIG_ITEM_NOT_FOUND` | 404 | Config key does not exist for the service. |
|
|
124
|
+
| `CONFIG_EDIT_NOT_SUPPORTED`| 405 | CE v0.1 does not support config editing — reserved for EE/Cloud. |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 9. System Codes
|
|
129
|
+
|
|
130
|
+
| Code | HTTP | Meaning |
|
|
131
|
+
|-----------------------|------|------------------------------------------------------------------------|
|
|
132
|
+
| `DATABASE_UNAVAILABLE`| 503 | Backend cannot reach SQLite database. |
|
|
133
|
+
| `BOOTSTRAP_FAILED` | 500 | Required environment variable missing — surfaced only via startup logs.|
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 10. Reserved Future Codes
|
|
138
|
+
|
|
139
|
+
The following codes are reserved for EE/Cloud and MUST NOT be emitted by CE v0.1:
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
TENANT_NOT_FOUND
|
|
143
|
+
ORGANIZATION_NOT_FOUND
|
|
144
|
+
SUBSCRIPTION_REQUIRED
|
|
145
|
+
PERMISSION_DENIED
|
|
146
|
+
ROLE_NOT_FOUND
|
|
147
|
+
SECRET_NOT_FOUND
|
|
148
|
+
LICENSE_INVALID
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 11. Mapping to AuditEvent
|
|
154
|
+
|
|
155
|
+
When Backend emits an error response that should also produce an AuditEvent (e.g. `AGENT_TOKEN_INVALID`, `CSRF_TOKEN_MISMATCH`), it writes:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"result": "FAILURE",
|
|
160
|
+
"metadata": {
|
|
161
|
+
"errorCode": "<one of the codes above>"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
This keeps the audit log queryable by error code without proliferating AuditResult enum values.
|