@hahnpro/hpc-api 2026.7.2 → 2026.7.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @hahnpro/hpc-api
2
2
 
3
+ # 2026.7.4
4
+
5
+ - Added optional `ToolMessage.statusText` for localized AI tool status responses
6
+
7
+ # 2026.7.3
8
+
9
+ - Added partial-object validation support to the `isAsset`, `isContent`, `isEvent`, `isLogbookEntry`, and `isTask` type guards
10
+ - Expanded `isAsset` to validate populated asset types as well as all supported asset fields
11
+ - Added stricter enum, resource-reference, and attachment-handling validation to the content analysis, event, and user-message type guards
12
+ - Changed `Event.level (string)` to `EventLevel`
13
+ - Updated `Task.expiryDate` and its type guard to accept strings as well as `Date` values
14
+
3
15
  # 2026.7.2
4
16
 
5
17
  - Added dedicated logbook API service, logbook interfaces, and mock support
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hahnpro/hpc-api",
3
- "version": "2026.7.2",
3
+ "version": "2026.7.4",
4
4
  "description": "Module for easy access to the HahnPRO Cloud API",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -210,6 +210,7 @@ export interface ToolMessage extends BaseMessage {
210
210
  toolType?: ToolType;
211
211
  agentStack?: AgentId[];
212
212
  status?: ToolMessageStatus;
213
+ statusText?: string;
213
214
  result?: any;
214
215
  args?: SelectionMessage | any;
215
216
  contextVariables?: Record<string, unknown>;
@@ -8,7 +8,7 @@ export interface Event extends Resource {
8
8
  tsRef?: string;
9
9
  eventRef?: string;
10
10
  cause?: string;
11
- level: string;
11
+ level: EventLevel;
12
12
  group?: string;
13
13
  owner?: Owner;
14
14
  createdBy?: Author;
@@ -38,7 +38,7 @@ export interface Task extends Api {
38
38
  eventRef$name?: string;
39
39
  gitHubNr?: number;
40
40
  schedule?: string;
41
- expiryDate?: Date;
41
+ expiryDate?: string | Date;
42
42
  parent?: string;
43
43
  parent$name?: string;
44
44
  subTasks?: string[];
@@ -1,7 +1,7 @@
1
1
  import { type UserMessage } from './ai.interface';
2
2
  import type { Asset } from './asset.interface';
3
3
  import type { Author } from './author.interface';
4
- import type { Content, ContentAnalysis } from './content.interface';
4
+ import { type Content, type ContentAnalysis } from './content.interface';
5
5
  import { type Event } from './event.interface';
6
6
  import { type LogbookEntry } from './logbook.interface';
7
7
  import { type Owner } from './owner.interface';
@@ -11,10 +11,20 @@ export declare function isAuthor(value: unknown): value is Author;
11
11
  export declare function isOwner(value: unknown): value is Owner;
12
12
  export declare function isStorage(value: unknown): value is Storage;
13
13
  export declare function isContentAnalysis(value: unknown): value is ContentAnalysis;
14
- export declare function isAsset(value: unknown): value is Asset;
15
- export declare function isContent(value: unknown): value is Content;
16
- export declare function isEvent(value: unknown): value is Event;
14
+ export declare function isAsset(value: unknown, isPartial?: false): value is Asset;
15
+ export declare function isAsset(value: unknown, isPartial: true): value is Partial<Asset>;
16
+ export declare function isAsset(value: unknown, isPartial: boolean): value is Asset | Partial<Asset>;
17
+ export declare function isContent(value: unknown, isPartial?: false): value is Content;
18
+ export declare function isContent(value: unknown, isPartial: true): value is Partial<Content>;
19
+ export declare function isContent(value: unknown, isPartial: boolean): value is Content | Partial<Content>;
20
+ export declare function isEvent(value: unknown, isPartial?: false): value is Event;
21
+ export declare function isEvent(value: unknown, isPartial: true): value is Partial<Event>;
22
+ export declare function isEvent(value: unknown, isPartial: boolean): value is Event | Partial<Event>;
17
23
  export declare function isAssignee(value: unknown): value is Assignee;
18
- export declare function isLogbookEntry(value: unknown): value is LogbookEntry;
19
- export declare function isTask(value: unknown): value is Task;
24
+ export declare function isLogbookEntry(value: unknown, isPartial?: false): value is LogbookEntry;
25
+ export declare function isLogbookEntry(value: unknown, isPartial: true): value is Partial<LogbookEntry>;
26
+ export declare function isLogbookEntry(value: unknown, isPartial: boolean): value is LogbookEntry | Partial<LogbookEntry>;
27
+ export declare function isTask(value: unknown, isPartial?: false): value is Task;
28
+ export declare function isTask(value: unknown, isPartial: true): value is Partial<Task>;
29
+ export declare function isTask(value: unknown, isPartial: boolean): value is Task | Partial<Task>;
20
30
  export declare function isUserMessage(value: unknown): value is UserMessage;
@@ -12,9 +12,11 @@ exports.isLogbookEntry = isLogbookEntry;
12
12
  exports.isTask = isTask;
13
13
  exports.isUserMessage = isUserMessage;
14
14
  const ai_interface_1 = require("./ai.interface");
15
+ const content_interface_1 = require("./content.interface");
15
16
  const event_interface_1 = require("./event.interface");
16
17
  const logbook_interface_1 = require("./logbook.interface");
17
18
  const owner_interface_1 = require("./owner.interface");
19
+ const resource_interface_1 = require("./resource.interface");
18
20
  const task_interface_1 = require("./task.interface");
19
21
  function isRecord(value) {
20
22
  return typeof value === 'object' && value !== null;
@@ -32,10 +34,14 @@ const isArrayOf = (value, predicate) => Array.isArray(value) && value.every(pred
32
34
  const isOptionalArrayOf = (value, predicate) => value === undefined || isArrayOf(value, predicate);
33
35
  const isStringArray = (value) => isArrayOf(value, isString);
34
36
  const isOptionalStringArray = (value) => isOptionalArrayOf(value, isString);
37
+ const isOptionalUnknownArray = (value) => value === undefined || Array.isArray(value);
38
+ const hasOwn = (value, property) => Object.prototype.hasOwnProperty.call(value, property);
35
39
  const isMessageAttachment = (value) => isRecord(value) && isOptionalString(value.id) && isString(value.filename) && isString(value.text);
40
+ const isResourceReference = (value) => isRecord(value) && isString(value.id) && isEnumValue(resource_interface_1.ResourceType, value.resourceType) && isOptionalBoolean(value.dependent);
36
41
  const isOneOf = (value, allowed) => allowed.includes(value);
37
42
  const isEnumValue = (target, value) => Object.values(target).includes(value);
38
43
  const hasPermissions = (value) => isStringArray(value.readPermissions) && isStringArray(value.readWritePermissions);
44
+ const hasOptionalPermissions = (value) => isOptionalStringArray(value.readPermissions) && isOptionalStringArray(value.readWritePermissions);
39
45
  const hasResourceMeta = (value, options) => {
40
46
  const { owner, author, date } = options;
41
47
  if (owner && value.owner !== undefined && !owner(value.owner)) {
@@ -89,61 +95,114 @@ function isContentAnalysis(value) {
89
95
  }
90
96
  return (isString(value.id) &&
91
97
  isString(value.contentId) &&
92
- isString(value.status) &&
98
+ isEnumValue(content_interface_1.ContentAnalysisStatus, value.status) &&
93
99
  isOptionalString(value.error) &&
94
100
  isOptionalString(value.text) &&
95
101
  isOptionalArrayOf(value.pages, (page) => isRecord(page) && isNumber(page.pageNumber) && isOptionalString(page.text)));
96
102
  }
97
- function isAsset(value) {
103
+ function isTemplate(value) {
104
+ return isRecord(value) && isString(value.id) && isString(value.name) && isRecord(value.template);
105
+ }
106
+ function isAssetType(value) {
98
107
  if (!isRecord(value)) {
99
108
  return false;
100
109
  }
101
- return (isString(value.id) &&
102
- isOptionalString(value.translationId) &&
110
+ const hasValidAllowedParents = value.allowedParents === undefined || isStringArray(value.allowedParents) || isArrayOf(value.allowedParents, isAssetType);
111
+ const hasValidSupertype = value.supertype === undefined || isString(value.supertype) || isAssetType(value.supertype);
112
+ const hasValidTabPermissions = value.tabPermissions === undefined || (isRecord(value.tabPermissions) && Object.values(value.tabPermissions).every(isStringArray));
113
+ const hasValidTemplates = value.templates === undefined || isStringArray(value.templates) || isArrayOf(value.templates, isTemplate);
114
+ return (isOptionalString(value.id) &&
103
115
  isString(value.name) &&
104
- isOptionalString(value.description) &&
116
+ isOptionalStringArray(value.tags) &&
117
+ isOptionalString(value.translationId) &&
118
+ hasValidAllowedParents &&
119
+ isOptionalString(value.allowedParent$name) &&
105
120
  hasPermissions(value) &&
106
- isString(value.type) &&
121
+ hasValidSupertype &&
122
+ isOptionalString(value.supertype$name) &&
123
+ hasOwn(value, 'typeSchema') &&
124
+ hasOwn(value, 'uiSchema') &&
125
+ isOptionalString(value.author) &&
126
+ isOptionalNumber(value.revision) &&
127
+ isOptionalBoolean(value.isSystemAssetType) &&
128
+ isOptionalString(value.startTab) &&
129
+ hasValidTabPermissions &&
130
+ isOptionalNumber(value.templateVersion) &&
131
+ hasValidTemplates &&
132
+ hasResourceMeta(value, { owner: isOwner, author: isAuthor, date: isString }));
133
+ }
134
+ function isAsset(value, isPartial = false) {
135
+ if (!isRecord(value)) {
136
+ return false;
137
+ }
138
+ let requiredFieldsValid = false;
139
+ if (!isPartial) {
140
+ requiredFieldsValid =
141
+ isOptionalString(value.id) && isString(value.name) && hasPermissions(value) && (isString(value.type) || isAssetType(value.type));
142
+ }
143
+ else {
144
+ requiredFieldsValid =
145
+ isOptionalString(value.id) &&
146
+ isOptionalString(value.name) &&
147
+ hasOptionalPermissions(value) &&
148
+ isOptional(value.type, (type) => isString(type) || isAssetType(type));
149
+ }
150
+ return (requiredFieldsValid &&
151
+ isOptionalString(value.externalKey) &&
152
+ isOptionalString(value.translationId) &&
107
153
  isOptionalString(value.type$name) &&
108
154
  isOptionalStringArray(value.tags) &&
109
155
  isOptionalString(value.parent) &&
110
156
  isOptionalString(value.parent$name) &&
157
+ isOptionalStringArray(value.ancestors) &&
158
+ isOptionalUnknownArray(value.relations) &&
159
+ isOptionalString(value.image) &&
111
160
  isOptionalStringArray(value.attachments) &&
112
161
  isOptionalStringArray(value.notificationEndpoints) &&
113
162
  isOptionalStringArray(value.aliases) &&
114
- isOptional(value.data, isRecord) &&
115
- isOptional(value.timeseries, isRecord) &&
116
- isOptional(value.event, isRecord) &&
117
- hasResourceMeta(value, { owner: isOwner, author: isAuthor }));
163
+ isOptionalString(value.author) &&
164
+ isOptionalNumber(value.revision) &&
165
+ hasResourceMeta(value, { owner: isOwner, author: isAuthor, date: isString }));
118
166
  }
119
- function isContent(value) {
167
+ function isContent(value, isPartial = false) {
120
168
  if (!isRecord(value)) {
121
169
  return false;
122
170
  }
123
171
  const hasValidAnalysis = value.analysis === undefined || isString(value.analysis) || isContentAnalysis(value.analysis);
124
- return (isOptionalString(value.id) &&
125
- isString(value.fileId) &&
126
- isString(value.filename) &&
172
+ let requiredFieldsValid = false;
173
+ if (!isPartial) {
174
+ requiredFieldsValid =
175
+ isString(value.fileId) && isString(value.filename) && isString(value.mimetype) && isNumber(value.size) && hasPermissions(value);
176
+ }
177
+ else {
178
+ requiredFieldsValid =
179
+ isOptionalString(value.fileId) &&
180
+ isOptionalString(value.filename) &&
181
+ isOptionalString(value.mimetype) &&
182
+ isOptionalNumber(value.size) &&
183
+ hasOptionalPermissions(value);
184
+ }
185
+ return (requiredFieldsValid &&
186
+ isOptionalString(value.id) &&
127
187
  isOptionalString(value.description) &&
128
- isString(value.mimetype) &&
129
- isNumber(value.size) &&
130
- hasPermissions(value) &&
131
188
  isOptionalStringArray(value.tags) &&
132
189
  isOptionalStringArray(value.assets) &&
133
190
  isOptionalArrayOf(value.files, isStorage) &&
134
- hasResourceMeta(value, { owner: isOwner, author: isAuthor, date: isString }) &&
135
- hasValidAnalysis);
191
+ hasValidAnalysis &&
192
+ hasResourceMeta(value, { owner: isOwner, author: isAuthor, date: isString }));
136
193
  }
137
- function isEvent(value) {
194
+ function isEvent(value, isPartial = false) {
138
195
  if (!isRecord(value)) {
139
196
  return false;
140
197
  }
141
- return (isOptionalString(value.id) &&
142
- isString(value.name) &&
198
+ const requiredFieldsValid = isPartial
199
+ ? isOptionalString(value.name) && hasOptionalPermissions(value) && isOptional(value.level, (level) => isEnumValue(event_interface_1.EventLevel, level))
200
+ : isString(value.name) && hasPermissions(value) && isEnumValue(event_interface_1.EventLevel, value.level);
201
+ return (requiredFieldsValid &&
202
+ isOptionalString(value.id) &&
143
203
  isOptionalString(value.description) &&
144
204
  isOptionalStringArray(value.tags) &&
145
- hasPermissions(value) &&
146
- isEnumValue(event_interface_1.EventLevel, value.level) &&
205
+ isOptionalArrayOf(value.refs, isResourceReference) &&
147
206
  isOptional(value.data, isRecord) &&
148
207
  isOptionalString(value.assetRef) &&
149
208
  isOptionalString(value.assetRef$name) &&
@@ -152,20 +211,27 @@ function isEvent(value) {
152
211
  isOptionalString(value.eventRef) &&
153
212
  isOptionalString(value.cause) &&
154
213
  isOptionalString(value.group) &&
155
- hasResourceMeta(value, { owner: isOwner, author: isAuthor, date: isString }));
214
+ hasResourceMeta(value, { owner: isOwner, author: isAuthor, date: (candidate) => isString(candidate) || isDate(candidate) }));
156
215
  }
157
216
  function isAssignee(value) {
158
217
  return isRecord(value) && isString(value.id) && isEnumValue(task_interface_1.AssigneeType, value.type);
159
218
  }
160
- function isLogbookEntry(value) {
219
+ function isLogbookEntry(value, isPartial = false) {
161
220
  if (!isRecord(value)) {
162
221
  return false;
163
222
  }
164
- return (isString(value.taskId) &&
165
- isString(value.date) &&
166
- isNumber(value.duration) &&
167
- isEnumValue(logbook_interface_1.LogbookEntrySource, value.source) &&
168
- isString(value.id) &&
223
+ const requiredFieldsValid = isPartial
224
+ ? isOptionalString(value.taskId) &&
225
+ isOptionalString(value.date) &&
226
+ isOptionalNumber(value.duration) &&
227
+ isOptional(value.source, (source) => isEnumValue(logbook_interface_1.LogbookEntrySource, source)) &&
228
+ isOptionalString(value.id)
229
+ : isString(value.taskId) &&
230
+ isString(value.date) &&
231
+ isNumber(value.duration) &&
232
+ isEnumValue(logbook_interface_1.LogbookEntrySource, value.source) &&
233
+ isString(value.id);
234
+ return (requiredFieldsValid &&
169
235
  isOptionalString(value.comment) &&
170
236
  isOptionalString(value.createdAt) &&
171
237
  isOptionalString(value.updatedAt) &&
@@ -173,34 +239,37 @@ function isLogbookEntry(value) {
173
239
  isOptional(value.data, isRecord) &&
174
240
  isOptional(value.createdBy, isAuthor));
175
241
  }
176
- function isTask(value) {
242
+ function isTask(value, isPartial = false) {
177
243
  if (!isRecord(value)) {
178
244
  return false;
179
245
  }
180
246
  const hasValidStatusHistory = value.statusHistoryLog === undefined ||
181
247
  (Array.isArray(value.statusHistoryLog) && value.statusHistoryLog.every((status) => isEnumValue(task_interface_1.TaskStatus, status)));
182
- return (isOptionalString(value.id) &&
248
+ const requiredFieldsValid = isPartial
249
+ ? isOptionalString(value.name) &&
250
+ isOptional(value.priority, (priority) => isEnumValue(task_interface_1.Priority, priority)) &&
251
+ hasOptionalPermissions(value) &&
252
+ isOptionalArrayOf(value.assignedTo, isAssignee)
253
+ : isString(value.name) && isEnumValue(task_interface_1.Priority, value.priority) && hasPermissions(value) && isArrayOf(value.assignedTo, isAssignee);
254
+ return (requiredFieldsValid &&
255
+ isOptionalString(value.id) &&
183
256
  isOptionalDateOrString(value.createdAt) &&
184
257
  isOptionalDateOrString(value.updatedAt) &&
185
258
  isOptionalDateOrString(value.deletedAt) &&
186
259
  isOptionalNumber(value.revision) &&
187
260
  hasResourceMeta(value, { owner: isOwner, author: isAuthor, date: (candidate) => isString(candidate) || candidate instanceof Date }) &&
188
- isString(value.name) &&
189
261
  isOptionalString(value.description) &&
190
- isEnumValue(task_interface_1.Priority, value.priority) &&
191
262
  isOptionalStringArray(value.tags) &&
192
- hasPermissions(value) &&
193
263
  isOptionalString(value.assetRef) &&
194
264
  isOptionalString(value.assetRef$name) &&
195
265
  isOptionalString(value.eventRef) &&
196
266
  isOptionalString(value.eventRef$name) &&
197
267
  isOptionalNumber(value.gitHubNr) &&
198
268
  isOptionalString(value.schedule) &&
199
- (value.expiryDate === undefined || value.expiryDate instanceof Date) &&
269
+ isOptionalDateOrString(value.expiryDate) &&
200
270
  isOptionalString(value.parent) &&
201
271
  isOptionalString(value.parent$name) &&
202
272
  isOptionalStringArray(value.subTasks) &&
203
- isArrayOf(value.assignedTo, isAssignee) &&
204
273
  isOptionalString(value.acceptedBy) &&
205
274
  (value.status === undefined || isEnumValue(task_interface_1.TaskStatus, value.status)) &&
206
275
  hasValidStatusHistory &&
@@ -220,5 +289,6 @@ function isUserMessage(value) {
220
289
  isOptionalString(value.content) &&
221
290
  isOptionalBoolean(value.hidden) &&
222
291
  isOptionalBoolean(value.useWebSearch) &&
292
+ isOptional(value.attachmentHandling, (mode) => isEnumValue(ai_interface_1.AttachmentHandlingMode, mode)) &&
223
293
  isOptionalArrayOf(value.attachments, isMessageAttachment));
224
294
  }
@@ -8,7 +8,6 @@ export interface UserSettings extends Api {
8
8
  creationWriteRoles?: Permission[];
9
9
  deletionRequested?: boolean;
10
10
  favoriteLabelsOrder?: Record<string, number>;
11
- language?: string;
12
11
  tableSettings?: TableSetting[];
13
12
  userId?: string;
14
13
  }