@api-client/ui 0.1.2 → 0.1.3
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/build/src/bindings/base/IoThread.d.ts +2 -2
- package/build/src/bindings/base/IoThread.d.ts.map +1 -1
- package/build/src/bindings/base/IoThread.js +4 -4
- package/build/src/bindings/base/IoThread.js.map +1 -1
- package/build/src/bindings/base/PlatformBindings.js +2 -2
- package/build/src/bindings/base/PlatformBindings.js.map +1 -1
- package/package.json +1 -1
- package/src/bindings/base/IoThread.ts +7 -7
- package/src/bindings/base/PlatformBindings.ts +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Exception } from '@api-client/core/exceptions/exception.js';
|
|
2
2
|
import { type IoEvent, type IoCommand, type IoNotification } from './PlatformBindings.js';
|
|
3
3
|
/**
|
|
4
4
|
* The base IO thread class containing the communication logic with the clients.
|
|
@@ -19,7 +19,7 @@ export declare abstract class IoThread {
|
|
|
19
19
|
* To be called by the IO thread implementation when receiving a message from the client.
|
|
20
20
|
*/
|
|
21
21
|
protected handleMessage(event: IoCommand | IoEvent): void;
|
|
22
|
-
protected notifyError(id: number, error:
|
|
22
|
+
protected notifyError(id: number, error: Exception): void;
|
|
23
23
|
protected getFunction(fn: string): Function | undefined;
|
|
24
24
|
/**
|
|
25
25
|
* Calls the function on self, creates a response event, and dispatches it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IoThread.d.ts","sourceRoot":"","sources":["../../../../src/bindings/base/IoThread.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"IoThread.d.ts","sourceRoot":"","sources":["../../../../src/bindings/base/IoThread.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,0CAA0C,CAAA;AACpE,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEzF;;GAEG;AACH,8BAAsB,QAAQ;IAC5B;;OAEG;IACH,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAEpC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,GAAG,IAAI;IAE7D;;OAEG;IACH,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,GAAG,IAAI;IA0CzD,SAAS,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI;IAWzD,SAAS,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAiBvD;;;;;;OAMG;cAEa,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBhF;;;;;OAKG;IACH,SAAS,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;CAQjE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
/* eslint-disable no-console */
|
|
3
|
-
import {
|
|
3
|
+
import { Exception } from '@api-client/core/exceptions/exception.js';
|
|
4
4
|
/**
|
|
5
5
|
* The base IO thread class containing the communication logic with the clients.
|
|
6
6
|
*/
|
|
@@ -23,7 +23,7 @@ export class IoThread {
|
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
if (typeof fn !== 'string' || !fn) {
|
|
26
|
-
const err = new
|
|
26
|
+
const err = new Exception('Invalid message received on the io-channel. The second argument must be a function name to call.', { status: 400 });
|
|
27
27
|
this.notifyError(id, err);
|
|
28
28
|
console.warn(err.message);
|
|
29
29
|
return;
|
|
@@ -31,7 +31,7 @@ export class IoThread {
|
|
|
31
31
|
const callable = this.getFunction(fn);
|
|
32
32
|
const isFunction = typeof callable === 'function';
|
|
33
33
|
if (!isFunction) {
|
|
34
|
-
const err = new
|
|
34
|
+
const err = new Exception(`Invalid message received on the io-channel. The function "${fn}" is either not implemented or invalid.`, { status: 400 });
|
|
35
35
|
this.notifyError(id, err);
|
|
36
36
|
console.warn(err.message);
|
|
37
37
|
return;
|
|
@@ -86,7 +86,7 @@ export class IoThread {
|
|
|
86
86
|
catch (e) {
|
|
87
87
|
event.type = 'error';
|
|
88
88
|
event.message = e.message;
|
|
89
|
-
if (e.
|
|
89
|
+
if (e.status) {
|
|
90
90
|
event.result = e;
|
|
91
91
|
}
|
|
92
92
|
this.postMessage(event);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IoThread.js","sourceRoot":"","sources":["../../../../src/bindings/base/IoThread.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,+BAA+B;AAC/B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"IoThread.js","sourceRoot":"","sources":["../../../../src/bindings/base/IoThread.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable no-console */\nimport { Exception } from '@api-client/core/exceptions/exception.js'\nimport { type IoEvent, type IoCommand, type IoNotification } from './PlatformBindings.js'\n\n/**\n * The base IO thread class containing the communication logic with the clients.\n */\nexport abstract class IoThread {\n /**\n * Initializes the communication channel with the clients.\n */\n abstract initialize(): Promise<void>\n\n /**\n * The IO thread must implement this method to send the message to the client with\n * their particular implementation of message passing.\n *\n * @param message The message to send.\n */\n abstract postMessage(message: IoNotification | IoEvent): void\n\n /**\n * To be called by the IO thread implementation when receiving a message from the client.\n */\n protected handleMessage(event: IoCommand | IoEvent): void {\n if (!event.kind) {\n console.warn('Invalid message received on the app-config-channel.', event)\n return\n }\n if (event.kind === 'IO#Event') {\n // message sent by self.\n return\n }\n const { args, fn, id } = event\n\n if (typeof id !== 'number') {\n console.warn('Invalid message received on the app-config-channel. The id must be a number.')\n return\n }\n\n if (typeof fn !== 'string' || !fn) {\n const err = new Exception(\n 'Invalid message received on the io-channel. The second argument must be a function name to call.',\n { status: 400 }\n )\n this.notifyError(id, err)\n console.warn(err.message)\n return\n }\n\n const callable = this.getFunction(fn)\n const isFunction = typeof callable === 'function'\n\n if (!isFunction) {\n const err = new Exception(\n `Invalid message received on the io-channel. The function \"${fn}\" is either not implemented or invalid.`,\n { status: 400 }\n )\n this.notifyError(id, err)\n console.warn(err.message)\n return\n }\n\n this.call(callable, id, args)\n }\n\n protected notifyError(id: number, error: Exception): void {\n const event: IoEvent = {\n kind: 'IO#Event',\n id,\n type: 'error',\n result: error,\n }\n this.postMessage(event)\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n protected getFunction(fn: string): Function | undefined {\n const path = fn.trim().split('.')\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n let current: any = this\n path.forEach((key) => {\n if (!current) {\n return\n }\n const scope = current\n current = current[key as any]\n if (current && current.bind) {\n current = current.bind(scope)\n }\n })\n return current\n }\n\n /**\n * Calls the function on self, creates a response event, and dispatches it.\n *\n * @param fnName The function name to call.\n * @param id The request id sent back to the client.\n * @param args The function arguments.\n */\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n protected async call(callable: Function, id: number, args: any[]): Promise<void> {\n const event: IoEvent = {\n kind: 'IO#Event',\n id,\n type: 'result',\n }\n try {\n const promise = (callable as (...init: any[]) => Promise<any>)(...args)\n event.result = await promise\n this.postMessage(event)\n } catch (e) {\n event.type = 'error'\n event.message = (e as Error).message\n if ((e as Exception).status) {\n event.result = e\n }\n this.postMessage(event)\n }\n }\n\n /**\n * Sends a message to the clients that is a request to send a client DOM event.\n *\n * @param eventPath The path in the `Events` prototype.\n * @param args The arguments to call the event with.\n */\n protected notifyClients(eventPath: string, ...args: any[]): void {\n const info: IoNotification = {\n kind: 'IO#Notification',\n args,\n path: eventPath,\n }\n this.postMessage(info)\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
|
2
|
-
import {
|
|
2
|
+
import { Exception } from '@api-client/core/exceptions/exception.js';
|
|
3
3
|
import { Events } from '../../events/Events.js';
|
|
4
4
|
/**
|
|
5
5
|
* A base class for all platform bindings.
|
|
@@ -122,7 +122,7 @@ export class PlatformBindings {
|
|
|
122
122
|
else if (type === 'error') {
|
|
123
123
|
const apiErr = result;
|
|
124
124
|
if (apiErr && apiErr.code) {
|
|
125
|
-
info.reject(
|
|
125
|
+
info.reject(Exception.fromRawException(apiErr, 'Unknown exception'));
|
|
126
126
|
}
|
|
127
127
|
else {
|
|
128
128
|
info.reject(new Error(message));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlatformBindings.js","sourceRoot":"","sources":["../../../../src/bindings/base/PlatformBindings.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-function-type */\nimport { ApiError, type IApiError } from '@api-client/core/runtime/store/Errors.js'\nimport { Events } from '../../events/Events.js'\n\n/**\n * A command sent from the client to a IO thread.\n */\nexport interface IoCommand {\n kind: 'IO#Command'\n id: number\n fn: string\n args: unknown[]\n}\n\n/**\n * An event dispatched from the IO thread to the clients.\n */\nexport interface IoEvent {\n kind: 'IO#Event'\n id: number\n type: 'error' | 'result'\n message?: string\n result?: unknown\n}\n\n/**\n * A special kind of an event from the IO thread to the clients that asks to notify the client\n * using the events system.\n */\nexport interface IoNotification {\n kind: 'IO#Notification'\n path: string\n args: unknown[]\n}\n\n/**\n * Events queue on the client side.\n * This is used when communication with the IO thread via Promises is impossible and event based.\n * The client wraps the execution into a promise and pushes this schema into the queue.\n * When the event is dispatched by the IO thread it resolves/rejects cached promise.\n */\nexport interface QueueItem {\n id: number\n resolve: (value: unknown) => void\n reject: (reason?: Error) => void\n // helpful for debugging\n fn: string\n args: unknown[]\n}\n\n/**\n * A base class for all platform bindings.\n *\n * Platform bindings is the way how the application runs a platform specific logic.\n *\n * For example, it implements how the application stores the state or implements file picker / file saver.\n * Depending on the platform (Electron, web, Chrome, more?) it uses different set of bindings\n * defined in the target application. This creates a framework for the bindings to exist.\n *\n * The IO thread can be any process that is separated from the browser tab context.\n * Can be a WebWorker, ServiceWorker, of an API call to a server.\n * When communication with the binding is not possible via the Promise API\n * this system should be used to communicate with the background page.\n *\n * ```typescript\n * class MyBinding extends ParentBaseBinding {\n * channel: BroadcastChannel;\n * constructor() {\n * super();\n * this.channel = new BroadcastChannel('my-channel');\n * }\n *\n * doStuff(arg: any): Promise<any> {\n * return this.invoke('doStuff', 'own argument', arg);\n * }\n * }\n * ```\n *\n * This assumes that the IO thread has the `doStuff` function implemented.\n * The IO thread extends the `IoThread` class which has the defined the communication logic.\n */\nexport abstract class PlatformBindings {\n /**\n * Used with the queue as the identifier of the request.\n * USe the `getId()` to read a unique request id.\n */\n private id = 0\n\n protected queue: QueueItem[] = []\n\n /**\n * Initializes the bindings.\n */\n abstract initialize(): Promise<void>\n\n /**\n * @returns A unique for the current session id.\n */\n protected getId(): number {\n this.id += 1\n return this.id\n }\n\n /**\n * This method to be implemented by child classes that uses the events system to communicate with the\n * IO thread. The argument is the prepared command message ready to be sent to the IO thread.\n * Specific implementation of the communication channel is left to the child class.\n *\n * @param cmd The command to send to the IO thread.\n */\n protected abstract sendIoCommand(cmd: IoCommand): void\n\n /**\n * Invokes a function in the IO thread.\n *\n * @param fn The function name to invoke (or an identifier understood by the IO thread)\n * @param args The function arguments to pass.\n * @returns A promise that should be returned to the client's application logic.\n * The promise is resolved when the IO thread sends an event with the same identifier generated with this call.\n */\n protected invoke(fn: string, ...args: unknown[]): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const id = this.getId()\n const item = {\n resolve,\n reject,\n id,\n fn,\n args,\n }\n this.queue.push(item)\n const cmd: IoCommand = {\n id,\n fn,\n args,\n kind: 'IO#Command',\n }\n this.sendIoCommand(cmd)\n })\n }\n\n /**\n * To be called by the child class when the IO thread send an event.\n * It recognizes the type of the message sent by the IO thread an performs the requested operation.\n *\n * @param message The message sent by the IO thread.\n */\n protected handleIoMessage(message: IoCommand | IoEvent | IoNotification): void {\n if (!message.kind) {\n // eslint-disable-next-line no-console\n console.warn('Invalid message received on the app-config-channel.', message)\n return\n }\n if (message.kind === 'IO#Command') {\n // message sent by self.\n return\n }\n if (message.kind === 'IO#Notification') {\n this.notify(message)\n } else if (message.kind === 'IO#Event') {\n this.resolve(message)\n }\n }\n\n /**\n * Resolves a pending promise stored in the `queue`.\n *\n * @param event The IO thread event\n */\n protected resolve(event: IoEvent): void {\n const { id, type, message, result } = event\n if (typeof id !== 'number') {\n // eslint-disable-next-line no-console\n console.warn(`Unknown event from the IO thread. Id is not a number.`, event)\n return\n }\n const index = this.queue.findIndex((i) => i.id === id)\n if (index < 0) {\n // this might be used by another tab.\n return\n }\n const info = this.queue[index]\n this.queue.splice(index, 1)\n\n if (type === 'result') {\n info.resolve(result)\n } else if (type === 'error') {\n const apiErr = result as IApiError | undefined\n if (apiErr && apiErr.code) {\n info.reject(new ApiError(apiErr))\n } else {\n info.reject(new Error(message))\n }\n } else {\n // eslint-disable-next-line no-console\n console.warn(`Unknown event from the IO thread`, event)\n }\n }\n\n /**\n * Notifies this tab about something using the `Events` definition.\n *\n * This expects that the event has the path to the event function,\n * for example `Events.Config.Environment.State.created`.\n *\n * @param event The IO thread event\n */\n protected notify(event: IoNotification): void {\n const { path, args } = event\n const parts = path.split('.')\n let current = Events as unknown\n if (parts[0] === 'Events') {\n parts.shift()\n }\n for (const part of parts) {\n // @ts-expect-error It's dynamic access to a deep property.\n if (!current[part]) {\n // eslint-disable-next-line no-console\n console.warn(`Invalid notification path`, path)\n return\n }\n // @ts-expect-error It's dynamic access to a deep property.\n current = current[part]\n }\n ;(current as Function)(...args)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"PlatformBindings.js","sourceRoot":"","sources":["../../../../src/bindings/base/PlatformBindings.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-function-type */\nimport { Exception, type ExceptionSchema } from '@api-client/core/exceptions/exception.js'\nimport { Events } from '../../events/Events.js'\n\n/**\n * A command sent from the client to a IO thread.\n */\nexport interface IoCommand {\n kind: 'IO#Command'\n id: number\n fn: string\n args: unknown[]\n}\n\n/**\n * An event dispatched from the IO thread to the clients.\n */\nexport interface IoEvent {\n kind: 'IO#Event'\n id: number\n type: 'error' | 'result'\n message?: string\n result?: unknown\n}\n\n/**\n * A special kind of an event from the IO thread to the clients that asks to notify the client\n * using the events system.\n */\nexport interface IoNotification {\n kind: 'IO#Notification'\n path: string\n args: unknown[]\n}\n\n/**\n * Events queue on the client side.\n * This is used when communication with the IO thread via Promises is impossible and event based.\n * The client wraps the execution into a promise and pushes this schema into the queue.\n * When the event is dispatched by the IO thread it resolves/rejects cached promise.\n */\nexport interface QueueItem {\n id: number\n resolve: (value: unknown) => void\n reject: (reason?: Error) => void\n // helpful for debugging\n fn: string\n args: unknown[]\n}\n\n/**\n * A base class for all platform bindings.\n *\n * Platform bindings is the way how the application runs a platform specific logic.\n *\n * For example, it implements how the application stores the state or implements file picker / file saver.\n * Depending on the platform (Electron, web, Chrome, more?) it uses different set of bindings\n * defined in the target application. This creates a framework for the bindings to exist.\n *\n * The IO thread can be any process that is separated from the browser tab context.\n * Can be a WebWorker, ServiceWorker, of an API call to a server.\n * When communication with the binding is not possible via the Promise API\n * this system should be used to communicate with the background page.\n *\n * ```typescript\n * class MyBinding extends ParentBaseBinding {\n * channel: BroadcastChannel;\n * constructor() {\n * super();\n * this.channel = new BroadcastChannel('my-channel');\n * }\n *\n * doStuff(arg: any): Promise<any> {\n * return this.invoke('doStuff', 'own argument', arg);\n * }\n * }\n * ```\n *\n * This assumes that the IO thread has the `doStuff` function implemented.\n * The IO thread extends the `IoThread` class which has the defined the communication logic.\n */\nexport abstract class PlatformBindings {\n /**\n * Used with the queue as the identifier of the request.\n * USe the `getId()` to read a unique request id.\n */\n private id = 0\n\n protected queue: QueueItem[] = []\n\n /**\n * Initializes the bindings.\n */\n abstract initialize(): Promise<void>\n\n /**\n * @returns A unique for the current session id.\n */\n protected getId(): number {\n this.id += 1\n return this.id\n }\n\n /**\n * This method to be implemented by child classes that uses the events system to communicate with the\n * IO thread. The argument is the prepared command message ready to be sent to the IO thread.\n * Specific implementation of the communication channel is left to the child class.\n *\n * @param cmd The command to send to the IO thread.\n */\n protected abstract sendIoCommand(cmd: IoCommand): void\n\n /**\n * Invokes a function in the IO thread.\n *\n * @param fn The function name to invoke (or an identifier understood by the IO thread)\n * @param args The function arguments to pass.\n * @returns A promise that should be returned to the client's application logic.\n * The promise is resolved when the IO thread sends an event with the same identifier generated with this call.\n */\n protected invoke(fn: string, ...args: unknown[]): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const id = this.getId()\n const item = {\n resolve,\n reject,\n id,\n fn,\n args,\n }\n this.queue.push(item)\n const cmd: IoCommand = {\n id,\n fn,\n args,\n kind: 'IO#Command',\n }\n this.sendIoCommand(cmd)\n })\n }\n\n /**\n * To be called by the child class when the IO thread send an event.\n * It recognizes the type of the message sent by the IO thread an performs the requested operation.\n *\n * @param message The message sent by the IO thread.\n */\n protected handleIoMessage(message: IoCommand | IoEvent | IoNotification): void {\n if (!message.kind) {\n // eslint-disable-next-line no-console\n console.warn('Invalid message received on the app-config-channel.', message)\n return\n }\n if (message.kind === 'IO#Command') {\n // message sent by self.\n return\n }\n if (message.kind === 'IO#Notification') {\n this.notify(message)\n } else if (message.kind === 'IO#Event') {\n this.resolve(message)\n }\n }\n\n /**\n * Resolves a pending promise stored in the `queue`.\n *\n * @param event The IO thread event\n */\n protected resolve(event: IoEvent): void {\n const { id, type, message, result } = event\n if (typeof id !== 'number') {\n // eslint-disable-next-line no-console\n console.warn(`Unknown event from the IO thread. Id is not a number.`, event)\n return\n }\n const index = this.queue.findIndex((i) => i.id === id)\n if (index < 0) {\n // this might be used by another tab.\n return\n }\n const info = this.queue[index]\n this.queue.splice(index, 1)\n\n if (type === 'result') {\n info.resolve(result)\n } else if (type === 'error') {\n const apiErr = result as ExceptionSchema | undefined\n if (apiErr && apiErr.code) {\n info.reject(Exception.fromRawException(apiErr, 'Unknown exception'))\n } else {\n info.reject(new Error(message))\n }\n } else {\n // eslint-disable-next-line no-console\n console.warn(`Unknown event from the IO thread`, event)\n }\n }\n\n /**\n * Notifies this tab about something using the `Events` definition.\n *\n * This expects that the event has the path to the event function,\n * for example `Events.Config.Environment.State.created`.\n *\n * @param event The IO thread event\n */\n protected notify(event: IoNotification): void {\n const { path, args } = event\n const parts = path.split('.')\n let current = Events as unknown\n if (parts[0] === 'Events') {\n parts.shift()\n }\n for (const part of parts) {\n // @ts-expect-error It's dynamic access to a deep property.\n if (!current[part]) {\n // eslint-disable-next-line no-console\n console.warn(`Invalid notification path`, path)\n return\n }\n // @ts-expect-error It's dynamic access to a deep property.\n current = current[part]\n }\n ;(current as Function)(...args)\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
/* eslint-disable no-console */
|
|
3
|
-
import {
|
|
3
|
+
import { Exception } from '@api-client/core/exceptions/exception.js'
|
|
4
4
|
import { type IoEvent, type IoCommand, type IoNotification } from './PlatformBindings.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -40,9 +40,9 @@ export abstract class IoThread {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
if (typeof fn !== 'string' || !fn) {
|
|
43
|
-
const err = new
|
|
43
|
+
const err = new Exception(
|
|
44
44
|
'Invalid message received on the io-channel. The second argument must be a function name to call.',
|
|
45
|
-
400
|
|
45
|
+
{ status: 400 }
|
|
46
46
|
)
|
|
47
47
|
this.notifyError(id, err)
|
|
48
48
|
console.warn(err.message)
|
|
@@ -53,9 +53,9 @@ export abstract class IoThread {
|
|
|
53
53
|
const isFunction = typeof callable === 'function'
|
|
54
54
|
|
|
55
55
|
if (!isFunction) {
|
|
56
|
-
const err = new
|
|
56
|
+
const err = new Exception(
|
|
57
57
|
`Invalid message received on the io-channel. The function "${fn}" is either not implemented or invalid.`,
|
|
58
|
-
400
|
|
58
|
+
{ status: 400 }
|
|
59
59
|
)
|
|
60
60
|
this.notifyError(id, err)
|
|
61
61
|
console.warn(err.message)
|
|
@@ -65,7 +65,7 @@ export abstract class IoThread {
|
|
|
65
65
|
this.call(callable, id, args)
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
protected notifyError(id: number, error:
|
|
68
|
+
protected notifyError(id: number, error: Exception): void {
|
|
69
69
|
const event: IoEvent = {
|
|
70
70
|
kind: 'IO#Event',
|
|
71
71
|
id,
|
|
@@ -114,7 +114,7 @@ export abstract class IoThread {
|
|
|
114
114
|
} catch (e) {
|
|
115
115
|
event.type = 'error'
|
|
116
116
|
event.message = (e as Error).message
|
|
117
|
-
if ((e as
|
|
117
|
+
if ((e as Exception).status) {
|
|
118
118
|
event.result = e
|
|
119
119
|
}
|
|
120
120
|
this.postMessage(event)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
|
|
2
|
-
import {
|
|
2
|
+
import { Exception, type ExceptionSchema } from '@api-client/core/exceptions/exception.js'
|
|
3
3
|
import { Events } from '../../events/Events.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -185,9 +185,9 @@ export abstract class PlatformBindings {
|
|
|
185
185
|
if (type === 'result') {
|
|
186
186
|
info.resolve(result)
|
|
187
187
|
} else if (type === 'error') {
|
|
188
|
-
const apiErr = result as
|
|
188
|
+
const apiErr = result as ExceptionSchema | undefined
|
|
189
189
|
if (apiErr && apiErr.code) {
|
|
190
|
-
info.reject(
|
|
190
|
+
info.reject(Exception.fromRawException(apiErr, 'Unknown exception'))
|
|
191
191
|
} else {
|
|
192
192
|
info.reject(new Error(message))
|
|
193
193
|
}
|