@furo/open-models 1.16.3 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +659 -290
- package/dist/API_OPTIONS.js +5 -4
- package/dist/API_OPTIONS.js.map +1 -1
- package/dist/Fetcher.d.ts +2 -1
- package/dist/Fetcher.js +5 -5
- package/dist/Fetcher.js.map +1 -1
- package/dist/StrictFetcher.d.ts +58 -0
- package/dist/StrictFetcher.js +420 -0
- package/dist/StrictFetcher.js.map +1 -0
- package/dist/decorators/ModelDecorators.d.ts +11 -13
- package/dist/decorators/ModelDecorators.js +34 -14
- package/dist/decorators/ModelDecorators.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -12
- package/web-types.json +1 -1
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { FieldNode } from "./FieldNode.js";
|
|
2
|
+
export class StrictFetcher {
|
|
3
|
+
constructor(options, method, path, ReqType, ResType, bodyField) {
|
|
4
|
+
this.isLoading = false;
|
|
5
|
+
this.responseHandler = new Map();
|
|
6
|
+
this.API_OPTIONS = options;
|
|
7
|
+
this.path = path;
|
|
8
|
+
this.bodyField = bodyField;
|
|
9
|
+
this.method = method;
|
|
10
|
+
this.ReqType = ReqType;
|
|
11
|
+
this.ResType = ResType;
|
|
12
|
+
// Build the proto name map from the REQ type's field descriptors
|
|
13
|
+
this.reqProtoNameMap = new Map();
|
|
14
|
+
this.reqFieldConstructorMap = new Map();
|
|
15
|
+
const tempReq = new ReqType();
|
|
16
|
+
tempReq.__meta.nodeFields.forEach(field => {
|
|
17
|
+
this.reqProtoNameMap.set(field.fieldName, field.protoName);
|
|
18
|
+
this.reqFieldConstructorMap.set(field.fieldName, field.FieldConstructor);
|
|
19
|
+
});
|
|
20
|
+
this.abortController = new AbortController();
|
|
21
|
+
const { signal } = this.abortController;
|
|
22
|
+
this.requestInit = {
|
|
23
|
+
method: this.method,
|
|
24
|
+
signal,
|
|
25
|
+
headers: this.API_OPTIONS.headers,
|
|
26
|
+
redirect: "follow",
|
|
27
|
+
};
|
|
28
|
+
this.timeout = this.API_OPTIONS.timeout ?? 300000;
|
|
29
|
+
}
|
|
30
|
+
setRequestOptions(ri) {
|
|
31
|
+
const { signal } = this.abortController;
|
|
32
|
+
this.requestInit = {
|
|
33
|
+
method: this.method,
|
|
34
|
+
headers: this.API_OPTIONS.headers,
|
|
35
|
+
signal,
|
|
36
|
+
...ri,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
setHandlers(handlers) {
|
|
40
|
+
this.onResponse = handlers.onResponse;
|
|
41
|
+
this.onResponseError = handlers.onResponseError;
|
|
42
|
+
this.onRequestStarted = handlers.onRequestStarted;
|
|
43
|
+
this.onRequestFinished = handlers.onRequestFinished;
|
|
44
|
+
this.onRequestAborted = handlers.onRequestAborted;
|
|
45
|
+
this.onResponseRaw = handlers.onResponseRaw;
|
|
46
|
+
this.onResponseErrorRaw = handlers.onResponseErrorRaw;
|
|
47
|
+
this.onResponseParseError = handlers.onResponseParseError;
|
|
48
|
+
this.onResponseErrorParseError = handlers.onResponseErrorParseError;
|
|
49
|
+
this.onFatalError = handlers.onFatalError;
|
|
50
|
+
}
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
52
|
+
abortPendingRequest(reason) {
|
|
53
|
+
if (!this.isLoading) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
clearTimeout(this.timeoutId);
|
|
57
|
+
this.isLoading = false;
|
|
58
|
+
this.abortController.abort(reason);
|
|
59
|
+
if (this.onRequestAborted) {
|
|
60
|
+
this.onRequestAborted(reason);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
invoke(rqo, options) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
if (this.isLoading) {
|
|
66
|
+
this.abortPendingRequest("invoke triggered before response");
|
|
67
|
+
}
|
|
68
|
+
this.abortController = new AbortController();
|
|
69
|
+
const { signal } = this.abortController;
|
|
70
|
+
this.requestInit = {
|
|
71
|
+
method: this.method,
|
|
72
|
+
signal,
|
|
73
|
+
headers: this.API_OPTIONS.headers,
|
|
74
|
+
};
|
|
75
|
+
if (options) {
|
|
76
|
+
this.setRequestOptions(options);
|
|
77
|
+
}
|
|
78
|
+
this.isLoading = true;
|
|
79
|
+
const { evaluatedPath, evaluatedBody } = this.buildPathAndBodyfield(this.path, this.bodyField, rqo);
|
|
80
|
+
if (evaluatedBody) {
|
|
81
|
+
this.requestInit.body = evaluatedBody;
|
|
82
|
+
}
|
|
83
|
+
clearTimeout(this.timeoutId);
|
|
84
|
+
const request = new Request(evaluatedPath, this.requestInit);
|
|
85
|
+
this.timeoutId = setTimeout(() => {
|
|
86
|
+
this.abortController.abort(`Timeout of ${String(this.timeout)}ms reached`);
|
|
87
|
+
if (this.onRequestAborted) {
|
|
88
|
+
this.onRequestAborted(rqo);
|
|
89
|
+
}
|
|
90
|
+
console.error(`RequestService fetch aborted: Timeout of ${String(this.timeout)}ms reached`);
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
92
|
+
reject(rqo);
|
|
93
|
+
}, this.timeout);
|
|
94
|
+
if (this.onRequestStarted) {
|
|
95
|
+
this.onRequestStarted(rqo);
|
|
96
|
+
}
|
|
97
|
+
fetch(request)
|
|
98
|
+
.then(response => {
|
|
99
|
+
this._reworkRequest(response)
|
|
100
|
+
.then(data => {
|
|
101
|
+
resolve(data);
|
|
102
|
+
})
|
|
103
|
+
.catch(reject);
|
|
104
|
+
if (this.onRequestFinished) {
|
|
105
|
+
this.onRequestFinished(rqo);
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
.catch((err) => {
|
|
109
|
+
this.isLoading = false;
|
|
110
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
111
|
+
if (this.onRequestAborted) {
|
|
112
|
+
this.onRequestAborted(rqo);
|
|
113
|
+
}
|
|
114
|
+
if (this.onRequestFinished) {
|
|
115
|
+
this.onRequestFinished(rqo);
|
|
116
|
+
}
|
|
117
|
+
console.error("RequestService fetch aborted: ", err);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
if (this.onRequestFinished) {
|
|
121
|
+
this.onRequestFinished(rqo);
|
|
122
|
+
}
|
|
123
|
+
if (this.onFatalError) {
|
|
124
|
+
this.onFatalError(err);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
128
|
+
reject(err);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
_reworkRequest(response) {
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
this.isLoading = false;
|
|
135
|
+
clearTimeout(this.timeoutId);
|
|
136
|
+
const status = response.status;
|
|
137
|
+
if (status === 0 || (status >= 200 && status < 300)) {
|
|
138
|
+
this.lastResponse = response;
|
|
139
|
+
if (this.onResponseRaw) {
|
|
140
|
+
this.onResponseRaw(response);
|
|
141
|
+
}
|
|
142
|
+
this._parseResponse(response)
|
|
143
|
+
.then(r => {
|
|
144
|
+
resolve(r);
|
|
145
|
+
if (this.onResponse) {
|
|
146
|
+
this.onResponse(r, response);
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
.catch((error) => {
|
|
150
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
151
|
+
reject(error);
|
|
152
|
+
if (this.onResponseParseError) {
|
|
153
|
+
this.onResponseParseError(error, response);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
this.lastResponse = response;
|
|
159
|
+
if (this.onResponseErrorRaw) {
|
|
160
|
+
this.onResponseErrorRaw(response);
|
|
161
|
+
}
|
|
162
|
+
this._parseResponse(response)
|
|
163
|
+
.then(r => {
|
|
164
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
165
|
+
reject(r);
|
|
166
|
+
if (this.onResponseError) {
|
|
167
|
+
this.onResponseError(r, response);
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
.catch((error) => {
|
|
171
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
172
|
+
reject(error);
|
|
173
|
+
if (this.onResponseErrorParseError) {
|
|
174
|
+
this.onResponseErrorParseError(error, response);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
_parseResponse(response) {
|
|
181
|
+
return new Promise((resolve, reject) => {
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime data may not match types (REST API input)
|
|
183
|
+
if (response) {
|
|
184
|
+
this.responseHandler.set("text/plain", r => {
|
|
185
|
+
r.text()
|
|
186
|
+
.then(text => {
|
|
187
|
+
resolve(text);
|
|
188
|
+
})
|
|
189
|
+
.catch((err) => {
|
|
190
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
191
|
+
reject(err);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
this.responseHandler.set("text/html", r => {
|
|
195
|
+
r.text()
|
|
196
|
+
.then(text => {
|
|
197
|
+
resolve(text);
|
|
198
|
+
})
|
|
199
|
+
.catch((err) => {
|
|
200
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
201
|
+
reject(err);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
this.responseHandler.set("application/json", r => {
|
|
205
|
+
r.json()
|
|
206
|
+
.then(json => {
|
|
207
|
+
if (this.API_OPTIONS.UseProtoNames) {
|
|
208
|
+
// Use FieldNode-based conversion instead of generic Mapper
|
|
209
|
+
const resNode = new this.ResType();
|
|
210
|
+
resNode.__fromProtoNameJson(json);
|
|
211
|
+
resolve(resNode.__toLiteral());
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
resolve(json);
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
.catch((err) => {
|
|
218
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
219
|
+
reject(err);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
this.responseHandler.set("application/x-ndjson", r => {
|
|
223
|
+
const preserveProtoNames = this.API_OPTIONS.UseProtoNames;
|
|
224
|
+
const ResTypeCtor = this.ResType;
|
|
225
|
+
const reader = r.body?.getReader();
|
|
226
|
+
if (!reader) {
|
|
227
|
+
throw new Error("NDJSON response has no readable body");
|
|
228
|
+
}
|
|
229
|
+
const decoder = new TextDecoder();
|
|
230
|
+
let buffer = "";
|
|
231
|
+
const iterator = {
|
|
232
|
+
async *[Symbol.asyncIterator]() {
|
|
233
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- loop exits via break on done
|
|
234
|
+
while (true) {
|
|
235
|
+
const { done, value } = await reader.read();
|
|
236
|
+
if (done)
|
|
237
|
+
break;
|
|
238
|
+
buffer += decoder.decode(value, { stream: true });
|
|
239
|
+
const lines = buffer.split("\n");
|
|
240
|
+
buffer = lines.pop() ?? "";
|
|
241
|
+
for (const line of lines) {
|
|
242
|
+
const trimmed = line.trim();
|
|
243
|
+
if (trimmed === "") {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
let parsed;
|
|
247
|
+
try {
|
|
248
|
+
parsed = JSON.parse(trimmed);
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
throw new Error(`Failed to parse NDJSON line: ${trimmed}`);
|
|
252
|
+
}
|
|
253
|
+
if (preserveProtoNames) {
|
|
254
|
+
const resNode = new ResTypeCtor();
|
|
255
|
+
resNode.__fromProtoNameJson(parsed);
|
|
256
|
+
yield resNode.__toLiteral();
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
yield parsed;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (buffer.trim() !== "") {
|
|
264
|
+
try {
|
|
265
|
+
const parsed = JSON.parse(buffer.trim());
|
|
266
|
+
if (preserveProtoNames) {
|
|
267
|
+
const resNode = new ResTypeCtor();
|
|
268
|
+
resNode.__fromProtoNameJson(parsed);
|
|
269
|
+
yield resNode.__toLiteral();
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
yield parsed;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
throw new Error(`Failed to parse final NDJSON line: ${buffer.trim()}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
resolve(iterator);
|
|
282
|
+
});
|
|
283
|
+
this.responseHandler.set("application/octet-stream", r => {
|
|
284
|
+
r.arrayBuffer()
|
|
285
|
+
.then(buffer => {
|
|
286
|
+
resolve(buffer);
|
|
287
|
+
})
|
|
288
|
+
.catch((err) => {
|
|
289
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
290
|
+
reject(err);
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
this.responseHandler.set("application/pdf", r => {
|
|
294
|
+
r.blob()
|
|
295
|
+
.then(blob => {
|
|
296
|
+
resolve(blob);
|
|
297
|
+
})
|
|
298
|
+
.catch((err) => {
|
|
299
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
300
|
+
reject(err);
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
this.responseHandler.set("image/jpeg", r => {
|
|
304
|
+
r.blob()
|
|
305
|
+
.then(blob => {
|
|
306
|
+
resolve(blob);
|
|
307
|
+
})
|
|
308
|
+
.catch((err) => {
|
|
309
|
+
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers
|
|
310
|
+
reject(err);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
const contentType = response.headers.get("content-type");
|
|
314
|
+
let handler = contentType?.split(";")[0].trim();
|
|
315
|
+
handler ??= "application/json";
|
|
316
|
+
let typeHandler = this.responseHandler.get(handler);
|
|
317
|
+
if (typeHandler === undefined) {
|
|
318
|
+
console.error("No parser for", handler);
|
|
319
|
+
typeHandler = this.responseHandler.get("application/json");
|
|
320
|
+
}
|
|
321
|
+
if (typeHandler) {
|
|
322
|
+
typeHandler(response);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
reject(new Error("no response"));
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
buildPathAndBodyfield(path, bodyField, rqo) {
|
|
331
|
+
let evaluatedPath = path;
|
|
332
|
+
let evaluatedBody;
|
|
333
|
+
const keysForBodyOrQueryParams = new Map();
|
|
334
|
+
Object.keys(rqo).forEach(key => {
|
|
335
|
+
keysForBodyOrQueryParams.set(key, key);
|
|
336
|
+
});
|
|
337
|
+
// Build a reverse map: protoName → camelCase fieldName for path template resolution
|
|
338
|
+
const protoToFieldMap = new Map();
|
|
339
|
+
this.reqProtoNameMap.forEach((protoName, fieldName) => {
|
|
340
|
+
protoToFieldMap.set(protoName, fieldName);
|
|
341
|
+
});
|
|
342
|
+
const fields = [...path.matchAll(/\{([^}]+)}/g)];
|
|
343
|
+
// Replace URL templates with values: /v1/cube/{cube_id} => /v1/cube/12
|
|
344
|
+
// Path templates use proto names, but rqo uses camelCase keys
|
|
345
|
+
fields.forEach(field => {
|
|
346
|
+
const protoName = field[1];
|
|
347
|
+
const camelKey = (protoToFieldMap.get(protoName) ?? protoName);
|
|
348
|
+
const rqoValue = rqo[camelKey];
|
|
349
|
+
evaluatedPath = evaluatedPath.replace(field[0], String(rqoValue));
|
|
350
|
+
keysForBodyOrQueryParams.delete(camelKey);
|
|
351
|
+
});
|
|
352
|
+
if (bodyField === "*") {
|
|
353
|
+
// Use FieldNode serialization for body when UseProtoNames is true
|
|
354
|
+
if (this.API_OPTIONS.UseProtoNames) {
|
|
355
|
+
const reqNode = new this.ReqType();
|
|
356
|
+
// Build a literal from remaining keys
|
|
357
|
+
const literalBody = {};
|
|
358
|
+
keysForBodyOrQueryParams.forEach(key => {
|
|
359
|
+
literalBody[key] = rqo[key];
|
|
360
|
+
});
|
|
361
|
+
reqNode.__fromLiteral(literalBody);
|
|
362
|
+
evaluatedBody = JSON.stringify(reqNode.__toJson());
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
const body = {};
|
|
366
|
+
keysForBodyOrQueryParams.forEach(key => {
|
|
367
|
+
body[key] = rqo[key];
|
|
368
|
+
});
|
|
369
|
+
evaluatedBody = JSON.stringify(body);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
// Build query params
|
|
374
|
+
const params = [];
|
|
375
|
+
if (bodyField !== undefined) {
|
|
376
|
+
keysForBodyOrQueryParams.delete(bodyField);
|
|
377
|
+
}
|
|
378
|
+
keysForBodyOrQueryParams.forEach(key => {
|
|
379
|
+
// Use the reqProtoNameMap for proto name lookup instead of generic conversion
|
|
380
|
+
const paramName = this.API_OPTIONS.UseProtoNamesForQueryParams ? (this.reqProtoNameMap.get(key) ?? key) : key;
|
|
381
|
+
if (Array.isArray(rqo[key])) {
|
|
382
|
+
rqo[key].forEach(e => {
|
|
383
|
+
params.push(`${paramName}=${String(e)}`);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
params.push(`${paramName}=${String(rqo[key])}`);
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
if (params.length) {
|
|
391
|
+
evaluatedPath = `${evaluatedPath}?${params.join("&")}`;
|
|
392
|
+
}
|
|
393
|
+
if (bodyField !== undefined) {
|
|
394
|
+
// Use FieldNode serialization for the named body field when UseProtoNames is true
|
|
395
|
+
if (this.API_OPTIONS.UseProtoNames) {
|
|
396
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- FieldConstructor stored from meta is untyped
|
|
397
|
+
const FieldCtor = this.reqFieldConstructorMap.get(bodyField);
|
|
398
|
+
if (FieldCtor) {
|
|
399
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call -- FieldConstructor is dynamically resolved from meta
|
|
400
|
+
const fieldNode = new FieldCtor(undefined);
|
|
401
|
+
fieldNode.__fromLiteral(rqo[bodyField]);
|
|
402
|
+
evaluatedBody = JSON.stringify(fieldNode.__toJson());
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
evaluatedBody = JSON.stringify(rqo[bodyField]);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
evaluatedBody = JSON.stringify(rqo[bodyField]);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
evaluatedPath = `${this.API_OPTIONS.serverAddr}${this.API_OPTIONS.ApiBaseURL}${evaluatedPath}`;
|
|
414
|
+
return {
|
|
415
|
+
evaluatedPath,
|
|
416
|
+
evaluatedBody,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
//# sourceMappingURL=StrictFetcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StrictFetcher.js","sourceRoot":"","sources":["../src/StrictFetcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { FieldNode } from \"./FieldNode\";\n\nexport interface IApiOptions {\n serverAddr: string;\n ApiBaseURL: string;\n headers?: Headers;\n timeout?: number;\n UseProtoNames: boolean;\n UseProtoNamesForQueryParams: boolean;\n}\n\ninterface Handlers<REQ, RES> {\n onResponse?: (response: RES, serverResponse: Response) => void;\n onResponseError?: (parsedResponse: unknown, serverResponse: Response) => void;\n onRequestStarted?: (req: REQ) => void;\n onRequestFinished?: (req: REQ) => void;\n onRequestAborted?: (req: REQ) => void;\n onResponseRaw?: (serverResponse: Response) => void;\n onResponseErrorRaw?: (serverResponse: Response) => void;\n onResponseParseError?: (error: unknown, serverResponse: Response) => void;\n onResponseErrorParseError?: (error: unknown, serverResponse: Response) => void;\n onFatalError?: (error: unknown) => void;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype FieldNodeConstructor = new (initData?: any, parent?: FieldNode, parentAttributeName?: string) => FieldNode;\n\nexport class StrictFetcher<REQ, RES> {\n public timeout: number;\n public lastResponse: Response | undefined;\n public isLoading = false;\n\n private path: string;\n private requestInit: RequestInit;\n private method: string;\n private responseHandler: Map<string, (r: Response) => void> = new Map<string, (r: Response) => void>();\n private abortController: AbortController;\n private timeoutId: ReturnType<typeof setTimeout> | number | undefined;\n private bodyField: keyof REQ | \"*\" | undefined;\n private API_OPTIONS: IApiOptions;\n\n private ReqType: FieldNodeConstructor;\n private ResType: FieldNodeConstructor;\n\n // Maps camelCase fieldName → protoName from the REQ type's field descriptors\n private reqProtoNameMap: Map<string, string>;\n // Maps camelCase fieldName → FieldConstructor from the REQ type's field descriptors\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private reqFieldConstructorMap: Map<string, any>;\n\n constructor(\n options: IApiOptions,\n method: string,\n path: string,\n ReqType: FieldNodeConstructor,\n ResType: FieldNodeConstructor,\n bodyField?: keyof REQ | \"*\",\n ) {\n this.API_OPTIONS = options;\n this.path = path;\n this.bodyField = bodyField;\n this.method = method;\n this.ReqType = ReqType;\n this.ResType = ResType;\n\n // Build the proto name map from the REQ type's field descriptors\n this.reqProtoNameMap = new Map<string, string>();\n this.reqFieldConstructorMap = new Map<string, FieldNodeConstructor>();\n const tempReq = new ReqType();\n tempReq.__meta.nodeFields.forEach(field => {\n this.reqProtoNameMap.set(field.fieldName, field.protoName);\n this.reqFieldConstructorMap.set(field.fieldName, field.FieldConstructor as FieldNodeConstructor);\n });\n\n this.abortController = new AbortController();\n const { signal } = this.abortController;\n this.requestInit = {\n method: this.method,\n signal,\n headers: this.API_OPTIONS.headers,\n redirect: \"follow\",\n };\n\n this.timeout = this.API_OPTIONS.timeout ?? 300000;\n }\n\n public setRequestOptions(ri: RequestInit) {\n const { signal } = this.abortController;\n this.requestInit = {\n method: this.method,\n headers: this.API_OPTIONS.headers,\n signal,\n ...ri,\n };\n }\n\n public setHandlers(handlers: Handlers<REQ, RES>) {\n this.onResponse = handlers.onResponse;\n this.onResponseError = handlers.onResponseError;\n this.onRequestStarted = handlers.onRequestStarted;\n this.onRequestFinished = handlers.onRequestFinished;\n this.onRequestAborted = handlers.onRequestAborted;\n this.onResponseRaw = handlers.onResponseRaw;\n this.onResponseErrorRaw = handlers.onResponseErrorRaw;\n this.onResponseParseError = handlers.onResponseParseError;\n this.onResponseErrorParseError = handlers.onResponseErrorParseError;\n this.onFatalError = handlers.onFatalError;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public abortPendingRequest(reason: any): void {\n if (!this.isLoading) {\n return;\n }\n clearTimeout(this.timeoutId);\n this.isLoading = false;\n this.abortController.abort(reason);\n\n if (this.onRequestAborted) {\n this.onRequestAborted(reason as REQ);\n }\n }\n\n public invoke(rqo: REQ, options?: RequestInit): Promise<RES> {\n return new Promise((resolve, reject) => {\n if (this.isLoading) {\n this.abortPendingRequest(\"invoke triggered before response\");\n }\n\n this.abortController = new AbortController();\n const { signal } = this.abortController;\n\n this.requestInit = {\n method: this.method,\n signal,\n headers: this.API_OPTIONS.headers,\n };\n\n if (options) {\n this.setRequestOptions(options);\n }\n\n this.isLoading = true;\n\n const { evaluatedPath, evaluatedBody } = this.buildPathAndBodyfield(this.path, this.bodyField, rqo);\n if (evaluatedBody) {\n this.requestInit.body = evaluatedBody;\n }\n\n clearTimeout(this.timeoutId);\n const request = new Request(evaluatedPath, this.requestInit);\n this.timeoutId = setTimeout(() => {\n this.abortController.abort(`Timeout of ${String(this.timeout)}ms reached`);\n if (this.onRequestAborted) {\n this.onRequestAborted(rqo);\n }\n\n console.error(`RequestService fetch aborted: Timeout of ${String(this.timeout)}ms reached`);\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(rqo);\n }, this.timeout);\n\n if (this.onRequestStarted) {\n this.onRequestStarted(rqo);\n }\n\n fetch(request)\n .then(response => {\n this._reworkRequest(response)\n .then(data => {\n resolve(data);\n })\n .catch(reject);\n if (this.onRequestFinished) {\n this.onRequestFinished(rqo);\n }\n })\n .catch((err: unknown) => {\n this.isLoading = false;\n\n if (err instanceof Error && err.name === \"AbortError\") {\n if (this.onRequestAborted) {\n this.onRequestAborted(rqo);\n }\n if (this.onRequestFinished) {\n this.onRequestFinished(rqo);\n }\n\n console.error(\"RequestService fetch aborted: \", err);\n } else {\n if (this.onRequestFinished) {\n this.onRequestFinished(rqo);\n }\n\n if (this.onFatalError) {\n this.onFatalError(err);\n }\n }\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(err);\n });\n });\n }\n\n _reworkRequest(response: Response): Promise<RES> {\n return new Promise((resolve, reject) => {\n this.isLoading = false;\n clearTimeout(this.timeoutId);\n const status = response.status;\n\n if (status === 0 || (status >= 200 && status < 300)) {\n this.lastResponse = response;\n\n if (this.onResponseRaw) {\n this.onResponseRaw(response);\n }\n\n this._parseResponse(response)\n .then(r => {\n resolve(r as RES);\n if (this.onResponse) {\n this.onResponse(r as RES, response);\n }\n })\n .catch((error: unknown) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(error);\n if (this.onResponseParseError) {\n this.onResponseParseError(error, response);\n }\n });\n } else {\n this.lastResponse = response;\n if (this.onResponseErrorRaw) {\n this.onResponseErrorRaw(response);\n }\n\n this._parseResponse(response)\n .then(r => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(r);\n if (this.onResponseError) {\n this.onResponseError(r, response);\n }\n })\n .catch((error: unknown) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(error);\n if (this.onResponseErrorParseError) {\n this.onResponseErrorParseError(error, response);\n }\n });\n }\n });\n }\n\n _parseResponse(response: Response) {\n return new Promise((resolve, reject) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime data may not match types (REST API input)\n if (response) {\n this.responseHandler.set(\"text/plain\", r => {\n r.text()\n .then(text => {\n resolve(text);\n })\n .catch((err: unknown) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(err);\n });\n });\n\n this.responseHandler.set(\"text/html\", r => {\n r.text()\n .then(text => {\n resolve(text);\n })\n .catch((err: unknown) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(err);\n });\n });\n\n this.responseHandler.set(\"application/json\", r => {\n r.json()\n .then(json => {\n if (this.API_OPTIONS.UseProtoNames) {\n // Use FieldNode-based conversion instead of generic Mapper\n const resNode = new this.ResType();\n resNode.__fromProtoNameJson(json);\n resolve(resNode.__toLiteral());\n } else {\n resolve(json);\n }\n })\n .catch((err: unknown) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(err);\n });\n });\n\n this.responseHandler.set(\"application/x-ndjson\", r => {\n const preserveProtoNames = this.API_OPTIONS.UseProtoNames;\n const ResTypeCtor = this.ResType;\n\n const reader = r.body?.getReader();\n if (!reader) {\n throw new Error(\"NDJSON response has no readable body\");\n }\n\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n const iterator = {\n async *[Symbol.asyncIterator](): AsyncGenerator<RES> {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- loop exits via break on done\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed === \"\") {\n continue;\n }\n\n let parsed: RES;\n try {\n parsed = JSON.parse(trimmed) as RES;\n } catch {\n throw new Error(`Failed to parse NDJSON line: ${trimmed}`);\n }\n\n if (preserveProtoNames) {\n const resNode = new ResTypeCtor();\n resNode.__fromProtoNameJson(parsed);\n yield resNode.__toLiteral() as RES;\n } else {\n yield parsed;\n }\n }\n }\n\n if (buffer.trim() !== \"\") {\n try {\n const parsed = JSON.parse(buffer.trim()) as RES;\n if (preserveProtoNames) {\n const resNode = new ResTypeCtor();\n resNode.__fromProtoNameJson(parsed);\n yield resNode.__toLiteral() as RES;\n } else {\n yield parsed;\n }\n } catch {\n throw new Error(`Failed to parse final NDJSON line: ${buffer.trim()}`);\n }\n }\n },\n };\n\n resolve(iterator);\n });\n\n this.responseHandler.set(\"application/octet-stream\", r => {\n r.arrayBuffer()\n .then(buffer => {\n resolve(buffer);\n })\n .catch((err: unknown) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(err);\n });\n });\n this.responseHandler.set(\"application/pdf\", r => {\n r.blob()\n .then(blob => {\n resolve(blob);\n })\n .catch((err: unknown) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(err);\n });\n });\n this.responseHandler.set(\"image/jpeg\", r => {\n r.blob()\n .then(blob => {\n resolve(blob);\n })\n .catch((err: unknown) => {\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors -- changing rejection types would break downstream error handlers\n reject(err);\n });\n });\n\n const contentType = response.headers.get(\"content-type\");\n let handler = contentType?.split(\";\")[0].trim();\n handler ??= \"application/json\";\n let typeHandler = this.responseHandler.get(handler);\n\n if (typeHandler === undefined) {\n console.error(\"No parser for\", handler);\n typeHandler = this.responseHandler.get(\"application/json\");\n }\n\n if (typeHandler) {\n typeHandler(response);\n }\n } else {\n reject(new Error(\"no response\"));\n }\n });\n }\n\n private buildPathAndBodyfield(\n path: string,\n bodyField: keyof REQ | \"*\" | undefined,\n rqo: REQ,\n ): {\n evaluatedPath: string;\n evaluatedBody: string | undefined;\n } {\n let evaluatedPath = path;\n let evaluatedBody;\n\n const keysForBodyOrQueryParams = new Map<string, keyof REQ>();\n Object.keys(rqo as object).forEach(key => {\n keysForBodyOrQueryParams.set(key, key as keyof REQ);\n });\n\n // Build a reverse map: protoName → camelCase fieldName for path template resolution\n const protoToFieldMap = new Map<string, string>();\n this.reqProtoNameMap.forEach((protoName, fieldName) => {\n protoToFieldMap.set(protoName, fieldName);\n });\n\n const fields = [...path.matchAll(/\\{([^}]+)}/g)];\n // Replace URL templates with values: /v1/cube/{cube_id} => /v1/cube/12\n // Path templates use proto names, but rqo uses camelCase keys\n fields.forEach(field => {\n const protoName = field[1];\n const camelKey = (protoToFieldMap.get(protoName) ?? protoName) as keyof REQ;\n const rqoValue = rqo[camelKey];\n evaluatedPath = evaluatedPath.replace(field[0], String(rqoValue));\n keysForBodyOrQueryParams.delete(camelKey as string);\n });\n\n if (bodyField === \"*\") {\n // Use FieldNode serialization for body when UseProtoNames is true\n if (this.API_OPTIONS.UseProtoNames) {\n const reqNode = new this.ReqType();\n // Build a literal from remaining keys\n const literalBody: Record<string, unknown> = {};\n keysForBodyOrQueryParams.forEach(key => {\n literalBody[key as string] = rqo[key];\n });\n reqNode.__fromLiteral(literalBody);\n evaluatedBody = JSON.stringify(reqNode.__toJson());\n } else {\n const body: Record<string, unknown> = {};\n keysForBodyOrQueryParams.forEach(key => {\n body[key as string] = rqo[key];\n });\n evaluatedBody = JSON.stringify(body);\n }\n } else {\n // Build query params\n const params: string[] = [];\n if (bodyField !== undefined) {\n keysForBodyOrQueryParams.delete(bodyField as string);\n }\n keysForBodyOrQueryParams.forEach(key => {\n // Use the reqProtoNameMap for proto name lookup instead of generic conversion\n const paramName = this.API_OPTIONS.UseProtoNamesForQueryParams ? (this.reqProtoNameMap.get(key as string) ?? (key as string)) : (key as string);\n if (Array.isArray(rqo[key])) {\n (rqo[key] as unknown[]).forEach(e => {\n params.push(`${paramName}=${String(e)}`);\n });\n } else {\n params.push(`${paramName}=${String(rqo[key])}`);\n }\n });\n if (params.length) {\n evaluatedPath = `${evaluatedPath}?${params.join(\"&\")}`;\n }\n\n if (bodyField !== undefined) {\n // Use FieldNode serialization for the named body field when UseProtoNames is true\n if (this.API_OPTIONS.UseProtoNames) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- FieldConstructor stored from meta is untyped\n const FieldCtor = this.reqFieldConstructorMap.get(bodyField as string);\n if (FieldCtor) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call -- FieldConstructor is dynamically resolved from meta\n const fieldNode = new FieldCtor(undefined) as FieldNode;\n fieldNode.__fromLiteral(rqo[bodyField]);\n evaluatedBody = JSON.stringify(fieldNode.__toJson());\n } else {\n evaluatedBody = JSON.stringify(rqo[bodyField]);\n }\n } else {\n evaluatedBody = JSON.stringify(rqo[bodyField]);\n }\n }\n }\n\n evaluatedPath = `${this.API_OPTIONS.serverAddr}${this.API_OPTIONS.ApiBaseURL}${evaluatedPath}`;\n\n return {\n evaluatedPath,\n evaluatedBody,\n };\n }\n\n onResponse?: (response: RES, serverResponse: Response) => void;\n onResponseError?: (parsedResponse: unknown, serverResponse: Response) => void;\n onRequestStarted?: (req: REQ) => void;\n onRequestFinished?: (req: REQ) => void;\n onRequestAborted?: (req: REQ) => void;\n onResponseRaw?: (serverResponse: Response) => void;\n onResponseErrorRaw?: (serverResponse: Response) => void;\n onResponseParseError?: (error: unknown, serverResponse: Response) => void;\n onResponseErrorParseError?: (error: unknown, serverResponse: Response) => void;\n onFatalError?: (error: unknown) => void;\n}\n"]}
|
|
@@ -44,17 +44,15 @@ interface FieldNodeLike {
|
|
|
44
44
|
* const cubeModel = ModelBindings(CubeEntityModel.model);
|
|
45
45
|
*
|
|
46
46
|
* class MyComponent extends LitElement {
|
|
47
|
-
* //
|
|
48
|
-
* @cubeModel.bind()
|
|
49
|
-
* private _modelUpdated: unknown;
|
|
50
|
-
*
|
|
51
|
-
* // Triggers re-render when cube.length changes
|
|
47
|
+
* // Bind to a nested field value - updates when cube.length changes
|
|
52
48
|
* @cubeModel.bind("cube.length")
|
|
53
|
-
*
|
|
49
|
+
* @state()
|
|
50
|
+
* private cubeLength: number = 0;
|
|
54
51
|
*
|
|
55
|
-
* //
|
|
52
|
+
* // Bind to model validity
|
|
56
53
|
* @cubeModel.bind("__isValid", "validity-changed")
|
|
57
|
-
*
|
|
54
|
+
* @state()
|
|
55
|
+
* private isValid: boolean = true;
|
|
58
56
|
*
|
|
59
57
|
* // React to any field value change on the model
|
|
60
58
|
* @cubeModel.onEvent("field-value-changed")
|
|
@@ -75,13 +73,13 @@ interface FieldNodeLike {
|
|
|
75
73
|
*/
|
|
76
74
|
export declare function ModelBindings<TEventMap extends ModelEventMap = ModelEventMap>(model: FieldNodeLike): {
|
|
77
75
|
/**
|
|
78
|
-
*
|
|
79
|
-
* When
|
|
76
|
+
* Binds a component property to a model field value.
|
|
77
|
+
* When the field changes, the property is automatically updated.
|
|
80
78
|
*
|
|
81
|
-
* @param path -
|
|
82
|
-
* @param eventType - Event to listen for (defaults to "
|
|
79
|
+
* @param path - Path to the field (e.g., "cube.length", "__isValid")
|
|
80
|
+
* @param eventType - Event to listen for (defaults to "this-field-value-changed")
|
|
83
81
|
*/
|
|
84
|
-
bind(path
|
|
82
|
+
bind(path: string, eventType?: ModelEventType): (target: object, propertyKey: string) => void;
|
|
85
83
|
/**
|
|
86
84
|
* Binds a method to an event on the root model.
|
|
87
85
|
* When the event fires, the method is called.
|
|
@@ -23,17 +23,15 @@ const MODEL_EVENT_METHODS = Symbol.for("__modelEventMethods__");
|
|
|
23
23
|
* const cubeModel = ModelBindings(CubeEntityModel.model);
|
|
24
24
|
*
|
|
25
25
|
* class MyComponent extends LitElement {
|
|
26
|
-
* //
|
|
27
|
-
* @cubeModel.bind()
|
|
28
|
-
* private _modelUpdated: unknown;
|
|
29
|
-
*
|
|
30
|
-
* // Triggers re-render when cube.length changes
|
|
26
|
+
* // Bind to a nested field value - updates when cube.length changes
|
|
31
27
|
* @cubeModel.bind("cube.length")
|
|
32
|
-
*
|
|
28
|
+
* @state()
|
|
29
|
+
* private cubeLength: number = 0;
|
|
33
30
|
*
|
|
34
|
-
* //
|
|
31
|
+
* // Bind to model validity
|
|
35
32
|
* @cubeModel.bind("__isValid", "validity-changed")
|
|
36
|
-
*
|
|
33
|
+
* @state()
|
|
34
|
+
* private isValid: boolean = true;
|
|
37
35
|
*
|
|
38
36
|
* // React to any field value change on the model
|
|
39
37
|
* @cubeModel.onEvent("field-value-changed")
|
|
@@ -55,11 +53,11 @@ const MODEL_EVENT_METHODS = Symbol.for("__modelEventMethods__");
|
|
|
55
53
|
export function ModelBindings(model) {
|
|
56
54
|
return {
|
|
57
55
|
/**
|
|
58
|
-
*
|
|
59
|
-
* When
|
|
56
|
+
* Binds a component property to a model field value.
|
|
57
|
+
* When the field changes, the property is automatically updated.
|
|
60
58
|
*
|
|
61
|
-
* @param path -
|
|
62
|
-
* @param eventType - Event to listen for (defaults to "
|
|
59
|
+
* @param path - Path to the field (e.g., "cube.length", "__isValid")
|
|
60
|
+
* @param eventType - Event to listen for (defaults to "this-field-value-changed")
|
|
63
61
|
*/
|
|
64
62
|
bind(path, eventType = "update") {
|
|
65
63
|
return function bindDecorator(target, propertyKey) {
|
|
@@ -134,6 +132,26 @@ function getFieldForPath(model, path) {
|
|
|
134
132
|
}
|
|
135
133
|
return model;
|
|
136
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Get the value for a path from the model.
|
|
137
|
+
*/
|
|
138
|
+
function getValueForPath(model, path) {
|
|
139
|
+
if (path.startsWith("__")) {
|
|
140
|
+
// Direct property access for internal properties
|
|
141
|
+
return model[path];
|
|
142
|
+
}
|
|
143
|
+
if (!path.includes(".")) {
|
|
144
|
+
// Direct child field
|
|
145
|
+
const field = model[path];
|
|
146
|
+
return field?.value ?? field;
|
|
147
|
+
}
|
|
148
|
+
// Nested path - get the field and return its value
|
|
149
|
+
if (model.__getFieldNodeByPath) {
|
|
150
|
+
const field = model.__getFieldNodeByPath(path);
|
|
151
|
+
return field?.value ?? field;
|
|
152
|
+
}
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
137
155
|
/**
|
|
138
156
|
* Patch connectedCallback/disconnectedCallback for bind decorators.
|
|
139
157
|
*/
|
|
@@ -155,9 +173,11 @@ function patchBindLifecycle(ctor) {
|
|
|
155
173
|
const listeners = new Map();
|
|
156
174
|
this[MODEL_BIND_LISTENERS] = listeners;
|
|
157
175
|
metadata.forEach(({ model, path, eventType }, propKey) => {
|
|
158
|
-
const field =
|
|
176
|
+
const field = getFieldForPath(model, path);
|
|
177
|
+
// Set initial value
|
|
178
|
+
this[propKey] = getValueForPath(model, path);
|
|
159
179
|
const listener = () => {
|
|
160
|
-
this
|
|
180
|
+
this[propKey] = getValueForPath(model, path);
|
|
161
181
|
};
|
|
162
182
|
listeners.set(propKey, { listener, field, eventType });
|
|
163
183
|
field.__addEventListener(eventType, listener);
|