capacitor-rfid-plugin-ox 0.3.5 → 0.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { Plugin } from '@capacitor/core';\n\nexport interface RFIDPlugin extends Plugin {\n isConnected(): Promise<{ connected: boolean }>;\n\n startScan(): Promise<void>;\n stopScan(): Promise<void>;\n clearData(): Promise<void>;\n\n getScanData(): Promise<any>;\n getOutputPower(): Promise<{ value: number }>;\n setOutputPower(options: { power: number }): Promise<{ value: number }>;\n\n getRange(): Promise<{ value: number }>;\n setRange(options: { range: number }): Promise<{ value: number }>;\n\n getQueryMode(): Promise<{ value: 0 | 1 | 2 | 3 }>;\n setQueryMode(options: {\n queryMode:\n | 0 // epc\n | 1 // epc+tid\n | 2 // epc+user\n | 3; // fasttid\n }): Promise<{ value: number }>;\n\n getReaderType(): Promise<{ value: number }>; // 80 - short, others - long distance mode\n getFirmwareVersion(): Promise<{ value: string }>;\n\n writeEpc(options: {\n epc: string;\n password?: string;\n }): Promise<{ value: number }>;\n writeEpcString(options: {\n epc: string;\n password?: string;\n }): Promise<{ value: number }>;\n\n startSearch(options: { searchableTags: string[], playSound: boolean }): Promise<void>;\n stopSearch(): Promise<void>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { Plugin, PluginListenerHandle } from '@capacitor/core';\n\n/**\n * What the connected Reader can do. Mode gating comes from here, not from the\n * reader type — a desktop reader that can write must not be gated like one\n * that cannot.\n */\nexport interface ReaderCapabilities {\n /** Reader can write an EPC to a tag (Generate & Set mode depends on it). */\n canWrite: boolean;\n /** Reader reports RSSI (Find mode depends on it). */\n hasRssi: boolean;\n /** Reader is a handheld terminal rather than a desk device. */\n isHandheld: boolean;\n /** Output power range in dBm. The power slider renders this range. */\n power: {\n min: number;\n max: number;\n default: number;\n };\n}\n\n/**\n * The four states an operator can act on.\n *\n * `isConnected()` is too coarse for this: a reader that is plugged in but\n * silent answers `false` the same way a missing one does, and the operator\n * needs a different move in each case. `isConnected()` stays as it is.\n */\nexport type ReaderConnectionStatus =\n /** An attempt is running. */\n | 'connecting'\n /** The reader is open and answering. */\n | 'connected'\n /** No reader to talk to — nothing found, or found but not openable. */\n | 'not-found'\n /** The port opened but the reader did not answer a command. */\n | 'not-responding';\n\n/**\n * Why the reader is unusable. The status alone does not say what to do next:\n * a busy reader needs another program closed, a missing one needs the\n * connection checked. The UI picks its message from the reason when there is\n * one.\n *\n * These name what happened to the *reader*, never how it is wired. A driver\n * for a device with no serial port has to be able to answer in this\n * vocabulary too, and the operator has to be told the truth either way —\n * so nothing here says \"COM port\" or \"USB\". The device-specific sentence\n * belongs in `detail`.\n */\nexport type ReaderConnectionReason =\n /** Another program holds the reader. Only one may have it at a time. */\n | 'busy'\n /** No reader in sight — nothing connected, or nothing that is a reader. */\n | 'not-detected'\n /** The reader was there and then went away. */\n | 'disconnected'\n /** The reader is reachable but did not answer. */\n | 'no-answer'\n /**\n * Several readers are connected and none was picked. Guessing here would\n * attach tags read by the wrong device, so nothing is opened until\n * `selectReaderPort` says which one.\n */\n | 'not-chosen';\n\nexport interface ReaderConnectionState {\n status: ReaderConnectionStatus;\n reason?: ReaderConnectionReason;\n /**\n * Driver text: the port list, the command code, the OS error. This is the\n * one field allowed to talk about the wiring, because nothing branches on\n * it — it is shown as-is for support, not translated.\n */\n detail?: string;\n}\n\n/**\n * One reader the driver could talk to.\n *\n * `path` is the identity — `COM3` on Windows, `/dev/cu.usbserial-110`\n * elsewhere. Two identical CH340 adapters carry no serial number of their own,\n * so the path is all that separates them.\n *\n * The caller treats it as **opaque**: it compares, stores and hands it back,\n * and never reads meaning out of it. A driver for a device that is not a\n * serial port puts its own identity here.\n */\nexport interface ReaderPort {\n path: string;\n /** What the OS calls the device. For the operator to read, not to match on. */\n label?: string;\n vendorId?: string;\n productId?: string;\n}\n\nexport interface RFIDPlugin extends Plugin {\n /**\n * Capabilities of the connected Reader.\n *\n * Implementations that predate this method reject. That is a signal, not a\n * failure: the caller treats a rejection as a handheld Mobile Reader.\n */\n getCapabilities(): Promise<ReaderCapabilities>;\n\n /**\n * Connection state for the first render. The stream of later changes comes\n * from the `onConnectionState` listener — \"not responding\" is only found out\n * after a timeout, so it cannot be a return value.\n *\n * A reader is an exclusive resource, so its state is only knowable while it\n * is held: an implementation that is not connected may start an attempt here\n * and answer `connecting`, with the outcome arriving on the listener.\n *\n * Implementations that predate this method reject. The caller then hides the\n * indicator instead of guessing.\n */\n getConnectionState(): Promise<ReaderConnectionState>;\n\n /**\n * The readers plugged in right now, newest listing every call — a port that\n * was there a minute ago may be gone.\n *\n * Only readers, not every serial port: what the caller does with this list\n * is offer it as a choice, and a Bluetooth port is not a choice.\n *\n * Implementations that predate this method reject. The caller then keeps\n * whatever the driver picks on its own.\n */\n listReaderPorts(): Promise<{ ports: ReaderPort[] }>;\n\n /**\n * Use this reader from now on. Reconnects when another port is open.\n *\n * The choice itself is not stored here: the driver is restarted with the\n * app, and where a choice belongs is the caller's question. The caller\n * remembers the path and says it again on the next start.\n *\n * Rejects when the path is not in the current `listReaderPorts()` — a\n * remembered reader that was unplugged has to be chosen again, not opened\n * blindly.\n */\n selectReaderPort(options: { path: string }): Promise<void>;\n\n isConnected(): Promise<{ connected: boolean }>;\n\n startScan(): Promise<void>;\n stopScan(): Promise<void>;\n clearData(): Promise<void>;\n\n getScanData(): Promise<any>;\n getOutputPower(): Promise<{ value: number }>;\n setOutputPower(options: { power: number }): Promise<{ value: number }>;\n\n getRange(): Promise<{ value: number }>;\n setRange(options: { range: number }): Promise<{ value: number }>;\n\n getQueryMode(): Promise<{ value: 0 | 1 | 2 | 3 }>;\n setQueryMode(options: {\n queryMode:\n | 0 // epc\n | 1 // epc+tid\n | 2 // epc+user\n | 3; // fasttid\n }): Promise<{ value: number }>;\n\n getReaderType(): Promise<{ value: number }>; // 80 - short, others - long distance mode\n getFirmwareVersion(): Promise<{ value: string }>;\n\n writeEpc(options: {\n epc: string;\n password?: string;\n }): Promise<{ value: number }>;\n writeEpcString(options: {\n epc: string;\n password?: string;\n }): Promise<{ value: number }>;\n\n startSearch(options: { searchableTags: string[], playSound: boolean }): Promise<void>;\n stopSearch(): Promise<void>;\n\n /** Every connection state change. Fires only on a change, not on a poll. */\n addListener(\n eventName: 'onConnectionState',\n listener: (state: ReaderConnectionState) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: string,\n listenerFunc: (...args: any[]) => any,\n ): Promise<PluginListenerHandle>;\n}\n"]}
@@ -0,0 +1,30 @@
1
+ import type { RFIDPlugin } from './definitions';
2
+ /**
3
+ * The bridge built by the `@capacitor-community/electron` preload
4
+ * (`electron-rt.ts`). Its `addListener` returns an id **string** and is
5
+ * synchronous — `removeListener` takes that same id.
6
+ */
7
+ export interface ElectronBridge {
8
+ addListener(eventName: string, callback: (...args: any[]) => void): string;
9
+ removeListener(id: string): void;
10
+ }
11
+ /**
12
+ * On native platforms Capacitor wraps the `addListener` result into a
13
+ * `PluginListenerHandle` itself (`addListenerNative`), but only when
14
+ * `PluginHeaders` are present. Electron has none, so the bridge's raw id
15
+ * string reaches the UI as-is and `handle.remove()` is missing: the listener
16
+ * is never removed, and scanning does not start the second time the modal
17
+ * opens.
18
+ *
19
+ * Do not wrap it with a `Proxy`. Methods of an object exposed through
20
+ * `contextBridge` arrive as `writable: false, configurable: false`, and for
21
+ * such a property a `get` trap must return **that exact value** — even a
22
+ * bound copy is rejected. Otherwise the engine throws the error we saw on
23
+ * the device:
24
+ * TypeError: 'get' on proxy: property 'startScan' is a read-only and
25
+ * non-configurable data property on the proxy target but the proxy did
26
+ * not return its actual value
27
+ * So the bridge is used as the prototype instead: the other methods are
28
+ * found on it as usual, and only `addListener` is defined on top.
29
+ */
30
+ export declare function withListenerHandles(bridge: ElectronBridge): RFIDPlugin;
@@ -0,0 +1,55 @@
1
+ const SCAN_EVENT = 'onScanEvent';
2
+ /**
3
+ * The Electron main process sends the tags it read in one message per 250 ms
4
+ * window instead of one per frame — a single tag is read about 44 times a
5
+ * second. The contract does not change: the array is unrolled here, so a
6
+ * listener still gets one tag per call.
7
+ */
8
+ const SCAN_BATCH_EVENT = 'onScanEventBatch';
9
+ /**
10
+ * On native platforms Capacitor wraps the `addListener` result into a
11
+ * `PluginListenerHandle` itself (`addListenerNative`), but only when
12
+ * `PluginHeaders` are present. Electron has none, so the bridge's raw id
13
+ * string reaches the UI as-is and `handle.remove()` is missing: the listener
14
+ * is never removed, and scanning does not start the second time the modal
15
+ * opens.
16
+ *
17
+ * Do not wrap it with a `Proxy`. Methods of an object exposed through
18
+ * `contextBridge` arrive as `writable: false, configurable: false`, and for
19
+ * such a property a `get` trap must return **that exact value** — even a
20
+ * bound copy is rejected. Otherwise the engine throws the error we saw on
21
+ * the device:
22
+ * TypeError: 'get' on proxy: property 'startScan' is a read-only and
23
+ * non-configurable data property on the proxy target but the proxy did
24
+ * not return its actual value
25
+ * So the bridge is used as the prototype instead: the other methods are
26
+ * found on it as usual, and only `addListener` is defined on top.
27
+ */
28
+ export function withListenerHandles(bridge) {
29
+ const plugin = Object.create(bridge);
30
+ // A plain `plugin.addListener = ...` does not work: the prototype property
31
+ // is `writable: false`, so [[Set]] blocks it.
32
+ Object.defineProperty(plugin, 'addListener', {
33
+ value: async (eventName, callback) => {
34
+ const ids = [bridge.addListener(eventName, callback)];
35
+ if (eventName === SCAN_EVENT) {
36
+ // A desktop app older than the batch sends one message per tag on
37
+ // `onScanEvent`, a newer one sends only batches. Both are listened
38
+ // for, because the bundle in the browser and the installed desktop
39
+ // app are updated separately; only one of them ever fires.
40
+ ids.push(bridge.addListener(SCAN_BATCH_EVENT, (batch) => {
41
+ for (const event of batch)
42
+ callback(event);
43
+ }));
44
+ }
45
+ return {
46
+ remove: async () => {
47
+ for (const id of ids)
48
+ bridge.removeListener(id);
49
+ },
50
+ };
51
+ },
52
+ });
53
+ return plugin;
54
+ }
55
+ //# sourceMappingURL=electron-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"electron-bridge.js","sourceRoot":"","sources":["../../src/electron-bridge.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,GAAG,aAAa,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAsB;IACxD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAe,CAAC;IAEnD,2EAA2E;IAC3E,8CAA8C;IAC9C,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE;QAC3C,KAAK,EAAE,KAAK,EACV,SAAiB,EACjB,QAAkC,EACH,EAAE;YACjC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;YAEtD,IAAI,SAAS,KAAK,UAAU,EAAE;gBAC5B,kEAAkE;gBAClE,mEAAmE;gBACnE,mEAAmE;gBACnE,2DAA2D;gBAC3D,GAAG,CAAC,IAAI,CACN,MAAM,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,KAAgB,EAAE,EAAE;oBACxD,KAAK,MAAM,KAAK,IAAI,KAAK;wBAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAC7C,CAAC,CAAC,CACH,CAAC;aACH;YAED,OAAO;gBACL,MAAM,EAAE,KAAK,IAAI,EAAE;oBACjB,KAAK,MAAM,EAAE,IAAI,GAAG;wBAAE,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;gBAClD,CAAC;aACF,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\nimport type { RFIDPlugin } from './definitions';\n\n/**\n * The bridge built by the `@capacitor-community/electron` preload\n * (`electron-rt.ts`). Its `addListener` returns an id **string** and is\n * synchronous — `removeListener` takes that same id.\n */\nexport interface ElectronBridge {\n addListener(eventName: string, callback: (...args: any[]) => void): string;\n removeListener(id: string): void;\n}\n\nconst SCAN_EVENT = 'onScanEvent';\n\n/**\n * The Electron main process sends the tags it read in one message per 250 ms\n * window instead of one per frame — a single tag is read about 44 times a\n * second. The contract does not change: the array is unrolled here, so a\n * listener still gets one tag per call.\n */\nconst SCAN_BATCH_EVENT = 'onScanEventBatch';\n\n/**\n * On native platforms Capacitor wraps the `addListener` result into a\n * `PluginListenerHandle` itself (`addListenerNative`), but only when\n * `PluginHeaders` are present. Electron has none, so the bridge's raw id\n * string reaches the UI as-is and `handle.remove()` is missing: the listener\n * is never removed, and scanning does not start the second time the modal\n * opens.\n *\n * Do not wrap it with a `Proxy`. Methods of an object exposed through\n * `contextBridge` arrive as `writable: false, configurable: false`, and for\n * such a property a `get` trap must return **that exact value** — even a\n * bound copy is rejected. Otherwise the engine throws the error we saw on\n * the device:\n * TypeError: 'get' on proxy: property 'startScan' is a read-only and\n * non-configurable data property on the proxy target but the proxy did\n * not return its actual value\n * So the bridge is used as the prototype instead: the other methods are\n * found on it as usual, and only `addListener` is defined on top.\n */\nexport function withListenerHandles(bridge: ElectronBridge): RFIDPlugin {\n const plugin = Object.create(bridge) as RFIDPlugin;\n\n // A plain `plugin.addListener = ...` does not work: the prototype property\n // is `writable: false`, so [[Set]] blocks it.\n Object.defineProperty(plugin, 'addListener', {\n value: async (\n eventName: string,\n callback: (...args: any[]) => void,\n ): Promise<PluginListenerHandle> => {\n const ids = [bridge.addListener(eventName, callback)];\n\n if (eventName === SCAN_EVENT) {\n // A desktop app older than the batch sends one message per tag on\n // `onScanEvent`, a newer one sends only batches. Both are listened\n // for, because the bundle in the browser and the installed desktop\n // app are updated separately; only one of them ever fires.\n ids.push(\n bridge.addListener(SCAN_BATCH_EVENT, (batch: unknown[]) => {\n for (const event of batch) callback(event);\n }),\n );\n }\n\n return {\n remove: async () => {\n for (const id of ids) bridge.removeListener(id);\n },\n };\n },\n });\n\n return plugin;\n}\n"]}
package/dist/esm/index.js CHANGED
@@ -1,6 +1,15 @@
1
1
  import { registerPlugin } from '@capacitor/core';
2
+ import { withListenerHandles } from './electron-bridge';
2
3
  const RFID = registerPlugin('RFID', {
3
4
  web: () => import('./web').then(m => new m.RFIDWeb()),
5
+ electron: () => {
6
+ var _a, _b;
7
+ const bridge = (_b = (_a = window.CapacitorCustomPlatform) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.RFID;
8
+ if (!bridge) {
9
+ throw new Error('RFID is not registered in the Electron runtime. Register the driver in electron-plugins.js.');
10
+ }
11
+ return withListenerHandles(bridge);
12
+ },
4
13
  });
5
14
  export * from './definitions';
6
15
  export { RFID };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,IAAI,GAAG,cAAc,CAAa,MAAM,EAAE;IAC9C,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;CACtD,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { RFIDPlugin } from './definitions';\n\nconst RFID = registerPlugin<RFIDPlugin>('RFID', {\n web: () => import('./web').then(m => new m.RFIDWeb()),\n});\n\nexport * from './definitions';\nexport { RFID };\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAMxD,MAAM,IAAI,GAAG,cAAc,CAAa,MAAM,EAAE;IAC9C,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;IACrD,QAAQ,EAAE,GAAG,EAAE;;QACb,MAAM,MAAM,eAAI,MAAyB,CAAC,uBAAuB,0CAAE,OAAO,0CACtE,IAAI,CAAC;QAET,IAAI,CAAC,MAAM,EAAE;YACX,MAAM,IAAI,KAAK,CACb,6FAA6F,CAC9F,CAAC;SACH;QAED,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;CACF,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { RFIDPlugin } from './definitions';\nimport type { ElectronBridge } from './electron-bridge';\nimport { withListenerHandles } from './electron-bridge';\n\ntype ElectronWindow = Window & {\n CapacitorCustomPlatform?: { plugins?: { RFID?: ElectronBridge } };\n};\n\nconst RFID = registerPlugin<RFIDPlugin>('RFID', {\n web: () => import('./web').then(m => new m.RFIDWeb()),\n electron: () => {\n const bridge = (window as ElectronWindow).CapacitorCustomPlatform?.plugins\n ?.RFID;\n\n if (!bridge) {\n throw new Error(\n 'RFID is not registered in the Electron runtime. Register the driver in electron-plugins.js.',\n );\n }\n\n return withListenerHandles(bridge);\n },\n});\n\nexport * from './definitions';\nexport { RFID };\n"]}
package/dist/esm/web.d.ts CHANGED
@@ -1,35 +1,54 @@
1
1
  import { WebPlugin } from '@capacitor/core';
2
- import type { RFIDPlugin } from './definitions';
2
+ import type { PluginListenerHandle } from '@capacitor/core';
3
+ import type { ReaderCapabilities, ReaderConnectionState, ReaderPort, RFIDPlugin } from './definitions';
3
4
  export declare class RFIDWeb extends WebPlugin implements RFIDPlugin {
5
+ /**
6
+ * The one method the browser can answer truthfully. Everything else rejects:
7
+ * a silent `resolve` makes the UI report a success that never happened.
8
+ */
4
9
  isConnected(): Promise<{
5
10
  connected: boolean;
6
11
  }>;
12
+ /**
13
+ * Events never fire without a Reader, so registering a listener here would be
14
+ * the same silent lie as a resolving `startScan()`.
15
+ */
16
+ addListener(): Promise<PluginListenerHandle>;
17
+ getCapabilities(): Promise<ReaderCapabilities>;
18
+ /**
19
+ * Not `not-found`: that state tells the operator to check the cable, and
20
+ * there is no cable to check in a browser. The rejection carries the one
21
+ * useful sentence — open the desktop app or the handheld.
22
+ */
23
+ getConnectionState(): Promise<ReaderConnectionState>;
24
+ /**
25
+ * Not an empty list: "no readers plugged in" would send the operator to look
26
+ * for a cable, and the browser has no serial ports to look at.
27
+ */
28
+ listReaderPorts(): Promise<{
29
+ ports: ReaderPort[];
30
+ }>;
31
+ selectReaderPort(): Promise<void>;
7
32
  startScan(): Promise<void>;
8
33
  stopScan(): Promise<void>;
9
34
  clearData(): Promise<void>;
10
- getScanData(): Promise<void>;
35
+ getScanData(): Promise<any>;
11
36
  getOutputPower(): Promise<{
12
37
  value: number;
13
38
  }>;
14
- setOutputPower(options: {
15
- power: number;
16
- }): Promise<{
39
+ setOutputPower(): Promise<{
17
40
  value: number;
18
41
  }>;
19
42
  getRange(): Promise<{
20
43
  value: number;
21
44
  }>;
22
- setRange(options: {
23
- range: number;
24
- }): Promise<{
45
+ setRange(): Promise<{
25
46
  value: number;
26
47
  }>;
27
48
  getQueryMode(): Promise<{
28
49
  value: 0 | 1 | 2 | 3;
29
50
  }>;
30
- setQueryMode(options: {
31
- queryMode: 0 | 1 | 2 | 3;
32
- }): Promise<{
51
+ setQueryMode(): Promise<{
33
52
  value: number;
34
53
  }>;
35
54
  getReaderType(): Promise<{
@@ -38,21 +57,12 @@ export declare class RFIDWeb extends WebPlugin implements RFIDPlugin {
38
57
  getFirmwareVersion(): Promise<{
39
58
  value: string;
40
59
  }>;
41
- writeEpc(options: {
42
- epc: string;
43
- password?: string;
44
- }): Promise<{
60
+ writeEpc(): Promise<{
45
61
  value: number;
46
62
  }>;
47
- writeEpcString(options: {
48
- epc: string;
49
- password?: string;
50
- }): Promise<{
63
+ writeEpcString(): Promise<{
51
64
  value: number;
52
65
  }>;
53
- startSearch(options: {
54
- searchableTags: string[];
55
- playSound: boolean;
56
- }): Promise<void>;
66
+ startSearch(): Promise<void>;
57
67
  stopSearch(): Promise<void>;
58
68
  }
package/dist/esm/web.js CHANGED
@@ -1,58 +1,88 @@
1
1
  import { WebPlugin } from '@capacitor/core';
2
+ const NO_READER_ON_WEB = 'No RFID Reader in the browser. Use the desktop app (ox-desktop) or the Android handheld.';
2
3
  export class RFIDWeb extends WebPlugin {
3
- isConnected() {
4
- return Promise.resolve({ connected: false });
5
- }
6
- startScan() {
7
- return Promise.resolve();
8
- }
9
- stopScan() {
10
- return Promise.resolve();
11
- }
12
- clearData() {
13
- return Promise.resolve();
14
- }
15
- getScanData() {
16
- return Promise.resolve();
4
+ /**
5
+ * The one method the browser can answer truthfully. Everything else rejects:
6
+ * a silent `resolve` makes the UI report a success that never happened.
7
+ */
8
+ async isConnected() {
9
+ return { connected: false };
10
+ }
11
+ /**
12
+ * Events never fire without a Reader, so registering a listener here would be
13
+ * the same silent lie as a resolving `startScan()`.
14
+ */
15
+ async addListener() {
16
+ throw this.unimplemented(NO_READER_ON_WEB);
17
+ }
18
+ async getCapabilities() {
19
+ throw this.unimplemented(NO_READER_ON_WEB);
20
+ }
21
+ /**
22
+ * Not `not-found`: that state tells the operator to check the cable, and
23
+ * there is no cable to check in a browser. The rejection carries the one
24
+ * useful sentence — open the desktop app or the handheld.
25
+ */
26
+ async getConnectionState() {
27
+ throw this.unimplemented(NO_READER_ON_WEB);
28
+ }
29
+ /**
30
+ * Not an empty list: "no readers plugged in" would send the operator to look
31
+ * for a cable, and the browser has no serial ports to look at.
32
+ */
33
+ async listReaderPorts() {
34
+ throw this.unimplemented(NO_READER_ON_WEB);
35
+ }
36
+ async selectReaderPort() {
37
+ throw this.unimplemented(NO_READER_ON_WEB);
38
+ }
39
+ async startScan() {
40
+ throw this.unimplemented(NO_READER_ON_WEB);
41
+ }
42
+ async stopScan() {
43
+ throw this.unimplemented(NO_READER_ON_WEB);
44
+ }
45
+ async clearData() {
46
+ throw this.unimplemented(NO_READER_ON_WEB);
47
+ }
48
+ async getScanData() {
49
+ throw this.unimplemented(NO_READER_ON_WEB);
17
50
  }
18
51
  async getOutputPower() {
19
- return { value: 0 };
52
+ throw this.unimplemented(NO_READER_ON_WEB);
20
53
  }
21
- async setOutputPower(options) {
22
- return { value: options.power };
54
+ async setOutputPower() {
55
+ throw this.unimplemented(NO_READER_ON_WEB);
23
56
  }
24
57
  async getRange() {
25
- return { value: 0 };
58
+ throw this.unimplemented(NO_READER_ON_WEB);
26
59
  }
27
- async setRange(options) {
28
- return { value: options.range };
60
+ async setRange() {
61
+ throw this.unimplemented(NO_READER_ON_WEB);
29
62
  }
30
63
  async getQueryMode() {
31
- return { value: 0 };
64
+ throw this.unimplemented(NO_READER_ON_WEB);
32
65
  }
33
- async setQueryMode(options) {
34
- return { value: options.queryMode };
66
+ async setQueryMode() {
67
+ throw this.unimplemented(NO_READER_ON_WEB);
35
68
  }
36
69
  async getReaderType() {
37
- return { value: 0 };
70
+ throw this.unimplemented(NO_READER_ON_WEB);
38
71
  }
39
72
  async getFirmwareVersion() {
40
- return { value: 'not implemented' };
73
+ throw this.unimplemented(NO_READER_ON_WEB);
41
74
  }
42
- async writeEpc(options) {
43
- console.log(options.epc);
44
- return { value: -1 };
75
+ async writeEpc() {
76
+ throw this.unimplemented(NO_READER_ON_WEB);
45
77
  }
46
- async writeEpcString(options) {
47
- console.log(options.epc);
48
- return { value: -1 };
78
+ async writeEpcString() {
79
+ throw this.unimplemented(NO_READER_ON_WEB);
49
80
  }
50
- async startSearch(options) {
51
- console.log(options.searchableTags);
52
- return Promise.resolve();
81
+ async startSearch() {
82
+ throw this.unimplemented(NO_READER_ON_WEB);
53
83
  }
54
84
  async stopSearch() {
55
- return Promise.resolve();
85
+ throw this.unimplemented(NO_READER_ON_WEB);
56
86
  }
57
87
  }
58
88
  //# sourceMappingURL=web.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,OAAQ,SAAQ,SAAS;IACpC,WAAW;QACT,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,SAAS;QACP,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,QAAQ;QACN,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,SAAS;QACP,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,WAAW;QACT,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAA0B;QAC7C,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAA0B;QACvC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAElB;QACC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAGd;QACC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAEzB,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAGpB;QACC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAEzB,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAyD;QACzE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAEpC,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { RFIDPlugin } from './definitions';\n\nexport class RFIDWeb extends WebPlugin implements RFIDPlugin {\n isConnected(): Promise<{ connected: boolean }> {\n return Promise.resolve({ connected: false });\n }\n\n startScan(): Promise<void> {\n return Promise.resolve();\n }\n\n stopScan(): Promise<void> {\n return Promise.resolve();\n }\n\n clearData(): Promise<void> {\n return Promise.resolve();\n }\n\n getScanData(): Promise<void> {\n return Promise.resolve();\n }\n\n async getOutputPower(): Promise<{ value: number }> {\n return { value: 0 };\n }\n\n async setOutputPower(options: { power: number }): Promise<{ value: number }> {\n return { value: options.power };\n }\n\n async getRange(): Promise<{ value: number }> {\n return { value: 0 };\n }\n\n async setRange(options: { range: number }): Promise<{ value: number }> {\n return { value: options.range };\n }\n\n async getQueryMode(): Promise<{ value: 0 | 1 | 2 | 3 }> {\n return { value: 0 };\n }\n\n async setQueryMode(options: {\n queryMode: 0 | 1 | 2 | 3;\n }): Promise<{ value: number }> {\n return { value: options.queryMode };\n }\n\n async getReaderType(): Promise<{ value: number }> {\n return { value: 0 };\n }\n\n async getFirmwareVersion(): Promise<{ value: string }> {\n return { value: 'not implemented' };\n }\n\n async writeEpc(options: {\n epc: string;\n password?: string;\n }): Promise<{ value: number }> {\n console.log(options.epc);\n\n return { value: -1 };\n }\n\n async writeEpcString(options: {\n epc: string;\n password?: string;\n }): Promise<{ value: number }> {\n console.log(options.epc);\n\n return { value: -1 };\n }\n\n async startSearch(options: { searchableTags: string[], playSound: boolean }): Promise<void> {\n console.log(options.searchableTags);\n\n return Promise.resolve();\n }\n\n async stopSearch(): Promise<void> {\n return Promise.resolve();\n }\n}\n"]}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAU5C,MAAM,gBAAgB,GACpB,0FAA0F,CAAC;AAE7F,MAAM,OAAO,OAAQ,SAAQ,SAAS;IACpC;;;OAGG;IACH,KAAK,CAAC,WAAW;QACf,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,WAAW;QACf,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,kBAAkB;QACtB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,kBAAkB;QACtB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport type { PluginListenerHandle } from '@capacitor/core';\n\nimport type {\n ReaderCapabilities,\n ReaderConnectionState,\n ReaderPort,\n RFIDPlugin,\n} from './definitions';\n\nconst NO_READER_ON_WEB =\n 'No RFID Reader in the browser. Use the desktop app (ox-desktop) or the Android handheld.';\n\nexport class RFIDWeb extends WebPlugin implements RFIDPlugin {\n /**\n * The one method the browser can answer truthfully. Everything else rejects:\n * a silent `resolve` makes the UI report a success that never happened.\n */\n async isConnected(): Promise<{ connected: boolean }> {\n return { connected: false };\n }\n\n /**\n * Events never fire without a Reader, so registering a listener here would be\n * the same silent lie as a resolving `startScan()`.\n */\n async addListener(): Promise<PluginListenerHandle> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async getCapabilities(): Promise<ReaderCapabilities> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n /**\n * Not `not-found`: that state tells the operator to check the cable, and\n * there is no cable to check in a browser. The rejection carries the one\n * useful sentence — open the desktop app or the handheld.\n */\n async getConnectionState(): Promise<ReaderConnectionState> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n /**\n * Not an empty list: \"no readers plugged in\" would send the operator to look\n * for a cable, and the browser has no serial ports to look at.\n */\n async listReaderPorts(): Promise<{ ports: ReaderPort[] }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async selectReaderPort(): Promise<void> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async startScan(): Promise<void> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async stopScan(): Promise<void> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async clearData(): Promise<void> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async getScanData(): Promise<any> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async getOutputPower(): Promise<{ value: number }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async setOutputPower(): Promise<{ value: number }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async getRange(): Promise<{ value: number }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async setRange(): Promise<{ value: number }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async getQueryMode(): Promise<{ value: 0 | 1 | 2 | 3 }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async setQueryMode(): Promise<{ value: number }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async getReaderType(): Promise<{ value: number }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async getFirmwareVersion(): Promise<{ value: string }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async writeEpc(): Promise<{ value: number }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async writeEpcString(): Promise<{ value: number }> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async startSearch(): Promise<void> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n\n async stopSearch(): Promise<void> {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n}\n"]}
@@ -4,64 +4,157 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var core = require('@capacitor/core');
6
6
 
7
+ const SCAN_EVENT = 'onScanEvent';
8
+ /**
9
+ * The Electron main process sends the tags it read in one message per 250 ms
10
+ * window instead of one per frame — a single tag is read about 44 times a
11
+ * second. The contract does not change: the array is unrolled here, so a
12
+ * listener still gets one tag per call.
13
+ */
14
+ const SCAN_BATCH_EVENT = 'onScanEventBatch';
15
+ /**
16
+ * On native platforms Capacitor wraps the `addListener` result into a
17
+ * `PluginListenerHandle` itself (`addListenerNative`), but only when
18
+ * `PluginHeaders` are present. Electron has none, so the bridge's raw id
19
+ * string reaches the UI as-is and `handle.remove()` is missing: the listener
20
+ * is never removed, and scanning does not start the second time the modal
21
+ * opens.
22
+ *
23
+ * Do not wrap it with a `Proxy`. Methods of an object exposed through
24
+ * `contextBridge` arrive as `writable: false, configurable: false`, and for
25
+ * such a property a `get` trap must return **that exact value** — even a
26
+ * bound copy is rejected. Otherwise the engine throws the error we saw on
27
+ * the device:
28
+ * TypeError: 'get' on proxy: property 'startScan' is a read-only and
29
+ * non-configurable data property on the proxy target but the proxy did
30
+ * not return its actual value
31
+ * So the bridge is used as the prototype instead: the other methods are
32
+ * found on it as usual, and only `addListener` is defined on top.
33
+ */
34
+ function withListenerHandles(bridge) {
35
+ const plugin = Object.create(bridge);
36
+ // A plain `plugin.addListener = ...` does not work: the prototype property
37
+ // is `writable: false`, so [[Set]] blocks it.
38
+ Object.defineProperty(plugin, 'addListener', {
39
+ value: async (eventName, callback) => {
40
+ const ids = [bridge.addListener(eventName, callback)];
41
+ if (eventName === SCAN_EVENT) {
42
+ // A desktop app older than the batch sends one message per tag on
43
+ // `onScanEvent`, a newer one sends only batches. Both are listened
44
+ // for, because the bundle in the browser and the installed desktop
45
+ // app are updated separately; only one of them ever fires.
46
+ ids.push(bridge.addListener(SCAN_BATCH_EVENT, (batch) => {
47
+ for (const event of batch)
48
+ callback(event);
49
+ }));
50
+ }
51
+ return {
52
+ remove: async () => {
53
+ for (const id of ids)
54
+ bridge.removeListener(id);
55
+ },
56
+ };
57
+ },
58
+ });
59
+ return plugin;
60
+ }
61
+
7
62
  const RFID = core.registerPlugin('RFID', {
8
63
  web: () => Promise.resolve().then(function () { return web; }).then(m => new m.RFIDWeb()),
64
+ electron: () => {
65
+ var _a, _b;
66
+ const bridge = (_b = (_a = window.CapacitorCustomPlatform) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.RFID;
67
+ if (!bridge) {
68
+ throw new Error('RFID is not registered in the Electron runtime. Register the driver in electron-plugins.js.');
69
+ }
70
+ return withListenerHandles(bridge);
71
+ },
9
72
  });
10
73
 
74
+ const NO_READER_ON_WEB = 'No RFID Reader in the browser. Use the desktop app (ox-desktop) or the Android handheld.';
11
75
  class RFIDWeb extends core.WebPlugin {
12
- isConnected() {
13
- return Promise.resolve({ connected: false });
14
- }
15
- startScan() {
16
- return Promise.resolve();
17
- }
18
- stopScan() {
19
- return Promise.resolve();
20
- }
21
- clearData() {
22
- return Promise.resolve();
23
- }
24
- getScanData() {
25
- return Promise.resolve();
76
+ /**
77
+ * The one method the browser can answer truthfully. Everything else rejects:
78
+ * a silent `resolve` makes the UI report a success that never happened.
79
+ */
80
+ async isConnected() {
81
+ return { connected: false };
82
+ }
83
+ /**
84
+ * Events never fire without a Reader, so registering a listener here would be
85
+ * the same silent lie as a resolving `startScan()`.
86
+ */
87
+ async addListener() {
88
+ throw this.unimplemented(NO_READER_ON_WEB);
89
+ }
90
+ async getCapabilities() {
91
+ throw this.unimplemented(NO_READER_ON_WEB);
92
+ }
93
+ /**
94
+ * Not `not-found`: that state tells the operator to check the cable, and
95
+ * there is no cable to check in a browser. The rejection carries the one
96
+ * useful sentence — open the desktop app or the handheld.
97
+ */
98
+ async getConnectionState() {
99
+ throw this.unimplemented(NO_READER_ON_WEB);
100
+ }
101
+ /**
102
+ * Not an empty list: "no readers plugged in" would send the operator to look
103
+ * for a cable, and the browser has no serial ports to look at.
104
+ */
105
+ async listReaderPorts() {
106
+ throw this.unimplemented(NO_READER_ON_WEB);
107
+ }
108
+ async selectReaderPort() {
109
+ throw this.unimplemented(NO_READER_ON_WEB);
110
+ }
111
+ async startScan() {
112
+ throw this.unimplemented(NO_READER_ON_WEB);
113
+ }
114
+ async stopScan() {
115
+ throw this.unimplemented(NO_READER_ON_WEB);
116
+ }
117
+ async clearData() {
118
+ throw this.unimplemented(NO_READER_ON_WEB);
119
+ }
120
+ async getScanData() {
121
+ throw this.unimplemented(NO_READER_ON_WEB);
26
122
  }
27
123
  async getOutputPower() {
28
- return { value: 0 };
124
+ throw this.unimplemented(NO_READER_ON_WEB);
29
125
  }
30
- async setOutputPower(options) {
31
- return { value: options.power };
126
+ async setOutputPower() {
127
+ throw this.unimplemented(NO_READER_ON_WEB);
32
128
  }
33
129
  async getRange() {
34
- return { value: 0 };
130
+ throw this.unimplemented(NO_READER_ON_WEB);
35
131
  }
36
- async setRange(options) {
37
- return { value: options.range };
132
+ async setRange() {
133
+ throw this.unimplemented(NO_READER_ON_WEB);
38
134
  }
39
135
  async getQueryMode() {
40
- return { value: 0 };
136
+ throw this.unimplemented(NO_READER_ON_WEB);
41
137
  }
42
- async setQueryMode(options) {
43
- return { value: options.queryMode };
138
+ async setQueryMode() {
139
+ throw this.unimplemented(NO_READER_ON_WEB);
44
140
  }
45
141
  async getReaderType() {
46
- return { value: 0 };
142
+ throw this.unimplemented(NO_READER_ON_WEB);
47
143
  }
48
144
  async getFirmwareVersion() {
49
- return { value: 'not implemented' };
145
+ throw this.unimplemented(NO_READER_ON_WEB);
50
146
  }
51
- async writeEpc(options) {
52
- console.log(options.epc);
53
- return { value: -1 };
147
+ async writeEpc() {
148
+ throw this.unimplemented(NO_READER_ON_WEB);
54
149
  }
55
- async writeEpcString(options) {
56
- console.log(options.epc);
57
- return { value: -1 };
150
+ async writeEpcString() {
151
+ throw this.unimplemented(NO_READER_ON_WEB);
58
152
  }
59
- async startSearch(options) {
60
- console.log(options.searchableTags);
61
- return Promise.resolve();
153
+ async startSearch() {
154
+ throw this.unimplemented(NO_READER_ON_WEB);
62
155
  }
63
156
  async stopSearch() {
64
- return Promise.resolve();
157
+ throw this.unimplemented(NO_READER_ON_WEB);
65
158
  }
66
159
  }
67
160
 
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst RFID = registerPlugin('RFID', {\n web: () => import('./web').then(m => new m.RFIDWeb()),\n});\nexport * from './definitions';\nexport { RFID };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class RFIDWeb extends WebPlugin {\n isConnected() {\n return Promise.resolve({ connected: false });\n }\n startScan() {\n return Promise.resolve();\n }\n stopScan() {\n return Promise.resolve();\n }\n clearData() {\n return Promise.resolve();\n }\n getScanData() {\n return Promise.resolve();\n }\n async getOutputPower() {\n return { value: 0 };\n }\n async setOutputPower(options) {\n return { value: options.power };\n }\n async getRange() {\n return { value: 0 };\n }\n async setRange(options) {\n return { value: options.range };\n }\n async getQueryMode() {\n return { value: 0 };\n }\n async setQueryMode(options) {\n return { value: options.queryMode };\n }\n async getReaderType() {\n return { value: 0 };\n }\n async getFirmwareVersion() {\n return { value: 'not implemented' };\n }\n async writeEpc(options) {\n console.log(options.epc);\n return { value: -1 };\n }\n async writeEpcString(options) {\n console.log(options.epc);\n return { value: -1 };\n }\n async startSearch(options) {\n console.log(options.searchableTags);\n return Promise.resolve();\n }\n async stopSearch() {\n return Promise.resolve();\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;;;AACK,MAAC,IAAI,GAAGA,mBAAc,CAAC,MAAM,EAAE;AACpC,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;AACzD,CAAC;;ACFM,MAAM,OAAO,SAASC,cAAS,CAAC;AACvC,IAAI,WAAW,GAAG;AAClB,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;AACrD,KAAK;AACL,IAAI,SAAS,GAAG;AAChB,QAAQ,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AACjC,KAAK;AACL,IAAI,QAAQ,GAAG;AACf,QAAQ,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AACjC,KAAK;AACL,IAAI,SAAS,GAAG;AAChB,QAAQ,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AACjC,KAAK;AACL,IAAI,WAAW,GAAG;AAClB,QAAQ,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AACjC,KAAK;AACL,IAAI,MAAM,cAAc,GAAG;AAC3B,QAAQ,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAC5B,KAAK;AACL,IAAI,MAAM,cAAc,CAAC,OAAO,EAAE;AAClC,QAAQ,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;AACxC,KAAK;AACL,IAAI,MAAM,QAAQ,GAAG;AACrB,QAAQ,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAC5B,KAAK;AACL,IAAI,MAAM,QAAQ,CAAC,OAAO,EAAE;AAC5B,QAAQ,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;AACxC,KAAK;AACL,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAC5B,KAAK;AACL,IAAI,MAAM,YAAY,CAAC,OAAO,EAAE;AAChC,QAAQ,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC;AAC5C,KAAK;AACL,IAAI,MAAM,aAAa,GAAG;AAC1B,QAAQ,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AAC5B,KAAK;AACL,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;AAC5C,KAAK;AACL,IAAI,MAAM,QAAQ,CAAC,OAAO,EAAE;AAC5B,QAAQ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACjC,QAAQ,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;AAC7B,KAAK;AACL,IAAI,MAAM,cAAc,CAAC,OAAO,EAAE;AAClC,QAAQ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACjC,QAAQ,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;AAC7B,KAAK;AACL,IAAI,MAAM,WAAW,CAAC,OAAO,EAAE;AAC/B,QAAQ,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;AAC5C,QAAQ,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AACjC,KAAK;AACL,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;AACjC,KAAK;AACL;;;;;;;;;"}
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/electron-bridge.js","esm/index.js","esm/web.js"],"sourcesContent":["const SCAN_EVENT = 'onScanEvent';\n/**\n * The Electron main process sends the tags it read in one message per 250 ms\n * window instead of one per frame — a single tag is read about 44 times a\n * second. The contract does not change: the array is unrolled here, so a\n * listener still gets one tag per call.\n */\nconst SCAN_BATCH_EVENT = 'onScanEventBatch';\n/**\n * On native platforms Capacitor wraps the `addListener` result into a\n * `PluginListenerHandle` itself (`addListenerNative`), but only when\n * `PluginHeaders` are present. Electron has none, so the bridge's raw id\n * string reaches the UI as-is and `handle.remove()` is missing: the listener\n * is never removed, and scanning does not start the second time the modal\n * opens.\n *\n * Do not wrap it with a `Proxy`. Methods of an object exposed through\n * `contextBridge` arrive as `writable: false, configurable: false`, and for\n * such a property a `get` trap must return **that exact value** — even a\n * bound copy is rejected. Otherwise the engine throws the error we saw on\n * the device:\n * TypeError: 'get' on proxy: property 'startScan' is a read-only and\n * non-configurable data property on the proxy target but the proxy did\n * not return its actual value\n * So the bridge is used as the prototype instead: the other methods are\n * found on it as usual, and only `addListener` is defined on top.\n */\nexport function withListenerHandles(bridge) {\n const plugin = Object.create(bridge);\n // A plain `plugin.addListener = ...` does not work: the prototype property\n // is `writable: false`, so [[Set]] blocks it.\n Object.defineProperty(plugin, 'addListener', {\n value: async (eventName, callback) => {\n const ids = [bridge.addListener(eventName, callback)];\n if (eventName === SCAN_EVENT) {\n // A desktop app older than the batch sends one message per tag on\n // `onScanEvent`, a newer one sends only batches. Both are listened\n // for, because the bundle in the browser and the installed desktop\n // app are updated separately; only one of them ever fires.\n ids.push(bridge.addListener(SCAN_BATCH_EVENT, (batch) => {\n for (const event of batch)\n callback(event);\n }));\n }\n return {\n remove: async () => {\n for (const id of ids)\n bridge.removeListener(id);\n },\n };\n },\n });\n return plugin;\n}\n//# sourceMappingURL=electron-bridge.js.map","import { registerPlugin } from '@capacitor/core';\nimport { withListenerHandles } from './electron-bridge';\nconst RFID = registerPlugin('RFID', {\n web: () => import('./web').then(m => new m.RFIDWeb()),\n electron: () => {\n var _a, _b;\n const bridge = (_b = (_a = window.CapacitorCustomPlatform) === null || _a === void 0 ? void 0 : _a.plugins) === null || _b === void 0 ? void 0 : _b.RFID;\n if (!bridge) {\n throw new Error('RFID is not registered in the Electron runtime. Register the driver in electron-plugins.js.');\n }\n return withListenerHandles(bridge);\n },\n});\nexport * from './definitions';\nexport { RFID };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nconst NO_READER_ON_WEB = 'No RFID Reader in the browser. Use the desktop app (ox-desktop) or the Android handheld.';\nexport class RFIDWeb extends WebPlugin {\n /**\n * The one method the browser can answer truthfully. Everything else rejects:\n * a silent `resolve` makes the UI report a success that never happened.\n */\n async isConnected() {\n return { connected: false };\n }\n /**\n * Events never fire without a Reader, so registering a listener here would be\n * the same silent lie as a resolving `startScan()`.\n */\n async addListener() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async getCapabilities() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n /**\n * Not `not-found`: that state tells the operator to check the cable, and\n * there is no cable to check in a browser. The rejection carries the one\n * useful sentence — open the desktop app or the handheld.\n */\n async getConnectionState() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n /**\n * Not an empty list: \"no readers plugged in\" would send the operator to look\n * for a cable, and the browser has no serial ports to look at.\n */\n async listReaderPorts() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async selectReaderPort() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async startScan() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async stopScan() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async clearData() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async getScanData() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async getOutputPower() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async setOutputPower() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async getRange() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async setRange() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async getQueryMode() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async setQueryMode() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async getReaderType() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async getFirmwareVersion() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async writeEpc() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async writeEpcString() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async startSearch() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n async stopSearch() {\n throw this.unimplemented(NO_READER_ON_WEB);\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;;;AAAA,MAAM,UAAU,GAAG,aAAa,CAAC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,mBAAmB,CAAC,MAAM,EAAE;AAC5C,IAAI,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACzC;AACA;AACA,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE;AACjD,QAAQ,KAAK,EAAE,OAAO,SAAS,EAAE,QAAQ,KAAK;AAC9C,YAAY,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC;AAClE,YAAY,IAAI,SAAS,KAAK,UAAU,EAAE;AAC1C;AACA;AACA;AACA;AACA,gBAAgB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,KAAK,KAAK;AACzE,oBAAoB,KAAK,MAAM,KAAK,IAAI,KAAK;AAC7C,wBAAwB,QAAQ,CAAC,KAAK,CAAC,CAAC;AACxC,iBAAiB,CAAC,CAAC,CAAC;AACpB,aAAa;AACb,YAAY,OAAO;AACnB,gBAAgB,MAAM,EAAE,YAAY;AACpC,oBAAoB,KAAK,MAAM,EAAE,IAAI,GAAG;AACxC,wBAAwB,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;AAClD,iBAAiB;AACjB,aAAa,CAAC;AACd,SAAS;AACT,KAAK,CAAC,CAAC;AACP,IAAI,OAAO,MAAM,CAAC;AAClB;;ACnDK,MAAC,IAAI,GAAGA,mBAAc,CAAC,MAAM,EAAE;AACpC,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;AACzD,IAAI,QAAQ,EAAE,MAAM;AACpB,QAAQ,IAAI,EAAE,EAAE,EAAE,CAAC;AACnB,QAAQ,MAAM,MAAM,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,uBAAuB,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,MAAM,IAAI,IAAI,EAAE,KAAK,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;AACjK,QAAQ,IAAI,CAAC,MAAM,EAAE;AACrB,YAAY,MAAM,IAAI,KAAK,CAAC,6FAA6F,CAAC,CAAC;AAC3H,SAAS;AACT,QAAQ,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC3C,KAAK;AACL,CAAC;;ACXD,MAAM,gBAAgB,GAAG,0FAA0F,CAAC;AAC7G,MAAM,OAAO,SAASC,cAAS,CAAC;AACvC;AACA;AACA;AACA;AACA,IAAI,MAAM,WAAW,GAAG;AACxB,QAAQ,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACpC,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,MAAM,WAAW,GAAG;AACxB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,eAAe,GAAG;AAC5B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL;AACA;AACA;AACA;AACA,IAAI,MAAM,eAAe,GAAG;AAC5B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,gBAAgB,GAAG;AAC7B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,SAAS,GAAG;AACtB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,QAAQ,GAAG;AACrB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,SAAS,GAAG;AACtB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,WAAW,GAAG;AACxB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,cAAc,GAAG;AAC3B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,cAAc,GAAG;AAC3B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,QAAQ,GAAG;AACrB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,QAAQ,GAAG;AACrB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,aAAa,GAAG;AAC1B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,kBAAkB,GAAG;AAC/B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,QAAQ,GAAG;AACrB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,cAAc,GAAG;AAC3B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,WAAW,GAAG;AACxB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,UAAU,GAAG;AACvB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;AACnD,KAAK;AACL;;;;;;;;;"}