@opensoftware/contracts 2.1.0 → 2.2.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/README.md CHANGED
@@ -51,9 +51,11 @@ Each format has one schema, generated from `typespec/`, and fixtures that CONTRA
51
51
  `openapi/openapi.json` also holds the paths of the module APIs, from the operations in `typespec/` (ADR 0048). The
52
52
  first is gatekeeper's: `POST /v1/gates` and `GET /v1/gates/{gateId}` with the models `GateRequest`, `GateView` and
53
53
  `ApiProblem` (RFC 9457). The second is intake's (ADR 0063): `POST /v1/work-items` and
54
- `GET /v1/work-items/{workItemId}` with the models `WorkSubmission`, `WorkItemView` and `WorkRequest`. The third is the
54
+ `GET /v1/work-items/{workItemId}` with the models `WorkSubmission`, `WorkItemView` and `WorkRequest`, and
55
+ `GET /v1/inbox` with `WorkItemList`. The third is the
55
56
  foreman's (ADR 0067): `POST /v1/runs`, `GET /v1/runs/{runId}` and `POST /v1/runs/{runId}/signals` with the models
56
- `RunView`, `StageView`, `CheckView` (ADR 0069) and `RunSignal`. `pnpm build` compiles the operations with the TypeSpec OpenAPI 3 emitter and copies their
57
+ `RunView`, `StageView`, `CheckView` (ADR 0069) and `RunSignal`. All three answer `GET /v1/health` with the models
58
+ `Health` and `HealthCheck` (`HealthApi`, ADR 0086). `pnpm build` compiles the operations with the TypeSpec OpenAPI 3 emitter and copies their
57
59
  paths next to the named models; an operation that uses a type that is no model fails the build. The package exports
58
60
  the type `paths`, which types a client such as openapi-fetch.
59
61
 
@@ -100,9 +102,10 @@ One-time setup (no credential is ever stored in the repository):
100
102
  repository is published.
101
103
  2. GitHub: the publish job runs in the environment `npm` (Settings → Environments; GitHub creates it on the first
102
104
  run).
103
- 3. First version only: npm adds a trusted publisher only to a package that exists, so a maintainer publishes the
104
- first version by hand, from the release tag, with their own npm login and two-factor authentication:
105
- `pnpm --filter "<package>..." build`, `pnpm --dir <folder> pack`, then `npm publish <file>.tgz --access public`.
105
+ 3. New package only: npm adds a trusted publisher only to a package that exists. Before the release pull request
106
+ with its first version merges, a maintainer creates it: build and pack it as version `0.0.0`, then run
107
+ `npm publish <file>.tgz --tag placeholder --access public` without `--otp`. npm stages that version, so the
108
+ package exists and nothing is public (`skills/release-packages`).
106
109
  4. Then add the trusted publisher, on npmjs.com (package settings → Trusted publishing) or with
107
110
  `npm trust github <package> --file publish-<name>.yml --repository sesigl/open-software-factory --environment npm
108
111
  --allow-publish --allow-stage-publish`. Every later version publishes through OIDC only, with a provenance
@@ -33,6 +33,40 @@ export type paths = {
33
33
  patch?: never;
34
34
  trace?: never;
35
35
  };
