@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.
@@ -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
- * // Triggers re-render on any model update
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
- * private cubeLength: unknown;
49
+ * @state()
50
+ * private cubeLength: number = 0;
54
51
  *
55
- * // Triggers re-render on model validity changes
52
+ * // Bind to model validity
56
53
  * @cubeModel.bind("__isValid", "validity-changed")
57
- * private isValid: unknown;
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
- * Triggers a render update when a model event fires.
79
- * When called without arguments, listens on the model root for the "update" event.
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 - Optional path to a field (e.g., "cube.length"). When omitted, listens on the model root.
82
- * @param eventType - Event to listen for (defaults to "update")
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?: string, eventType?: ModelEventType): (target: object, propertyKey: string) => void;
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
- * // Triggers re-render on any model update
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
- * private cubeLength: unknown;
28
+ * @state()
29
+ * private cubeLength: number = 0;
33
30
  *
34
- * // Triggers re-render on model validity changes
31
+ * // Bind to model validity
35
32
  * @cubeModel.bind("__isValid", "validity-changed")
36
- * private isValid: unknown;
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
- * Triggers a render update when a model event fires.
59
- * When called without arguments, listens on the model root for the "update" event.
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 - Optional path to a field (e.g., "cube.length"). When omitted, listens on the model root.
62
- * @param eventType - Event to listen for (defaults to "update")
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 = path ? getFieldForPath(model, path) : model;
176
+ const field = getFieldForPath(model, path);
177
+ // Set initial value
178
+ this[propKey] = getValueForPath(model, path);
159
179
  const listener = () => {
160
- this.requestUpdate();
180
+ this[propKey] = getValueForPath(model, path);
161
181
  };
162
182
  listeners.set(propKey, { listener, field, eventType });
163
183
  field.__addEventListener(eventType, listener);