@munchi_oy/react-native-epson-printer 1.0.7 → 1.0.8
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/README.md +27 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/version.d.ts +1 -1
- package/ios/Vendors/Epson/MunchiEpsonModule.swift +285 -249
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,6 +30,25 @@ This package provides:
|
|
|
30
30
|
|
|
31
31
|
This package does not include Star or Sunmi drivers.
|
|
32
32
|
|
|
33
|
+
## Runtime Contract
|
|
34
|
+
|
|
35
|
+
For both iOS and Android, the SDK aims to provide this behavior:
|
|
36
|
+
|
|
37
|
+
- Native printer work may take time, especially for Bluetooth connection, status checks, and image printing.
|
|
38
|
+
- Slow printer operations are acceptable; visible app hangs are not.
|
|
39
|
+
- Printer work must not block the app UI/main thread while running.
|
|
40
|
+
- Errors from native printer operations must reject back to JS and must not be swallowed.
|
|
41
|
+
- Image and logo printing may be more expensive than text-only receipts, but must still remain asynchronous from the app's point of view.
|
|
42
|
+
|
|
43
|
+
## Observed Performance Expectations
|
|
44
|
+
|
|
45
|
+
These are real-device expectations, not strict guarantees:
|
|
46
|
+
|
|
47
|
+
- iOS: around 3s end-to-end can be acceptable if the app UI remains responsive.
|
|
48
|
+
- Android: the first print may take around 5-6s, with later warm prints often dropping to around 2-3s.
|
|
49
|
+
- Actual timing depends on connection state, Bluetooth behavior, printer readiness, and whether the receipt includes images.
|
|
50
|
+
- Responsiveness and correct JS error propagation matter more than raw duration.
|
|
51
|
+
|
|
33
52
|
## Behavior Support (implemented)
|
|
34
53
|
|
|
35
54
|
| Behavior | Status | Details |
|
|
@@ -41,6 +60,7 @@ This package does not include Star or Sunmi drivers.
|
|
|
41
60
|
| Retry for transient busy/timeout states | Implemented | Native operations retry for retryable states (`BUSY`, `IN_USE`, timeout-family errors). |
|
|
42
61
|
| Print receive timeout guard | Implemented | Native print call fails with `PRINT_TIMEOUT` if printer callback does not return within 30s. |
|
|
43
62
|
| iOS stale-session recovery | Implemented | One-shot session recovery + reconnect + retry for stale/busy/offline connection scenarios. |
|
|
63
|
+
| Non-blocking native printer execution | Implemented | Native connect / print / status work is executed off the app UI thread on both iOS and Android. |
|
|
44
64
|
| Post-print auto-disconnect | Implemented | JS driver schedules disconnect after 5s idle after print completion. |
|
|
45
65
|
| Android warm reconnect cache | Implemented | Native Android keeps a short-lived connection cache (up to 120s) for faster reconnect. |
|
|
46
66
|
| Discovery cleanup/filtering | Implemented | Duplicate targets are deduped and Epson sub-devices such as `[local_display]` are filtered out. |
|
|
@@ -194,6 +214,13 @@ await printer.printEmbedded({
|
|
|
194
214
|
});
|
|
195
215
|
```
|
|
196
216
|
|
|
217
|
+
### Image printing expectations
|
|
218
|
+
|
|
219
|
+
- Image printing is supported.
|
|
220
|
+
- Image printing can take longer than text-only receipts because the image may need decode, resize, rasterization, and transport work.
|
|
221
|
+
- This extra work should not block the app UI.
|
|
222
|
+
- If image printing fails, the error should still reject back to JS like any other print failure.
|
|
223
|
+
|
|
197
224
|
### Cash drawer
|
|
198
225
|
|
|
199
226
|
```ts
|
package/dist/index.js
CHANGED
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
`,align:"center",bold:!0})}else i==="B"?e.push({type:"text",text:c+`
|
|
9
9
|
`,bold:!0}):i==="R"?e.push({type:"text",text:c+`
|
|
10
10
|
`,bold:!0}):e.push({type:"text",text:c+`
|
|
11
|
-
`,align:"left"})}return e.push({type:"feed",lines:3}),e.push({type:"cut"}),{commands:e}};var x=class{constructor(e){this.logger=e}queue=Promise.resolve();isQueuePaused=!1;resumeQueueResolver=null;isPaused(){return this.isQueuePaused}pause(){this.isQueuePaused=!0}resume(){this.isQueuePaused&&(this.isQueuePaused=!1,this.resumeQueueResolver&&(this.resumeQueueResolver(),this.resumeQueueResolver=null))}async waitUntilResumed(){if(this.isQueuePaused)return new Promise(e=>{let r=this.resumeQueueResolver;this.resumeQueueResolver=()=>{r&&r(),e()}})}enqueue(e){return new Promise((r,n)=>{let i=async()=>{this.isQueuePaused&&(this.logger?.info?.("[EpsonPrinter] Queue is PAUSED. Waiting for resume..."),await this.waitUntilResumed(),this.logger?.info?.("[EpsonPrinter] Queue RESUMED."));try{let o=await e();r(o)}catch(o){n(o)}};this.queue=this.queue.then(i,i)})}enqueueBackground(e){this.queue=this.queue.then(e,e)}};var A=class{constructor(e){this.config=e}recoveryTimer=null;start(){this.recoveryTimer||(this.config.logger?.info?.("[EpsonPrinter] Starting recovery polling..."),this.recoveryTimer=setInterval(async()=>{try{let e=await this.config.getStatus();if(e.online&&!e.coverOpen&&e.errorStatus==="NONE")this.config.logger?.info?.("[EpsonPrinter] Poller detected healthy status. Requesting queue resume."),this.config.onRecovered();else{let n=`[EpsonPrinter] Polling... Status: Online=${e.online}, Cover=${e.coverOpen}, Err=${e.errorStatus}`;this.config.logger?.info?.(n)}}catch(e){this.config.logger?.error("[EpsonPrinter] Recovery poll failed",e)}},2e3))}stop(){this.recoveryTimer&&(this.config.logger?.info?.("[EpsonPrinter] Stopping recovery polling."),clearInterval(this.recoveryTimer),this.recoveryTimer=null)}};var L=class{constructor(e){this.logger=e}sessionId=null;sessionInitPromise=null;getSessionId(){return this.sessionId}async ensureSession(){if(!m)throw new Error("Native module not found");return this.sessionId?this.sessionId:this.sessionInitPromise?this.sessionInitPromise:(this.sessionInitPromise=m.initSession().then(e=>(this.sessionId=e,e)).finally(()=>{this.sessionInitPromise=null}),this.sessionInitPromise)}async disposeSession(){if(!m||!this.sessionId){this.sessionId=null;return}let e=this.sessionId;this.sessionId=null;try{await m.disposeSession(e)}catch(r){this.logger?.error("[EpsonPrinter] Dispose session failed",r)}}};var U=class{constructor(e){this.config=e}statusCallbacks=new Set;latestHardwareStatus=null;statusRefreshPromise=null;statusRefreshTimer=null;subscribe(e){return this.statusCallbacks.add(e),this.latestHardwareStatus?e(this.latestHardwareStatus):this.config.getConnectionStatus()!=="CONNECTED"?e(this.config.defaultStatus):this.refreshNow(),()=>{this.statusCallbacks.delete(e)}}handleStatusEvent(){this.scheduleRefresh()}handleConnected(){this.scheduleRefresh(0)}handleDisconnected(){this.clearRefreshTimer(),this.setHardwareStatus(this.config.defaultStatus)}clear(){this.clearRefreshTimer()}async refreshNow(){if(this.config.getConnectionStatus()!=="CONNECTED"){this.setHardwareStatus(this.config.defaultStatus);return}if(this.statusRefreshPromise){await this.statusRefreshPromise;return}this.statusRefreshPromise=(async()=>{try{let e=await this.config.getStatus();this.setHardwareStatus(e)}catch(e){this.config.logger?.error("[EpsonPrinter] Status refresh failed",e),this.latestHardwareStatus||this.setHardwareStatus(this.config.defaultStatus)}})().finally(()=>{this.statusRefreshPromise=null}),await this.statusRefreshPromise}emitHardwareStatus(e){for(let r of this.statusCallbacks)r(e)}setHardwareStatus(e){this.latestHardwareStatus=e,this.emitHardwareStatus(e)}clearRefreshTimer(){this.statusRefreshTimer&&(clearTimeout(this.statusRefreshTimer),this.statusRefreshTimer=null)}scheduleRefresh(e=150){this.config.getConnectionStatus()==="CONNECTED"&&(this.statusRefreshTimer||(this.statusRefreshTimer=setTimeout(()=>{this.statusRefreshTimer=null,this.refreshNow()},e)))}};var Q={online:!1,coverOpen:!1,paperEmpty:!1,paper:"EMPTY",errorStatus:"NONE",drawerOpen:!1},Me=5e3,F=class{disconnectTimer=null;connectionStatus="DISCONNECTED";isConnecting=!1;target=null;defaultTarget;model;lang;logger;sessionManager;queueController;recoveryController;statusController;eventRouter;constructor(e){this.logger=e.logger,this.defaultTarget=e.target??null,this.model=e.model,this.lang=e.lang??0,this.sessionManager=new L(this.logger),this.queueController=new x(this.logger),this.recoveryController=new A({logger:this.logger,getStatus:()=>this.getStatus(),onRecovered:()=>this.resumeQueue()}),this.statusController=new U({logger:this.logger,defaultStatus:Q,getConnectionStatus:()=>this.connectionStatus,getStatus:()=>this.getStatus()}),this.eventRouter=new w({logger:this.logger,getSessionId:()=>this.sessionManager.getSessionId(),getConnectionStatus:()=>this.connectionStatus,onEvent:r=>{r.statusEventType!==null&&(this.statusController.handleStatusEvent(),r.isRecoveryEvent&&this.queueController.isPaused()&&(this.logger?.info?.("[EpsonPrinter] Printer recovered (Event). Resuming queue..."),this.resumeQueue())),r.connectionStatus!==null&&(r.connectionStatus==="CONNECTED"&&(this.connectionStatus="CONNECTED"),r.connectionStatus==="CONNECTED"&&this.statusController.handleConnected(),r.connectionStatus==="DISCONNECTED"&&(this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected()))}})}resumeQueue(){if(!this.queueController.isPaused())return;this.logger?.info?.("[EpsonPrinter] Resuming queue..."),this.recoveryController.stop(),this.queueController.resume()}isIosConnectionRecoveryCandidate(e){return W.Platform.OS!=="ios"?!1:e.code==="CONNECTION_FAILED"||e.code==="TIMEOUT"&&e.translationCode==="printer.error.connection_timeout"||e.translationCode==="printer.error.offline"}hasTargetInUseToken(e){if(!e||typeof e!="object")return!1;let r=String(e.code??"").toUpperCase(),n=String(e.message??"").toUpperCase();return r.includes("TARGET_IN_USE")||n.includes("TARGET_IN_USE")}isIosConnectBusyRecoveryCandidate(e){return W.Platform.OS!=="ios"||e.translationCode!=="printer.error.busy"?!1:!this.hasTargetInUseToken(e.originalError)}async recoverIosSessionForPrint(){if(!m)throw new Error("Native module not found");let e=this.target??this.defaultTarget;if(!e)throw new Error("Printer target is required");let r=this.sessionManager.getSessionId();if(r)try{await m.disconnect(r)}catch(i){this.logger?.error("[EpsonPrinter] iOS recovery disconnect failed (best-effort)",i)}await this.sessionManager.disposeSession(),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED");let n=await this.sessionManager.ensureSession();return await S(()=>m.connect(n,e,Me,this.model,this.lang)),this.target=e,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected(),n}async recoverIosSessionForConnect(e,r){if(!m)throw new Error("Native module not found");let n=this.sessionManager.getSessionId();if(n)try{await m.disconnect(n)}catch(o){this.logger?.error("[EpsonPrinter] iOS connect recovery disconnect failed (best-effort)",o)}await this.sessionManager.disposeSession(),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED");let i=await this.sessionManager.ensureSession();await S(()=>m.connect(i,e,r,this.model,this.lang)),this.target=e,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected()}async connect(e,r=5e3){let n=e??this.defaultTarget;if(!n){let i=new Error("Printer target is required");throw this.logger?.error("[EpsonPrinter] Connect failed: missing target",i),i}return this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),this.queueController.enqueue(async()=>{if(!m){this.logger?.error("[EpsonPrinter] Native module not found");return}if(this.connectionStatus==="CONNECTED"&&this.target===n)return;let i=await this.sessionManager.ensureSession();this.isConnecting=!0,this.connectionStatus="CONNECTING",this.eventRouter.emitStatus("CONNECTING");let o=!1;try{await S(()=>m.connect(i,n,r,this.model,this.lang)),this.target=n,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.isConnecting=!1,this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected()}catch(T){let c=f(T);if(!o&&this.isIosConnectBusyRecoveryCandidate(c)){o=!0,this.logger?.error("[EpsonPrinter] iOS busy connect suspected stale session. Recovering connection and retrying connect once...",c);try{await this.recoverIosSessionForConnect(n,r),this.logger?.info?.("[EpsonPrinter] iOS connect recovery succeeded."),this.isConnecting=!1;return}catch(l){let P=f(l);throw this.logger?.error("[EpsonPrinter] iOS connect recovery failed",P),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.isConnecting=!1,P}}throw this.logger?.error(`[EpsonPrinter] Connect failed for ${n}`,c),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.isConnecting=!1,c}})}async print(e){if(!m)return;this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null);let r=0,n=!1;return this.queueController.enqueue(async()=>{let i=await this.sessionManager.ensureSession(),o=se(e);for(;;){r++,this.logger?.info?.(`[EpsonPrinter] Print attempt ${r}`);try{await S(()=>m.print(i,o));break}catch(T){let c=ne(T);if(!n&&this.isIosConnectionRecoveryCandidate(c)){n=!0,this.logger?.error("[EpsonPrinter] iOS stale session suspected. Recovering connection and retrying print once...",c);try{i=await this.recoverIosSessionForPrint(),this.logger?.info?.("[EpsonPrinter] iOS session recovery succeeded. Retrying print...");continue}catch(l){let P=f(l);throw this.logger?.error("[EpsonPrinter] iOS session recovery failed",P),P}}if(c.isHardwareError){this.queueController.pause(),this.logger?.error(`[EpsonPrinter] Hardware error on attempt ${r}. Waiting for recovery before retry...`,c),this.recoveryController.start(),await this.queueController.waitUntilResumed(),this.logger?.info?.("[EpsonPrinter] Recovery detected. Sending cut to flush partial print before retry...");try{await m.print(i,[{cmd:"addCut"}])}catch{}this.logger?.info?.("[EpsonPrinter] Retrying print job...")}else throw this.logger?.error(`[EpsonPrinter] Print failed (non-recoverable) on attempt ${r}`,c),c}}}).finally(()=>{this.disconnectTimer&&clearTimeout(this.disconnectTimer),this.disconnectTimer=setTimeout(()=>{this.performDisconnect()},5e3)})}performDisconnect(){this.queueController.enqueueBackground(async()=>{if(!this.disconnectTimer)return;let e=this.sessionManager.getSessionId();if(m&&this.connectionStatus==="CONNECTED"&&e)try{await m.disconnect(e),this.connectionStatus="DISCONNECTED",this.target=null,this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),await this.sessionManager.disposeSession()}catch(r){this.logger?.error("[EpsonPrinter] Auto-Disconnect failed",r)}this.disconnectTimer=null})}async printEmbedded(e){try{let r=oe(e);return await this.print(r)}catch(r){let n=f(r);throw String(r).includes("MunchiPrinterError")||this.logger?.error("[EpsonPrinter] Embedded print failed",n),n}}async disconnect(){return this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),this.queueController.enqueue(async()=>{if(!m)return;let e=this.sessionManager.getSessionId();if(e)try{await m.disconnect(e),this.connectionStatus="DISCONNECTED",this.target=null,this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.eventRouter.removeStatusListener(),this.recoveryController.stop()}catch(r){this.logger?.error("[EpsonPrinter] Disconnect failed",r)}finally{this.statusController.clear(),await this.sessionManager.disposeSession()}})}async getStatus(){if(!m)return Q;let e=this.sessionManager.getSessionId();if(!e)return Q;try{return await m.getStatus(e)}catch(r){throw this.logger?.error("[EpsonPrinter] GetStatus failed",r),f(r)}}async openDrawer(){let e={commands:[{type:"drawer"}]};return this.print(e)}onConnectionChange(e){return this.eventRouter.onConnectionChange(e)}onStatusChange(e){return this.statusController.subscribe(e)}};var ue=require("react-native");var ae=ue.NativeModules.MunchiEpsonModule,we={bluetooth:["BT:"],tcp:["TCP:","TCPS:"],usb:["USB:"]},be=t=>t.includes("[local_"),xe=(t,e)=>e?we[e].some(n=>t.startsWith(n)):!0,ce=async t=>{if(!ae)return console.warn("[EpsonDiscovery] Native module not found"),[];try{return(await ae.discover({timeout:t.timeout})).map(ie).filter(r=>!r||be(r.target)?!1:xe(r.target,t.connectionType))}catch(e){let r=f(e);throw console.error("[EpsonDiscovery] Discovery failed",r),r}};var Ae=[[/^TM-m10/i,0],[/^TM-m30III/i,29],[/^TM-m30II/i,21],[/^TM-m30/i,1],[/^TM-m50II/i,30],[/^TM-m50/i,23],[/^TM-m55/i,31],[/^TM-P20II/i,27],[/^TM-P20/i,2],[/^TM-P60II/i,4],[/^TM-P60/i,3],[/^TM-P80II/i,28],[/^TM-P80/i,5],[/^TM-T20/i,6],[/^TM-T60/i,7],[/^TM-T70/i,8],[/^TM-T81/i,9],[/^TM-T82/i,10],[/^TM-T83III/i,19],[/^TM-T83/i,11],[/^TM-T88VII/i,24],[/^TM-T88/i,12],[/^TM-T90KP/i,14],[/^TM-T90/i,13],[/^TM-T100/i,20],[/^TM-U220II/i,32],[/^TM-U220/i,15],[/^TM-U330/i,16],[/^TM-L90LFC/i,25],[/^TM-L90/i,17],[/^TM-L100/i,26],[/^TM-H6000/i,18]],le=t=>{for(let[e,r]of Ae)if(e.test(t))return r;return null};var de=t=>{let e=f(t),r=e.message.toUpperCase(),n=t instanceof p?t.isHardwareError:z(t),i=e.translationCode==="printer.error.busy"||r.includes("BUSY")||r.includes("IN_USE")||r.includes("PRINT_BUSY"),o=e.code==="TIMEOUT"||e.translationCode==="printer.error.connection_timeout"||r.includes("TIMEOUT"),T=e.code==="CONNECTION_FAILED"||e.translationCode==="printer.error.offline",c=e.code==="DISCOVERY_FAILED",l="UNKNOWN";return n?l="HARDWARE":i?l="BUSY":o?l="TIMEOUT":T?l="CONNECTION":c?l="DISCOVERY":e.code==="PRINT_FAILED"&&(l="PRINT"),{code:e.code,translationCode:e.translationCode,message:e.message,category:l,isHardwareError:n,retryable:i||o,shouldPauseQueue:n,raw:t}},Le=t=>de(t);var me=Ne(require("react")),R=require("react");var ge=(0,R.createContext)(void 0),Ue=({config:t,logger:e,children:r})=>{let[n,i]=(0,R.useState)();(0,R.useEffect)(()=>{e&&B(e)},[e]);let o=(0,R.useMemo)(()=>{let c={...t,logger:e??t.logger};return K(c)},[t.lang,t.model,t.target,e]),T=(0,R.useMemo)(()=>({printer:o,config:t,isReady:!0,error:n}),[o,t,n]);return me.default.createElement(ge.Provider,{value:T},r)},k=()=>{let t=(0,R.useContext)(ge);if(!t)throw new Error("usePrinter must be used within a PrinterProvider");return t};var E=require("react");function Fe(t={}){let{enabled:e=!0}=t,{printer:r,config:n}=k(),[i,o]=(0,E.useState)("DISCONNECTED"),[T,c]=(0,E.useState)(null),[l,P]=(0,E.useState)(null),X=(0,E.useRef)("DISCONNECTED"),$=(0,E.useRef)(null),d=l!==null,I=(0,E.useCallback)(C=>{$.current=C,P(C)},[]),_=(0,E.useCallback)(C=>{if(C instanceof Error&&C.message){I(C.message);return}if(typeof C=="string"&&C.length>0){I(C);return}I("Unknown printer error")},[I]),a=(0,E.useCallback)(()=>{$.current!==null&&I(null)},[I]);return(0,E.useEffect)(()=>r.onConnectionChange(O=>{X.current=O,o(O),O==="CONNECTED"&&a()}),[a,r]),(0,E.useEffect)(()=>e?r.onStatusChange(O=>{c(O),a()}):void 0,[a,e,r]),(0,E.useEffect)(()=>{e&&i==="CONNECTED"&&r.getStatus().then(C=>{c(C),a()}).catch(_)},[_,a,i,e,r]),(0,E.useEffect)(()=>{let C=X.current;if(e){C==="DISCONNECTED"&&i==="DISCONNECTED"&&r.connect(n.target,5e3).then(a).catch(_);return}(i==="CONNECTED"||i==="CONNECTING")&&r.disconnect().then(a).catch(_)},[_,a,n.target,i,e,r]),{connectionStatus:i,hardwareStatus:T,isError:d,errorMessage:l}}var Te="1.0.7";function K(t){return new F({...t,logger:t.logger??Y()})}0&&(module.exports={Epos2CallbackCode,Epos2ConnectionEvent,Epos2ErrorStatus,Epos2Font,Epos2Lang,Epos2StatusEvent,EpsonModel,FontSize,MunchiPrinterError,PrinterError,PrinterErrorCode,PrinterProvider,PrinterTranslationCode,VERSION,discoverPrinters,getGlobalLogger,getPrinter,resolveEpsonError,resolveModelFromBluetoothName,resolvePrinterError,setGlobalLogger,usePrinter,usePrinterStatus});
|
|
11
|
+
`,align:"left"})}return e.push({type:"feed",lines:3}),e.push({type:"cut"}),{commands:e}};var x=class{constructor(e){this.logger=e}queue=Promise.resolve();isQueuePaused=!1;resumeQueueResolver=null;isPaused(){return this.isQueuePaused}pause(){this.isQueuePaused=!0}resume(){this.isQueuePaused&&(this.isQueuePaused=!1,this.resumeQueueResolver&&(this.resumeQueueResolver(),this.resumeQueueResolver=null))}async waitUntilResumed(){if(this.isQueuePaused)return new Promise(e=>{let r=this.resumeQueueResolver;this.resumeQueueResolver=()=>{r&&r(),e()}})}enqueue(e){return new Promise((r,n)=>{let i=async()=>{this.isQueuePaused&&(this.logger?.info?.("[EpsonPrinter] Queue is PAUSED. Waiting for resume..."),await this.waitUntilResumed(),this.logger?.info?.("[EpsonPrinter] Queue RESUMED."));try{let o=await e();r(o)}catch(o){n(o)}};this.queue=this.queue.then(i,i)})}enqueueBackground(e){this.queue=this.queue.then(e,e)}};var A=class{constructor(e){this.config=e}recoveryTimer=null;start(){this.recoveryTimer||(this.config.logger?.info?.("[EpsonPrinter] Starting recovery polling..."),this.recoveryTimer=setInterval(async()=>{try{let e=await this.config.getStatus();if(e.online&&!e.coverOpen&&e.errorStatus==="NONE")this.config.logger?.info?.("[EpsonPrinter] Poller detected healthy status. Requesting queue resume."),this.config.onRecovered();else{let n=`[EpsonPrinter] Polling... Status: Online=${e.online}, Cover=${e.coverOpen}, Err=${e.errorStatus}`;this.config.logger?.info?.(n)}}catch(e){this.config.logger?.error("[EpsonPrinter] Recovery poll failed",e)}},2e3))}stop(){this.recoveryTimer&&(this.config.logger?.info?.("[EpsonPrinter] Stopping recovery polling."),clearInterval(this.recoveryTimer),this.recoveryTimer=null)}};var L=class{constructor(e){this.logger=e}sessionId=null;sessionInitPromise=null;getSessionId(){return this.sessionId}async ensureSession(){if(!m)throw new Error("Native module not found");return this.sessionId?this.sessionId:this.sessionInitPromise?this.sessionInitPromise:(this.sessionInitPromise=m.initSession().then(e=>(this.sessionId=e,e)).finally(()=>{this.sessionInitPromise=null}),this.sessionInitPromise)}async disposeSession(){if(!m||!this.sessionId){this.sessionId=null;return}let e=this.sessionId;this.sessionId=null;try{await m.disposeSession(e)}catch(r){this.logger?.error("[EpsonPrinter] Dispose session failed",r)}}};var U=class{constructor(e){this.config=e}statusCallbacks=new Set;latestHardwareStatus=null;statusRefreshPromise=null;statusRefreshTimer=null;subscribe(e){return this.statusCallbacks.add(e),this.latestHardwareStatus?e(this.latestHardwareStatus):this.config.getConnectionStatus()!=="CONNECTED"?e(this.config.defaultStatus):this.refreshNow(),()=>{this.statusCallbacks.delete(e)}}handleStatusEvent(){this.scheduleRefresh()}handleConnected(){this.scheduleRefresh(0)}handleDisconnected(){this.clearRefreshTimer(),this.setHardwareStatus(this.config.defaultStatus)}clear(){this.clearRefreshTimer()}async refreshNow(){if(this.config.getConnectionStatus()!=="CONNECTED"){this.setHardwareStatus(this.config.defaultStatus);return}if(this.statusRefreshPromise){await this.statusRefreshPromise;return}this.statusRefreshPromise=(async()=>{try{let e=await this.config.getStatus();this.setHardwareStatus(e)}catch(e){this.config.logger?.error("[EpsonPrinter] Status refresh failed",e),this.latestHardwareStatus||this.setHardwareStatus(this.config.defaultStatus)}})().finally(()=>{this.statusRefreshPromise=null}),await this.statusRefreshPromise}emitHardwareStatus(e){for(let r of this.statusCallbacks)r(e)}setHardwareStatus(e){this.latestHardwareStatus=e,this.emitHardwareStatus(e)}clearRefreshTimer(){this.statusRefreshTimer&&(clearTimeout(this.statusRefreshTimer),this.statusRefreshTimer=null)}scheduleRefresh(e=150){this.config.getConnectionStatus()==="CONNECTED"&&(this.statusRefreshTimer||(this.statusRefreshTimer=setTimeout(()=>{this.statusRefreshTimer=null,this.refreshNow()},e)))}};var Q={online:!1,coverOpen:!1,paperEmpty:!1,paper:"EMPTY",errorStatus:"NONE",drawerOpen:!1},Me=5e3,F=class{disconnectTimer=null;connectionStatus="DISCONNECTED";isConnecting=!1;target=null;defaultTarget;model;lang;logger;sessionManager;queueController;recoveryController;statusController;eventRouter;constructor(e){this.logger=e.logger,this.defaultTarget=e.target??null,this.model=e.model,this.lang=e.lang??0,this.sessionManager=new L(this.logger),this.queueController=new x(this.logger),this.recoveryController=new A({logger:this.logger,getStatus:()=>this.getStatus(),onRecovered:()=>this.resumeQueue()}),this.statusController=new U({logger:this.logger,defaultStatus:Q,getConnectionStatus:()=>this.connectionStatus,getStatus:()=>this.getStatus()}),this.eventRouter=new w({logger:this.logger,getSessionId:()=>this.sessionManager.getSessionId(),getConnectionStatus:()=>this.connectionStatus,onEvent:r=>{r.statusEventType!==null&&(this.statusController.handleStatusEvent(),r.isRecoveryEvent&&this.queueController.isPaused()&&(this.logger?.info?.("[EpsonPrinter] Printer recovered (Event). Resuming queue..."),this.resumeQueue())),r.connectionStatus!==null&&(r.connectionStatus==="CONNECTED"&&(this.connectionStatus="CONNECTED"),r.connectionStatus==="CONNECTED"&&this.statusController.handleConnected(),r.connectionStatus==="DISCONNECTED"&&(this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected()))}})}resumeQueue(){if(!this.queueController.isPaused())return;this.logger?.info?.("[EpsonPrinter] Resuming queue..."),this.recoveryController.stop(),this.queueController.resume()}isIosConnectionRecoveryCandidate(e){return W.Platform.OS!=="ios"?!1:e.code==="CONNECTION_FAILED"||e.code==="TIMEOUT"&&e.translationCode==="printer.error.connection_timeout"||e.translationCode==="printer.error.offline"}hasTargetInUseToken(e){if(!e||typeof e!="object")return!1;let r=String(e.code??"").toUpperCase(),n=String(e.message??"").toUpperCase();return r.includes("TARGET_IN_USE")||n.includes("TARGET_IN_USE")}isIosConnectBusyRecoveryCandidate(e){return W.Platform.OS!=="ios"||e.translationCode!=="printer.error.busy"?!1:!this.hasTargetInUseToken(e.originalError)}async recoverIosSessionForPrint(){if(!m)throw new Error("Native module not found");let e=this.target??this.defaultTarget;if(!e)throw new Error("Printer target is required");let r=this.sessionManager.getSessionId();if(r)try{await m.disconnect(r)}catch(i){this.logger?.error("[EpsonPrinter] iOS recovery disconnect failed (best-effort)",i)}await this.sessionManager.disposeSession(),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED");let n=await this.sessionManager.ensureSession();return await S(()=>m.connect(n,e,Me,this.model,this.lang)),this.target=e,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected(),n}async recoverIosSessionForConnect(e,r){if(!m)throw new Error("Native module not found");let n=this.sessionManager.getSessionId();if(n)try{await m.disconnect(n)}catch(o){this.logger?.error("[EpsonPrinter] iOS connect recovery disconnect failed (best-effort)",o)}await this.sessionManager.disposeSession(),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED");let i=await this.sessionManager.ensureSession();await S(()=>m.connect(i,e,r,this.model,this.lang)),this.target=e,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected()}async connect(e,r=5e3){let n=e??this.defaultTarget;if(!n){let i=new Error("Printer target is required");throw this.logger?.error("[EpsonPrinter] Connect failed: missing target",i),i}return this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),this.queueController.enqueue(async()=>{if(!m){this.logger?.error("[EpsonPrinter] Native module not found");return}if(this.connectionStatus==="CONNECTED"&&this.target===n)return;let i=await this.sessionManager.ensureSession();this.isConnecting=!0,this.connectionStatus="CONNECTING",this.eventRouter.emitStatus("CONNECTING");let o=!1;try{await S(()=>m.connect(i,n,r,this.model,this.lang)),this.target=n,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.isConnecting=!1,this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected()}catch(T){let c=f(T);if(!o&&this.isIosConnectBusyRecoveryCandidate(c)){o=!0,this.logger?.error("[EpsonPrinter] iOS busy connect suspected stale session. Recovering connection and retrying connect once...",c);try{await this.recoverIosSessionForConnect(n,r),this.logger?.info?.("[EpsonPrinter] iOS connect recovery succeeded."),this.isConnecting=!1;return}catch(l){let P=f(l);throw this.logger?.error("[EpsonPrinter] iOS connect recovery failed",P),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.isConnecting=!1,P}}throw this.logger?.error(`[EpsonPrinter] Connect failed for ${n}`,c),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.isConnecting=!1,c}})}async print(e){if(!m)return;this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null);let r=0,n=!1;return this.queueController.enqueue(async()=>{let i=await this.sessionManager.ensureSession(),o=se(e);for(;;){r++,this.logger?.info?.(`[EpsonPrinter] Print attempt ${r}`);try{await S(()=>m.print(i,o));break}catch(T){let c=ne(T);if(!n&&this.isIosConnectionRecoveryCandidate(c)){n=!0,this.logger?.error("[EpsonPrinter] iOS stale session suspected. Recovering connection and retrying print once...",c);try{i=await this.recoverIosSessionForPrint(),this.logger?.info?.("[EpsonPrinter] iOS session recovery succeeded. Retrying print...");continue}catch(l){let P=f(l);throw this.logger?.error("[EpsonPrinter] iOS session recovery failed",P),P}}if(c.isHardwareError){this.queueController.pause(),this.logger?.error(`[EpsonPrinter] Hardware error on attempt ${r}. Waiting for recovery before retry...`,c),this.recoveryController.start(),await this.queueController.waitUntilResumed(),this.logger?.info?.("[EpsonPrinter] Recovery detected. Sending cut to flush partial print before retry...");try{await m.print(i,[{cmd:"addCut"}])}catch{}this.logger?.info?.("[EpsonPrinter] Retrying print job...")}else throw this.logger?.error(`[EpsonPrinter] Print failed (non-recoverable) on attempt ${r}`,c),c}}}).finally(()=>{this.disconnectTimer&&clearTimeout(this.disconnectTimer),this.disconnectTimer=setTimeout(()=>{this.performDisconnect()},5e3)})}performDisconnect(){this.queueController.enqueueBackground(async()=>{if(!this.disconnectTimer)return;let e=this.sessionManager.getSessionId();if(m&&this.connectionStatus==="CONNECTED"&&e)try{await m.disconnect(e),this.connectionStatus="DISCONNECTED",this.target=null,this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),await this.sessionManager.disposeSession()}catch(r){this.logger?.error("[EpsonPrinter] Auto-Disconnect failed",r)}this.disconnectTimer=null})}async printEmbedded(e){try{let r=oe(e);return await this.print(r)}catch(r){let n=f(r);throw String(r).includes("MunchiPrinterError")||this.logger?.error("[EpsonPrinter] Embedded print failed",n),n}}async disconnect(){return this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),this.queueController.enqueue(async()=>{if(!m)return;let e=this.sessionManager.getSessionId();if(e)try{await m.disconnect(e),this.connectionStatus="DISCONNECTED",this.target=null,this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.eventRouter.removeStatusListener(),this.recoveryController.stop()}catch(r){this.logger?.error("[EpsonPrinter] Disconnect failed",r)}finally{this.statusController.clear(),await this.sessionManager.disposeSession()}})}async getStatus(){if(!m)return Q;let e=this.sessionManager.getSessionId();if(!e)return Q;try{return await m.getStatus(e)}catch(r){throw this.logger?.error("[EpsonPrinter] GetStatus failed",r),f(r)}}async openDrawer(){let e={commands:[{type:"drawer"}]};return this.print(e)}onConnectionChange(e){return this.eventRouter.onConnectionChange(e)}onStatusChange(e){return this.statusController.subscribe(e)}};var ue=require("react-native");var ae=ue.NativeModules.MunchiEpsonModule,we={bluetooth:["BT:"],tcp:["TCP:","TCPS:"],usb:["USB:"]},be=t=>t.includes("[local_"),xe=(t,e)=>e?we[e].some(n=>t.startsWith(n)):!0,ce=async t=>{if(!ae)return console.warn("[EpsonDiscovery] Native module not found"),[];try{return(await ae.discover({timeout:t.timeout})).map(ie).filter(r=>!r||be(r.target)?!1:xe(r.target,t.connectionType))}catch(e){let r=f(e);throw console.error("[EpsonDiscovery] Discovery failed",r),r}};var Ae=[[/^TM-m10/i,0],[/^TM-m30III/i,29],[/^TM-m30II/i,21],[/^TM-m30/i,1],[/^TM-m50II/i,30],[/^TM-m50/i,23],[/^TM-m55/i,31],[/^TM-P20II/i,27],[/^TM-P20/i,2],[/^TM-P60II/i,4],[/^TM-P60/i,3],[/^TM-P80II/i,28],[/^TM-P80/i,5],[/^TM-T20/i,6],[/^TM-T60/i,7],[/^TM-T70/i,8],[/^TM-T81/i,9],[/^TM-T82/i,10],[/^TM-T83III/i,19],[/^TM-T83/i,11],[/^TM-T88VII/i,24],[/^TM-T88/i,12],[/^TM-T90KP/i,14],[/^TM-T90/i,13],[/^TM-T100/i,20],[/^TM-U220II/i,32],[/^TM-U220/i,15],[/^TM-U330/i,16],[/^TM-L90LFC/i,25],[/^TM-L90/i,17],[/^TM-L100/i,26],[/^TM-H6000/i,18]],le=t=>{for(let[e,r]of Ae)if(e.test(t))return r;return null};var de=t=>{let e=f(t),r=e.message.toUpperCase(),n=t instanceof p?t.isHardwareError:z(t),i=e.translationCode==="printer.error.busy"||r.includes("BUSY")||r.includes("IN_USE")||r.includes("PRINT_BUSY"),o=e.code==="TIMEOUT"||e.translationCode==="printer.error.connection_timeout"||r.includes("TIMEOUT"),T=e.code==="CONNECTION_FAILED"||e.translationCode==="printer.error.offline",c=e.code==="DISCOVERY_FAILED",l="UNKNOWN";return n?l="HARDWARE":i?l="BUSY":o?l="TIMEOUT":T?l="CONNECTION":c?l="DISCOVERY":e.code==="PRINT_FAILED"&&(l="PRINT"),{code:e.code,translationCode:e.translationCode,message:e.message,category:l,isHardwareError:n,retryable:i||o,shouldPauseQueue:n,raw:t}},Le=t=>de(t);var me=Ne(require("react")),R=require("react");var ge=(0,R.createContext)(void 0),Ue=({config:t,logger:e,children:r})=>{let[n,i]=(0,R.useState)();(0,R.useEffect)(()=>{e&&B(e)},[e]);let o=(0,R.useMemo)(()=>{let c={...t,logger:e??t.logger};return K(c)},[t.lang,t.model,t.target,e]),T=(0,R.useMemo)(()=>({printer:o,config:t,isReady:!0,error:n}),[o,t,n]);return me.default.createElement(ge.Provider,{value:T},r)},k=()=>{let t=(0,R.useContext)(ge);if(!t)throw new Error("usePrinter must be used within a PrinterProvider");return t};var E=require("react");function Fe(t={}){let{enabled:e=!0}=t,{printer:r,config:n}=k(),[i,o]=(0,E.useState)("DISCONNECTED"),[T,c]=(0,E.useState)(null),[l,P]=(0,E.useState)(null),X=(0,E.useRef)("DISCONNECTED"),$=(0,E.useRef)(null),d=l!==null,I=(0,E.useCallback)(C=>{$.current=C,P(C)},[]),_=(0,E.useCallback)(C=>{if(C instanceof Error&&C.message){I(C.message);return}if(typeof C=="string"&&C.length>0){I(C);return}I("Unknown printer error")},[I]),a=(0,E.useCallback)(()=>{$.current!==null&&I(null)},[I]);return(0,E.useEffect)(()=>r.onConnectionChange(O=>{X.current=O,o(O),O==="CONNECTED"&&a()}),[a,r]),(0,E.useEffect)(()=>e?r.onStatusChange(O=>{c(O),a()}):void 0,[a,e,r]),(0,E.useEffect)(()=>{e&&i==="CONNECTED"&&r.getStatus().then(C=>{c(C),a()}).catch(_)},[_,a,i,e,r]),(0,E.useEffect)(()=>{let C=X.current;if(e){C==="DISCONNECTED"&&i==="DISCONNECTED"&&r.connect(n.target,5e3).then(a).catch(_);return}(i==="CONNECTED"||i==="CONNECTING")&&r.disconnect().then(a).catch(_)},[_,a,n.target,i,e,r]),{connectionStatus:i,hardwareStatus:T,isError:d,errorMessage:l}}var Te="1.0.8";function K(t){return new F({...t,logger:t.logger??Y()})}0&&(module.exports={Epos2CallbackCode,Epos2ConnectionEvent,Epos2ErrorStatus,Epos2Font,Epos2Lang,Epos2StatusEvent,EpsonModel,FontSize,MunchiPrinterError,PrinterError,PrinterErrorCode,PrinterProvider,PrinterTranslationCode,VERSION,discoverPrinters,getGlobalLogger,getPrinter,resolveEpsonError,resolveModelFromBluetoothName,resolvePrinterError,setGlobalLogger,usePrinter,usePrinterStatus});
|
package/dist/index.mjs
CHANGED
|
@@ -8,4 +8,4 @@ var q={},z=t=>{q.logger=t},G=()=>q.logger;import{Platform as j}from"react-native
|
|
|
8
8
|
`,align:"center",bold:!0})}else i==="B"?e.push({type:"text",text:c+`
|
|
9
9
|
`,bold:!0}):i==="R"?e.push({type:"text",text:c+`
|
|
10
10
|
`,bold:!0}):e.push({type:"text",text:c+`
|
|
11
|
-
`,align:"left"})}return e.push({type:"feed",lines:3}),e.push({type:"cut"}),{commands:e}};var v=class{constructor(e){this.logger=e}queue=Promise.resolve();isQueuePaused=!1;resumeQueueResolver=null;isPaused(){return this.isQueuePaused}pause(){this.isQueuePaused=!0}resume(){this.isQueuePaused&&(this.isQueuePaused=!1,this.resumeQueueResolver&&(this.resumeQueueResolver(),this.resumeQueueResolver=null))}async waitUntilResumed(){if(this.isQueuePaused)return new Promise(e=>{let r=this.resumeQueueResolver;this.resumeQueueResolver=()=>{r&&r(),e()}})}enqueue(e){return new Promise((r,n)=>{let i=async()=>{this.isQueuePaused&&(this.logger?.info?.("[EpsonPrinter] Queue is PAUSED. Waiting for resume..."),await this.waitUntilResumed(),this.logger?.info?.("[EpsonPrinter] Queue RESUMED."));try{let o=await e();r(o)}catch(o){n(o)}};this.queue=this.queue.then(i,i)})}enqueueBackground(e){this.queue=this.queue.then(e,e)}};var D=class{constructor(e){this.config=e}recoveryTimer=null;start(){this.recoveryTimer||(this.config.logger?.info?.("[EpsonPrinter] Starting recovery polling..."),this.recoveryTimer=setInterval(async()=>{try{let e=await this.config.getStatus();if(e.online&&!e.coverOpen&&e.errorStatus==="NONE")this.config.logger?.info?.("[EpsonPrinter] Poller detected healthy status. Requesting queue resume."),this.config.onRecovered();else{let n=`[EpsonPrinter] Polling... Status: Online=${e.online}, Cover=${e.coverOpen}, Err=${e.errorStatus}`;this.config.logger?.info?.(n)}}catch(e){this.config.logger?.error("[EpsonPrinter] Recovery poll failed",e)}},2e3))}stop(){this.recoveryTimer&&(this.config.logger?.info?.("[EpsonPrinter] Stopping recovery polling."),clearInterval(this.recoveryTimer),this.recoveryTimer=null)}};var M=class{constructor(e){this.logger=e}sessionId=null;sessionInitPromise=null;getSessionId(){return this.sessionId}async ensureSession(){if(!m)throw new Error("Native module not found");return this.sessionId?this.sessionId:this.sessionInitPromise?this.sessionInitPromise:(this.sessionInitPromise=m.initSession().then(e=>(this.sessionId=e,e)).finally(()=>{this.sessionInitPromise=null}),this.sessionInitPromise)}async disposeSession(){if(!m||!this.sessionId){this.sessionId=null;return}let e=this.sessionId;this.sessionId=null;try{await m.disposeSession(e)}catch(r){this.logger?.error("[EpsonPrinter] Dispose session failed",r)}}};var w=class{constructor(e){this.config=e}statusCallbacks=new Set;latestHardwareStatus=null;statusRefreshPromise=null;statusRefreshTimer=null;subscribe(e){return this.statusCallbacks.add(e),this.latestHardwareStatus?e(this.latestHardwareStatus):this.config.getConnectionStatus()!=="CONNECTED"?e(this.config.defaultStatus):this.refreshNow(),()=>{this.statusCallbacks.delete(e)}}handleStatusEvent(){this.scheduleRefresh()}handleConnected(){this.scheduleRefresh(0)}handleDisconnected(){this.clearRefreshTimer(),this.setHardwareStatus(this.config.defaultStatus)}clear(){this.clearRefreshTimer()}async refreshNow(){if(this.config.getConnectionStatus()!=="CONNECTED"){this.setHardwareStatus(this.config.defaultStatus);return}if(this.statusRefreshPromise){await this.statusRefreshPromise;return}this.statusRefreshPromise=(async()=>{try{let e=await this.config.getStatus();this.setHardwareStatus(e)}catch(e){this.config.logger?.error("[EpsonPrinter] Status refresh failed",e),this.latestHardwareStatus||this.setHardwareStatus(this.config.defaultStatus)}})().finally(()=>{this.statusRefreshPromise=null}),await this.statusRefreshPromise}emitHardwareStatus(e){for(let r of this.statusCallbacks)r(e)}setHardwareStatus(e){this.latestHardwareStatus=e,this.emitHardwareStatus(e)}clearRefreshTimer(){this.statusRefreshTimer&&(clearTimeout(this.statusRefreshTimer),this.statusRefreshTimer=null)}scheduleRefresh(e=150){this.config.getConnectionStatus()==="CONNECTED"&&(this.statusRefreshTimer||(this.statusRefreshTimer=setTimeout(()=>{this.statusRefreshTimer=null,this.refreshNow()},e)))}};var F={online:!1,coverOpen:!1,paperEmpty:!1,paper:"EMPTY",errorStatus:"NONE",drawerOpen:!1},fe=5e3,b=class{disconnectTimer=null;connectionStatus="DISCONNECTED";isConnecting=!1;target=null;defaultTarget;model;lang;logger;sessionManager;queueController;recoveryController;statusController;eventRouter;constructor(e){this.logger=e.logger,this.defaultTarget=e.target??null,this.model=e.model,this.lang=e.lang??0,this.sessionManager=new M(this.logger),this.queueController=new v(this.logger),this.recoveryController=new D({logger:this.logger,getStatus:()=>this.getStatus(),onRecovered:()=>this.resumeQueue()}),this.statusController=new w({logger:this.logger,defaultStatus:F,getConnectionStatus:()=>this.connectionStatus,getStatus:()=>this.getStatus()}),this.eventRouter=new y({logger:this.logger,getSessionId:()=>this.sessionManager.getSessionId(),getConnectionStatus:()=>this.connectionStatus,onEvent:r=>{r.statusEventType!==null&&(this.statusController.handleStatusEvent(),r.isRecoveryEvent&&this.queueController.isPaused()&&(this.logger?.info?.("[EpsonPrinter] Printer recovered (Event). Resuming queue..."),this.resumeQueue())),r.connectionStatus!==null&&(r.connectionStatus==="CONNECTED"&&(this.connectionStatus="CONNECTED"),r.connectionStatus==="CONNECTED"&&this.statusController.handleConnected(),r.connectionStatus==="DISCONNECTED"&&(this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected()))}})}resumeQueue(){if(!this.queueController.isPaused())return;this.logger?.info?.("[EpsonPrinter] Resuming queue..."),this.recoveryController.stop(),this.queueController.resume()}isIosConnectionRecoveryCandidate(e){return j.OS!=="ios"?!1:e.code==="CONNECTION_FAILED"||e.code==="TIMEOUT"&&e.translationCode==="printer.error.connection_timeout"||e.translationCode==="printer.error.offline"}hasTargetInUseToken(e){if(!e||typeof e!="object")return!1;let r=String(e.code??"").toUpperCase(),n=String(e.message??"").toUpperCase();return r.includes("TARGET_IN_USE")||n.includes("TARGET_IN_USE")}isIosConnectBusyRecoveryCandidate(e){return j.OS!=="ios"||e.translationCode!=="printer.error.busy"?!1:!this.hasTargetInUseToken(e.originalError)}async recoverIosSessionForPrint(){if(!m)throw new Error("Native module not found");let e=this.target??this.defaultTarget;if(!e)throw new Error("Printer target is required");let r=this.sessionManager.getSessionId();if(r)try{await m.disconnect(r)}catch(i){this.logger?.error("[EpsonPrinter] iOS recovery disconnect failed (best-effort)",i)}await this.sessionManager.disposeSession(),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED");let n=await this.sessionManager.ensureSession();return await P(()=>m.connect(n,e,fe,this.model,this.lang)),this.target=e,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected(),n}async recoverIosSessionForConnect(e,r){if(!m)throw new Error("Native module not found");let n=this.sessionManager.getSessionId();if(n)try{await m.disconnect(n)}catch(o){this.logger?.error("[EpsonPrinter] iOS connect recovery disconnect failed (best-effort)",o)}await this.sessionManager.disposeSession(),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED");let i=await this.sessionManager.ensureSession();await P(()=>m.connect(i,e,r,this.model,this.lang)),this.target=e,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected()}async connect(e,r=5e3){let n=e??this.defaultTarget;if(!n){let i=new Error("Printer target is required");throw this.logger?.error("[EpsonPrinter] Connect failed: missing target",i),i}return this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),this.queueController.enqueue(async()=>{if(!m){this.logger?.error("[EpsonPrinter] Native module not found");return}if(this.connectionStatus==="CONNECTED"&&this.target===n)return;let i=await this.sessionManager.ensureSession();this.isConnecting=!0,this.connectionStatus="CONNECTING",this.eventRouter.emitStatus("CONNECTING");let o=!1;try{await P(()=>m.connect(i,n,r,this.model,this.lang)),this.target=n,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.isConnecting=!1,this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected()}catch(T){let c=C(T);if(!o&&this.isIosConnectBusyRecoveryCandidate(c)){o=!0,this.logger?.error("[EpsonPrinter] iOS busy connect suspected stale session. Recovering connection and retrying connect once...",c);try{await this.recoverIosSessionForConnect(n,r),this.logger?.info?.("[EpsonPrinter] iOS connect recovery succeeded."),this.isConnecting=!1;return}catch(l){let p=C(l);throw this.logger?.error("[EpsonPrinter] iOS connect recovery failed",p),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.isConnecting=!1,p}}throw this.logger?.error(`[EpsonPrinter] Connect failed for ${n}`,c),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.isConnecting=!1,c}})}async print(e){if(!m)return;this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null);let r=0,n=!1;return this.queueController.enqueue(async()=>{let i=await this.sessionManager.ensureSession(),o=$(e);for(;;){r++,this.logger?.info?.(`[EpsonPrinter] Print attempt ${r}`);try{await P(()=>m.print(i,o));break}catch(T){let c=K(T);if(!n&&this.isIosConnectionRecoveryCandidate(c)){n=!0,this.logger?.error("[EpsonPrinter] iOS stale session suspected. Recovering connection and retrying print once...",c);try{i=await this.recoverIosSessionForPrint(),this.logger?.info?.("[EpsonPrinter] iOS session recovery succeeded. Retrying print...");continue}catch(l){let p=C(l);throw this.logger?.error("[EpsonPrinter] iOS session recovery failed",p),p}}if(c.isHardwareError){this.queueController.pause(),this.logger?.error(`[EpsonPrinter] Hardware error on attempt ${r}. Waiting for recovery before retry...`,c),this.recoveryController.start(),await this.queueController.waitUntilResumed(),this.logger?.info?.("[EpsonPrinter] Recovery detected. Sending cut to flush partial print before retry...");try{await m.print(i,[{cmd:"addCut"}])}catch{}this.logger?.info?.("[EpsonPrinter] Retrying print job...")}else throw this.logger?.error(`[EpsonPrinter] Print failed (non-recoverable) on attempt ${r}`,c),c}}}).finally(()=>{this.disconnectTimer&&clearTimeout(this.disconnectTimer),this.disconnectTimer=setTimeout(()=>{this.performDisconnect()},5e3)})}performDisconnect(){this.queueController.enqueueBackground(async()=>{if(!this.disconnectTimer)return;let e=this.sessionManager.getSessionId();if(m&&this.connectionStatus==="CONNECTED"&&e)try{await m.disconnect(e),this.connectionStatus="DISCONNECTED",this.target=null,this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),await this.sessionManager.disposeSession()}catch(r){this.logger?.error("[EpsonPrinter] Auto-Disconnect failed",r)}this.disconnectTimer=null})}async printEmbedded(e){try{let r=J(e);return await this.print(r)}catch(r){let n=C(r);throw String(r).includes("MunchiPrinterError")||this.logger?.error("[EpsonPrinter] Embedded print failed",n),n}}async disconnect(){return this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),this.queueController.enqueue(async()=>{if(!m)return;let e=this.sessionManager.getSessionId();if(e)try{await m.disconnect(e),this.connectionStatus="DISCONNECTED",this.target=null,this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.eventRouter.removeStatusListener(),this.recoveryController.stop()}catch(r){this.logger?.error("[EpsonPrinter] Disconnect failed",r)}finally{this.statusController.clear(),await this.sessionManager.disposeSession()}})}async getStatus(){if(!m)return F;let e=this.sessionManager.getSessionId();if(!e)return F;try{return await m.getStatus(e)}catch(r){throw this.logger?.error("[EpsonPrinter] GetStatus failed",r),C(r)}}async openDrawer(){let e={commands:[{type:"drawer"}]};return this.print(e)}onConnectionChange(e){return this.eventRouter.onConnectionChange(e)}onStatusChange(e){return this.statusController.subscribe(e)}};import{NativeModules as Re}from"react-native";var Z=Re.MunchiEpsonModule,pe={bluetooth:["BT:"],tcp:["TCP:","TCPS:"],usb:["USB:"]},Ne=t=>t.includes("[local_"),Pe=(t,e)=>e?pe[e].some(n=>t.startsWith(n)):!0,Ie=async t=>{if(!Z)return console.warn("[EpsonDiscovery] Native module not found"),[];try{return(await Z.discover({timeout:t.timeout})).map(X).filter(r=>!r||Ne(r.target)?!1:Pe(r.target,t.connectionType))}catch(e){let r=C(e);throw console.error("[EpsonDiscovery] Discovery failed",r),r}};var Se=[[/^TM-m10/i,0],[/^TM-m30III/i,29],[/^TM-m30II/i,21],[/^TM-m30/i,1],[/^TM-m50II/i,30],[/^TM-m50/i,23],[/^TM-m55/i,31],[/^TM-P20II/i,27],[/^TM-P20/i,2],[/^TM-P60II/i,4],[/^TM-P60/i,3],[/^TM-P80II/i,28],[/^TM-P80/i,5],[/^TM-T20/i,6],[/^TM-T60/i,7],[/^TM-T70/i,8],[/^TM-T81/i,9],[/^TM-T82/i,10],[/^TM-T83III/i,19],[/^TM-T83/i,11],[/^TM-T88VII/i,24],[/^TM-T88/i,12],[/^TM-T90KP/i,14],[/^TM-T90/i,13],[/^TM-T100/i,20],[/^TM-U220II/i,32],[/^TM-U220/i,15],[/^TM-U330/i,16],[/^TM-L90LFC/i,25],[/^TM-L90/i,17],[/^TM-L100/i,26],[/^TM-H6000/i,18]],_e=t=>{for(let[e,r]of Se)if(e.test(t))return r;return null};var Oe=t=>{let e=C(t),r=e.message.toUpperCase(),n=t instanceof R?t.isHardwareError:A(t),i=e.translationCode==="printer.error.busy"||r.includes("BUSY")||r.includes("IN_USE")||r.includes("PRINT_BUSY"),o=e.code==="TIMEOUT"||e.translationCode==="printer.error.connection_timeout"||r.includes("TIMEOUT"),T=e.code==="CONNECTION_FAILED"||e.translationCode==="printer.error.offline",c=e.code==="DISCOVERY_FAILED",l="UNKNOWN";return n?l="HARDWARE":i?l="BUSY":o?l="TIMEOUT":T?l="CONNECTION":c?l="DISCOVERY":e.code==="PRINT_FAILED"&&(l="PRINT"),{code:e.code,translationCode:e.translationCode,message:e.message,category:l,isHardwareError:n,retryable:i||o,shouldPauseQueue:n,raw:t}},Ot=t=>Oe(t);import ye from"react";import{createContext as ve,useContext as De,useEffect as Me,useMemo as ee,useState as we}from"react";var te=ve(void 0),bt=({config:t,logger:e,children:r})=>{let[n,i]=we();Me(()=>{e&&z(e)},[e]);let o=ee(()=>{let c={...t,logger:e??t.logger};return ne(c)},[t.lang,t.model,t.target,e]),T=ee(()=>({printer:o,config:t,isReady:!0,error:n}),[o,t,n]);return ye.createElement(te.Provider,{value:T},r)},re=()=>{let t=De(te);if(!t)throw new Error("usePrinter must be used within a PrinterProvider");return t};import{useCallback as B,useEffect as x,useRef as ie,useState as Y}from"react";function Ut(t={}){let{enabled:e=!0}=t,{printer:r,config:n}=re(),[i,o]=Y("DISCONNECTED"),[T,c]=Y(null),[l,p]=Y(null),H=ie("DISCONNECTED"),V=ie(null),d=l!==null,N=B(E=>{V.current=E,p(E)},[]),I=B(E=>{if(E instanceof Error&&E.message){N(E.message);return}if(typeof E=="string"&&E.length>0){N(E);return}N("Unknown printer error")},[N]),a=B(()=>{V.current!==null&&N(null)},[N]);return x(()=>r.onConnectionChange(S=>{H.current=S,o(S),S==="CONNECTED"&&a()}),[a,r]),x(()=>e?r.onStatusChange(S=>{c(S),a()}):void 0,[a,e,r]),x(()=>{e&&i==="CONNECTED"&&r.getStatus().then(E=>{c(E),a()}).catch(I)},[I,a,i,e,r]),x(()=>{let E=H.current;if(e){E==="DISCONNECTED"&&i==="DISCONNECTED"&&r.connect(n.target,5e3).then(a).catch(I);return}(i==="CONNECTED"||i==="CONNECTING")&&r.disconnect().then(a).catch(I)},[I,a,n.target,i,e,r]),{connectionStatus:i,hardwareStatus:T,isError:d,errorMessage:l}}var be="1.0.7";function ne(t){return new b({...t,logger:t.logger??G()})}export{ce as Epos2CallbackCode,ae as Epos2ConnectionEvent,ue as Epos2ErrorStatus,le as Epos2Font,W as Epos2Lang,Q as Epos2StatusEvent,k as EpsonModel,U as FontSize,h as MunchiPrinterError,R as PrinterError,_ as PrinterErrorCode,bt as PrinterProvider,O as PrinterTranslationCode,be as VERSION,Ie as discoverPrinters,G as getGlobalLogger,ne as getPrinter,Ot as resolveEpsonError,_e as resolveModelFromBluetoothName,Oe as resolvePrinterError,z as setGlobalLogger,re as usePrinter,Ut as usePrinterStatus};
|
|
11
|
+
`,align:"left"})}return e.push({type:"feed",lines:3}),e.push({type:"cut"}),{commands:e}};var v=class{constructor(e){this.logger=e}queue=Promise.resolve();isQueuePaused=!1;resumeQueueResolver=null;isPaused(){return this.isQueuePaused}pause(){this.isQueuePaused=!0}resume(){this.isQueuePaused&&(this.isQueuePaused=!1,this.resumeQueueResolver&&(this.resumeQueueResolver(),this.resumeQueueResolver=null))}async waitUntilResumed(){if(this.isQueuePaused)return new Promise(e=>{let r=this.resumeQueueResolver;this.resumeQueueResolver=()=>{r&&r(),e()}})}enqueue(e){return new Promise((r,n)=>{let i=async()=>{this.isQueuePaused&&(this.logger?.info?.("[EpsonPrinter] Queue is PAUSED. Waiting for resume..."),await this.waitUntilResumed(),this.logger?.info?.("[EpsonPrinter] Queue RESUMED."));try{let o=await e();r(o)}catch(o){n(o)}};this.queue=this.queue.then(i,i)})}enqueueBackground(e){this.queue=this.queue.then(e,e)}};var D=class{constructor(e){this.config=e}recoveryTimer=null;start(){this.recoveryTimer||(this.config.logger?.info?.("[EpsonPrinter] Starting recovery polling..."),this.recoveryTimer=setInterval(async()=>{try{let e=await this.config.getStatus();if(e.online&&!e.coverOpen&&e.errorStatus==="NONE")this.config.logger?.info?.("[EpsonPrinter] Poller detected healthy status. Requesting queue resume."),this.config.onRecovered();else{let n=`[EpsonPrinter] Polling... Status: Online=${e.online}, Cover=${e.coverOpen}, Err=${e.errorStatus}`;this.config.logger?.info?.(n)}}catch(e){this.config.logger?.error("[EpsonPrinter] Recovery poll failed",e)}},2e3))}stop(){this.recoveryTimer&&(this.config.logger?.info?.("[EpsonPrinter] Stopping recovery polling."),clearInterval(this.recoveryTimer),this.recoveryTimer=null)}};var M=class{constructor(e){this.logger=e}sessionId=null;sessionInitPromise=null;getSessionId(){return this.sessionId}async ensureSession(){if(!m)throw new Error("Native module not found");return this.sessionId?this.sessionId:this.sessionInitPromise?this.sessionInitPromise:(this.sessionInitPromise=m.initSession().then(e=>(this.sessionId=e,e)).finally(()=>{this.sessionInitPromise=null}),this.sessionInitPromise)}async disposeSession(){if(!m||!this.sessionId){this.sessionId=null;return}let e=this.sessionId;this.sessionId=null;try{await m.disposeSession(e)}catch(r){this.logger?.error("[EpsonPrinter] Dispose session failed",r)}}};var w=class{constructor(e){this.config=e}statusCallbacks=new Set;latestHardwareStatus=null;statusRefreshPromise=null;statusRefreshTimer=null;subscribe(e){return this.statusCallbacks.add(e),this.latestHardwareStatus?e(this.latestHardwareStatus):this.config.getConnectionStatus()!=="CONNECTED"?e(this.config.defaultStatus):this.refreshNow(),()=>{this.statusCallbacks.delete(e)}}handleStatusEvent(){this.scheduleRefresh()}handleConnected(){this.scheduleRefresh(0)}handleDisconnected(){this.clearRefreshTimer(),this.setHardwareStatus(this.config.defaultStatus)}clear(){this.clearRefreshTimer()}async refreshNow(){if(this.config.getConnectionStatus()!=="CONNECTED"){this.setHardwareStatus(this.config.defaultStatus);return}if(this.statusRefreshPromise){await this.statusRefreshPromise;return}this.statusRefreshPromise=(async()=>{try{let e=await this.config.getStatus();this.setHardwareStatus(e)}catch(e){this.config.logger?.error("[EpsonPrinter] Status refresh failed",e),this.latestHardwareStatus||this.setHardwareStatus(this.config.defaultStatus)}})().finally(()=>{this.statusRefreshPromise=null}),await this.statusRefreshPromise}emitHardwareStatus(e){for(let r of this.statusCallbacks)r(e)}setHardwareStatus(e){this.latestHardwareStatus=e,this.emitHardwareStatus(e)}clearRefreshTimer(){this.statusRefreshTimer&&(clearTimeout(this.statusRefreshTimer),this.statusRefreshTimer=null)}scheduleRefresh(e=150){this.config.getConnectionStatus()==="CONNECTED"&&(this.statusRefreshTimer||(this.statusRefreshTimer=setTimeout(()=>{this.statusRefreshTimer=null,this.refreshNow()},e)))}};var F={online:!1,coverOpen:!1,paperEmpty:!1,paper:"EMPTY",errorStatus:"NONE",drawerOpen:!1},fe=5e3,b=class{disconnectTimer=null;connectionStatus="DISCONNECTED";isConnecting=!1;target=null;defaultTarget;model;lang;logger;sessionManager;queueController;recoveryController;statusController;eventRouter;constructor(e){this.logger=e.logger,this.defaultTarget=e.target??null,this.model=e.model,this.lang=e.lang??0,this.sessionManager=new M(this.logger),this.queueController=new v(this.logger),this.recoveryController=new D({logger:this.logger,getStatus:()=>this.getStatus(),onRecovered:()=>this.resumeQueue()}),this.statusController=new w({logger:this.logger,defaultStatus:F,getConnectionStatus:()=>this.connectionStatus,getStatus:()=>this.getStatus()}),this.eventRouter=new y({logger:this.logger,getSessionId:()=>this.sessionManager.getSessionId(),getConnectionStatus:()=>this.connectionStatus,onEvent:r=>{r.statusEventType!==null&&(this.statusController.handleStatusEvent(),r.isRecoveryEvent&&this.queueController.isPaused()&&(this.logger?.info?.("[EpsonPrinter] Printer recovered (Event). Resuming queue..."),this.resumeQueue())),r.connectionStatus!==null&&(r.connectionStatus==="CONNECTED"&&(this.connectionStatus="CONNECTED"),r.connectionStatus==="CONNECTED"&&this.statusController.handleConnected(),r.connectionStatus==="DISCONNECTED"&&(this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected()))}})}resumeQueue(){if(!this.queueController.isPaused())return;this.logger?.info?.("[EpsonPrinter] Resuming queue..."),this.recoveryController.stop(),this.queueController.resume()}isIosConnectionRecoveryCandidate(e){return j.OS!=="ios"?!1:e.code==="CONNECTION_FAILED"||e.code==="TIMEOUT"&&e.translationCode==="printer.error.connection_timeout"||e.translationCode==="printer.error.offline"}hasTargetInUseToken(e){if(!e||typeof e!="object")return!1;let r=String(e.code??"").toUpperCase(),n=String(e.message??"").toUpperCase();return r.includes("TARGET_IN_USE")||n.includes("TARGET_IN_USE")}isIosConnectBusyRecoveryCandidate(e){return j.OS!=="ios"||e.translationCode!=="printer.error.busy"?!1:!this.hasTargetInUseToken(e.originalError)}async recoverIosSessionForPrint(){if(!m)throw new Error("Native module not found");let e=this.target??this.defaultTarget;if(!e)throw new Error("Printer target is required");let r=this.sessionManager.getSessionId();if(r)try{await m.disconnect(r)}catch(i){this.logger?.error("[EpsonPrinter] iOS recovery disconnect failed (best-effort)",i)}await this.sessionManager.disposeSession(),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED");let n=await this.sessionManager.ensureSession();return await P(()=>m.connect(n,e,fe,this.model,this.lang)),this.target=e,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected(),n}async recoverIosSessionForConnect(e,r){if(!m)throw new Error("Native module not found");let n=this.sessionManager.getSessionId();if(n)try{await m.disconnect(n)}catch(o){this.logger?.error("[EpsonPrinter] iOS connect recovery disconnect failed (best-effort)",o)}await this.sessionManager.disposeSession(),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED");let i=await this.sessionManager.ensureSession();await P(()=>m.connect(i,e,r,this.model,this.lang)),this.target=e,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected()}async connect(e,r=5e3){let n=e??this.defaultTarget;if(!n){let i=new Error("Printer target is required");throw this.logger?.error("[EpsonPrinter] Connect failed: missing target",i),i}return this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),this.queueController.enqueue(async()=>{if(!m){this.logger?.error("[EpsonPrinter] Native module not found");return}if(this.connectionStatus==="CONNECTED"&&this.target===n)return;let i=await this.sessionManager.ensureSession();this.isConnecting=!0,this.connectionStatus="CONNECTING",this.eventRouter.emitStatus("CONNECTING");let o=!1;try{await P(()=>m.connect(i,n,r,this.model,this.lang)),this.target=n,this.connectionStatus="CONNECTED",this.eventRouter.emitStatus("CONNECTED"),this.isConnecting=!1,this.eventRouter.ensureStatusListener(),this.eventRouter.ensureConnectionListener(),this.statusController.handleConnected()}catch(T){let c=C(T);if(!o&&this.isIosConnectBusyRecoveryCandidate(c)){o=!0,this.logger?.error("[EpsonPrinter] iOS busy connect suspected stale session. Recovering connection and retrying connect once...",c);try{await this.recoverIosSessionForConnect(n,r),this.logger?.info?.("[EpsonPrinter] iOS connect recovery succeeded."),this.isConnecting=!1;return}catch(l){let p=C(l);throw this.logger?.error("[EpsonPrinter] iOS connect recovery failed",p),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.isConnecting=!1,p}}throw this.logger?.error(`[EpsonPrinter] Connect failed for ${n}`,c),this.connectionStatus="DISCONNECTED",this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.isConnecting=!1,c}})}async print(e){if(!m)return;this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null);let r=0,n=!1;return this.queueController.enqueue(async()=>{let i=await this.sessionManager.ensureSession(),o=$(e);for(;;){r++,this.logger?.info?.(`[EpsonPrinter] Print attempt ${r}`);try{await P(()=>m.print(i,o));break}catch(T){let c=K(T);if(!n&&this.isIosConnectionRecoveryCandidate(c)){n=!0,this.logger?.error("[EpsonPrinter] iOS stale session suspected. Recovering connection and retrying print once...",c);try{i=await this.recoverIosSessionForPrint(),this.logger?.info?.("[EpsonPrinter] iOS session recovery succeeded. Retrying print...");continue}catch(l){let p=C(l);throw this.logger?.error("[EpsonPrinter] iOS session recovery failed",p),p}}if(c.isHardwareError){this.queueController.pause(),this.logger?.error(`[EpsonPrinter] Hardware error on attempt ${r}. Waiting for recovery before retry...`,c),this.recoveryController.start(),await this.queueController.waitUntilResumed(),this.logger?.info?.("[EpsonPrinter] Recovery detected. Sending cut to flush partial print before retry...");try{await m.print(i,[{cmd:"addCut"}])}catch{}this.logger?.info?.("[EpsonPrinter] Retrying print job...")}else throw this.logger?.error(`[EpsonPrinter] Print failed (non-recoverable) on attempt ${r}`,c),c}}}).finally(()=>{this.disconnectTimer&&clearTimeout(this.disconnectTimer),this.disconnectTimer=setTimeout(()=>{this.performDisconnect()},5e3)})}performDisconnect(){this.queueController.enqueueBackground(async()=>{if(!this.disconnectTimer)return;let e=this.sessionManager.getSessionId();if(m&&this.connectionStatus==="CONNECTED"&&e)try{await m.disconnect(e),this.connectionStatus="DISCONNECTED",this.target=null,this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),await this.sessionManager.disposeSession()}catch(r){this.logger?.error("[EpsonPrinter] Auto-Disconnect failed",r)}this.disconnectTimer=null})}async printEmbedded(e){try{let r=J(e);return await this.print(r)}catch(r){let n=C(r);throw String(r).includes("MunchiPrinterError")||this.logger?.error("[EpsonPrinter] Embedded print failed",n),n}}async disconnect(){return this.disconnectTimer&&(clearTimeout(this.disconnectTimer),this.disconnectTimer=null),this.queueController.enqueue(async()=>{if(!m)return;let e=this.sessionManager.getSessionId();if(e)try{await m.disconnect(e),this.connectionStatus="DISCONNECTED",this.target=null,this.statusController.handleDisconnected(),this.eventRouter.emitStatus("DISCONNECTED"),this.eventRouter.removeStatusListener(),this.recoveryController.stop()}catch(r){this.logger?.error("[EpsonPrinter] Disconnect failed",r)}finally{this.statusController.clear(),await this.sessionManager.disposeSession()}})}async getStatus(){if(!m)return F;let e=this.sessionManager.getSessionId();if(!e)return F;try{return await m.getStatus(e)}catch(r){throw this.logger?.error("[EpsonPrinter] GetStatus failed",r),C(r)}}async openDrawer(){let e={commands:[{type:"drawer"}]};return this.print(e)}onConnectionChange(e){return this.eventRouter.onConnectionChange(e)}onStatusChange(e){return this.statusController.subscribe(e)}};import{NativeModules as Re}from"react-native";var Z=Re.MunchiEpsonModule,pe={bluetooth:["BT:"],tcp:["TCP:","TCPS:"],usb:["USB:"]},Ne=t=>t.includes("[local_"),Pe=(t,e)=>e?pe[e].some(n=>t.startsWith(n)):!0,Ie=async t=>{if(!Z)return console.warn("[EpsonDiscovery] Native module not found"),[];try{return(await Z.discover({timeout:t.timeout})).map(X).filter(r=>!r||Ne(r.target)?!1:Pe(r.target,t.connectionType))}catch(e){let r=C(e);throw console.error("[EpsonDiscovery] Discovery failed",r),r}};var Se=[[/^TM-m10/i,0],[/^TM-m30III/i,29],[/^TM-m30II/i,21],[/^TM-m30/i,1],[/^TM-m50II/i,30],[/^TM-m50/i,23],[/^TM-m55/i,31],[/^TM-P20II/i,27],[/^TM-P20/i,2],[/^TM-P60II/i,4],[/^TM-P60/i,3],[/^TM-P80II/i,28],[/^TM-P80/i,5],[/^TM-T20/i,6],[/^TM-T60/i,7],[/^TM-T70/i,8],[/^TM-T81/i,9],[/^TM-T82/i,10],[/^TM-T83III/i,19],[/^TM-T83/i,11],[/^TM-T88VII/i,24],[/^TM-T88/i,12],[/^TM-T90KP/i,14],[/^TM-T90/i,13],[/^TM-T100/i,20],[/^TM-U220II/i,32],[/^TM-U220/i,15],[/^TM-U330/i,16],[/^TM-L90LFC/i,25],[/^TM-L90/i,17],[/^TM-L100/i,26],[/^TM-H6000/i,18]],_e=t=>{for(let[e,r]of Se)if(e.test(t))return r;return null};var Oe=t=>{let e=C(t),r=e.message.toUpperCase(),n=t instanceof R?t.isHardwareError:A(t),i=e.translationCode==="printer.error.busy"||r.includes("BUSY")||r.includes("IN_USE")||r.includes("PRINT_BUSY"),o=e.code==="TIMEOUT"||e.translationCode==="printer.error.connection_timeout"||r.includes("TIMEOUT"),T=e.code==="CONNECTION_FAILED"||e.translationCode==="printer.error.offline",c=e.code==="DISCOVERY_FAILED",l="UNKNOWN";return n?l="HARDWARE":i?l="BUSY":o?l="TIMEOUT":T?l="CONNECTION":c?l="DISCOVERY":e.code==="PRINT_FAILED"&&(l="PRINT"),{code:e.code,translationCode:e.translationCode,message:e.message,category:l,isHardwareError:n,retryable:i||o,shouldPauseQueue:n,raw:t}},Ot=t=>Oe(t);import ye from"react";import{createContext as ve,useContext as De,useEffect as Me,useMemo as ee,useState as we}from"react";var te=ve(void 0),bt=({config:t,logger:e,children:r})=>{let[n,i]=we();Me(()=>{e&&z(e)},[e]);let o=ee(()=>{let c={...t,logger:e??t.logger};return ne(c)},[t.lang,t.model,t.target,e]),T=ee(()=>({printer:o,config:t,isReady:!0,error:n}),[o,t,n]);return ye.createElement(te.Provider,{value:T},r)},re=()=>{let t=De(te);if(!t)throw new Error("usePrinter must be used within a PrinterProvider");return t};import{useCallback as B,useEffect as x,useRef as ie,useState as Y}from"react";function Ut(t={}){let{enabled:e=!0}=t,{printer:r,config:n}=re(),[i,o]=Y("DISCONNECTED"),[T,c]=Y(null),[l,p]=Y(null),H=ie("DISCONNECTED"),V=ie(null),d=l!==null,N=B(E=>{V.current=E,p(E)},[]),I=B(E=>{if(E instanceof Error&&E.message){N(E.message);return}if(typeof E=="string"&&E.length>0){N(E);return}N("Unknown printer error")},[N]),a=B(()=>{V.current!==null&&N(null)},[N]);return x(()=>r.onConnectionChange(S=>{H.current=S,o(S),S==="CONNECTED"&&a()}),[a,r]),x(()=>e?r.onStatusChange(S=>{c(S),a()}):void 0,[a,e,r]),x(()=>{e&&i==="CONNECTED"&&r.getStatus().then(E=>{c(E),a()}).catch(I)},[I,a,i,e,r]),x(()=>{let E=H.current;if(e){E==="DISCONNECTED"&&i==="DISCONNECTED"&&r.connect(n.target,5e3).then(a).catch(I);return}(i==="CONNECTED"||i==="CONNECTING")&&r.disconnect().then(a).catch(I)},[I,a,n.target,i,e,r]),{connectionStatus:i,hardwareStatus:T,isError:d,errorMessage:l}}var be="1.0.8";function ne(t){return new b({...t,logger:t.logger??G()})}export{ce as Epos2CallbackCode,ae as Epos2ConnectionEvent,ue as Epos2ErrorStatus,le as Epos2Font,W as Epos2Lang,Q as Epos2StatusEvent,k as EpsonModel,U as FontSize,h as MunchiPrinterError,R as PrinterError,_ as PrinterErrorCode,bt as PrinterProvider,O as PrinterTranslationCode,be as VERSION,Ie as discoverPrinters,G as getGlobalLogger,ne as getPrinter,Ot as resolveEpsonError,_e as resolveModelFromBluetoothName,Oe as resolvePrinterError,z as setGlobalLogger,re as usePrinter,Ut as usePrinterStatus};
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "1.0.
|
|
1
|
+
export declare const VERSION = "1.0.8";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
|
@@ -24,6 +24,7 @@ class MunchiEpsonModule: RCTEventEmitter, Epos2ConnectionDelegate, Epos2PtrStatu
|
|
|
24
24
|
private var discoveryResolve: RCTPromiseResolveBlock?
|
|
25
25
|
private var discoveryReject: RCTPromiseRejectBlock?
|
|
26
26
|
private var foundPrinters: [NSDictionary] = []
|
|
27
|
+
private let printerQueue = DispatchQueue(label: "com.munchiepsonprinter.epson")
|
|
27
28
|
|
|
28
29
|
override func supportedEvents() -> [String]! {
|
|
29
30
|
return ["onPrinterStatusChange", "onPrinterConnectionChange", "onPrinterReceive"]
|
|
@@ -95,319 +96,354 @@ class MunchiEpsonModule: RCTEventEmitter, Epos2ConnectionDelegate, Epos2PtrStatu
|
|
|
95
96
|
|
|
96
97
|
@objc(initSession:rejecter:)
|
|
97
98
|
func initSession(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
printerQueue.async { [weak self] in
|
|
100
|
+
guard let self = self else { return }
|
|
101
|
+
|
|
102
|
+
let sessionId = UUID().uuidString
|
|
103
|
+
self.sessions[sessionId] = EpsonSession(sessionId: sessionId)
|
|
104
|
+
resolve(sessionId)
|
|
105
|
+
}
|
|
101
106
|
}
|
|
102
107
|
|
|
103
108
|
@objc(disposeSession:resolver:rejecter:)
|
|
104
109
|
func disposeSession(_ sessionId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
105
|
-
|
|
110
|
+
printerQueue.async { [weak self] in
|
|
111
|
+
guard let self = self else { return }
|
|
112
|
+
|
|
113
|
+
guard let session = self.sessions.removeValue(forKey: sessionId) else {
|
|
114
|
+
resolve(true)
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
self.teardownPrinter(session, disconnect: true)
|
|
106
119
|
resolve(true)
|
|
107
|
-
return
|
|
108
120
|
}
|
|
109
|
-
|
|
110
|
-
teardownPrinter(session, disconnect: true)
|
|
111
|
-
resolve(true)
|
|
112
121
|
}
|
|
113
122
|
|
|
114
123
|
@objc(connect:target:timeout:model:lang:resolver:rejecter:)
|
|
115
124
|
func connect(_ sessionId: String, target: String, timeout: Double, model: Int, lang: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return
|
|
119
|
-
}
|
|
125
|
+
printerQueue.async { [weak self] in
|
|
126
|
+
guard let self = self else { return }
|
|
120
127
|
|
|
121
|
-
|
|
128
|
+
guard let session = self.sessions[sessionId] else {
|
|
129
|
+
reject("SESSION_ERROR", "Session not found", nil)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
122
132
|
|
|
123
|
-
|
|
124
|
-
teardownPrinter(session, disconnect: true)
|
|
125
|
-
connectionDelay = 0.5
|
|
126
|
-
}
|
|
133
|
+
var connectionDelay = 0.0
|
|
127
134
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
reject("SESSION_ERROR", "Session disposed while connecting", nil)
|
|
132
|
-
return
|
|
135
|
+
if session.printer != nil {
|
|
136
|
+
self.teardownPrinter(session, disconnect: true)
|
|
137
|
+
connectionDelay = 0.5
|
|
133
138
|
}
|
|
134
139
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
+
self.printerQueue.asyncAfter(deadline: .now() + connectionDelay) { [weak self] in
|
|
141
|
+
guard let self = self else { return }
|
|
142
|
+
guard let latestSession = self.sessions[sessionId] else {
|
|
143
|
+
reject("SESSION_ERROR", "Session disposed while connecting", nil)
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if let ownerSessionId = self.targetToSessionId[target], ownerSessionId != sessionId {
|
|
148
|
+
if let ownerSession = self.sessions[ownerSessionId] {
|
|
149
|
+
if ownerSession.printResolve != nil {
|
|
150
|
+
reject("TARGET_IN_USE", "Target is busy with an active print job: \(target)", nil)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
_ = self.teardownPrinter(ownerSession, disconnect: true)
|
|
154
|
+
} else {
|
|
155
|
+
self.targetToSessionId.removeValue(forKey: target)
|
|
140
156
|
}
|
|
141
|
-
_ = self.teardownPrinter(ownerSession, disconnect: true)
|
|
142
|
-
} else {
|
|
143
|
-
self.targetToSessionId.removeValue(forKey: target)
|
|
144
157
|
}
|
|
145
|
-
}
|
|
146
158
|
|
|
147
|
-
|
|
148
|
-
|
|
159
|
+
let safeLang = self.normalizedLanguage(lang)
|
|
160
|
+
let safeModel = self.normalizedModel(model)
|
|
149
161
|
|
|
150
|
-
|
|
162
|
+
latestSession.printer = Epos2Printer(printerSeries: safeModel, lang: safeLang)
|
|
151
163
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
164
|
+
guard let p = latestSession.printer else {
|
|
165
|
+
reject("INIT_ERROR", "Failed to initialize printer object", nil)
|
|
166
|
+
return
|
|
167
|
+
}
|
|
156
168
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
169
|
+
p.setConnectionEventDelegate(self)
|
|
170
|
+
p.setStatusChangeEventDelegate(self)
|
|
171
|
+
p.setReceiveEventDelegate(self)
|
|
172
|
+
self.printerToSessionId[ObjectIdentifier(p)] = sessionId
|
|
173
|
+
latestSession.target = target
|
|
162
174
|
|
|
163
|
-
|
|
164
|
-
|
|
175
|
+
let connectTimeout = Int(timeout)
|
|
176
|
+
let result = p.connect(target, timeout: connectTimeout)
|
|
165
177
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
178
|
+
if result == EPOS2_SUCCESS.rawValue {
|
|
179
|
+
_ = p.startMonitor()
|
|
180
|
+
self.targetToSessionId[target] = sessionId
|
|
181
|
+
resolve("Connected to \(target)")
|
|
182
|
+
} else {
|
|
183
|
+
self.teardownPrinter(latestSession, disconnect: false)
|
|
184
|
+
reject("CONNECT_ERROR", "Failed to connect: \(result)", nil)
|
|
185
|
+
}
|
|
173
186
|
}
|
|
174
187
|
}
|
|
175
188
|
}
|
|
176
189
|
|
|
177
190
|
@objc(disconnect:resolver:rejecter:)
|
|
178
191
|
func disconnect(_ sessionId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return
|
|
182
|
-
}
|
|
192
|
+
printerQueue.async { [weak self] in
|
|
193
|
+
guard let self = self else { return }
|
|
183
194
|
|
|
184
|
-
|
|
195
|
+
guard let session = self.sessions[sessionId] else {
|
|
196
|
+
resolve(true)
|
|
197
|
+
return
|
|
198
|
+
}
|
|
185
199
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
200
|
+
let result = self.teardownPrinter(session, disconnect: true)
|
|
201
|
+
|
|
202
|
+
if result == nil || result == EPOS2_SUCCESS.rawValue {
|
|
203
|
+
resolve(true)
|
|
204
|
+
} else {
|
|
205
|
+
resolve(false)
|
|
206
|
+
}
|
|
190
207
|
}
|
|
191
208
|
}
|
|
192
209
|
|
|
193
210
|
// --- Delegate Methods ---
|
|
194
211
|
|
|
195
212
|
func onConnection(_ deviceObj: Any!, eventType: Int32) {
|
|
196
|
-
|
|
197
|
-
let
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
printerQueue.async { [weak self] in
|
|
214
|
+
guard let self = self else { return }
|
|
215
|
+
guard
|
|
216
|
+
let obj = deviceObj as AnyObject?,
|
|
217
|
+
let sessionId = self.printerToSessionId[ObjectIdentifier(obj)],
|
|
218
|
+
let session = self.sessions[sessionId]
|
|
219
|
+
else { return }
|
|
220
|
+
|
|
221
|
+
var status = "UNKNOWN"
|
|
222
|
+
switch eventType {
|
|
223
|
+
case EPOS2_EVENT_RECONNECTING.rawValue:
|
|
224
|
+
status = "RECONNECTING"
|
|
225
|
+
case EPOS2_EVENT_RECONNECT.rawValue:
|
|
226
|
+
status = "RECONNECTED"
|
|
227
|
+
case EPOS2_EVENT_DISCONNECT.rawValue:
|
|
228
|
+
status = "DISCONNECTED"
|
|
229
|
+
default:
|
|
230
|
+
break
|
|
231
|
+
}
|
|
213
232
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
233
|
+
self.sendEvent(withName: "onPrinterConnectionChange", body: [
|
|
234
|
+
"sessionId": session.sessionId,
|
|
235
|
+
"status": status,
|
|
236
|
+
"target": session.target ?? ""
|
|
237
|
+
])
|
|
238
|
+
}
|
|
219
239
|
}
|
|
220
240
|
|
|
221
241
|
func onPtrStatusChange(_ printerObj: Epos2Printer!, eventType: Int32) {
|
|
222
|
-
|
|
223
|
-
let
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
242
|
+
printerQueue.async { [weak self] in
|
|
243
|
+
guard let self = self else { return }
|
|
244
|
+
guard
|
|
245
|
+
let sessionId = self.printerToSessionId[ObjectIdentifier(printerObj)],
|
|
246
|
+
let session = self.sessions[sessionId]
|
|
247
|
+
else { return }
|
|
248
|
+
|
|
249
|
+
self.sendEvent(withName: "onPrinterStatusChange", body: [
|
|
250
|
+
"sessionId": session.sessionId,
|
|
251
|
+
"target": session.target ?? "",
|
|
252
|
+
"eventType": eventType
|
|
253
|
+
])
|
|
254
|
+
}
|
|
232
255
|
}
|
|
233
256
|
|
|
234
257
|
func onPtrReceive(_ printerObj: Epos2Printer!, code: Int32, status: Epos2PrinterStatusInfo!, printJobId: String!) {
|
|
235
|
-
|
|
236
|
-
let
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
258
|
+
printerQueue.async { [weak self] in
|
|
259
|
+
guard let self = self else { return }
|
|
260
|
+
guard
|
|
261
|
+
let sessionId = self.printerToSessionId[ObjectIdentifier(printerObj)],
|
|
262
|
+
let session = self.sessions[sessionId]
|
|
263
|
+
else { return }
|
|
264
|
+
|
|
265
|
+
session.printTimeoutWork?.cancel()
|
|
266
|
+
session.printTimeoutWork = nil
|
|
267
|
+
|
|
268
|
+
if let resolve = session.printResolve, let reject = session.printReject {
|
|
269
|
+
if code == EPOS2_CODE_SUCCESS.rawValue {
|
|
270
|
+
resolve(true)
|
|
271
|
+
} else {
|
|
272
|
+
reject("PRINT_FAILURE", "Print finished with error code: \(code)", nil)
|
|
273
|
+
}
|
|
274
|
+
session.printResolve = nil
|
|
275
|
+
session.printReject = nil
|
|
248
276
|
}
|
|
249
|
-
session.printResolve = nil
|
|
250
|
-
session.printReject = nil
|
|
251
|
-
}
|
|
252
277
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
278
|
+
self.sendEvent(withName: "onPrinterReceive", body: [
|
|
279
|
+
"sessionId": session.sessionId,
|
|
280
|
+
"target": session.target ?? "",
|
|
281
|
+
"code": code
|
|
282
|
+
])
|
|
283
|
+
}
|
|
258
284
|
}
|
|
259
285
|
|
|
260
286
|
@objc(print:commands:resolver:rejecter:)
|
|
261
287
|
func print(_ sessionId: String, commands: NSArray, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
288
|
+
printerQueue.async { [weak self] in
|
|
289
|
+
guard let self = self else { return }
|
|
290
|
+
guard let session = self.sessions[sessionId], let p = session.printer else {
|
|
291
|
+
reject("PRINT_ERROR", "Printer not connected", nil)
|
|
292
|
+
return
|
|
293
|
+
}
|
|
266
294
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
295
|
+
if session.printResolve != nil {
|
|
296
|
+
reject("PRINT_BUSY", "Another print job is in progress", nil)
|
|
297
|
+
return
|
|
298
|
+
}
|
|
271
299
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
300
|
+
p.clearCommandBuffer()
|
|
301
|
+
|
|
302
|
+
for command in commands {
|
|
303
|
+
if let cmd = command as? NSDictionary, let type = cmd["cmd"] as? String {
|
|
304
|
+
switch type {
|
|
305
|
+
case "addText":
|
|
306
|
+
if let data = cmd["data"] as? String {
|
|
307
|
+
if let align = cmd["align"] as? String {
|
|
308
|
+
var alignVal = EPOS2_ALIGN_LEFT.rawValue
|
|
309
|
+
if align == "center" { alignVal = EPOS2_ALIGN_CENTER.rawValue }
|
|
310
|
+
else if align == "right" { alignVal = EPOS2_ALIGN_RIGHT.rawValue }
|
|
311
|
+
p.addTextAlign(alignVal)
|
|
312
|
+
}
|
|
313
|
+
if let bold = cmd["bold"] as? Bool {
|
|
314
|
+
p.addTextStyle(EPOS2_PARAM_DEFAULT, ul: EPOS2_PARAM_DEFAULT, em: bold ? EPOS2_TRUE : EPOS2_FALSE, color: EPOS2_PARAM_DEFAULT)
|
|
315
|
+
}
|
|
316
|
+
if let size = cmd["size"] as? String {
|
|
317
|
+
}
|
|
318
|
+
p.addText(data)
|
|
319
|
+
}
|
|
320
|
+
case "addTextAlign":
|
|
321
|
+
if let align = cmd["align"] as? String {
|
|
322
|
+
var alignVal = EPOS2_ALIGN_LEFT.rawValue
|
|
323
|
+
if align == "center" { alignVal = EPOS2_ALIGN_CENTER.rawValue }
|
|
324
|
+
else if align == "right" { alignVal = EPOS2_ALIGN_RIGHT.rawValue }
|
|
325
|
+
p.addTextAlign(alignVal)
|
|
326
|
+
}
|
|
327
|
+
case "addTextStyle":
|
|
328
|
+
if let bold = cmd["bold"] as? Bool {
|
|
329
|
+
p.addTextStyle(EPOS2_PARAM_DEFAULT, ul: EPOS2_PARAM_DEFAULT, em: bold ? EPOS2_TRUE : EPOS2_FALSE, color: EPOS2_PARAM_DEFAULT)
|
|
330
|
+
}
|
|
331
|
+
case "addTextSize":
|
|
332
|
+
if let w = cmd["width"] as? Int, let h = cmd["height"] as? Int {
|
|
333
|
+
p.addTextSize(Int(w), height: Int(h))
|
|
334
|
+
}
|
|
335
|
+
case "addBarcode":
|
|
336
|
+
if let data = cmd["data"] as? String, let typeStr = cmd["type"] as? String {
|
|
337
|
+
var type = EPOS2_BARCODE_CODE39.rawValue
|
|
338
|
+
if typeStr == "UPC-A" { type = EPOS2_BARCODE_UPC_A.rawValue }
|
|
339
|
+
else if typeStr == "UPC-E" { type = EPOS2_BARCODE_UPC_E.rawValue }
|
|
340
|
+
else if typeStr == "EAN13" { type = EPOS2_BARCODE_EAN13.rawValue }
|
|
341
|
+
else if typeStr == "EAN8" { type = EPOS2_BARCODE_EAN8.rawValue }
|
|
342
|
+
else if typeStr == "CODE39" { type = EPOS2_BARCODE_CODE39.rawValue }
|
|
343
|
+
else if typeStr == "ITF" { type = EPOS2_BARCODE_ITF.rawValue }
|
|
344
|
+
else if typeStr == "CODABAR" { type = EPOS2_BARCODE_CODABAR.rawValue }
|
|
345
|
+
|
|
346
|
+
p.addBarcode(data, type: type, hri: EPOS2_HRI_BELOW.rawValue, font: EPOS2_FONT_A.rawValue, width: 2, height: 100)
|
|
347
|
+
}
|
|
348
|
+
case "addSymbol":
|
|
349
|
+
if let data = cmd["data"] as? String {
|
|
350
|
+
p.addSymbol(data, type: EPOS2_SYMBOL_QRCODE_MODEL_2.rawValue, level: EPOS2_LEVEL_M.rawValue, width: 3, height: 3, size: 0)
|
|
351
|
+
}
|
|
352
|
+
case "addCut":
|
|
353
|
+
p.addCut(EPOS2_CUT_FEED.rawValue)
|
|
354
|
+
case "addFeedLine":
|
|
355
|
+
if let line = cmd["line"] as? Int {
|
|
356
|
+
p.addFeedLine(Int(line))
|
|
357
|
+
}
|
|
358
|
+
case "addPulse":
|
|
359
|
+
p.addPulse(EPOS2_DRAWER_2PIN.rawValue, time: EPOS2_PULSE_100.rawValue)
|
|
360
|
+
case "addTextLang":
|
|
361
|
+
if let lang = cmd["lang"] as? Int {
|
|
362
|
+
p.addTextLang(Int32(lang))
|
|
363
|
+
}
|
|
364
|
+
case "addTextFont":
|
|
365
|
+
if let font = cmd["font"] as? Int {
|
|
366
|
+
p.addTextFont(Int32(font))
|
|
367
|
+
}
|
|
368
|
+
case "addImage":
|
|
369
|
+
if let image = self.image(for: cmd) {
|
|
370
|
+
let width = Int(image.size.width.rounded(.up))
|
|
371
|
+
let height = Int(image.size.height.rounded(.up))
|
|
372
|
+
p.add(
|
|
373
|
+
image,
|
|
374
|
+
x: 0,
|
|
375
|
+
y: 0,
|
|
376
|
+
width: width,
|
|
377
|
+
height: height,
|
|
378
|
+
color: EPOS2_COLOR_1.rawValue,
|
|
379
|
+
mode: EPOS2_MODE_MONO.rawValue,
|
|
380
|
+
halftone: EPOS2_HALFTONE_DITHER.rawValue,
|
|
381
|
+
brightness: Double(EPOS2_PARAM_DEFAULT),
|
|
382
|
+
compress: EPOS2_COMPRESS_AUTO.rawValue
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
default:
|
|
386
|
+
break
|
|
291
387
|
}
|
|
292
|
-
case "addTextAlign":
|
|
293
|
-
if let align = cmd["align"] as? String {
|
|
294
|
-
var alignVal = EPOS2_ALIGN_LEFT.rawValue
|
|
295
|
-
if align == "center" { alignVal = EPOS2_ALIGN_CENTER.rawValue }
|
|
296
|
-
else if align == "right" { alignVal = EPOS2_ALIGN_RIGHT.rawValue }
|
|
297
|
-
p.addTextAlign(alignVal)
|
|
298
|
-
}
|
|
299
|
-
case "addTextStyle":
|
|
300
|
-
if let bold = cmd["bold"] as? Bool {
|
|
301
|
-
p.addTextStyle(EPOS2_PARAM_DEFAULT, ul: EPOS2_PARAM_DEFAULT, em: bold ? EPOS2_TRUE : EPOS2_FALSE, color: EPOS2_PARAM_DEFAULT)
|
|
302
|
-
}
|
|
303
|
-
case "addTextSize":
|
|
304
|
-
if let w = cmd["width"] as? Int, let h = cmd["height"] as? Int {
|
|
305
|
-
p.addTextSize(Int(w), height: Int(h))
|
|
306
|
-
}
|
|
307
|
-
case "addBarcode":
|
|
308
|
-
if let data = cmd["data"] as? String, let typeStr = cmd["type"] as? String {
|
|
309
|
-
var type = EPOS2_BARCODE_CODE39.rawValue
|
|
310
|
-
if typeStr == "UPC-A" { type = EPOS2_BARCODE_UPC_A.rawValue }
|
|
311
|
-
else if typeStr == "UPC-E" { type = EPOS2_BARCODE_UPC_E.rawValue }
|
|
312
|
-
else if typeStr == "EAN13" { type = EPOS2_BARCODE_EAN13.rawValue }
|
|
313
|
-
else if typeStr == "EAN8" { type = EPOS2_BARCODE_EAN8.rawValue }
|
|
314
|
-
else if typeStr == "CODE39" { type = EPOS2_BARCODE_CODE39.rawValue }
|
|
315
|
-
else if typeStr == "ITF" { type = EPOS2_BARCODE_ITF.rawValue }
|
|
316
|
-
else if typeStr == "CODABAR" { type = EPOS2_BARCODE_CODABAR.rawValue }
|
|
317
|
-
|
|
318
|
-
p.addBarcode(data, type: type, hri: EPOS2_HRI_BELOW.rawValue, font: EPOS2_FONT_A.rawValue, width: 2, height: 100)
|
|
319
|
-
}
|
|
320
|
-
case "addSymbol":
|
|
321
|
-
if let data = cmd["data"] as? String {
|
|
322
|
-
p.addSymbol(data, type: EPOS2_SYMBOL_QRCODE_MODEL_2.rawValue, level: EPOS2_LEVEL_M.rawValue, width: 3, height: 3, size: 0)
|
|
323
|
-
}
|
|
324
|
-
case "addCut":
|
|
325
|
-
p.addCut(EPOS2_CUT_FEED.rawValue)
|
|
326
|
-
case "addFeedLine":
|
|
327
|
-
if let line = cmd["line"] as? Int {
|
|
328
|
-
p.addFeedLine(Int(line))
|
|
329
|
-
}
|
|
330
|
-
case "addPulse":
|
|
331
|
-
p.addPulse(EPOS2_DRAWER_2PIN.rawValue, time: EPOS2_PULSE_100.rawValue)
|
|
332
|
-
case "addTextLang":
|
|
333
|
-
if let lang = cmd["lang"] as? Int {
|
|
334
|
-
p.addTextLang(Int32(lang))
|
|
335
|
-
}
|
|
336
|
-
case "addTextFont":
|
|
337
|
-
if let font = cmd["font"] as? Int {
|
|
338
|
-
p.addTextFont(Int32(font))
|
|
339
|
-
}
|
|
340
|
-
case "addImage":
|
|
341
|
-
if let image = image(for: cmd) {
|
|
342
|
-
let width = Int(image.size.width.rounded(.up))
|
|
343
|
-
let height = Int(image.size.height.rounded(.up))
|
|
344
|
-
p.add(
|
|
345
|
-
image,
|
|
346
|
-
x: 0,
|
|
347
|
-
y: 0,
|
|
348
|
-
width: width,
|
|
349
|
-
height: height,
|
|
350
|
-
color: EPOS2_COLOR_1.rawValue,
|
|
351
|
-
mode: EPOS2_MODE_MONO.rawValue,
|
|
352
|
-
halftone: EPOS2_HALFTONE_DITHER.rawValue,
|
|
353
|
-
brightness: Double(EPOS2_PARAM_DEFAULT),
|
|
354
|
-
compress: EPOS2_COMPRESS_AUTO.rawValue
|
|
355
|
-
)
|
|
356
|
-
}
|
|
357
|
-
default:
|
|
358
|
-
break
|
|
359
388
|
}
|
|
360
389
|
}
|
|
361
|
-
}
|
|
362
390
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
391
|
+
session.printResolve = resolve
|
|
392
|
+
session.printReject = reject
|
|
393
|
+
|
|
394
|
+
let result = p.sendData(Int(EPOS2_PARAM_DEFAULT))
|
|
395
|
+
if result != EPOS2_SUCCESS.rawValue {
|
|
396
|
+
let errorMsg = self.getErrorDescription(result)
|
|
397
|
+
session.printResolve = nil
|
|
398
|
+
session.printReject = nil
|
|
399
|
+
reject("PRINT_ERROR", "Failed to send data: \(result) (\(errorMsg))", nil)
|
|
400
|
+
} else {
|
|
401
|
+
let timeoutWork = DispatchWorkItem { [weak self] in
|
|
402
|
+
guard let self = self else { return }
|
|
403
|
+
|
|
404
|
+
self.printerQueue.async { [weak self] in
|
|
405
|
+
guard
|
|
406
|
+
let self = self,
|
|
407
|
+
let timedSession = self.sessions[sessionId]
|
|
408
|
+
else { return }
|
|
409
|
+
|
|
410
|
+
if let reject = timedSession.printReject {
|
|
411
|
+
reject("PRINT_TIMEOUT", "Print timed out waiting for printer response", nil)
|
|
412
|
+
}
|
|
413
|
+
timedSession.printResolve = nil
|
|
414
|
+
timedSession.printReject = nil
|
|
415
|
+
timedSession.printTimeoutWork = nil
|
|
416
|
+
timedSession.printer?.clearCommandBuffer()
|
|
417
|
+
}
|
|
381
418
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
timedSession.printTimeoutWork = nil
|
|
385
|
-
timedSession.printer?.clearCommandBuffer()
|
|
419
|
+
session.printTimeoutWork = timeoutWork
|
|
420
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 30, execute: timeoutWork)
|
|
386
421
|
}
|
|
387
|
-
session.printTimeoutWork = timeoutWork
|
|
388
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 30, execute: timeoutWork)
|
|
389
422
|
}
|
|
390
423
|
}
|
|
391
424
|
|
|
392
425
|
@objc(getStatus:resolver:rejecter:)
|
|
393
426
|
func getStatus(_ sessionId: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
427
|
+
printerQueue.async { [weak self] in
|
|
428
|
+
guard let self = self else { return }
|
|
429
|
+
guard let session = self.sessions[sessionId], let p = session.printer else {
|
|
430
|
+
reject("STATUS_ERROR", "Printer not connected", nil)
|
|
431
|
+
return
|
|
432
|
+
}
|
|
398
433
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
434
|
+
if let status = p.getStatus() {
|
|
435
|
+
let statusDict: [String: Any] = [
|
|
436
|
+
"online": status.connection == EPOS2_TRUE,
|
|
437
|
+
"coverOpen": status.coverOpen == EPOS2_TRUE,
|
|
438
|
+
"paper": status.paper == EPOS2_PAPER_EMPTY.rawValue ? "EMPTY" : (status.paper == EPOS2_PAPER_NEAR_END.rawValue ? "NEAR_EMPTY" : "OK"),
|
|
439
|
+
"paperEmpty": status.paper == EPOS2_PAPER_EMPTY.rawValue,
|
|
440
|
+
"drawerOpen": status.drawer == EPOS2_DRAWER_HIGH.rawValue,
|
|
441
|
+
"errorStatus": status.errorStatus == EPOS2_MECHANICAL_ERR.rawValue ? "MECHANICAL_ERR" : (status.errorStatus == EPOS2_AUTOCUTTER_ERR.rawValue ? "AUTOCUTTER_ERR" : "NONE")
|
|
442
|
+
]
|
|
443
|
+
resolve(statusDict)
|
|
444
|
+
} else {
|
|
445
|
+
reject("STATUS_ERROR", "Failed to retrieve status", nil)
|
|
446
|
+
}
|
|
411
447
|
}
|
|
412
448
|
}
|
|
413
449
|
|