36
+ "/v1/health": {
37
+ parameters: {
38
+ query?: never;
39
+ header?: never;
40
+ path?: never;
41
+ cookie?: never;
42
+ };
43
+ /** @description The server's health. Needs no token, and names no secret. 503 when a check fails. */
44
+ get: operations["HealthApi_getHealth"];
45
+ put?: never;
46
+ post?: never;
47
+ delete?: never;
48
+ options?: never;
49
+ head?: never;
50
+ patch?: never;
51
+ trace?: never;
52
+ };
53
+ "/v1/inbox": {
54
+ parameters: {
55
+ query?: never;
56
+ header?: never;
57
+ path?: never;
58
+ cookie?: never;
59
+ };
60
+ /** @description The 50 latest work items, the one received last first; with `status`, only the work items in that status. */
61
+ get: operations["IntakeApi_listWorkItems"];
62
+ put?: never;
63
+ post?: never;
64
+ delete?: never;
65
+ options?: never;
66
+ head?: never;
67
+ patch?: never;
68
+ trace?: never;
69
+ };
36
70
  "/v1/runs": {
37
71
  parameters: {
38
72
  query?: never;
@@ -439,6 +473,19 @@ export type components = {
439
473
  /** @description The record, once the gate is decided. */
440
474
  record?: components["schemas"]["GateRecord"];
441
475
  };
476
+ /** @description The state of a server: `ok` when every check is ok. */
477
+ Health: {
478
+ status: "ok" | "failing";
479
+ checks: components["schemas"]["HealthCheck"][];
480
+ };
481
+ /** @description One system a server needs, such as its database or NATS, and whether the server reaches it now. */
482
+ HealthCheck: {
483
+ /** @description The system, like "database", "nats" or "temporal". */
484
+ name: components["schemas"]["Name"];
485
+ ok: boolean;
486
+ /** @description What failed and how to fix it, when `ok` is false. Never a secret. */
487
+ detail?: string;
488
+ };
442
489
  /** @description A hostname without scheme or port, for example "api.linear.app". */
443
490
  Hostname: string;
444
491
  /** @description An identifier chosen by the producer. ULIDs are recommended; consumers treat it as opaque. */
@@ -840,6 +887,8 @@ export type components = {
840
887
  startedAt: string;
841
888
  /** Format: date-time */
842
889
  endedAt?: string;
890
+ /** @description The OpenTelemetry trace of the run: the first 32 hex digits of the SHA-256 of `runId` (ADR 0087). */
891
+ traceId?: components["schemas"]["TraceId"];
843
892
  /** @description The stages of the workflow, in order. */
844
893
  stages: components["schemas"]["StageView"][];
845
894
  };
@@ -1039,6 +1088,10 @@ export type components = {
1039
1088
  /** @description Related material: an error report, a change, a document. */
1040
1089
  links?: components["schemas"]["Link"][];
1041
1090
  };
1091
+ /** @description intake: the latest work items, as `GET /v1/inbox` answers them, the one received last first. */
1092
+ WorkItemList: {
1093
+ workItems: components["schemas"]["WorkItemView"][];
1094
+ };
1042
1095
  /**
1043
1096
  * @description Where a work item stands: received, then as its run in the foreman goes (ADR 0071).
1044
1097
  * @enum {string}
@@ -1200,6 +1253,75 @@ export interface operations {
1200
1253
  };
1201
1254
  };
1202
1255
  };
1256
+ HealthApi_getHealth: {
1257
+ parameters: {
1258
+ query?: never;
1259
+ header?: never;
1260
+ path?: never;
1261
+ cookie?: never;
1262
+ };
1263
+ requestBody?: never;
1264
+ responses: {
1265
+ /** @description The request has succeeded. */
1266
+ 200: {
1267
+ headers: {
1268
+ [name: string]: unknown;
1269
+ };
1270
+ content: {
1271
+ "application/json": components["schemas"]["Health"];
1272
+ };
1273
+ };
1274
+ /** @description Service unavailable. */
1275
+ 503: {
1276
+ headers: {
1277
+ [name: string]: unknown;
1278
+ };
1279
+ content: {
1280
+ "application/json": components["schemas"]["Health"];
1281
+ };
1282
+ };
1283
+ };
1284
+ };
1285
+ IntakeApi_listWorkItems: {
1286
+ parameters: {
1287
+ query?: {
1288
+ status?: components["schemas"]["WorkItemStatus"];
1289
+ };
1290
+ header?: never;
1291
+ path?: never;
1292
+ cookie?: never;
1293
+ };
1294
+ requestBody?: never;
1295
+ responses: {
1296
+ /** @description The request has succeeded. */
1297
+ 200: {
1298
+ headers: {
1299
+ [name: string]: unknown;
1300
+ };
1301
+ content: {
1302
+ "application/json": components["schemas"]["WorkItemList"];
1303
+ };
1304
+ };
1305
+ /** @description The server could not understand the request due to invalid syntax. */
1306
+ 400: {
1307
+ headers: {
1308
+ [name: string]: unknown;
1309
+ };
1310
+ content: {
1311
+ "application/problem+json": components["schemas"]["ApiProblem"];
1312
+ };
1313
+ };
1314
+ /** @description Access is unauthorized. */
1315
+ 401: {
1316
+ headers: {
1317
+ [name: string]: unknown;
1318
+ };
1319
+ content: {
1320
+ "application/problem+json": components["schemas"]["ApiProblem"];
1321
+ };
1322
+ };
1323
+ };
1324
+ };
1203
1325
  ForemanApi_listRuns: {
1204
1326
  parameters: {
1205
1327
  query?: {
package/dist/index.d.ts CHANGED
@@ -26,12 +26,15 @@ export type GateView = Schemas["GateView"];
26
26
  export type ApiProblem = Schemas["ApiProblem"];
27
27
  export type WorkSubmission = Schemas["WorkSubmission"];
28
28
  export type WorkItemView = Schemas["WorkItemView"];
29
+ export type WorkItemList = Schemas["WorkItemList"];
29
30
  export type WorkRequest = Schemas["WorkRequest"];
30
31
  export type RunView = Schemas["RunView"];
31
32
  export type StageView = Schemas["StageView"];
32
33
  export type CheckView = Schemas["CheckView"];
33
34
  export type RunSignal = Schemas["RunSignal"];
34
35
  export type SandboxSpec = Schemas["SandboxSpec"];
36
+ export type Health = Schemas["Health"];
37
+ export type HealthCheck = Schemas["HealthCheck"];
35
38
  /** One reason a document does not match its format. `path` is a JSON Pointer into the document. */
36
39
  export interface Problem {
37
40
  path: string;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Open Software Factory contracts",
5
- "version": "2.1.0",
5
+ "version": "2.2.0",
6
6
  "description": "The shared formats as named models, and the HTTP APIs of the modules. Generated by `pnpm build` in contracts/ from typespec/. Do not edit.",
7
7
  "license": {
8
8
  "name": "Apache-2.0",
@@ -117,6 +117,87 @@
117
117
  }
118
118
  }
119
119
  },
120
+ "/v1/health": {
121
+ "get": {
122
+ "operationId": "HealthApi_getHealth",
123
+ "description": "The server's health. Needs no token, and names no secret. 503 when a check fails.",
124
+ "parameters": [],
125
+ "responses": {
126
+ "200": {
127
+ "description": "The request has succeeded.",
128
+ "content": {
129
+ "application/json": {
130
+ "schema": {
131
+ "$ref": "#/components/schemas/Health"
132
+ }
133
+ }
134
+ }
135
+ },
136
+ "503": {
137
+ "description": "Service unavailable.",
138
+ "content": {
139
+ "application/json": {
140
+ "schema": {
141
+ "$ref": "#/components/schemas/Health"
142
+ }
143
+ }
144
+ }
145
+ }
146
+ },
147
+ "security": [
148
+ {}
149
+ ]
150
+ }
151
+ },
152
+ "/v1/inbox": {
153
+ "get": {
154
+ "operationId": "IntakeApi_listWorkItems",
155
+ "description": "The 50 latest work items, the one received last first; with `status`, only the work items in that status.",
156
+ "parameters": [
157
+ {
158
+ "name": "status",
159
+ "in": "query",
160
+ "required": false,
161
+ "schema": {
162
+ "$ref": "#/components/schemas/WorkItemStatus"
163
+ },
164
+ "explode": false
165
+ }
166
+ ],
167
+ "responses": {
168
+ "200": {
169
+ "description": "The request has succeeded.",
170
+ "content": {
171
+ "application/json": {
172
+ "schema": {
173
+ "$ref": "#/components/schemas/WorkItemList"
174
+ }
175
+ }
176
+ }
177
+ },
178
+ "400": {
179
+ "description": "The server could not understand the request due to invalid syntax.",
180
+ "content": {
181
+ "application/problem+json": {
182
+ "schema": {
183
+ "$ref": "#/components/schemas/ApiProblem"
184
+ }
185
+ }
186
+ }
187
+ },
188
+ "401": {
189
+ "description": "Access is unauthorized.",
190
+ "content": {
191
+ "application/problem+json": {
192
+ "schema": {
193
+ "$ref": "#/components/schemas/ApiProblem"
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ }
200
+ },
120
201
  "/v1/runs": {
121
202
  "post": {
122
203
  "operationId": "ForemanApi_startRun",
@@ -1388,6 +1469,55 @@
1388
1469
  ],
1389
1470
  "description": "gatekeeper: a gate as the HTTP API shows it (ADR 0048)."
1390
1471
  },
1472
+ "Health": {
1473
+ "type": "object",
1474
+ "properties": {
1475
+ "status": {
1476
+ "anyOf": [
1477
+ {
1478
+ "type": "string",
1479
+ "const": "ok"
1480
+ },
1481
+ {
1482
+ "type": "string",
1483
+ "const": "failing"
1484
+ }
1485
+ ]
1486
+ },
1487
+ "checks": {
1488
+ "type": "array",
1489
+ "items": {
1490
+ "$ref": "#/components/schemas/HealthCheck"
1491
+ }
1492
+ }
1493
+ },
1494
+ "required": [
1495
+ "status",
1496
+ "checks"
1497
+ ],
1498
+ "description": "The state of a server: `ok` when every check is ok."
1499
+ },
1500
+ "HealthCheck": {
1501
+ "type": "object",
1502
+ "properties": {
1503
+ "name": {
1504
+ "$ref": "#/components/schemas/Name",
1505
+ "description": "The system, like \"database\", \"nats\" or \"temporal\"."
1506
+ },
1507
+ "ok": {
1508
+ "type": "boolean"
1509
+ },
1510
+ "detail": {
1511
+ "type": "string",
1512
+ "description": "What failed and how to fix it, when `ok` is false. Never a secret."
1513
+ }
1514
+ },
1515
+ "required": [
1516
+ "name",
1517
+ "ok"
1518
+ ],
1519
+ "description": "One system a server needs, such as its database or NATS, and whether the server reaches it now."
1520
+ },
1391
1521
  "Hostname": {
1392
1522
  "type": "string",
1393
1523
  "pattern": "^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?(\\.[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?)*$",
@@ -2423,6 +2553,10 @@
2423
2553
  "type": "string",
2424
2554
  "format": "date-time"
2425
2555
  },
2556
+ "traceId": {
2557
+ "$ref": "#/components/schemas/TraceId",
2558
+ "description": "The OpenTelemetry trace of the run: the first 32 hex digits of the SHA-256 of `runId` (ADR 0087)."
2559
+ },
2426
2560
  "stages": {
2427
2561
  "type": "array",
2428
2562
  "items": {
@@ -2959,6 +3093,21 @@
2959
3093
  ],
2960
3094
  "description": "One unit of requested work: the `data` of a `work.received@v1` CloudEvent."
2961
3095
  },
3096
+ "WorkItemList": {
3097
+ "type": "object",
3098
+ "properties": {
3099
+ "workItems": {
3100
+ "type": "array",
3101
+ "items": {
3102
+ "$ref": "#/components/schemas/WorkItemView"
3103
+ }
3104
+ }
3105
+ },
3106
+ "required": [
3107
+ "workItems"
3108
+ ],
3109
+ "description": "intake: the latest work items, as `GET /v1/inbox` answers them, the one received last first."
3110
+ },
2962
3111
  "WorkItemStatus": {
2963
3112
  "type": "string",
2964
3113
  "enum": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opensoftware/contracts",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "The shared formats of the open software factory: JSON Schemas, TypeScript types and the osf-contracts CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -44,7 +44,7 @@
44
44
  "@typespec/openapi": "1.17.0",
45
45
  "@typespec/openapi3": "1.17.0",
46
46
  "openapi-typescript": "7.13.0",
47
- "@opensoftware/testkit": "0.30.0"
47
+ "@opensoftware/testkit": "0.31.0"
48
48
  },
49
49
  "scripts": {
50
50
  "build": "node scripts/build.ts",
@@ -97,6 +97,9 @@ model RunView {
97
97
  startedAt: utcDateTime;
98
98
  endedAt?: utcDateTime;
99
99
 
100
+ /** The OpenTelemetry trace of the run: the first 32 hex digits of the SHA-256 of `runId` (ADR 0087). */
101
+ traceId?: TraceId;
102
+
100
103
  /** The stages of the workflow, in order. */
101
104
  stages: StageView[];
102
105
  }
@@ -0,0 +1,42 @@
1
+ // The health route that intake, gatekeeper and the foreman each serve (ADR 0086): the state of the server and of each
2
+ // system it needs. `console doctor` and the Compose profile's health checks read it.
3
+ import "@typespec/http";
4
+ import "./common.tsp";
5
+ import "./gatekeeper-api.tsp";
6
+
7
+ using TypeSpec.Http;
8
+
9
+ namespace Osf.Contracts;
10
+
11
+ /** One system a server needs, such as its database or NATS, and whether the server reaches it now. */
12
+ model HealthCheck {
13
+ /** The system, like "database", "nats" or "temporal". */
14
+ name: Name;
15
+
16
+ ok: boolean;
17
+
18
+ /** What failed and how to fix it, when `ok` is false. Never a secret. */
19
+ detail?: string;
20
+ }
21
+
22
+ /** The state of a server: `ok` when every check is ok. */
23
+ model Health {
24
+ status: "ok" | "failing";
25
+ checks: HealthCheck[];
26
+ }
27
+
28
+ namespace HealthApi {
29
+ /** The server's health. Needs no token, and names no secret. 503 when a check fails. */
30
+ @route("/v1/health")
31
+ @get
32
+ @useAuth(NoAuth)
33
+ op getHealth():
34
+ | {
35
+ @statusCode statusCode: 200;
36
+ @body health: Health;
37
+ }
38
+ | {
39
+ @statusCode statusCode: 503;
40
+ @body health: Health;
41
+ };
42
+ }
@@ -33,6 +33,14 @@ namespace IntakeApi {
33
33
  | GatekeeperApi.Failure<401>
34
34
  | GatekeeperApi.Failure<404>;
35
35
 
36
+ /** The 50 latest work items, the one received last first; with `status`, only the work items in that status. */
37
+ @route("/v1/inbox")
38
+ @get
39
+ op listWorkItems(@query status?: WorkItemStatus):
40
+ | WorkItemList
41
+ | GatekeeperApi.Failure<400>
42
+ | GatekeeperApi.Failure<401>;
43
+
36
44
  /** A work item, its status and every request that asked for it. */
37
45
  @route("/v1/work-items/{workItemId}")
38
46
  @get
@@ -43,6 +43,11 @@ model WorkRequest {
43
43
  receivedAt: utcDateTime;
44
44
  }
45
45
 
46
+ /** intake: the latest work items, as `GET /v1/inbox` answers them, the one received last first. */
47
+ model WorkItemList {
48
+ workItems: WorkItemView[];
49
+ }
50
+
46
51
  /** intake: a work item as the HTTP API shows it (ADR 0063). */
47
52
  model WorkItemView {
48
53
  /** Its ID is "wi_" and 20 hex digits of the SHA-256 of its dedupe key. */
package/typespec/main.tsp CHANGED
@@ -15,3 +15,4 @@ import "./intake-api.tsp";
15
15
  import "./foreman.tsp";
16
16
  import "./foreman-api.tsp";
17
17
  import "./sandbox.tsp";
18
+ import "./health.tsp";