@persei/perseed-api 5.0.28 → 5.0.29
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/ecosystem-alert.cjs +229 -0
- package/dist/ecosystem-alert.cjs.map +1 -0
- package/dist/ecosystem-alert.d.ts +1 -0
- package/dist/ecosystem-alert.mjs +229 -0
- package/dist/ecosystem-alert.mjs.map +1 -0
- package/dist/ecosystem-process-log.cjs.map +1 -1
- package/dist/ecosystem-process-log.mjs.map +1 -1
- package/dist/src/v2/modules/ecosystem/alert/alert.schema.d.ts.map +1 -1
- package/dist/src/v2/modules/ecosystem/alert/lib.d.ts +2 -0
- package/dist/src/v2/modules/ecosystem/alert/lib.d.ts.map +1 -0
- package/dist/src/v2/modules/ecosystem/process-log/process-log.schema.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const typebox = require("typebox");
|
|
4
|
+
const dates_schema = require("./dates.schema-npKpToAJ.cjs");
|
|
5
|
+
const AlertStatus = {
|
|
6
|
+
ACTIVE: "active",
|
|
7
|
+
RESOLVED: "resolved"
|
|
8
|
+
};
|
|
9
|
+
const alertStatusSchema = typebox.Type.Enum(Object.values(AlertStatus), {
|
|
10
|
+
title: "AlertStatus",
|
|
11
|
+
description: "Lifecycle state of an alert. An alert is open until it is resolved"
|
|
12
|
+
});
|
|
13
|
+
const AlertSeverity = {
|
|
14
|
+
INFO: "info",
|
|
15
|
+
LOW: "low",
|
|
16
|
+
MEDIUM: "medium",
|
|
17
|
+
HIGH: "high",
|
|
18
|
+
CRITICAL: "critical"
|
|
19
|
+
};
|
|
20
|
+
const alertSeveritySchema = typebox.Type.Enum(Object.values(AlertSeverity), {
|
|
21
|
+
title: "AlertSeverity",
|
|
22
|
+
description: "Severity of the alert, used to prioritise it"
|
|
23
|
+
});
|
|
24
|
+
const AlertEmitterType = {
|
|
25
|
+
TRIGGER: "trigger",
|
|
26
|
+
API: "api",
|
|
27
|
+
WEBHOOK: "webhook"
|
|
28
|
+
};
|
|
29
|
+
const alertEmitterTypeSchema = typebox.Type.Enum(Object.values(AlertEmitterType), {
|
|
30
|
+
title: "AlertEmitterType",
|
|
31
|
+
description: "Kind of emitter that raised the alert"
|
|
32
|
+
});
|
|
33
|
+
const alertEmitterSchema = typebox.Type.Object(
|
|
34
|
+
{
|
|
35
|
+
type: alertEmitterTypeSchema,
|
|
36
|
+
id: typebox.Type.Optional(
|
|
37
|
+
typebox.Type.Union([typebox.Type.String({ maxLength: 255 }), typebox.Type.Null()], {
|
|
38
|
+
description: "Identifier of the emitter within its type (trigger id, device id, service id…)"
|
|
39
|
+
})
|
|
40
|
+
),
|
|
41
|
+
name: typebox.Type.Optional(
|
|
42
|
+
typebox.Type.Union([typebox.Type.String({ maxLength: 255 }), typebox.Type.Null()], {
|
|
43
|
+
description: "Human readable name of the emitter"
|
|
44
|
+
})
|
|
45
|
+
),
|
|
46
|
+
reference: typebox.Type.Optional(
|
|
47
|
+
typebox.Type.Union([typebox.Type.String({ maxLength: 255 }), typebox.Type.Null()], {
|
|
48
|
+
description: "Identifier of the originating event in the emitting system, for traceability"
|
|
49
|
+
})
|
|
50
|
+
)
|
|
51
|
+
},
|
|
52
|
+
{ title: "AlertEmitter", description: "Who raised the alert", additionalProperties: false }
|
|
53
|
+
);
|
|
54
|
+
const alertEntityRefSchema = typebox.Type.Object(
|
|
55
|
+
{
|
|
56
|
+
type: typebox.Type.String({ maxLength: 64, description: "Kind of entity (user, phone, email, service…)" }),
|
|
57
|
+
value: typebox.Type.String({ maxLength: 255, description: "Identifier of the entity within its type" })
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
title: "AlertEntityRef",
|
|
61
|
+
description: "Reference to an entity by kind and identifier",
|
|
62
|
+
additionalProperties: false
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
const alertSchema = typebox.Type.Object(
|
|
66
|
+
{
|
|
67
|
+
id: typebox.Type.Number({ description: "Unique identifier of the alert" }),
|
|
68
|
+
project_id: typebox.Type.Optional(
|
|
69
|
+
typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()], {
|
|
70
|
+
description: "Project this alert belongs to. Null for an ecosystem-wide alert, the ones created and read through the `/ecosystem/:ecosystemName/alert` mount, which belong to no project"
|
|
71
|
+
})
|
|
72
|
+
),
|
|
73
|
+
alert_type_id: typebox.Type.Optional(
|
|
74
|
+
typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()], {
|
|
75
|
+
description: "Type of alert, as a row of the `alert_type` catalog of the ecosystem. Null for an alert that is not classified"
|
|
76
|
+
})
|
|
77
|
+
),
|
|
78
|
+
user_id: typebox.Type.Optional(
|
|
79
|
+
typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()], {
|
|
80
|
+
description: "Caaring user the alert is about, and one of the two things that decide who may read it: this user always reads their own alerts. Null when the subject is a patient with no user account, in which case `patient_id` is the one that identifies them"
|
|
81
|
+
})
|
|
82
|
+
),
|
|
83
|
+
patient_id: typebox.Type.Optional(
|
|
84
|
+
typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()], {
|
|
85
|
+
description: "Patient the alert is about, as the `id` of the `patient` CRF row of the project, and the other thing that decides who may read it: the professionals with access to that patient do. A patient may exist without a user account, so this is independent of `user_id`. It lives in the project database, so the column carries no foreign key and `project_id` is what says which database to read it from — an alert carrying it always carries a project"
|
|
86
|
+
})
|
|
87
|
+
),
|
|
88
|
+
severity: typebox.Type.Optional(
|
|
89
|
+
typebox.Type.Union([alertSeveritySchema, typebox.Type.Null()], { description: "Severity of the alert. Null when not graded" })
|
|
90
|
+
),
|
|
91
|
+
status: typebox.Type.Optional(alertStatusSchema),
|
|
92
|
+
title: typebox.Type.Optional(
|
|
93
|
+
typebox.Type.Union([typebox.Type.String({ maxLength: 255 }), typebox.Type.Null()], { description: "Short readable title" })
|
|
94
|
+
),
|
|
95
|
+
summary: typebox.Type.Optional(typebox.Type.Union([typebox.Type.String(), typebox.Type.Null()], { description: "Longer readable description" })),
|
|
96
|
+
emitter: alertEmitterSchema,
|
|
97
|
+
recipients: typebox.Type.Optional(
|
|
98
|
+
typebox.Type.Union([typebox.Type.Array(alertEntityRefSchema), typebox.Type.Null()], {
|
|
99
|
+
description: "Natural addressees of the alert. Null or empty when it has none"
|
|
100
|
+
})
|
|
101
|
+
),
|
|
102
|
+
related_entities: typebox.Type.Optional(
|
|
103
|
+
typebox.Type.Union([typebox.Type.Array(alertEntityRefSchema), typebox.Type.Null()], {
|
|
104
|
+
description: "Entities related to the alert without being addressees of it"
|
|
105
|
+
})
|
|
106
|
+
),
|
|
107
|
+
payload: typebox.Type.Optional(
|
|
108
|
+
typebox.Type.Union([typebox.Type.Record(typebox.Type.String(), typebox.Type.Unknown()), typebox.Type.Null()], {
|
|
109
|
+
description: "Structured data that originated the alert (measured value, threshold, form answer…)"
|
|
110
|
+
})
|
|
111
|
+
),
|
|
112
|
+
metadata: typebox.Type.Optional(
|
|
113
|
+
typebox.Type.Union([typebox.Type.Record(typebox.Type.String(), typebox.Type.Unknown()), typebox.Type.Null()], {
|
|
114
|
+
description: "Free extension point, so a new consumer does not need a schema change"
|
|
115
|
+
})
|
|
116
|
+
),
|
|
117
|
+
dedup_key: typebox.Type.Optional(
|
|
118
|
+
typebox.Type.String({
|
|
119
|
+
maxLength: 255,
|
|
120
|
+
description: "Fingerprint used to avoid storing the same alert twice. A create carrying a key that is already open in the same scope answers with the stored alert; a resolved alert does not hold its key, so a condition that recurs after being dealt with raises a new one. Optional for the client: the server generates a UUID when it is absent, so the column always carries a usable value"
|
|
121
|
+
})
|
|
122
|
+
),
|
|
123
|
+
triggered_at: typebox.Type.Optional(
|
|
124
|
+
typebox.Type.Union([typebox.Type.String(), typebox.Type.Null()], {
|
|
125
|
+
description: `When the event that originated the alert happened. ${dates_schema.EMITTED_DATETIME_NOTE}`,
|
|
126
|
+
examples: [dates_schema.API_DATETIME_EXAMPLE]
|
|
127
|
+
})
|
|
128
|
+
),
|
|
129
|
+
viewed_at: typebox.Type.Optional(
|
|
130
|
+
typebox.Type.Union([typebox.Type.String(), typebox.Type.Null()], {
|
|
131
|
+
description: `When the alert was first viewed. Null while unseen. ${dates_schema.EMITTED_DATETIME_NOTE}`,
|
|
132
|
+
examples: [dates_schema.API_DATETIME_EXAMPLE]
|
|
133
|
+
})
|
|
134
|
+
),
|
|
135
|
+
viewed_by: typebox.Type.Optional(
|
|
136
|
+
typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()], { description: "User who first viewed the alert" })
|
|
137
|
+
),
|
|
138
|
+
resolved_at: typebox.Type.Optional(
|
|
139
|
+
typebox.Type.Union([typebox.Type.String(), typebox.Type.Null()], {
|
|
140
|
+
description: `When the alert was resolved. Null while active. ${dates_schema.EMITTED_DATETIME_NOTE}`,
|
|
141
|
+
examples: [dates_schema.API_DATETIME_EXAMPLE]
|
|
142
|
+
})
|
|
143
|
+
),
|
|
144
|
+
resolved_by: typebox.Type.Optional(
|
|
145
|
+
typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()], { description: "User who resolved the alert" })
|
|
146
|
+
),
|
|
147
|
+
resolution_note: typebox.Type.Optional(
|
|
148
|
+
typebox.Type.Union([typebox.Type.String(), typebox.Type.Null()], { description: "Optional note left when resolving the alert" })
|
|
149
|
+
),
|
|
150
|
+
created_user: typebox.Type.Optional(
|
|
151
|
+
typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()], { description: "User who created the alert, when a user did" })
|
|
152
|
+
),
|
|
153
|
+
created_at: typebox.Type.Optional(
|
|
154
|
+
typebox.Type.String({
|
|
155
|
+
description: `When the row was created. ${dates_schema.EMITTED_DATETIME_NOTE}`,
|
|
156
|
+
examples: [dates_schema.API_DATETIME_EXAMPLE]
|
|
157
|
+
})
|
|
158
|
+
),
|
|
159
|
+
mod_time: typebox.Type.Optional(
|
|
160
|
+
typebox.Type.String({
|
|
161
|
+
description: `When the row was last modified. ${dates_schema.EMITTED_DATETIME_NOTE}`,
|
|
162
|
+
examples: [dates_schema.API_DATETIME_EXAMPLE]
|
|
163
|
+
})
|
|
164
|
+
)
|
|
165
|
+
},
|
|
166
|
+
{ title: "Alert", description: "An alert and its state (ecosystem level)" }
|
|
167
|
+
);
|
|
168
|
+
const createAlertSchema = typebox.Type.Object(
|
|
169
|
+
{
|
|
170
|
+
alert_type_id: typebox.Type.Optional(typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()])),
|
|
171
|
+
user_id: typebox.Type.Optional(typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()])),
|
|
172
|
+
patient_id: typebox.Type.Optional(typebox.Type.Union([typebox.Type.Number(), typebox.Type.Null()])),
|
|
173
|
+
severity: typebox.Type.Optional(typebox.Type.Union([alertSeveritySchema, typebox.Type.Null()])),
|
|
174
|
+
title: typebox.Type.Optional(typebox.Type.Union([typebox.Type.String({ maxLength: 255 }), typebox.Type.Null()])),
|
|
175
|
+
summary: typebox.Type.Optional(typebox.Type.Union([typebox.Type.String(), typebox.Type.Null()])),
|
|
176
|
+
emitter: alertEmitterSchema,
|
|
177
|
+
recipients: typebox.Type.Optional(typebox.Type.Union([typebox.Type.Array(alertEntityRefSchema), typebox.Type.Null()])),
|
|
178
|
+
related_entities: typebox.Type.Optional(typebox.Type.Union([typebox.Type.Array(alertEntityRefSchema), typebox.Type.Null()])),
|
|
179
|
+
payload: typebox.Type.Optional(typebox.Type.Union([typebox.Type.Record(typebox.Type.String(), typebox.Type.Unknown()), typebox.Type.Null()])),
|
|
180
|
+
metadata: typebox.Type.Optional(typebox.Type.Union([typebox.Type.Record(typebox.Type.String(), typebox.Type.Unknown()), typebox.Type.Null()])),
|
|
181
|
+
dedup_key: typebox.Type.Optional(typebox.Type.String({ maxLength: 255 })),
|
|
182
|
+
// `apiDateTime`, so the value reaches the service already a `Date` and no handler converts a
|
|
183
|
+
// string by hand. The wrapped type is the same `format: 'date-time'` as before, so the 200s and
|
|
184
|
+
// 400s of this field do not move — only what the service receives does.
|
|
185
|
+
triggered_at: typebox.Type.Optional(
|
|
186
|
+
typebox.Type.Union([dates_schema.apiDateTime, typebox.Type.Null()], {
|
|
187
|
+
description: `When the event that originated the alert happened. RFC 3339 with a mandatory offset — \`${dates_schema.API_DATETIME_EXAMPLE}\` is the shape the API emits, so a value read from here can be sent straight back. ${dates_schema.API_DATETIME_ACCEPTED_NOTE}. Stored as UTC`
|
|
188
|
+
})
|
|
189
|
+
)
|
|
190
|
+
},
|
|
191
|
+
{ title: "CreateAlert", description: "Payload to create an alert", additionalProperties: false }
|
|
192
|
+
);
|
|
193
|
+
const updateAlertSchema = typebox.Type.Partial(typebox.Type.Omit(createAlertSchema, ["emitter"]), {
|
|
194
|
+
title: "UpdateAlert",
|
|
195
|
+
description: "Payload to update an alert. Every field is optional. `emitter` cannot be changed after creation",
|
|
196
|
+
additionalProperties: false
|
|
197
|
+
});
|
|
198
|
+
const resolveAlertSchema = typebox.Type.Object(
|
|
199
|
+
{
|
|
200
|
+
resolution_note: typebox.Type.Optional(
|
|
201
|
+
typebox.Type.Union([typebox.Type.String(), typebox.Type.Null()], { description: "Optional note explaining the resolution" })
|
|
202
|
+
)
|
|
203
|
+
},
|
|
204
|
+
{ title: "ResolveAlert", description: "Payload to resolve an alert", additionalProperties: false }
|
|
205
|
+
);
|
|
206
|
+
const listAlertQuerySchema = typebox.Type.Object(
|
|
207
|
+
{
|
|
208
|
+
status: typebox.Type.Optional(alertStatusSchema),
|
|
209
|
+
severity: typebox.Type.Optional(alertSeveritySchema),
|
|
210
|
+
user_id: typebox.Type.Optional(typebox.Type.Number({ description: "Filter by the user the alert is about" })),
|
|
211
|
+
patient_id: typebox.Type.Optional(typebox.Type.Number({ description: "Filter by the patient the alert is about" })),
|
|
212
|
+
alert_type_id: typebox.Type.Optional(typebox.Type.Number({ description: "Filter by the type of the alert" }))
|
|
213
|
+
},
|
|
214
|
+
{ title: "ListAlertQuery", description: "Filters available on the alert list" }
|
|
215
|
+
);
|
|
216
|
+
exports.AlertEmitterType = AlertEmitterType;
|
|
217
|
+
exports.AlertSeverity = AlertSeverity;
|
|
218
|
+
exports.AlertStatus = AlertStatus;
|
|
219
|
+
exports.alertEmitterSchema = alertEmitterSchema;
|
|
220
|
+
exports.alertEmitterTypeSchema = alertEmitterTypeSchema;
|
|
221
|
+
exports.alertEntityRefSchema = alertEntityRefSchema;
|
|
222
|
+
exports.alertSchema = alertSchema;
|
|
223
|
+
exports.alertSeveritySchema = alertSeveritySchema;
|
|
224
|
+
exports.alertStatusSchema = alertStatusSchema;
|
|
225
|
+
exports.createAlertSchema = createAlertSchema;
|
|
226
|
+
exports.listAlertQuerySchema = listAlertQuerySchema;
|
|
227
|
+
exports.resolveAlertSchema = resolveAlertSchema;
|
|
228
|
+
exports.updateAlertSchema = updateAlertSchema;
|
|
229
|
+
//# sourceMappingURL=ecosystem-alert.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecosystem-alert.cjs","sources":["../../src/v2/modules/ecosystem/alert/alert.schema.ts"],"sourcesContent":["import { Type, Static, StaticDecode } from 'typebox'\n// From the schema file, not the module barrel (`@/modules/global/dates`) that every other consumer\n// imports — the one case where `no-restricted-imports` has to give way, as `process-log.schema.ts`\n// already does for the same reason.\n//\n// This module has a `lib.ts`, so this file is an entry point of the published `@persei/perseed-api`\n// bundle, which is browser code. The barrel re-exports `dates.middleware`, a `fastify-plugin` that\n// pulls the server dependencies behind it into that bundle. `validate-v2-modules` enforces this.\n// eslint-disable-next-line no-restricted-imports\nimport {\n API_DATETIME_ACCEPTED_NOTE,\n API_DATETIME_EXAMPLE,\n EMITTED_DATETIME_NOTE,\n apiDateTime,\n} from '@/modules/global/dates/dates.schema'\n\n// An alert stores the alert and its state, nothing else. Everything that happens\n// *because* of an alert (notifications, calls to external services, writing a\n// form) belongs to the action system: an alert is one more trigger source.\n\n// ── Enums / literal unions ────────────────────────────────────────────\n// Same shape as the action-system module: a const object as the source of truth\n// (ergonomic dot access, `AlertStatus.ACTIVE`) plus the schema derived from it.\n\nexport const AlertStatus = {\n ACTIVE: 'active',\n RESOLVED: 'resolved',\n} as const\nexport const alertStatusSchema = Type.Enum(Object.values(AlertStatus), {\n title: 'AlertStatus',\n description: 'Lifecycle state of an alert. An alert is open until it is resolved',\n})\nexport type AlertStatus = Static<typeof alertStatusSchema>\n\nexport const AlertSeverity = {\n INFO: 'info',\n LOW: 'low',\n MEDIUM: 'medium',\n HIGH: 'high',\n CRITICAL: 'critical',\n} as const\nexport const alertSeveritySchema = Type.Enum(Object.values(AlertSeverity), {\n title: 'AlertSeverity',\n description: 'Severity of the alert, used to prioritise it',\n})\nexport type AlertSeverity = Static<typeof alertSeveritySchema>\n\n// Who raised the alert. Closed union: the three entry paths the system has.\n// `webhook` is declared because it is the emitter an ingress endpoint will record\n// — the endpoint itself is a later issue, but an alert created by any other means\n// on behalf of a device must already be able to say so.\nexport const AlertEmitterType = {\n TRIGGER: 'trigger',\n API: 'api',\n WEBHOOK: 'webhook',\n} as const\nexport const alertEmitterTypeSchema = Type.Enum(Object.values(AlertEmitterType), {\n title: 'AlertEmitterType',\n description: 'Kind of emitter that raised the alert',\n})\nexport type AlertEmitterType = Static<typeof alertEmitterTypeSchema>\n\n// ── Embedded structures ──────────────────────────────────────────────\n\nexport const alertEmitterSchema = Type.Object(\n {\n type: alertEmitterTypeSchema,\n id: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Identifier of the emitter within its type (trigger id, device id, service id…)',\n }),\n ),\n name: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Human readable name of the emitter',\n }),\n ),\n reference: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Identifier of the originating event in the emitting system, for traceability',\n }),\n ),\n },\n { title: 'AlertEmitter', description: 'Who raised the alert', additionalProperties: false },\n)\nexport type AlertEmitterData = Static<typeof alertEmitterSchema>\n\n// Recipients and related entities share this shape on purpose: both answer\n// \"which entity, and which one of them\", and the pair differs only in the role it\n// plays — a recipient is a natural addressee of the alert, a related entity is\n// connected to it without being addressed. Same shape means a trigger reading\n// either one reads it the same way.\n//\n// `type` is an open string (a phone, an email, a caaring user, a service…) and\n// `value` is its identifier, so a new kind of recipient needs no migration.\nexport const alertEntityRefSchema = Type.Object(\n {\n type: Type.String({ maxLength: 64, description: 'Kind of entity (user, phone, email, service…)' }),\n value: Type.String({ maxLength: 255, description: 'Identifier of the entity within its type' }),\n },\n {\n title: 'AlertEntityRef',\n description: 'Reference to an entity by kind and identifier',\n additionalProperties: false,\n },\n)\nexport type AlertEntityRefData = Static<typeof alertEntityRefSchema>\n\n// ── alert ─────────────────────────────────────────────────────────────\n\nexport const alertSchema = Type.Object(\n {\n id: Type.Number({ description: 'Unique identifier of the alert' }),\n project_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description:\n 'Project this alert belongs to. Null for an ecosystem-wide alert, the ones created and read through the `/ecosystem/:ecosystemName/alert` mount, which belong to no project',\n }),\n ),\n alert_type_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description:\n 'Type of alert, as a row of the `alert_type` catalog of the ecosystem. Null for an alert that is not classified',\n }),\n ),\n user_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description:\n 'Caaring user the alert is about, and one of the two things that decide who may read it: this user always reads their own alerts. Null when the subject is a patient with no user account, in which case `patient_id` is the one that identifies them',\n }),\n ),\n patient_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description:\n 'Patient the alert is about, as the `id` of the `patient` CRF row of the project, and the other thing that decides who may read it: the professionals with access to that patient do. A patient may exist without a user account, so this is independent of `user_id`. It lives in the project database, so the column carries no foreign key and `project_id` is what says which database to read it from — an alert carrying it always carries a project',\n }),\n ),\n severity: Type.Optional(\n Type.Union([alertSeveritySchema, Type.Null()], { description: 'Severity of the alert. Null when not graded' }),\n ),\n status: Type.Optional(alertStatusSchema),\n title: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], { description: 'Short readable title' }),\n ),\n summary: Type.Optional(Type.Union([Type.String(), Type.Null()], { description: 'Longer readable description' })),\n emitter: alertEmitterSchema,\n recipients: Type.Optional(\n Type.Union([Type.Array(alertEntityRefSchema), Type.Null()], {\n description: 'Natural addressees of the alert. Null or empty when it has none',\n }),\n ),\n related_entities: Type.Optional(\n Type.Union([Type.Array(alertEntityRefSchema), Type.Null()], {\n description: 'Entities related to the alert without being addressees of it',\n }),\n ),\n payload: Type.Optional(\n Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {\n description: 'Structured data that originated the alert (measured value, threshold, form answer…)',\n }),\n ),\n metadata: Type.Optional(\n Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {\n description: 'Free extension point, so a new consumer does not need a schema change',\n }),\n ),\n dedup_key: Type.Optional(\n Type.String({\n maxLength: 255,\n description:\n 'Fingerprint used to avoid storing the same alert twice. A create carrying a key that is already open in the same scope answers with the stored alert; a resolved alert does not hold its key, so a condition that recurs after being dealt with raises a new one. Optional for the client: the server generates a UUID when it is absent, so the column always carries a usable value',\n }),\n ),\n triggered_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the event that originated the alert happened. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n viewed_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the alert was first viewed. Null while unseen. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n viewed_by: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'User who first viewed the alert' }),\n ),\n resolved_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the alert was resolved. Null while active. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n resolved_by: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'User who resolved the alert' }),\n ),\n resolution_note: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Optional note left when resolving the alert' }),\n ),\n created_user: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'User who created the alert, when a user did' }),\n ),\n created_at: Type.Optional(\n Type.String({\n description: `When the row was created. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n mod_time: Type.Optional(\n Type.String({\n description: `When the row was last modified. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'Alert', description: 'An alert and its state (ecosystem level)' },\n)\nexport type AlertData = Static<typeof alertSchema>\n\n// Written out rather than derived from `alertSchema`, for the same reason the action-system module\n// spells its request schemas out: an entity schema says what a row holds, a request schema says what\n// a client may send, and only the second can close itself. `Type.Omit` over an entity schema keeps\n// server-owned columns reachable through a body — here `status`, `resolved_*` and `viewed_*` are\n// absent because the server owns them, not because an `Omit` happened to remove them. Resolving\n// goes through its own endpoint; viewing is recorded by the read path.\nexport const createAlertSchema = Type.Object(\n {\n alert_type_id: Type.Optional(Type.Union([Type.Number(), Type.Null()])),\n user_id: Type.Optional(Type.Union([Type.Number(), Type.Null()])),\n patient_id: Type.Optional(Type.Union([Type.Number(), Type.Null()])),\n severity: Type.Optional(Type.Union([alertSeveritySchema, Type.Null()])),\n title: Type.Optional(Type.Union([Type.String({ maxLength: 255 }), Type.Null()])),\n summary: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n emitter: alertEmitterSchema,\n recipients: Type.Optional(Type.Union([Type.Array(alertEntityRefSchema), Type.Null()])),\n related_entities: Type.Optional(Type.Union([Type.Array(alertEntityRefSchema), Type.Null()])),\n payload: Type.Optional(Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()])),\n metadata: Type.Optional(Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()])),\n dedup_key: Type.Optional(Type.String({ maxLength: 255 })),\n // `apiDateTime`, so the value reaches the service already a `Date` and no handler converts a\n // string by hand. The wrapped type is the same `format: 'date-time'` as before, so the 200s and\n // 400s of this field do not move — only what the service receives does.\n triggered_at: Type.Optional(\n Type.Union([apiDateTime, Type.Null()], {\n description: `When the event that originated the alert happened. RFC 3339 with a mandatory offset — \\`${API_DATETIME_EXAMPLE}\\` is the shape the API emits, so a value read from here can be sent straight back. ${API_DATETIME_ACCEPTED_NOTE}. Stored as UTC`,\n }),\n ),\n },\n { title: 'CreateAlert', description: 'Payload to create an alert', additionalProperties: false },\n)\n// `StaticDecode`, not `Static`: this type describes what a *handler receives*, and the handler\n// receives the decoded body — `triggered_at` is a `Date` there. `Static` resolves in the encode\n// direction, which is the string that travelled on the wire, so it would describe the value one\n// step earlier than the one this type is used for.\nexport type CreateAlertData = StaticDecode<typeof createAlertSchema>\n\n/**\n * The same payload as it travels on the wire, before the boundary decodes it: `triggered_at` is\n * still the RFC 3339 string a client sends.\n *\n * Only clients of the HTTP interface need this — tests that build a request body, and any caller\n * assembling JSON. Everything on the server side of the validator wants `CreateAlertData`, which is\n * the decoded shape.\n */\nexport type CreateAlertRequestBody = Static<typeof createAlertSchema>\n\n// `emitter` is `Type.Omit`-ted, not just made optional by `Type.Partial`: who raised the alert is\n// fixed at creation the same way `status`/`resolved_*`/`viewed_*` already are (see\n// `createAlertSchema` above) — a client rewriting it through a PATCH would falsify that provenance\n// for an entity that carries clinical data. `Type.Partial` alone would only make the key optional,\n// not absent, so it would still accept and apply a client-supplied `emitter`.\n// `Type.Partial` rebuilds the object and does NOT inherit `additionalProperties`, so it is restated.\nexport const updateAlertSchema = Type.Partial(Type.Omit(createAlertSchema, ['emitter']), {\n title: 'UpdateAlert',\n description: 'Payload to update an alert. Every field is optional. `emitter` cannot be changed after creation',\n additionalProperties: false,\n})\nexport type UpdateAlertData = StaticDecode<typeof updateAlertSchema>\n\n// Resolving is its own endpoint rather than a `status` field on the update: it is\n// the single transition of the lifecycle, and it writes three columns at once\n// (`status`, `resolved_at`, `resolved_by`) that must never disagree. A plain\n// `PATCH {status: 'resolved'}` would let a client set the state without the two\n// columns that say who closed it and when.\nexport const resolveAlertSchema = Type.Object(\n {\n resolution_note: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Optional note explaining the resolution' }),\n ),\n },\n { title: 'ResolveAlert', description: 'Payload to resolve an alert', additionalProperties: false },\n)\nexport type ResolveAlertData = Static<typeof resolveAlertSchema>\n\n// Filters of the list endpoint, on top of the pagination query. Everything is\n// optional: with none of them the endpoint lists the project's alerts.\nexport const listAlertQuerySchema = Type.Object(\n {\n status: Type.Optional(alertStatusSchema),\n severity: Type.Optional(alertSeveritySchema),\n user_id: Type.Optional(Type.Number({ description: 'Filter by the user the alert is about' })),\n patient_id: Type.Optional(Type.Number({ description: 'Filter by the patient the alert is about' })),\n alert_type_id: Type.Optional(Type.Number({ description: 'Filter by the type of the alert' })),\n },\n { title: 'ListAlertQuery', description: 'Filters available on the alert list' },\n)\nexport type ListAlertQuery = Static<typeof listAlertQuerySchema>\n"],"names":["Type","EMITTED_DATETIME_NOTE","API_DATETIME_EXAMPLE","apiDateTime","API_DATETIME_ACCEPTED_NOTE"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './src/v2/modules/ecosystem/alert/lib'
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { a as API_DATETIME_EXAMPLE, E as EMITTED_DATETIME_NOTE, b as apiDateTime, A as API_DATETIME_ACCEPTED_NOTE } from "./dates.schema-BqkBcmM6.js";
|
|
3
|
+
const AlertStatus = {
|
|
4
|
+
ACTIVE: "active",
|
|
5
|
+
RESOLVED: "resolved"
|
|
6
|
+
};
|
|
7
|
+
const alertStatusSchema = Type.Enum(Object.values(AlertStatus), {
|
|
8
|
+
title: "AlertStatus",
|
|
9
|
+
description: "Lifecycle state of an alert. An alert is open until it is resolved"
|
|
10
|
+
});
|
|
11
|
+
const AlertSeverity = {
|
|
12
|
+
INFO: "info",
|
|
13
|
+
LOW: "low",
|
|
14
|
+
MEDIUM: "medium",
|
|
15
|
+
HIGH: "high",
|
|
16
|
+
CRITICAL: "critical"
|
|
17
|
+
};
|
|
18
|
+
const alertSeveritySchema = Type.Enum(Object.values(AlertSeverity), {
|
|
19
|
+
title: "AlertSeverity",
|
|
20
|
+
description: "Severity of the alert, used to prioritise it"
|
|
21
|
+
});
|
|
22
|
+
const AlertEmitterType = {
|
|
23
|
+
TRIGGER: "trigger",
|
|
24
|
+
API: "api",
|
|
25
|
+
WEBHOOK: "webhook"
|
|
26
|
+
};
|
|
27
|
+
const alertEmitterTypeSchema = Type.Enum(Object.values(AlertEmitterType), {
|
|
28
|
+
title: "AlertEmitterType",
|
|
29
|
+
description: "Kind of emitter that raised the alert"
|
|
30
|
+
});
|
|
31
|
+
const alertEmitterSchema = Type.Object(
|
|
32
|
+
{
|
|
33
|
+
type: alertEmitterTypeSchema,
|
|
34
|
+
id: Type.Optional(
|
|
35
|
+
Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {
|
|
36
|
+
description: "Identifier of the emitter within its type (trigger id, device id, service id…)"
|
|
37
|
+
})
|
|
38
|
+
),
|
|
39
|
+
name: Type.Optional(
|
|
40
|
+
Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {
|
|
41
|
+
description: "Human readable name of the emitter"
|
|
42
|
+
})
|
|
43
|
+
),
|
|
44
|
+
reference: Type.Optional(
|
|
45
|
+
Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {
|
|
46
|
+
description: "Identifier of the originating event in the emitting system, for traceability"
|
|
47
|
+
})
|
|
48
|
+
)
|
|
49
|
+
},
|
|
50
|
+
{ title: "AlertEmitter", description: "Who raised the alert", additionalProperties: false }
|
|
51
|
+
);
|
|
52
|
+
const alertEntityRefSchema = Type.Object(
|
|
53
|
+
{
|
|
54
|
+
type: Type.String({ maxLength: 64, description: "Kind of entity (user, phone, email, service…)" }),
|
|
55
|
+
value: Type.String({ maxLength: 255, description: "Identifier of the entity within its type" })
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
title: "AlertEntityRef",
|
|
59
|
+
description: "Reference to an entity by kind and identifier",
|
|
60
|
+
additionalProperties: false
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
const alertSchema = Type.Object(
|
|
64
|
+
{
|
|
65
|
+
id: Type.Number({ description: "Unique identifier of the alert" }),
|
|
66
|
+
project_id: Type.Optional(
|
|
67
|
+
Type.Union([Type.Number(), Type.Null()], {
|
|
68
|
+
description: "Project this alert belongs to. Null for an ecosystem-wide alert, the ones created and read through the `/ecosystem/:ecosystemName/alert` mount, which belong to no project"
|
|
69
|
+
})
|
|
70
|
+
),
|
|
71
|
+
alert_type_id: Type.Optional(
|
|
72
|
+
Type.Union([Type.Number(), Type.Null()], {
|
|
73
|
+
description: "Type of alert, as a row of the `alert_type` catalog of the ecosystem. Null for an alert that is not classified"
|
|
74
|
+
})
|
|
75
|
+
),
|
|
76
|
+
user_id: Type.Optional(
|
|
77
|
+
Type.Union([Type.Number(), Type.Null()], {
|
|
78
|
+
description: "Caaring user the alert is about, and one of the two things that decide who may read it: this user always reads their own alerts. Null when the subject is a patient with no user account, in which case `patient_id` is the one that identifies them"
|
|
79
|
+
})
|
|
80
|
+
),
|
|
81
|
+
patient_id: Type.Optional(
|
|
82
|
+
Type.Union([Type.Number(), Type.Null()], {
|
|
83
|
+
description: "Patient the alert is about, as the `id` of the `patient` CRF row of the project, and the other thing that decides who may read it: the professionals with access to that patient do. A patient may exist without a user account, so this is independent of `user_id`. It lives in the project database, so the column carries no foreign key and `project_id` is what says which database to read it from — an alert carrying it always carries a project"
|
|
84
|
+
})
|
|
85
|
+
),
|
|
86
|
+
severity: Type.Optional(
|
|
87
|
+
Type.Union([alertSeveritySchema, Type.Null()], { description: "Severity of the alert. Null when not graded" })
|
|
88
|
+
),
|
|
89
|
+
status: Type.Optional(alertStatusSchema),
|
|
90
|
+
title: Type.Optional(
|
|
91
|
+
Type.Union([Type.String({ maxLength: 255 }), Type.Null()], { description: "Short readable title" })
|
|
92
|
+
),
|
|
93
|
+
summary: Type.Optional(Type.Union([Type.String(), Type.Null()], { description: "Longer readable description" })),
|
|
94
|
+
emitter: alertEmitterSchema,
|
|
95
|
+
recipients: Type.Optional(
|
|
96
|
+
Type.Union([Type.Array(alertEntityRefSchema), Type.Null()], {
|
|
97
|
+
description: "Natural addressees of the alert. Null or empty when it has none"
|
|
98
|
+
})
|
|
99
|
+
),
|
|
100
|
+
related_entities: Type.Optional(
|
|
101
|
+
Type.Union([Type.Array(alertEntityRefSchema), Type.Null()], {
|
|
102
|
+
description: "Entities related to the alert without being addressees of it"
|
|
103
|
+
})
|
|
104
|
+
),
|
|
105
|
+
payload: Type.Optional(
|
|
106
|
+
Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {
|
|
107
|
+
description: "Structured data that originated the alert (measured value, threshold, form answer…)"
|
|
108
|
+
})
|
|
109
|
+
),
|
|
110
|
+
metadata: Type.Optional(
|
|
111
|
+
Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {
|
|
112
|
+
description: "Free extension point, so a new consumer does not need a schema change"
|
|
113
|
+
})
|
|
114
|
+
),
|
|
115
|
+
dedup_key: Type.Optional(
|
|
116
|
+
Type.String({
|
|
117
|
+
maxLength: 255,
|
|
118
|
+
description: "Fingerprint used to avoid storing the same alert twice. A create carrying a key that is already open in the same scope answers with the stored alert; a resolved alert does not hold its key, so a condition that recurs after being dealt with raises a new one. Optional for the client: the server generates a UUID when it is absent, so the column always carries a usable value"
|
|
119
|
+
})
|
|
120
|
+
),
|
|
121
|
+
triggered_at: Type.Optional(
|
|
122
|
+
Type.Union([Type.String(), Type.Null()], {
|
|
123
|
+
description: `When the event that originated the alert happened. ${EMITTED_DATETIME_NOTE}`,
|
|
124
|
+
examples: [API_DATETIME_EXAMPLE]
|
|
125
|
+
})
|
|
126
|
+
),
|
|
127
|
+
viewed_at: Type.Optional(
|
|
128
|
+
Type.Union([Type.String(), Type.Null()], {
|
|
129
|
+
description: `When the alert was first viewed. Null while unseen. ${EMITTED_DATETIME_NOTE}`,
|
|
130
|
+
examples: [API_DATETIME_EXAMPLE]
|
|
131
|
+
})
|
|
132
|
+
),
|
|
133
|
+
viewed_by: Type.Optional(
|
|
134
|
+
Type.Union([Type.Number(), Type.Null()], { description: "User who first viewed the alert" })
|
|
135
|
+
),
|
|
136
|
+
resolved_at: Type.Optional(
|
|
137
|
+
Type.Union([Type.String(), Type.Null()], {
|
|
138
|
+
description: `When the alert was resolved. Null while active. ${EMITTED_DATETIME_NOTE}`,
|
|
139
|
+
examples: [API_DATETIME_EXAMPLE]
|
|
140
|
+
})
|
|
141
|
+
),
|
|
142
|
+
resolved_by: Type.Optional(
|
|
143
|
+
Type.Union([Type.Number(), Type.Null()], { description: "User who resolved the alert" })
|
|
144
|
+
),
|
|
145
|
+
resolution_note: Type.Optional(
|
|
146
|
+
Type.Union([Type.String(), Type.Null()], { description: "Optional note left when resolving the alert" })
|
|
147
|
+
),
|
|
148
|
+
created_user: Type.Optional(
|
|
149
|
+
Type.Union([Type.Number(), Type.Null()], { description: "User who created the alert, when a user did" })
|
|
150
|
+
),
|
|
151
|
+
created_at: Type.Optional(
|
|
152
|
+
Type.String({
|
|
153
|
+
description: `When the row was created. ${EMITTED_DATETIME_NOTE}`,
|
|
154
|
+
examples: [API_DATETIME_EXAMPLE]
|
|
155
|
+
})
|
|
156
|
+
),
|
|
157
|
+
mod_time: Type.Optional(
|
|
158
|
+
Type.String({
|
|
159
|
+
description: `When the row was last modified. ${EMITTED_DATETIME_NOTE}`,
|
|
160
|
+
examples: [API_DATETIME_EXAMPLE]
|
|
161
|
+
})
|
|
162
|
+
)
|
|
163
|
+
},
|
|
164
|
+
{ title: "Alert", description: "An alert and its state (ecosystem level)" }
|
|
165
|
+
);
|
|
166
|
+
const createAlertSchema = Type.Object(
|
|
167
|
+
{
|
|
168
|
+
alert_type_id: Type.Optional(Type.Union([Type.Number(), Type.Null()])),
|
|
169
|
+
user_id: Type.Optional(Type.Union([Type.Number(), Type.Null()])),
|
|
170
|
+
patient_id: Type.Optional(Type.Union([Type.Number(), Type.Null()])),
|
|
171
|
+
severity: Type.Optional(Type.Union([alertSeveritySchema, Type.Null()])),
|
|
172
|
+
title: Type.Optional(Type.Union([Type.String({ maxLength: 255 }), Type.Null()])),
|
|
173
|
+
summary: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
|
174
|
+
emitter: alertEmitterSchema,
|
|
175
|
+
recipients: Type.Optional(Type.Union([Type.Array(alertEntityRefSchema), Type.Null()])),
|
|
176
|
+
related_entities: Type.Optional(Type.Union([Type.Array(alertEntityRefSchema), Type.Null()])),
|
|
177
|
+
payload: Type.Optional(Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()])),
|
|
178
|
+
metadata: Type.Optional(Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()])),
|
|
179
|
+
dedup_key: Type.Optional(Type.String({ maxLength: 255 })),
|
|
180
|
+
// `apiDateTime`, so the value reaches the service already a `Date` and no handler converts a
|
|
181
|
+
// string by hand. The wrapped type is the same `format: 'date-time'` as before, so the 200s and
|
|
182
|
+
// 400s of this field do not move — only what the service receives does.
|
|
183
|
+
triggered_at: Type.Optional(
|
|
184
|
+
Type.Union([apiDateTime, Type.Null()], {
|
|
185
|
+
description: `When the event that originated the alert happened. RFC 3339 with a mandatory offset — \`${API_DATETIME_EXAMPLE}\` is the shape the API emits, so a value read from here can be sent straight back. ${API_DATETIME_ACCEPTED_NOTE}. Stored as UTC`
|
|
186
|
+
})
|
|
187
|
+
)
|
|
188
|
+
},
|
|
189
|
+
{ title: "CreateAlert", description: "Payload to create an alert", additionalProperties: false }
|
|
190
|
+
);
|
|
191
|
+
const updateAlertSchema = Type.Partial(Type.Omit(createAlertSchema, ["emitter"]), {
|
|
192
|
+
title: "UpdateAlert",
|
|
193
|
+
description: "Payload to update an alert. Every field is optional. `emitter` cannot be changed after creation",
|
|
194
|
+
additionalProperties: false
|
|
195
|
+
});
|
|
196
|
+
const resolveAlertSchema = Type.Object(
|
|
197
|
+
{
|
|
198
|
+
resolution_note: Type.Optional(
|
|
199
|
+
Type.Union([Type.String(), Type.Null()], { description: "Optional note explaining the resolution" })
|
|
200
|
+
)
|
|
201
|
+
},
|
|
202
|
+
{ title: "ResolveAlert", description: "Payload to resolve an alert", additionalProperties: false }
|
|
203
|
+
);
|
|
204
|
+
const listAlertQuerySchema = Type.Object(
|
|
205
|
+
{
|
|
206
|
+
status: Type.Optional(alertStatusSchema),
|
|
207
|
+
severity: Type.Optional(alertSeveritySchema),
|
|
208
|
+
user_id: Type.Optional(Type.Number({ description: "Filter by the user the alert is about" })),
|
|
209
|
+
patient_id: Type.Optional(Type.Number({ description: "Filter by the patient the alert is about" })),
|
|
210
|
+
alert_type_id: Type.Optional(Type.Number({ description: "Filter by the type of the alert" }))
|
|
211
|
+
},
|
|
212
|
+
{ title: "ListAlertQuery", description: "Filters available on the alert list" }
|
|
213
|
+
);
|
|
214
|
+
export {
|
|
215
|
+
AlertEmitterType,
|
|
216
|
+
AlertSeverity,
|
|
217
|
+
AlertStatus,
|
|
218
|
+
alertEmitterSchema,
|
|
219
|
+
alertEmitterTypeSchema,
|
|
220
|
+
alertEntityRefSchema,
|
|
221
|
+
alertSchema,
|
|
222
|
+
alertSeveritySchema,
|
|
223
|
+
alertStatusSchema,
|
|
224
|
+
createAlertSchema,
|
|
225
|
+
listAlertQuerySchema,
|
|
226
|
+
resolveAlertSchema,
|
|
227
|
+
updateAlertSchema
|
|
228
|
+
};
|
|
229
|
+
//# sourceMappingURL=ecosystem-alert.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ecosystem-alert.mjs","sources":["../../src/v2/modules/ecosystem/alert/alert.schema.ts"],"sourcesContent":["import { Type, Static, StaticDecode } from 'typebox'\n// From the schema file, not the module barrel (`@/modules/global/dates`) that every other consumer\n// imports — the one case where `no-restricted-imports` has to give way, as `process-log.schema.ts`\n// already does for the same reason.\n//\n// This module has a `lib.ts`, so this file is an entry point of the published `@persei/perseed-api`\n// bundle, which is browser code. The barrel re-exports `dates.middleware`, a `fastify-plugin` that\n// pulls the server dependencies behind it into that bundle. `validate-v2-modules` enforces this.\n// eslint-disable-next-line no-restricted-imports\nimport {\n API_DATETIME_ACCEPTED_NOTE,\n API_DATETIME_EXAMPLE,\n EMITTED_DATETIME_NOTE,\n apiDateTime,\n} from '@/modules/global/dates/dates.schema'\n\n// An alert stores the alert and its state, nothing else. Everything that happens\n// *because* of an alert (notifications, calls to external services, writing a\n// form) belongs to the action system: an alert is one more trigger source.\n\n// ── Enums / literal unions ────────────────────────────────────────────\n// Same shape as the action-system module: a const object as the source of truth\n// (ergonomic dot access, `AlertStatus.ACTIVE`) plus the schema derived from it.\n\nexport const AlertStatus = {\n ACTIVE: 'active',\n RESOLVED: 'resolved',\n} as const\nexport const alertStatusSchema = Type.Enum(Object.values(AlertStatus), {\n title: 'AlertStatus',\n description: 'Lifecycle state of an alert. An alert is open until it is resolved',\n})\nexport type AlertStatus = Static<typeof alertStatusSchema>\n\nexport const AlertSeverity = {\n INFO: 'info',\n LOW: 'low',\n MEDIUM: 'medium',\n HIGH: 'high',\n CRITICAL: 'critical',\n} as const\nexport const alertSeveritySchema = Type.Enum(Object.values(AlertSeverity), {\n title: 'AlertSeverity',\n description: 'Severity of the alert, used to prioritise it',\n})\nexport type AlertSeverity = Static<typeof alertSeveritySchema>\n\n// Who raised the alert. Closed union: the three entry paths the system has.\n// `webhook` is declared because it is the emitter an ingress endpoint will record\n// — the endpoint itself is a later issue, but an alert created by any other means\n// on behalf of a device must already be able to say so.\nexport const AlertEmitterType = {\n TRIGGER: 'trigger',\n API: 'api',\n WEBHOOK: 'webhook',\n} as const\nexport const alertEmitterTypeSchema = Type.Enum(Object.values(AlertEmitterType), {\n title: 'AlertEmitterType',\n description: 'Kind of emitter that raised the alert',\n})\nexport type AlertEmitterType = Static<typeof alertEmitterTypeSchema>\n\n// ── Embedded structures ──────────────────────────────────────────────\n\nexport const alertEmitterSchema = Type.Object(\n {\n type: alertEmitterTypeSchema,\n id: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Identifier of the emitter within its type (trigger id, device id, service id…)',\n }),\n ),\n name: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Human readable name of the emitter',\n }),\n ),\n reference: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Identifier of the originating event in the emitting system, for traceability',\n }),\n ),\n },\n { title: 'AlertEmitter', description: 'Who raised the alert', additionalProperties: false },\n)\nexport type AlertEmitterData = Static<typeof alertEmitterSchema>\n\n// Recipients and related entities share this shape on purpose: both answer\n// \"which entity, and which one of them\", and the pair differs only in the role it\n// plays — a recipient is a natural addressee of the alert, a related entity is\n// connected to it without being addressed. Same shape means a trigger reading\n// either one reads it the same way.\n//\n// `type` is an open string (a phone, an email, a caaring user, a service…) and\n// `value` is its identifier, so a new kind of recipient needs no migration.\nexport const alertEntityRefSchema = Type.Object(\n {\n type: Type.String({ maxLength: 64, description: 'Kind of entity (user, phone, email, service…)' }),\n value: Type.String({ maxLength: 255, description: 'Identifier of the entity within its type' }),\n },\n {\n title: 'AlertEntityRef',\n description: 'Reference to an entity by kind and identifier',\n additionalProperties: false,\n },\n)\nexport type AlertEntityRefData = Static<typeof alertEntityRefSchema>\n\n// ── alert ─────────────────────────────────────────────────────────────\n\nexport const alertSchema = Type.Object(\n {\n id: Type.Number({ description: 'Unique identifier of the alert' }),\n project_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description:\n 'Project this alert belongs to. Null for an ecosystem-wide alert, the ones created and read through the `/ecosystem/:ecosystemName/alert` mount, which belong to no project',\n }),\n ),\n alert_type_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description:\n 'Type of alert, as a row of the `alert_type` catalog of the ecosystem. Null for an alert that is not classified',\n }),\n ),\n user_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description:\n 'Caaring user the alert is about, and one of the two things that decide who may read it: this user always reads their own alerts. Null when the subject is a patient with no user account, in which case `patient_id` is the one that identifies them',\n }),\n ),\n patient_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description:\n 'Patient the alert is about, as the `id` of the `patient` CRF row of the project, and the other thing that decides who may read it: the professionals with access to that patient do. A patient may exist without a user account, so this is independent of `user_id`. It lives in the project database, so the column carries no foreign key and `project_id` is what says which database to read it from — an alert carrying it always carries a project',\n }),\n ),\n severity: Type.Optional(\n Type.Union([alertSeveritySchema, Type.Null()], { description: 'Severity of the alert. Null when not graded' }),\n ),\n status: Type.Optional(alertStatusSchema),\n title: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], { description: 'Short readable title' }),\n ),\n summary: Type.Optional(Type.Union([Type.String(), Type.Null()], { description: 'Longer readable description' })),\n emitter: alertEmitterSchema,\n recipients: Type.Optional(\n Type.Union([Type.Array(alertEntityRefSchema), Type.Null()], {\n description: 'Natural addressees of the alert. Null or empty when it has none',\n }),\n ),\n related_entities: Type.Optional(\n Type.Union([Type.Array(alertEntityRefSchema), Type.Null()], {\n description: 'Entities related to the alert without being addressees of it',\n }),\n ),\n payload: Type.Optional(\n Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {\n description: 'Structured data that originated the alert (measured value, threshold, form answer…)',\n }),\n ),\n metadata: Type.Optional(\n Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {\n description: 'Free extension point, so a new consumer does not need a schema change',\n }),\n ),\n dedup_key: Type.Optional(\n Type.String({\n maxLength: 255,\n description:\n 'Fingerprint used to avoid storing the same alert twice. A create carrying a key that is already open in the same scope answers with the stored alert; a resolved alert does not hold its key, so a condition that recurs after being dealt with raises a new one. Optional for the client: the server generates a UUID when it is absent, so the column always carries a usable value',\n }),\n ),\n triggered_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the event that originated the alert happened. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n viewed_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the alert was first viewed. Null while unseen. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n viewed_by: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'User who first viewed the alert' }),\n ),\n resolved_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the alert was resolved. Null while active. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n resolved_by: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'User who resolved the alert' }),\n ),\n resolution_note: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Optional note left when resolving the alert' }),\n ),\n created_user: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'User who created the alert, when a user did' }),\n ),\n created_at: Type.Optional(\n Type.String({\n description: `When the row was created. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n mod_time: Type.Optional(\n Type.String({\n description: `When the row was last modified. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'Alert', description: 'An alert and its state (ecosystem level)' },\n)\nexport type AlertData = Static<typeof alertSchema>\n\n// Written out rather than derived from `alertSchema`, for the same reason the action-system module\n// spells its request schemas out: an entity schema says what a row holds, a request schema says what\n// a client may send, and only the second can close itself. `Type.Omit` over an entity schema keeps\n// server-owned columns reachable through a body — here `status`, `resolved_*` and `viewed_*` are\n// absent because the server owns them, not because an `Omit` happened to remove them. Resolving\n// goes through its own endpoint; viewing is recorded by the read path.\nexport const createAlertSchema = Type.Object(\n {\n alert_type_id: Type.Optional(Type.Union([Type.Number(), Type.Null()])),\n user_id: Type.Optional(Type.Union([Type.Number(), Type.Null()])),\n patient_id: Type.Optional(Type.Union([Type.Number(), Type.Null()])),\n severity: Type.Optional(Type.Union([alertSeveritySchema, Type.Null()])),\n title: Type.Optional(Type.Union([Type.String({ maxLength: 255 }), Type.Null()])),\n summary: Type.Optional(Type.Union([Type.String(), Type.Null()])),\n emitter: alertEmitterSchema,\n recipients: Type.Optional(Type.Union([Type.Array(alertEntityRefSchema), Type.Null()])),\n related_entities: Type.Optional(Type.Union([Type.Array(alertEntityRefSchema), Type.Null()])),\n payload: Type.Optional(Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()])),\n metadata: Type.Optional(Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()])),\n dedup_key: Type.Optional(Type.String({ maxLength: 255 })),\n // `apiDateTime`, so the value reaches the service already a `Date` and no handler converts a\n // string by hand. The wrapped type is the same `format: 'date-time'` as before, so the 200s and\n // 400s of this field do not move — only what the service receives does.\n triggered_at: Type.Optional(\n Type.Union([apiDateTime, Type.Null()], {\n description: `When the event that originated the alert happened. RFC 3339 with a mandatory offset — \\`${API_DATETIME_EXAMPLE}\\` is the shape the API emits, so a value read from here can be sent straight back. ${API_DATETIME_ACCEPTED_NOTE}. Stored as UTC`,\n }),\n ),\n },\n { title: 'CreateAlert', description: 'Payload to create an alert', additionalProperties: false },\n)\n// `StaticDecode`, not `Static`: this type describes what a *handler receives*, and the handler\n// receives the decoded body — `triggered_at` is a `Date` there. `Static` resolves in the encode\n// direction, which is the string that travelled on the wire, so it would describe the value one\n// step earlier than the one this type is used for.\nexport type CreateAlertData = StaticDecode<typeof createAlertSchema>\n\n/**\n * The same payload as it travels on the wire, before the boundary decodes it: `triggered_at` is\n * still the RFC 3339 string a client sends.\n *\n * Only clients of the HTTP interface need this — tests that build a request body, and any caller\n * assembling JSON. Everything on the server side of the validator wants `CreateAlertData`, which is\n * the decoded shape.\n */\nexport type CreateAlertRequestBody = Static<typeof createAlertSchema>\n\n// `emitter` is `Type.Omit`-ted, not just made optional by `Type.Partial`: who raised the alert is\n// fixed at creation the same way `status`/`resolved_*`/`viewed_*` already are (see\n// `createAlertSchema` above) — a client rewriting it through a PATCH would falsify that provenance\n// for an entity that carries clinical data. `Type.Partial` alone would only make the key optional,\n// not absent, so it would still accept and apply a client-supplied `emitter`.\n// `Type.Partial` rebuilds the object and does NOT inherit `additionalProperties`, so it is restated.\nexport const updateAlertSchema = Type.Partial(Type.Omit(createAlertSchema, ['emitter']), {\n title: 'UpdateAlert',\n description: 'Payload to update an alert. Every field is optional. `emitter` cannot be changed after creation',\n additionalProperties: false,\n})\nexport type UpdateAlertData = StaticDecode<typeof updateAlertSchema>\n\n// Resolving is its own endpoint rather than a `status` field on the update: it is\n// the single transition of the lifecycle, and it writes three columns at once\n// (`status`, `resolved_at`, `resolved_by`) that must never disagree. A plain\n// `PATCH {status: 'resolved'}` would let a client set the state without the two\n// columns that say who closed it and when.\nexport const resolveAlertSchema = Type.Object(\n {\n resolution_note: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Optional note explaining the resolution' }),\n ),\n },\n { title: 'ResolveAlert', description: 'Payload to resolve an alert', additionalProperties: false },\n)\nexport type ResolveAlertData = Static<typeof resolveAlertSchema>\n\n// Filters of the list endpoint, on top of the pagination query. Everything is\n// optional: with none of them the endpoint lists the project's alerts.\nexport const listAlertQuerySchema = Type.Object(\n {\n status: Type.Optional(alertStatusSchema),\n severity: Type.Optional(alertSeveritySchema),\n user_id: Type.Optional(Type.Number({ description: 'Filter by the user the alert is about' })),\n patient_id: Type.Optional(Type.Number({ description: 'Filter by the patient the alert is about' })),\n alert_type_id: Type.Optional(Type.Number({ description: 'Filter by the type of the alert' })),\n },\n { title: 'ListAlertQuery', description: 'Filters available on the alert list' },\n)\nexport type ListAlertQuery = Static<typeof listAlertQuerySchema>\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ecosystem-process-log.cjs","sources":["../../src/v2/modules/ecosystem/process-log/process-log.schema.ts"],"sourcesContent":["import { Type, Static, StaticDecode } from 'typebox'\n// From the schema file, not the module barrel (`@/modules/global/dates`) that every other consumer\n// imports — the one place where `no-restricted-imports` has to give way, hence the disable.\n//\n// This module has a `lib.ts`, so this file is an entry point of the published `@persei/perseed-api`\n// bundle, which is browser code. The barrel re-exports `dates.middleware`, a `fastify-plugin` that\n// pulls in `@v1/log/debug` and, transitively, the server dependencies behind it; bundling that\n// fails, and it fails naming a transitive JSON file (`ent/reversed.json: Could not parse JSON\n// file`) rather than the import that dragged it in, so the message points nowhere near the cause.\n//\n// `global/dates`'s own `lib.ts` sidesteps the same barrel for the same reason. The alternative —\n// inlining the two description constants — would duplicate the wording the whole API documents its\n// datetimes with, and let this module's copy drift from it silently.\n// eslint-disable-next-line no-restricted-imports\nimport {\n EMITTED_DATETIME_NOTE,\n API_DATETIME_EXAMPLE,\n API_DATETIME_ACCEPTED_NOTE,\n apiDateTime,\n} from '@/modules/global/dates/dates.schema'\n\n// `process_log` is the ecosystem-wide execution log (see README.md): rows written by the trigger\n// engine, the actions it runs and the v1 bulk upload. This module owns the schema for the whole\n// table, not only the trigger-engine rows — `code` is what tells them apart.\n\n// ── ProcessLogType (severity, NOT layout) ───────────────────────────────\n// Mirrors the v1 enum (`src/schemas/process_log/types.ts`) verbatim: it already ships on the wire\n// (`type` column) and changing its numeric values would be a breaking change for every existing row\n// and consumer. Restated here as a TypeBox schema — not imported from v1 — because `lib.ts` may\n// only export pure TypeBox (see below); v1 has no schema module of its own to import from.\nexport const ProcessLogType = {\n LOG: 0,\n RESULT: 1,\n WARNING: -1,\n ERROR: -2,\n} as const\nexport const processLogTypeSchema = Type.Enum(Object.values(ProcessLogType), {\n title: 'ProcessLogType',\n description: 'Severity of the log row (not a layout/kind marker): LOG, RESULT, WARNING or ERROR',\n})\nexport type ProcessLogType = Static<typeof processLogTypeSchema>\n\n// ── ProcessLogCode ───────────────────────────────────────────────────────\n//\n// Canonical enum now lives HERE (v2), not in `src/schemas/process_log/types.ts` (v1).\n//\n// Why: this module (`process-log`) is the one being extended with the trigger-engine codes as part\n// of #348, it already owns the model/service half of `process_log`, and every v2 consumer that needs\n// a *typed* extra_data contract (this schema file) has to sit next to the code enum it is keyed by.\n// The two v1 importers (`BulkUploadController.ts` and `IntrospectionController.ts`) import it from\n// here rather than from `@v1/schemas`, which keeps one enum instead of two that could drift. v1's\n// `types.ts` deliberately does NOT re-export the value: doing so closes the cycle `@v1/schemas` →\n// this module's barrel → `process-log.model.ts` → `@v1/schemas`, under which the enum resolves to\n// `undefined` at runtime. It keeps an `import type` only, which is erased at compile time.\nexport const ProcessLogCode = {\n BULK_UPLOAD_BATCH: 'bulk_upload_batch',\n BULK_UPLOAD_SUCCESS: 'bulk_upload_success',\n BULK_UPLOAD_ERROR: 'bulk_upload_error',\n // Trigger engine (#348). Written by `TriggerEngineService` (`action-system` module): one\n // `TRIGGER_EVALUATION` row per trigger evaluated, one `TRIGGER_ACTION` row per action it ran, and a\n // `TRIGGER_ERROR` row when a trigger's evaluation throws.\n TRIGGER_EVALUATION: 'trigger_evaluation',\n TRIGGER_ERROR: 'trigger_error',\n TRIGGER_ACTION: 'trigger_action',\n} as const\nexport const processLogCodeSchema = Type.Enum(Object.values(ProcessLogCode), {\n title: 'ProcessLogCode',\n description: 'What kind of event a process_log row records, and what shape its extra_data takes',\n})\nexport type ProcessLogCode = Static<typeof processLogCodeSchema>\n\n// ── extra_data shapes, one per trigger-engine code ───────────────────────\n// Bulk upload codes carry no typed extra_data today (nothing writes them yet outside the\n// filter-by-code reads in `BulkUploadController.ts`), so they are left out of the discriminated\n// union below rather than given a placeholder shape that no writer populates.\n\nexport const triggerEvaluationExtraDataSchema = Type.Object(\n {\n source: Type.String({ description: 'What fired the event: a model row or a displayer/form save' }),\n target: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Model/displayer name the trigger is bound to' }),\n ),\n operation: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'create/update/delete that fired the event' }),\n ),\n matched: Type.Boolean({ description: 'Whether the trigger conditions matched' }),\n conditions: Type.Optional(\n Type.Union([Type.Unknown(), Type.Null()], {\n description: 'jsonLogic conditions the trigger was configured with',\n }),\n ),\n relations: Type.Optional(\n Type.Union([Type.Unknown(), Type.Null()], {\n description: 'Relations the trigger declared to load onto `current`',\n }),\n ),\n relationsSkipped: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: 'Reason a declared relation could not be loaded, when one was skipped',\n }),\n ),\n },\n {\n title: 'TriggerEvaluationExtraData',\n description:\n 'extra_data of a `trigger_evaluation` row — how a trigger resolved, never the entity data it resolved against',\n additionalProperties: false,\n },\n)\nexport type TriggerEvaluationExtraData = Static<typeof triggerEvaluationExtraDataSchema>\n\nexport const triggerErrorExtraDataSchema = Type.Object(\n { error: Type.String({ description: 'String representation of the exception the trigger evaluation threw' }) },\n { title: 'TriggerErrorExtraData', description: 'extra_data of a `trigger_error` row', additionalProperties: false },\n)\nexport type TriggerErrorExtraData = Static<typeof triggerErrorExtraDataSchema>\n\nexport const triggerActionExtraDataSchema = Type.Object(\n {\n actionId: Type.Number({ description: 'id of the action row that ran' }),\n triggerId: Type.Number({ description: 'id of the trigger that ran this action' }),\n // Needed because the engine is shared: `triggerId` alone is ambiguous, since automatic and\n // manual triggers are different tables (`automatic_trigger`, `manual_trigger`) with overlapping\n // id ranges. Paired with `triggerId` this is what a consumer needs to resolve the trigger row.\n triggerModel: Type.String({ description: 'Table the trigger belongs to (automatic_trigger or manual_trigger)' }),\n executionOrder: Type.Number({ description: 'Order of this action within the trigger' }),\n type: Type.String({ description: 'Type of the action (e.g. ApiAction)' }),\n validation: Type.Unknown({ description: 'Result of validating the action context before running it' }),\n // `ok`/`output` describe an action that ran; `aborted`/`reason` an action that never did,\n // because validating its context failed (`resolveActionOutcome`). The two pairs are mutually\n // exclusive in practice but declared as four optionals rather than a union: `additionalProperties:\n // false` is what makes this schema worth having, and a row whose outcome keys are undeclared is\n // one the debugging popup cannot show a reason for — which is exactly the aborted case.\n ok: Type.Optional(Type.Union([Type.Boolean(), Type.Null()], { description: 'Whether the action call succeeded' })),\n output: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Failure output, when the action ran and failed' }),\n ),\n aborted: Type.Optional(Type.Boolean({ description: 'True when the action never ran' })),\n reason: Type.Optional(Type.String({ description: 'Why the action was aborted, e.g. context_validation' })),\n },\n { title: 'TriggerActionExtraData', description: 'extra_data of a `trigger_action` row', additionalProperties: false },\n)\nexport type TriggerActionExtraData = Static<typeof triggerActionExtraDataSchema>\n\n// Discriminated (by `code`) union tying each trigger-engine code to its extra_data shape. Usable\n// both to validate a row being created and to type one being read. Bulk upload codes are\n// deliberately absent (see comment above the individual schemas).\nexport const processLogTriggerEngineExtraDataSchema = Type.Union(\n [\n Type.Object({\n code: Type.Literal(ProcessLogCode.TRIGGER_EVALUATION),\n extra_data: triggerEvaluationExtraDataSchema,\n }),\n Type.Object({ code: Type.Literal(ProcessLogCode.TRIGGER_ERROR), extra_data: triggerErrorExtraDataSchema }),\n Type.Object({ code: Type.Literal(ProcessLogCode.TRIGGER_ACTION), extra_data: triggerActionExtraDataSchema }),\n ],\n {\n title: 'ProcessLogTriggerEngineExtraData',\n description: 'Ties each trigger-engine `code` to the shape its `extra_data` takes',\n },\n)\nexport type ProcessLogTriggerEngineExtraData = Static<typeof processLogTriggerEngineExtraDataSchema>\n\n// ── process_log entity ────────────────────────────────────────────────────\n// Full row shape, for the read side of the (still to be implemented) list endpoint. `extra_data` is\n// left as a free record here — a response schema describes what every row of the table can hold,\n// including the untyped bulk_upload rows, unlike `processLogTriggerEngineExtraDataSchema` above\n// which narrows by `code` for a writer/reader that already knows it is on the trigger-engine path.\nexport const processLogSchema = Type.Object(\n {\n id: Type.Number({ description: 'Unique identifier of the row' }),\n project_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'Project this row belongs to, when scoped to one' }),\n ),\n created_user: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description: 'User who caused the row to be written, when a user did',\n }),\n ),\n related_model: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], { description: 'Table/entity kind the row is about' }),\n ),\n related_id: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Id of the related entity, as a string',\n }),\n ),\n code: Type.Optional(Type.Union([processLogCodeSchema, Type.Null()])),\n log: Type.String({ description: 'Short human-readable message' }),\n long_log: Type.Optional(Type.Union([Type.String(), Type.Null()], { description: 'Extended message, when needed' })),\n extra_data: Type.Optional(\n Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {\n description: 'Structured data specific to `code` — see the per-code schemas for the trigger-engine codes',\n }),\n ),\n type: processLogTypeSchema,\n requires_attention: Type.Optional(Type.Boolean({ description: 'Whether the row needs a human to review it' })),\n reviewed: Type.Optional(Type.Boolean({ description: 'Whether the row has been reviewed' })),\n reviewed_date: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the row was reviewed. Null while unreviewed. ${EMITTED_DATETIME_NOTE}`,\n }),\n ),\n // Correlation to a parent row (#348): a `trigger_action` row's parent is the `trigger_evaluation`\n // (or `trigger_error`) row of the trigger that ran it, so an action's trace can always be walked\n // back to the evaluation that triggered it. Optional/nullable because most rows (bulk upload,\n // the trigger-evaluation row itself) have no parent, and because the column is applied out of\n // band per ecosystem — see README.md — so it may be entirely absent from a given row's database.\n parent_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description: \"Id of this row's parent process_log row, when it has one\",\n }),\n ),\n expires_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `Retention deadline; the row is purged after it, and never expires when null. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n created_at: Type.Optional(\n Type.String({\n description: `When the row was created. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n mod_time: Type.Optional(\n Type.String({\n description: `When the row was last modified. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'ProcessLog', description: 'A process_log row' },\n)\nexport type ProcessLogData = Static<typeof processLogSchema>\n\n// ── list query filters ────────────────────────────────────────────────────\n// Filters of the (upcoming) list endpoint, on top of the pagination query — see `alert.schema.ts`\n// `listAlertQuerySchema` for the sibling precedent. Everything is optional: with none of them the\n// endpoint lists everything in scope. Exported for the endpoint (implemented separately) to consume.\nexport const listProcessLogQuerySchema = Type.Object(\n {\n code: Type.Optional(processLogCodeSchema),\n type: Type.Optional(processLogTypeSchema),\n related_model: Type.Optional(Type.String({ description: 'Filter by the related entity kind' })),\n related_id: Type.Optional(Type.String({ description: 'Filter by the id of the related entity' })),\n parent_id: Type.Optional(Type.Number({ description: 'Filter by the id of the parent process_log row' })),\n requires_attention: Type.Optional(Type.Boolean({ description: 'Filter by whether the row needs review' })),\n reviewed: Type.Optional(Type.Boolean({ description: 'Filter by whether the row has been reviewed' })),\n // `apiDateTime`, not a bare string: it carries `format: 'date-time'`, so a malformed value is\n // rejected by the validator as a 400. A plain `Type.String` accepts anything and hands it to\n // `getMySQLDateTime(value, true)`, which throws a `PublicApiError` with no `statusCode` — a 500\n // for what is a bad request. Same type `alert.schema.ts` uses for its datetime fields.\n created_from: Type.Optional(\n Type.Union([apiDateTime], {\n description: `Only rows created at or after this instant. ${API_DATETIME_ACCEPTED_NOTE}. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n created_to: Type.Optional(\n Type.Union([apiDateTime], {\n description: `Only rows created at or before this instant. ${API_DATETIME_ACCEPTED_NOTE}. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'ListProcessLogQuery', description: 'Filters available on the process_log list' },\n)\n// `StaticDecode`, not `Static`: this type describes what the *handler receives*, and the two date\n// bounds carry `apiDateTime`, so they arrive decoded to a `Date`. `Static` would type them as the\n// strings the client sent and the service would format something it never gets.\nexport type ListProcessLogQuery = StaticDecode<typeof listProcessLogQuerySchema>\n"],"names":["Type","EMITTED_DATETIME_NOTE","API_DATETIME_EXAMPLE","apiDateTime","API_DATETIME_ACCEPTED_NOTE"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ecosystem-process-log.cjs","sources":["../../src/v2/modules/ecosystem/process-log/process-log.schema.ts"],"sourcesContent":["import { Type, Static, StaticDecode } from 'typebox'\n// From the schema file, not the module barrel (`@/modules/global/dates`) that every other consumer\n// imports — the one case where `no-restricted-imports` has to give way, as `alert.schema.ts` also\n// does for the same reason.\n//\n// This module has a `lib.ts`, so this file is an entry point of the published `@persei/perseed-api`\n// bundle, which is browser code. The barrel re-exports `dates.middleware`, a `fastify-plugin` that\n// pulls in `@v1/log/debug` and, transitively, the server dependencies behind it; bundling that\n// fails, and it fails naming a transitive JSON file (`ent/reversed.json: Could not parse JSON\n// file`) rather than the import that dragged it in, so the message points nowhere near the cause.\n//\n// `global/dates`'s own `lib.ts` sidesteps the same barrel for the same reason. The alternative —\n// inlining the two description constants — would duplicate the wording the whole API documents its\n// datetimes with, and let this module's copy drift from it silently.\n// eslint-disable-next-line no-restricted-imports\nimport {\n EMITTED_DATETIME_NOTE,\n API_DATETIME_EXAMPLE,\n API_DATETIME_ACCEPTED_NOTE,\n apiDateTime,\n} from '@/modules/global/dates/dates.schema'\n\n// `process_log` is the ecosystem-wide execution log (see README.md): rows written by the trigger\n// engine, the actions it runs and the v1 bulk upload. This module owns the schema for the whole\n// table, not only the trigger-engine rows — `code` is what tells them apart.\n\n// ── ProcessLogType (severity, NOT layout) ───────────────────────────────\n// Mirrors the v1 enum (`src/schemas/process_log/types.ts`) verbatim: it already ships on the wire\n// (`type` column) and changing its numeric values would be a breaking change for every existing row\n// and consumer. Restated here as a TypeBox schema — not imported from v1 — because `lib.ts` may\n// only export pure TypeBox (see below); v1 has no schema module of its own to import from.\nexport const ProcessLogType = {\n LOG: 0,\n RESULT: 1,\n WARNING: -1,\n ERROR: -2,\n} as const\nexport const processLogTypeSchema = Type.Enum(Object.values(ProcessLogType), {\n title: 'ProcessLogType',\n description: 'Severity of the log row (not a layout/kind marker): LOG, RESULT, WARNING or ERROR',\n})\nexport type ProcessLogType = Static<typeof processLogTypeSchema>\n\n// ── ProcessLogCode ───────────────────────────────────────────────────────\n//\n// Canonical enum now lives HERE (v2), not in `src/schemas/process_log/types.ts` (v1).\n//\n// Why: this module (`process-log`) is the one being extended with the trigger-engine codes as part\n// of #348, it already owns the model/service half of `process_log`, and every v2 consumer that needs\n// a *typed* extra_data contract (this schema file) has to sit next to the code enum it is keyed by.\n// The two v1 importers (`BulkUploadController.ts` and `IntrospectionController.ts`) import it from\n// here rather than from `@v1/schemas`, which keeps one enum instead of two that could drift. v1's\n// `types.ts` deliberately does NOT re-export the value: doing so closes the cycle `@v1/schemas` →\n// this module's barrel → `process-log.model.ts` → `@v1/schemas`, under which the enum resolves to\n// `undefined` at runtime. It keeps an `import type` only, which is erased at compile time.\nexport const ProcessLogCode = {\n BULK_UPLOAD_BATCH: 'bulk_upload_batch',\n BULK_UPLOAD_SUCCESS: 'bulk_upload_success',\n BULK_UPLOAD_ERROR: 'bulk_upload_error',\n // Trigger engine (#348). Written by `TriggerEngineService` (`action-system` module): one\n // `TRIGGER_EVALUATION` row per trigger evaluated, one `TRIGGER_ACTION` row per action it ran, and a\n // `TRIGGER_ERROR` row when a trigger's evaluation throws.\n TRIGGER_EVALUATION: 'trigger_evaluation',\n TRIGGER_ERROR: 'trigger_error',\n TRIGGER_ACTION: 'trigger_action',\n} as const\nexport const processLogCodeSchema = Type.Enum(Object.values(ProcessLogCode), {\n title: 'ProcessLogCode',\n description: 'What kind of event a process_log row records, and what shape its extra_data takes',\n})\nexport type ProcessLogCode = Static<typeof processLogCodeSchema>\n\n// ── extra_data shapes, one per trigger-engine code ───────────────────────\n// Bulk upload codes carry no typed extra_data today (nothing writes them yet outside the\n// filter-by-code reads in `BulkUploadController.ts`), so they are left out of the discriminated\n// union below rather than given a placeholder shape that no writer populates.\n\nexport const triggerEvaluationExtraDataSchema = Type.Object(\n {\n source: Type.String({ description: 'What fired the event: a model row or a displayer/form save' }),\n target: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Model/displayer name the trigger is bound to' }),\n ),\n operation: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'create/update/delete that fired the event' }),\n ),\n matched: Type.Boolean({ description: 'Whether the trigger conditions matched' }),\n conditions: Type.Optional(\n Type.Union([Type.Unknown(), Type.Null()], {\n description: 'jsonLogic conditions the trigger was configured with',\n }),\n ),\n relations: Type.Optional(\n Type.Union([Type.Unknown(), Type.Null()], {\n description: 'Relations the trigger declared to load onto `current`',\n }),\n ),\n relationsSkipped: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: 'Reason a declared relation could not be loaded, when one was skipped',\n }),\n ),\n },\n {\n title: 'TriggerEvaluationExtraData',\n description:\n 'extra_data of a `trigger_evaluation` row — how a trigger resolved, never the entity data it resolved against',\n additionalProperties: false,\n },\n)\nexport type TriggerEvaluationExtraData = Static<typeof triggerEvaluationExtraDataSchema>\n\nexport const triggerErrorExtraDataSchema = Type.Object(\n { error: Type.String({ description: 'String representation of the exception the trigger evaluation threw' }) },\n { title: 'TriggerErrorExtraData', description: 'extra_data of a `trigger_error` row', additionalProperties: false },\n)\nexport type TriggerErrorExtraData = Static<typeof triggerErrorExtraDataSchema>\n\nexport const triggerActionExtraDataSchema = Type.Object(\n {\n actionId: Type.Number({ description: 'id of the action row that ran' }),\n triggerId: Type.Number({ description: 'id of the trigger that ran this action' }),\n // Needed because the engine is shared: `triggerId` alone is ambiguous, since automatic and\n // manual triggers are different tables (`automatic_trigger`, `manual_trigger`) with overlapping\n // id ranges. Paired with `triggerId` this is what a consumer needs to resolve the trigger row.\n triggerModel: Type.String({ description: 'Table the trigger belongs to (automatic_trigger or manual_trigger)' }),\n executionOrder: Type.Number({ description: 'Order of this action within the trigger' }),\n type: Type.String({ description: 'Type of the action (e.g. ApiAction)' }),\n validation: Type.Unknown({ description: 'Result of validating the action context before running it' }),\n // `ok`/`output` describe an action that ran; `aborted`/`reason` an action that never did,\n // because validating its context failed (`resolveActionOutcome`). The two pairs are mutually\n // exclusive in practice but declared as four optionals rather than a union: `additionalProperties:\n // false` is what makes this schema worth having, and a row whose outcome keys are undeclared is\n // one the debugging popup cannot show a reason for — which is exactly the aborted case.\n ok: Type.Optional(Type.Union([Type.Boolean(), Type.Null()], { description: 'Whether the action call succeeded' })),\n output: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Failure output, when the action ran and failed' }),\n ),\n aborted: Type.Optional(Type.Boolean({ description: 'True when the action never ran' })),\n reason: Type.Optional(Type.String({ description: 'Why the action was aborted, e.g. context_validation' })),\n },\n { title: 'TriggerActionExtraData', description: 'extra_data of a `trigger_action` row', additionalProperties: false },\n)\nexport type TriggerActionExtraData = Static<typeof triggerActionExtraDataSchema>\n\n// Discriminated (by `code`) union tying each trigger-engine code to its extra_data shape. Usable\n// both to validate a row being created and to type one being read. Bulk upload codes are\n// deliberately absent (see comment above the individual schemas).\nexport const processLogTriggerEngineExtraDataSchema = Type.Union(\n [\n Type.Object({\n code: Type.Literal(ProcessLogCode.TRIGGER_EVALUATION),\n extra_data: triggerEvaluationExtraDataSchema,\n }),\n Type.Object({ code: Type.Literal(ProcessLogCode.TRIGGER_ERROR), extra_data: triggerErrorExtraDataSchema }),\n Type.Object({ code: Type.Literal(ProcessLogCode.TRIGGER_ACTION), extra_data: triggerActionExtraDataSchema }),\n ],\n {\n title: 'ProcessLogTriggerEngineExtraData',\n description: 'Ties each trigger-engine `code` to the shape its `extra_data` takes',\n },\n)\nexport type ProcessLogTriggerEngineExtraData = Static<typeof processLogTriggerEngineExtraDataSchema>\n\n// ── process_log entity ────────────────────────────────────────────────────\n// Full row shape, for the read side of the (still to be implemented) list endpoint. `extra_data` is\n// left as a free record here — a response schema describes what every row of the table can hold,\n// including the untyped bulk_upload rows, unlike `processLogTriggerEngineExtraDataSchema` above\n// which narrows by `code` for a writer/reader that already knows it is on the trigger-engine path.\nexport const processLogSchema = Type.Object(\n {\n id: Type.Number({ description: 'Unique identifier of the row' }),\n project_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'Project this row belongs to, when scoped to one' }),\n ),\n created_user: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description: 'User who caused the row to be written, when a user did',\n }),\n ),\n related_model: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], { description: 'Table/entity kind the row is about' }),\n ),\n related_id: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Id of the related entity, as a string',\n }),\n ),\n code: Type.Optional(Type.Union([processLogCodeSchema, Type.Null()])),\n log: Type.String({ description: 'Short human-readable message' }),\n long_log: Type.Optional(Type.Union([Type.String(), Type.Null()], { description: 'Extended message, when needed' })),\n extra_data: Type.Optional(\n Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {\n description: 'Structured data specific to `code` — see the per-code schemas for the trigger-engine codes',\n }),\n ),\n type: processLogTypeSchema,\n requires_attention: Type.Optional(Type.Boolean({ description: 'Whether the row needs a human to review it' })),\n reviewed: Type.Optional(Type.Boolean({ description: 'Whether the row has been reviewed' })),\n reviewed_date: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the row was reviewed. Null while unreviewed. ${EMITTED_DATETIME_NOTE}`,\n }),\n ),\n // Correlation to a parent row (#348): a `trigger_action` row's parent is the `trigger_evaluation`\n // (or `trigger_error`) row of the trigger that ran it, so an action's trace can always be walked\n // back to the evaluation that triggered it. Optional/nullable because most rows (bulk upload,\n // the trigger-evaluation row itself) have no parent, and because the column is applied out of\n // band per ecosystem — see README.md — so it may be entirely absent from a given row's database.\n parent_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description: \"Id of this row's parent process_log row, when it has one\",\n }),\n ),\n expires_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `Retention deadline; the row is purged after it, and never expires when null. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n created_at: Type.Optional(\n Type.String({\n description: `When the row was created. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n mod_time: Type.Optional(\n Type.String({\n description: `When the row was last modified. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'ProcessLog', description: 'A process_log row' },\n)\nexport type ProcessLogData = Static<typeof processLogSchema>\n\n// ── list query filters ────────────────────────────────────────────────────\n// Filters of the (upcoming) list endpoint, on top of the pagination query — see `alert.schema.ts`\n// `listAlertQuerySchema` for the sibling precedent. Everything is optional: with none of them the\n// endpoint lists everything in scope. Exported for the endpoint (implemented separately) to consume.\nexport const listProcessLogQuerySchema = Type.Object(\n {\n code: Type.Optional(processLogCodeSchema),\n type: Type.Optional(processLogTypeSchema),\n related_model: Type.Optional(Type.String({ description: 'Filter by the related entity kind' })),\n related_id: Type.Optional(Type.String({ description: 'Filter by the id of the related entity' })),\n parent_id: Type.Optional(Type.Number({ description: 'Filter by the id of the parent process_log row' })),\n requires_attention: Type.Optional(Type.Boolean({ description: 'Filter by whether the row needs review' })),\n reviewed: Type.Optional(Type.Boolean({ description: 'Filter by whether the row has been reviewed' })),\n // `apiDateTime`, not a bare string: it carries `format: 'date-time'`, so a malformed value is\n // rejected by the validator as a 400. A plain `Type.String` accepts anything and hands it to\n // `getMySQLDateTime(value, true)`, which throws a `PublicApiError` with no `statusCode` — a 500\n // for what is a bad request. Same type `alert.schema.ts` uses for its datetime fields.\n created_from: Type.Optional(\n Type.Union([apiDateTime], {\n description: `Only rows created at or after this instant. ${API_DATETIME_ACCEPTED_NOTE}. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n created_to: Type.Optional(\n Type.Union([apiDateTime], {\n description: `Only rows created at or before this instant. ${API_DATETIME_ACCEPTED_NOTE}. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'ListProcessLogQuery', description: 'Filters available on the process_log list' },\n)\n// `StaticDecode`, not `Static`: this type describes what the *handler receives*, and the two date\n// bounds carry `apiDateTime`, so they arrive decoded to a `Date`. `Static` would type them as the\n// strings the client sent and the service would format something it never gets.\nexport type ListProcessLogQuery = StaticDecode<typeof listProcessLogQuerySchema>\n"],"names":["Type","EMITTED_DATETIME_NOTE","API_DATETIME_EXAMPLE","apiDateTime","API_DATETIME_ACCEPTED_NOTE"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ecosystem-process-log.mjs","sources":["../../src/v2/modules/ecosystem/process-log/process-log.schema.ts"],"sourcesContent":["import { Type, Static, StaticDecode } from 'typebox'\n// From the schema file, not the module barrel (`@/modules/global/dates`) that every other consumer\n// imports — the one place where `no-restricted-imports` has to give way, hence the disable.\n//\n// This module has a `lib.ts`, so this file is an entry point of the published `@persei/perseed-api`\n// bundle, which is browser code. The barrel re-exports `dates.middleware`, a `fastify-plugin` that\n// pulls in `@v1/log/debug` and, transitively, the server dependencies behind it; bundling that\n// fails, and it fails naming a transitive JSON file (`ent/reversed.json: Could not parse JSON\n// file`) rather than the import that dragged it in, so the message points nowhere near the cause.\n//\n// `global/dates`'s own `lib.ts` sidesteps the same barrel for the same reason. The alternative —\n// inlining the two description constants — would duplicate the wording the whole API documents its\n// datetimes with, and let this module's copy drift from it silently.\n// eslint-disable-next-line no-restricted-imports\nimport {\n EMITTED_DATETIME_NOTE,\n API_DATETIME_EXAMPLE,\n API_DATETIME_ACCEPTED_NOTE,\n apiDateTime,\n} from '@/modules/global/dates/dates.schema'\n\n// `process_log` is the ecosystem-wide execution log (see README.md): rows written by the trigger\n// engine, the actions it runs and the v1 bulk upload. This module owns the schema for the whole\n// table, not only the trigger-engine rows — `code` is what tells them apart.\n\n// ── ProcessLogType (severity, NOT layout) ───────────────────────────────\n// Mirrors the v1 enum (`src/schemas/process_log/types.ts`) verbatim: it already ships on the wire\n// (`type` column) and changing its numeric values would be a breaking change for every existing row\n// and consumer. Restated here as a TypeBox schema — not imported from v1 — because `lib.ts` may\n// only export pure TypeBox (see below); v1 has no schema module of its own to import from.\nexport const ProcessLogType = {\n LOG: 0,\n RESULT: 1,\n WARNING: -1,\n ERROR: -2,\n} as const\nexport const processLogTypeSchema = Type.Enum(Object.values(ProcessLogType), {\n title: 'ProcessLogType',\n description: 'Severity of the log row (not a layout/kind marker): LOG, RESULT, WARNING or ERROR',\n})\nexport type ProcessLogType = Static<typeof processLogTypeSchema>\n\n// ── ProcessLogCode ───────────────────────────────────────────────────────\n//\n// Canonical enum now lives HERE (v2), not in `src/schemas/process_log/types.ts` (v1).\n//\n// Why: this module (`process-log`) is the one being extended with the trigger-engine codes as part\n// of #348, it already owns the model/service half of `process_log`, and every v2 consumer that needs\n// a *typed* extra_data contract (this schema file) has to sit next to the code enum it is keyed by.\n// The two v1 importers (`BulkUploadController.ts` and `IntrospectionController.ts`) import it from\n// here rather than from `@v1/schemas`, which keeps one enum instead of two that could drift. v1's\n// `types.ts` deliberately does NOT re-export the value: doing so closes the cycle `@v1/schemas` →\n// this module's barrel → `process-log.model.ts` → `@v1/schemas`, under which the enum resolves to\n// `undefined` at runtime. It keeps an `import type` only, which is erased at compile time.\nexport const ProcessLogCode = {\n BULK_UPLOAD_BATCH: 'bulk_upload_batch',\n BULK_UPLOAD_SUCCESS: 'bulk_upload_success',\n BULK_UPLOAD_ERROR: 'bulk_upload_error',\n // Trigger engine (#348). Written by `TriggerEngineService` (`action-system` module): one\n // `TRIGGER_EVALUATION` row per trigger evaluated, one `TRIGGER_ACTION` row per action it ran, and a\n // `TRIGGER_ERROR` row when a trigger's evaluation throws.\n TRIGGER_EVALUATION: 'trigger_evaluation',\n TRIGGER_ERROR: 'trigger_error',\n TRIGGER_ACTION: 'trigger_action',\n} as const\nexport const processLogCodeSchema = Type.Enum(Object.values(ProcessLogCode), {\n title: 'ProcessLogCode',\n description: 'What kind of event a process_log row records, and what shape its extra_data takes',\n})\nexport type ProcessLogCode = Static<typeof processLogCodeSchema>\n\n// ── extra_data shapes, one per trigger-engine code ───────────────────────\n// Bulk upload codes carry no typed extra_data today (nothing writes them yet outside the\n// filter-by-code reads in `BulkUploadController.ts`), so they are left out of the discriminated\n// union below rather than given a placeholder shape that no writer populates.\n\nexport const triggerEvaluationExtraDataSchema = Type.Object(\n {\n source: Type.String({ description: 'What fired the event: a model row or a displayer/form save' }),\n target: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Model/displayer name the trigger is bound to' }),\n ),\n operation: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'create/update/delete that fired the event' }),\n ),\n matched: Type.Boolean({ description: 'Whether the trigger conditions matched' }),\n conditions: Type.Optional(\n Type.Union([Type.Unknown(), Type.Null()], {\n description: 'jsonLogic conditions the trigger was configured with',\n }),\n ),\n relations: Type.Optional(\n Type.Union([Type.Unknown(), Type.Null()], {\n description: 'Relations the trigger declared to load onto `current`',\n }),\n ),\n relationsSkipped: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: 'Reason a declared relation could not be loaded, when one was skipped',\n }),\n ),\n },\n {\n title: 'TriggerEvaluationExtraData',\n description:\n 'extra_data of a `trigger_evaluation` row — how a trigger resolved, never the entity data it resolved against',\n additionalProperties: false,\n },\n)\nexport type TriggerEvaluationExtraData = Static<typeof triggerEvaluationExtraDataSchema>\n\nexport const triggerErrorExtraDataSchema = Type.Object(\n { error: Type.String({ description: 'String representation of the exception the trigger evaluation threw' }) },\n { title: 'TriggerErrorExtraData', description: 'extra_data of a `trigger_error` row', additionalProperties: false },\n)\nexport type TriggerErrorExtraData = Static<typeof triggerErrorExtraDataSchema>\n\nexport const triggerActionExtraDataSchema = Type.Object(\n {\n actionId: Type.Number({ description: 'id of the action row that ran' }),\n triggerId: Type.Number({ description: 'id of the trigger that ran this action' }),\n // Needed because the engine is shared: `triggerId` alone is ambiguous, since automatic and\n // manual triggers are different tables (`automatic_trigger`, `manual_trigger`) with overlapping\n // id ranges. Paired with `triggerId` this is what a consumer needs to resolve the trigger row.\n triggerModel: Type.String({ description: 'Table the trigger belongs to (automatic_trigger or manual_trigger)' }),\n executionOrder: Type.Number({ description: 'Order of this action within the trigger' }),\n type: Type.String({ description: 'Type of the action (e.g. ApiAction)' }),\n validation: Type.Unknown({ description: 'Result of validating the action context before running it' }),\n // `ok`/`output` describe an action that ran; `aborted`/`reason` an action that never did,\n // because validating its context failed (`resolveActionOutcome`). The two pairs are mutually\n // exclusive in practice but declared as four optionals rather than a union: `additionalProperties:\n // false` is what makes this schema worth having, and a row whose outcome keys are undeclared is\n // one the debugging popup cannot show a reason for — which is exactly the aborted case.\n ok: Type.Optional(Type.Union([Type.Boolean(), Type.Null()], { description: 'Whether the action call succeeded' })),\n output: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Failure output, when the action ran and failed' }),\n ),\n aborted: Type.Optional(Type.Boolean({ description: 'True when the action never ran' })),\n reason: Type.Optional(Type.String({ description: 'Why the action was aborted, e.g. context_validation' })),\n },\n { title: 'TriggerActionExtraData', description: 'extra_data of a `trigger_action` row', additionalProperties: false },\n)\nexport type TriggerActionExtraData = Static<typeof triggerActionExtraDataSchema>\n\n// Discriminated (by `code`) union tying each trigger-engine code to its extra_data shape. Usable\n// both to validate a row being created and to type one being read. Bulk upload codes are\n// deliberately absent (see comment above the individual schemas).\nexport const processLogTriggerEngineExtraDataSchema = Type.Union(\n [\n Type.Object({\n code: Type.Literal(ProcessLogCode.TRIGGER_EVALUATION),\n extra_data: triggerEvaluationExtraDataSchema,\n }),\n Type.Object({ code: Type.Literal(ProcessLogCode.TRIGGER_ERROR), extra_data: triggerErrorExtraDataSchema }),\n Type.Object({ code: Type.Literal(ProcessLogCode.TRIGGER_ACTION), extra_data: triggerActionExtraDataSchema }),\n ],\n {\n title: 'ProcessLogTriggerEngineExtraData',\n description: 'Ties each trigger-engine `code` to the shape its `extra_data` takes',\n },\n)\nexport type ProcessLogTriggerEngineExtraData = Static<typeof processLogTriggerEngineExtraDataSchema>\n\n// ── process_log entity ────────────────────────────────────────────────────\n// Full row shape, for the read side of the (still to be implemented) list endpoint. `extra_data` is\n// left as a free record here — a response schema describes what every row of the table can hold,\n// including the untyped bulk_upload rows, unlike `processLogTriggerEngineExtraDataSchema` above\n// which narrows by `code` for a writer/reader that already knows it is on the trigger-engine path.\nexport const processLogSchema = Type.Object(\n {\n id: Type.Number({ description: 'Unique identifier of the row' }),\n project_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'Project this row belongs to, when scoped to one' }),\n ),\n created_user: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description: 'User who caused the row to be written, when a user did',\n }),\n ),\n related_model: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], { description: 'Table/entity kind the row is about' }),\n ),\n related_id: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Id of the related entity, as a string',\n }),\n ),\n code: Type.Optional(Type.Union([processLogCodeSchema, Type.Null()])),\n log: Type.String({ description: 'Short human-readable message' }),\n long_log: Type.Optional(Type.Union([Type.String(), Type.Null()], { description: 'Extended message, when needed' })),\n extra_data: Type.Optional(\n Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {\n description: 'Structured data specific to `code` — see the per-code schemas for the trigger-engine codes',\n }),\n ),\n type: processLogTypeSchema,\n requires_attention: Type.Optional(Type.Boolean({ description: 'Whether the row needs a human to review it' })),\n reviewed: Type.Optional(Type.Boolean({ description: 'Whether the row has been reviewed' })),\n reviewed_date: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the row was reviewed. Null while unreviewed. ${EMITTED_DATETIME_NOTE}`,\n }),\n ),\n // Correlation to a parent row (#348): a `trigger_action` row's parent is the `trigger_evaluation`\n // (or `trigger_error`) row of the trigger that ran it, so an action's trace can always be walked\n // back to the evaluation that triggered it. Optional/nullable because most rows (bulk upload,\n // the trigger-evaluation row itself) have no parent, and because the column is applied out of\n // band per ecosystem — see README.md — so it may be entirely absent from a given row's database.\n parent_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description: \"Id of this row's parent process_log row, when it has one\",\n }),\n ),\n expires_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `Retention deadline; the row is purged after it, and never expires when null. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n created_at: Type.Optional(\n Type.String({\n description: `When the row was created. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n mod_time: Type.Optional(\n Type.String({\n description: `When the row was last modified. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'ProcessLog', description: 'A process_log row' },\n)\nexport type ProcessLogData = Static<typeof processLogSchema>\n\n// ── list query filters ────────────────────────────────────────────────────\n// Filters of the (upcoming) list endpoint, on top of the pagination query — see `alert.schema.ts`\n// `listAlertQuerySchema` for the sibling precedent. Everything is optional: with none of them the\n// endpoint lists everything in scope. Exported for the endpoint (implemented separately) to consume.\nexport const listProcessLogQuerySchema = Type.Object(\n {\n code: Type.Optional(processLogCodeSchema),\n type: Type.Optional(processLogTypeSchema),\n related_model: Type.Optional(Type.String({ description: 'Filter by the related entity kind' })),\n related_id: Type.Optional(Type.String({ description: 'Filter by the id of the related entity' })),\n parent_id: Type.Optional(Type.Number({ description: 'Filter by the id of the parent process_log row' })),\n requires_attention: Type.Optional(Type.Boolean({ description: 'Filter by whether the row needs review' })),\n reviewed: Type.Optional(Type.Boolean({ description: 'Filter by whether the row has been reviewed' })),\n // `apiDateTime`, not a bare string: it carries `format: 'date-time'`, so a malformed value is\n // rejected by the validator as a 400. A plain `Type.String` accepts anything and hands it to\n // `getMySQLDateTime(value, true)`, which throws a `PublicApiError` with no `statusCode` — a 500\n // for what is a bad request. Same type `alert.schema.ts` uses for its datetime fields.\n created_from: Type.Optional(\n Type.Union([apiDateTime], {\n description: `Only rows created at or after this instant. ${API_DATETIME_ACCEPTED_NOTE}. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n created_to: Type.Optional(\n Type.Union([apiDateTime], {\n description: `Only rows created at or before this instant. ${API_DATETIME_ACCEPTED_NOTE}. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'ListProcessLogQuery', description: 'Filters available on the process_log list' },\n)\n// `StaticDecode`, not `Static`: this type describes what the *handler receives*, and the two date\n// bounds carry `apiDateTime`, so they arrive decoded to a `Date`. `Static` would type them as the\n// strings the client sent and the service would format something it never gets.\nexport type ListProcessLogQuery = StaticDecode<typeof listProcessLogQuerySchema>\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ecosystem-process-log.mjs","sources":["../../src/v2/modules/ecosystem/process-log/process-log.schema.ts"],"sourcesContent":["import { Type, Static, StaticDecode } from 'typebox'\n// From the schema file, not the module barrel (`@/modules/global/dates`) that every other consumer\n// imports — the one case where `no-restricted-imports` has to give way, as `alert.schema.ts` also\n// does for the same reason.\n//\n// This module has a `lib.ts`, so this file is an entry point of the published `@persei/perseed-api`\n// bundle, which is browser code. The barrel re-exports `dates.middleware`, a `fastify-plugin` that\n// pulls in `@v1/log/debug` and, transitively, the server dependencies behind it; bundling that\n// fails, and it fails naming a transitive JSON file (`ent/reversed.json: Could not parse JSON\n// file`) rather than the import that dragged it in, so the message points nowhere near the cause.\n//\n// `global/dates`'s own `lib.ts` sidesteps the same barrel for the same reason. The alternative —\n// inlining the two description constants — would duplicate the wording the whole API documents its\n// datetimes with, and let this module's copy drift from it silently.\n// eslint-disable-next-line no-restricted-imports\nimport {\n EMITTED_DATETIME_NOTE,\n API_DATETIME_EXAMPLE,\n API_DATETIME_ACCEPTED_NOTE,\n apiDateTime,\n} from '@/modules/global/dates/dates.schema'\n\n// `process_log` is the ecosystem-wide execution log (see README.md): rows written by the trigger\n// engine, the actions it runs and the v1 bulk upload. This module owns the schema for the whole\n// table, not only the trigger-engine rows — `code` is what tells them apart.\n\n// ── ProcessLogType (severity, NOT layout) ───────────────────────────────\n// Mirrors the v1 enum (`src/schemas/process_log/types.ts`) verbatim: it already ships on the wire\n// (`type` column) and changing its numeric values would be a breaking change for every existing row\n// and consumer. Restated here as a TypeBox schema — not imported from v1 — because `lib.ts` may\n// only export pure TypeBox (see below); v1 has no schema module of its own to import from.\nexport const ProcessLogType = {\n LOG: 0,\n RESULT: 1,\n WARNING: -1,\n ERROR: -2,\n} as const\nexport const processLogTypeSchema = Type.Enum(Object.values(ProcessLogType), {\n title: 'ProcessLogType',\n description: 'Severity of the log row (not a layout/kind marker): LOG, RESULT, WARNING or ERROR',\n})\nexport type ProcessLogType = Static<typeof processLogTypeSchema>\n\n// ── ProcessLogCode ───────────────────────────────────────────────────────\n//\n// Canonical enum now lives HERE (v2), not in `src/schemas/process_log/types.ts` (v1).\n//\n// Why: this module (`process-log`) is the one being extended with the trigger-engine codes as part\n// of #348, it already owns the model/service half of `process_log`, and every v2 consumer that needs\n// a *typed* extra_data contract (this schema file) has to sit next to the code enum it is keyed by.\n// The two v1 importers (`BulkUploadController.ts` and `IntrospectionController.ts`) import it from\n// here rather than from `@v1/schemas`, which keeps one enum instead of two that could drift. v1's\n// `types.ts` deliberately does NOT re-export the value: doing so closes the cycle `@v1/schemas` →\n// this module's barrel → `process-log.model.ts` → `@v1/schemas`, under which the enum resolves to\n// `undefined` at runtime. It keeps an `import type` only, which is erased at compile time.\nexport const ProcessLogCode = {\n BULK_UPLOAD_BATCH: 'bulk_upload_batch',\n BULK_UPLOAD_SUCCESS: 'bulk_upload_success',\n BULK_UPLOAD_ERROR: 'bulk_upload_error',\n // Trigger engine (#348). Written by `TriggerEngineService` (`action-system` module): one\n // `TRIGGER_EVALUATION` row per trigger evaluated, one `TRIGGER_ACTION` row per action it ran, and a\n // `TRIGGER_ERROR` row when a trigger's evaluation throws.\n TRIGGER_EVALUATION: 'trigger_evaluation',\n TRIGGER_ERROR: 'trigger_error',\n TRIGGER_ACTION: 'trigger_action',\n} as const\nexport const processLogCodeSchema = Type.Enum(Object.values(ProcessLogCode), {\n title: 'ProcessLogCode',\n description: 'What kind of event a process_log row records, and what shape its extra_data takes',\n})\nexport type ProcessLogCode = Static<typeof processLogCodeSchema>\n\n// ── extra_data shapes, one per trigger-engine code ───────────────────────\n// Bulk upload codes carry no typed extra_data today (nothing writes them yet outside the\n// filter-by-code reads in `BulkUploadController.ts`), so they are left out of the discriminated\n// union below rather than given a placeholder shape that no writer populates.\n\nexport const triggerEvaluationExtraDataSchema = Type.Object(\n {\n source: Type.String({ description: 'What fired the event: a model row or a displayer/form save' }),\n target: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Model/displayer name the trigger is bound to' }),\n ),\n operation: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'create/update/delete that fired the event' }),\n ),\n matched: Type.Boolean({ description: 'Whether the trigger conditions matched' }),\n conditions: Type.Optional(\n Type.Union([Type.Unknown(), Type.Null()], {\n description: 'jsonLogic conditions the trigger was configured with',\n }),\n ),\n relations: Type.Optional(\n Type.Union([Type.Unknown(), Type.Null()], {\n description: 'Relations the trigger declared to load onto `current`',\n }),\n ),\n relationsSkipped: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: 'Reason a declared relation could not be loaded, when one was skipped',\n }),\n ),\n },\n {\n title: 'TriggerEvaluationExtraData',\n description:\n 'extra_data of a `trigger_evaluation` row — how a trigger resolved, never the entity data it resolved against',\n additionalProperties: false,\n },\n)\nexport type TriggerEvaluationExtraData = Static<typeof triggerEvaluationExtraDataSchema>\n\nexport const triggerErrorExtraDataSchema = Type.Object(\n { error: Type.String({ description: 'String representation of the exception the trigger evaluation threw' }) },\n { title: 'TriggerErrorExtraData', description: 'extra_data of a `trigger_error` row', additionalProperties: false },\n)\nexport type TriggerErrorExtraData = Static<typeof triggerErrorExtraDataSchema>\n\nexport const triggerActionExtraDataSchema = Type.Object(\n {\n actionId: Type.Number({ description: 'id of the action row that ran' }),\n triggerId: Type.Number({ description: 'id of the trigger that ran this action' }),\n // Needed because the engine is shared: `triggerId` alone is ambiguous, since automatic and\n // manual triggers are different tables (`automatic_trigger`, `manual_trigger`) with overlapping\n // id ranges. Paired with `triggerId` this is what a consumer needs to resolve the trigger row.\n triggerModel: Type.String({ description: 'Table the trigger belongs to (automatic_trigger or manual_trigger)' }),\n executionOrder: Type.Number({ description: 'Order of this action within the trigger' }),\n type: Type.String({ description: 'Type of the action (e.g. ApiAction)' }),\n validation: Type.Unknown({ description: 'Result of validating the action context before running it' }),\n // `ok`/`output` describe an action that ran; `aborted`/`reason` an action that never did,\n // because validating its context failed (`resolveActionOutcome`). The two pairs are mutually\n // exclusive in practice but declared as four optionals rather than a union: `additionalProperties:\n // false` is what makes this schema worth having, and a row whose outcome keys are undeclared is\n // one the debugging popup cannot show a reason for — which is exactly the aborted case.\n ok: Type.Optional(Type.Union([Type.Boolean(), Type.Null()], { description: 'Whether the action call succeeded' })),\n output: Type.Optional(\n Type.Union([Type.String(), Type.Null()], { description: 'Failure output, when the action ran and failed' }),\n ),\n aborted: Type.Optional(Type.Boolean({ description: 'True when the action never ran' })),\n reason: Type.Optional(Type.String({ description: 'Why the action was aborted, e.g. context_validation' })),\n },\n { title: 'TriggerActionExtraData', description: 'extra_data of a `trigger_action` row', additionalProperties: false },\n)\nexport type TriggerActionExtraData = Static<typeof triggerActionExtraDataSchema>\n\n// Discriminated (by `code`) union tying each trigger-engine code to its extra_data shape. Usable\n// both to validate a row being created and to type one being read. Bulk upload codes are\n// deliberately absent (see comment above the individual schemas).\nexport const processLogTriggerEngineExtraDataSchema = Type.Union(\n [\n Type.Object({\n code: Type.Literal(ProcessLogCode.TRIGGER_EVALUATION),\n extra_data: triggerEvaluationExtraDataSchema,\n }),\n Type.Object({ code: Type.Literal(ProcessLogCode.TRIGGER_ERROR), extra_data: triggerErrorExtraDataSchema }),\n Type.Object({ code: Type.Literal(ProcessLogCode.TRIGGER_ACTION), extra_data: triggerActionExtraDataSchema }),\n ],\n {\n title: 'ProcessLogTriggerEngineExtraData',\n description: 'Ties each trigger-engine `code` to the shape its `extra_data` takes',\n },\n)\nexport type ProcessLogTriggerEngineExtraData = Static<typeof processLogTriggerEngineExtraDataSchema>\n\n// ── process_log entity ────────────────────────────────────────────────────\n// Full row shape, for the read side of the (still to be implemented) list endpoint. `extra_data` is\n// left as a free record here — a response schema describes what every row of the table can hold,\n// including the untyped bulk_upload rows, unlike `processLogTriggerEngineExtraDataSchema` above\n// which narrows by `code` for a writer/reader that already knows it is on the trigger-engine path.\nexport const processLogSchema = Type.Object(\n {\n id: Type.Number({ description: 'Unique identifier of the row' }),\n project_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], { description: 'Project this row belongs to, when scoped to one' }),\n ),\n created_user: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description: 'User who caused the row to be written, when a user did',\n }),\n ),\n related_model: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], { description: 'Table/entity kind the row is about' }),\n ),\n related_id: Type.Optional(\n Type.Union([Type.String({ maxLength: 255 }), Type.Null()], {\n description: 'Id of the related entity, as a string',\n }),\n ),\n code: Type.Optional(Type.Union([processLogCodeSchema, Type.Null()])),\n log: Type.String({ description: 'Short human-readable message' }),\n long_log: Type.Optional(Type.Union([Type.String(), Type.Null()], { description: 'Extended message, when needed' })),\n extra_data: Type.Optional(\n Type.Union([Type.Record(Type.String(), Type.Unknown()), Type.Null()], {\n description: 'Structured data specific to `code` — see the per-code schemas for the trigger-engine codes',\n }),\n ),\n type: processLogTypeSchema,\n requires_attention: Type.Optional(Type.Boolean({ description: 'Whether the row needs a human to review it' })),\n reviewed: Type.Optional(Type.Boolean({ description: 'Whether the row has been reviewed' })),\n reviewed_date: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `When the row was reviewed. Null while unreviewed. ${EMITTED_DATETIME_NOTE}`,\n }),\n ),\n // Correlation to a parent row (#348): a `trigger_action` row's parent is the `trigger_evaluation`\n // (or `trigger_error`) row of the trigger that ran it, so an action's trace can always be walked\n // back to the evaluation that triggered it. Optional/nullable because most rows (bulk upload,\n // the trigger-evaluation row itself) have no parent, and because the column is applied out of\n // band per ecosystem — see README.md — so it may be entirely absent from a given row's database.\n parent_id: Type.Optional(\n Type.Union([Type.Number(), Type.Null()], {\n description: \"Id of this row's parent process_log row, when it has one\",\n }),\n ),\n expires_at: Type.Optional(\n Type.Union([Type.String(), Type.Null()], {\n description: `Retention deadline; the row is purged after it, and never expires when null. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n created_at: Type.Optional(\n Type.String({\n description: `When the row was created. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n mod_time: Type.Optional(\n Type.String({\n description: `When the row was last modified. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'ProcessLog', description: 'A process_log row' },\n)\nexport type ProcessLogData = Static<typeof processLogSchema>\n\n// ── list query filters ────────────────────────────────────────────────────\n// Filters of the (upcoming) list endpoint, on top of the pagination query — see `alert.schema.ts`\n// `listAlertQuerySchema` for the sibling precedent. Everything is optional: with none of them the\n// endpoint lists everything in scope. Exported for the endpoint (implemented separately) to consume.\nexport const listProcessLogQuerySchema = Type.Object(\n {\n code: Type.Optional(processLogCodeSchema),\n type: Type.Optional(processLogTypeSchema),\n related_model: Type.Optional(Type.String({ description: 'Filter by the related entity kind' })),\n related_id: Type.Optional(Type.String({ description: 'Filter by the id of the related entity' })),\n parent_id: Type.Optional(Type.Number({ description: 'Filter by the id of the parent process_log row' })),\n requires_attention: Type.Optional(Type.Boolean({ description: 'Filter by whether the row needs review' })),\n reviewed: Type.Optional(Type.Boolean({ description: 'Filter by whether the row has been reviewed' })),\n // `apiDateTime`, not a bare string: it carries `format: 'date-time'`, so a malformed value is\n // rejected by the validator as a 400. A plain `Type.String` accepts anything and hands it to\n // `getMySQLDateTime(value, true)`, which throws a `PublicApiError` with no `statusCode` — a 500\n // for what is a bad request. Same type `alert.schema.ts` uses for its datetime fields.\n created_from: Type.Optional(\n Type.Union([apiDateTime], {\n description: `Only rows created at or after this instant. ${API_DATETIME_ACCEPTED_NOTE}. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n created_to: Type.Optional(\n Type.Union([apiDateTime], {\n description: `Only rows created at or before this instant. ${API_DATETIME_ACCEPTED_NOTE}. ${EMITTED_DATETIME_NOTE}`,\n examples: [API_DATETIME_EXAMPLE],\n }),\n ),\n },\n { title: 'ListProcessLogQuery', description: 'Filters available on the process_log list' },\n)\n// `StaticDecode`, not `Static`: this type describes what the *handler receives*, and the two date\n// bounds carry `apiDateTime`, so they arrive decoded to a `Date`. `Static` would type them as the\n// strings the client sent and the service would format something it never gets.\nexport type ListProcessLogQuery = StaticDecode<typeof listProcessLogQuerySchema>\n"],"names":[],"mappings":";;AA+BO,MAAM,iBAAiB;AAAA,EAC5B,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO;AACT;AACO,MAAM,uBAAuB,KAAK,KAAK,OAAO,OAAO,cAAc,GAAG;AAAA,EAC3E,OAAO;AAAA,EACP,aAAa;AACf,CAAC;AAeM,MAAM,iBAAiB;AAAA,EAC5B,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,mBAAmB;AAAA;AAAA;AAAA;AAAA,EAInB,oBAAoB;AAAA,EACpB,eAAe;AAAA,EACf,gBAAgB;AAClB;AACO,MAAM,uBAAuB,KAAK,KAAK,OAAO,OAAO,cAAc,GAAG;AAAA,EAC3E,OAAO;AAAA,EACP,aAAa;AACf,CAAC;AAQM,MAAM,mCAAmC,KAAK;AAAA,EACnD;AAAA,IACE,QAAQ,KAAK,OAAO,EAAE,aAAa,8DAA8D;AAAA,IACjG,QAAQ,KAAK;AAAA,MACX,KAAK,MAAM,CAAC,KAAK,OAAA,GAAU,KAAK,MAAM,GAAG,EAAE,aAAa,gDAAgD;AAAA,IAAA;AAAA,IAE1G,WAAW,KAAK;AAAA,MACd,KAAK,MAAM,CAAC,KAAK,OAAA,GAAU,KAAK,MAAM,GAAG,EAAE,aAAa,6CAA6C;AAAA,IAAA;AAAA,IAEvG,SAAS,KAAK,QAAQ,EAAE,aAAa,0CAA0C;AAAA,IAC/E,YAAY,KAAK;AAAA,MACf,KAAK,MAAM,CAAC,KAAK,WAAW,KAAK,KAAA,CAAM,GAAG;AAAA,QACxC,aAAa;AAAA,MAAA,CACd;AAAA,IAAA;AAAA,IAEH,WAAW,KAAK;AAAA,MACd,KAAK,MAAM,CAAC,KAAK,WAAW,KAAK,KAAA,CAAM,GAAG;AAAA,QACxC,aAAa;AAAA,MAAA,CACd;AAAA,IAAA;AAAA,IAEH,kBAAkB,KAAK;AAAA,MACrB,KAAK,MAAM,CAAC,KAAK,UAAU,KAAK,KAAA,CAAM,GAAG;AAAA,QACvC,aAAa;AAAA,MAAA,CACd;AAAA,IAAA;AAAA,EACH;AAAA,EAEF;AAAA,IACE,OAAO;AAAA,IACP,aACE;AAAA,IACF,sBAAsB;AAAA,EAAA;AAE1B;AAGO,MAAM,8BAA8B,KAAK;AAAA,EAC9C,EAAE,OAAO,KAAK,OAAO,EAAE,aAAa,sEAAA,CAAuE,EAAA;AAAA,EAC3G,EAAE,OAAO,yBAAyB,aAAa,uCAAuC,sBAAsB,MAAA;AAC9G;AAGO,MAAM,+BAA+B,KAAK;AAAA,EAC/C;AAAA,IACE,UAAU,KAAK,OAAO,EAAE,aAAa,iCAAiC;AAAA,IACtE,WAAW,KAAK,OAAO,EAAE,aAAa,0CAA0C;AAAA;AAAA;AAAA;AAAA,IAIhF,cAAc,KAAK,OAAO,EAAE,aAAa,sEAAsE;AAAA,IAC/G,gBAAgB,KAAK,OAAO,EAAE,aAAa,2CAA2C;AAAA,IACtF,MAAM,KAAK,OAAO,EAAE,aAAa,uCAAuC;AAAA,IACxE,YAAY,KAAK,QAAQ,EAAE,aAAa,6DAA6D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMrG,IAAI,KAAK,SAAS,KAAK,MAAM,CAAC,KAAK,QAAA,GAAW,KAAK,MAAM,GAAG,EAAE,aAAa,oCAAA,CAAqC,CAAC;AAAA,IACjH,QAAQ,KAAK;AAAA,MACX,KAAK,MAAM,CAAC,KAAK,OAAA,GAAU,KAAK,MAAM,GAAG,EAAE,aAAa,kDAAkD;AAAA,IAAA;AAAA,IAE5G,SAAS,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,iCAAA,CAAkC,CAAC;AAAA,IACtF,QAAQ,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,uDAAuD,CAAC;AAAA,EAAA;AAAA,EAE3G,EAAE,OAAO,0BAA0B,aAAa,wCAAwC,sBAAsB,MAAA;AAChH;AAMO,MAAM,yCAAyC,KAAK;AAAA,EACzD;AAAA,IACE,KAAK,OAAO;AAAA,MACV,MAAM,KAAK,QAAQ,eAAe,kBAAkB;AAAA,MACpD,YAAY;AAAA,IAAA,CACb;AAAA,IACD,KAAK,OAAO,EAAE,MAAM,KAAK,QAAQ,eAAe,aAAa,GAAG,YAAY,6BAA6B;AAAA,IACzG,KAAK,OAAO,EAAE,MAAM,KAAK,QAAQ,eAAe,cAAc,GAAG,YAAY,6BAAA,CAA8B;AAAA,EAAA;AAAA,EAE7G;AAAA,IACE,OAAO;AAAA,IACP,aAAa;AAAA,EAAA;AAEjB;AAQO,MAAM,mBAAmB,KAAK;AAAA,EACnC;AAAA,IACE,IAAI,KAAK,OAAO,EAAE,aAAa,gCAAgC;AAAA,IAC/D,YAAY,KAAK;AAAA,MACf,KAAK,MAAM,CAAC,KAAK,OAAA,GAAU,KAAK,MAAM,GAAG,EAAE,aAAa,mDAAmD;AAAA,IAAA;AAAA,IAE7G,cAAc,KAAK;AAAA,MACjB,KAAK,MAAM,CAAC,KAAK,UAAU,KAAK,KAAA,CAAM,GAAG;AAAA,QACvC,aAAa;AAAA,MAAA,CACd;AAAA,IAAA;AAAA,IAEH,eAAe,KAAK;AAAA,MAClB,KAAK,MAAM,CAAC,KAAK,OAAO,EAAE,WAAW,KAAK,GAAG,KAAK,KAAA,CAAM,GAAG,EAAE,aAAa,sCAAsC;AAAA,IAAA;AAAA,IAElH,YAAY,KAAK;AAAA,MACf,KAAK,MAAM,CAAC,KAAK,OAAO,EAAE,WAAW,KAAK,GAAG,KAAK,KAAA,CAAM,GAAG;AAAA,QACzD,aAAa;AAAA,MAAA,CACd;AAAA,IAAA;AAAA,IAEH,MAAM,KAAK,SAAS,KAAK,MAAM,CAAC,sBAAsB,KAAK,KAAA,CAAM,CAAC,CAAC;AAAA,IACnE,KAAK,KAAK,OAAO,EAAE,aAAa,gCAAgC;AAAA,IAChE,UAAU,KAAK,SAAS,KAAK,MAAM,CAAC,KAAK,OAAA,GAAU,KAAK,MAAM,GAAG,EAAE,aAAa,gCAAA,CAAiC,CAAC;AAAA,IAClH,YAAY,KAAK;AAAA,MACf,KAAK,MAAM,CAAC,KAAK,OAAO,KAAK,UAAU,KAAK,SAAS,GAAG,KAAK,KAAA,CAAM,GAAG;AAAA,QACpE,aAAa;AAAA,MAAA,CACd;AAAA,IAAA;AAAA,IAEH,MAAM;AAAA,IACN,oBAAoB,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,6CAAA,CAA8C,CAAC;AAAA,IAC7G,UAAU,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,oCAAA,CAAqC,CAAC;AAAA,IAC1F,eAAe,KAAK;AAAA,MAClB,KAAK,MAAM,CAAC,KAAK,UAAU,KAAK,KAAA,CAAM,GAAG;AAAA,QACvC,aAAa,qDAAqD,qBAAqB;AAAA,MAAA,CACxF;AAAA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOH,WAAW,KAAK;AAAA,MACd,KAAK,MAAM,CAAC,KAAK,UAAU,KAAK,KAAA,CAAM,GAAG;AAAA,QACvC,aAAa;AAAA,MAAA,CACd;AAAA,IAAA;AAAA,IAEH,YAAY,KAAK;AAAA,MACf,KAAK,MAAM,CAAC,KAAK,UAAU,KAAK,KAAA,CAAM,GAAG;AAAA,QACvC,aAAa,gFAAgF,qBAAqB;AAAA,QAClH,UAAU,CAAC,oBAAoB;AAAA,MAAA,CAChC;AAAA,IAAA;AAAA,IAEH,YAAY,KAAK;AAAA,MACf,KAAK,OAAO;AAAA,QACV,aAAa,6BAA6B,qBAAqB;AAAA,QAC/D,UAAU,CAAC,oBAAoB;AAAA,MAAA,CAChC;AAAA,IAAA;AAAA,IAEH,UAAU,KAAK;AAAA,MACb,KAAK,OAAO;AAAA,QACV,aAAa,mCAAmC,qBAAqB;AAAA,QACrE,UAAU,CAAC,oBAAoB;AAAA,MAAA,CAChC;AAAA,IAAA;AAAA,EACH;AAAA,EAEF,EAAE,OAAO,cAAc,aAAa,oBAAA;AACtC;AAOO,MAAM,4BAA4B,KAAK;AAAA,EAC5C;AAAA,IACE,MAAM,KAAK,SAAS,oBAAoB;AAAA,IACxC,MAAM,KAAK,SAAS,oBAAoB;AAAA,IACxC,eAAe,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,oCAAA,CAAqC,CAAC;AAAA,IAC9F,YAAY,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,yCAAA,CAA0C,CAAC;AAAA,IAChG,WAAW,KAAK,SAAS,KAAK,OAAO,EAAE,aAAa,iDAAA,CAAkD,CAAC;AAAA,IACvG,oBAAoB,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,yCAAA,CAA0C,CAAC;AAAA,IACzG,UAAU,KAAK,SAAS,KAAK,QAAQ,EAAE,aAAa,8CAAA,CAA+C,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAKpG,cAAc,KAAK;AAAA,MACjB,KAAK,MAAM,CAAC,WAAW,GAAG;AAAA,QACxB,aAAa,+CAA+C,0BAA0B,KAAK,qBAAqB;AAAA,QAChH,UAAU,CAAC,oBAAoB;AAAA,MAAA,CAChC;AAAA,IAAA;AAAA,IAEH,YAAY,KAAK;AAAA,MACf,KAAK,MAAM,CAAC,WAAW,GAAG;AAAA,QACxB,aAAa,gDAAgD,0BAA0B,KAAK,qBAAqB;AAAA,QACjH,UAAU,CAAC,oBAAoB;AAAA,MAAA,CAChC;AAAA,IAAA;AAAA,EACH;AAAA,EAEF,EAAE,OAAO,uBAAuB,aAAa,4CAAA;AAC/C;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alert.schema.d.ts","sourceRoot":"","sources":["../../../../../../../src/v2/modules/ecosystem/alert/alert.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"alert.schema.d.ts","sourceRoot":"","sources":["../../../../../../../src/v2/modules/ecosystem/alert/alert.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAwBpD,eAAO,MAAM,WAAW;;;CAGd,CAAA;AACV,eAAO,MAAM,iBAAiB,uCAG5B,CAAA;AACF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE1D,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAA;AACV,eAAO,MAAM,mBAAmB,iEAG9B,CAAA;AACF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAM9D,eAAO,MAAM,gBAAgB;;;;CAInB,CAAA;AACV,eAAO,MAAM,sBAAsB,+CAGjC,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAIpE,eAAO,MAAM,kBAAkB;;;;;EAoB9B,CAAA;AACD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAUhE,eAAO,MAAM,oBAAoB;;;EAUhC,CAAA;AACD,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAIpE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2GvB,CAAA;AACD,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,WAAW,CAAC,CAAA;AAQlD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;EAwB7B,CAAA;AAKD,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAEpE;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAQrE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;EAI5B,CAAA;AACF,MAAM,MAAM,eAAe,GAAG,YAAY,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAOpE,eAAO,MAAM,kBAAkB;;EAO9B,CAAA;AACD,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAIhE,eAAO,MAAM,oBAAoB;;;;;;EAShC,CAAA;AACD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../../../../../../../src/v2/modules/ecosystem/alert/lib.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-log.schema.d.ts","sourceRoot":"","sources":["../../../../../../../src/v2/modules/ecosystem/process-log/process-log.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"process-log.schema.d.ts","sourceRoot":"","sources":["../../../../../../../src/v2/modules/ecosystem/process-log/process-log.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AA+BpD,eAAO,MAAM,cAAc;;;;;CAKjB,CAAA;AACV,eAAO,MAAM,oBAAoB,iCAG/B,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAchE,eAAO,MAAM,cAAc;;;;;;;CAUjB,CAAA;AACV,eAAO,MAAM,oBAAoB,+IAG/B,CAAA;AACF,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAOhE,eAAO,MAAM,gCAAgC;;;;;;;;EAgC5C,CAAA;AACD,MAAM,MAAM,0BAA0B,GAAG,MAAM,CAAC,OAAO,gCAAgC,CAAC,CAAA;AAExF,eAAO,MAAM,2BAA2B;;EAGvC,CAAA;AACD,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAE9E,eAAO,MAAM,4BAA4B;;;;;;;;;;;EAwBxC,CAAA;AACD,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC,OAAO,4BAA4B,CAAC,CAAA;AAKhF,eAAO,MAAM,sCAAsC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAalD,CAAA;AACD,MAAM,MAAM,gCAAgC,GAAG,MAAM,CAAC,OAAO,sCAAsC,CAAC,CAAA;AAOpG,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;EAiE5B,CAAA;AACD,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAM5D,eAAO,MAAM,yBAAyB;;;;;;;;;;EA2BrC,CAAA;AAID,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC,OAAO,yBAAyB,CAAC,CAAA"}
|