@signosoft/signpad-js 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -59,14 +59,13 @@ Without a valid lease, the component can still render, but driver initialization
59
59
  async function fetchLease() {
60
60
  try {
61
61
  const response = await fetch(
62
- "https://test.signosoft.com/api/v1/driver/leases",
62
+ "https://test.signosoft.com/api/v1/public/driver-leases/create",
63
63
  {
64
64
  method: "POST",
65
65
  headers: { "Content-Type": "application/json" },
66
66
  body: JSON.stringify({
67
- licenceKey: "YOUR-LICENSE-KEY",
67
+ token: "YOUR-LICENSE-TOKEN",
68
68
  validityHours: 24,
69
- port: 4204,
70
69
  }),
71
70
  },
72
71
  );
@@ -245,14 +244,13 @@ export class AppComponent implements AfterViewInit {
245
244
  public async fetchLease(): Promise<any> {
246
245
  try {
247
246
  const response = await fetch(
248
- "https://test.signosoft.com/api/v1/driver/leases",
247
+ "https://test.signosoft.com/api/v1/public/driver-leases/create",
249
248
  {
250
249
  method: "POST",
251
250
  headers: { "Content-Type": "application/json" },
252
251
  body: JSON.stringify({
253
- licenceKey: "YOUR-LICENSE-KEY",
252
+ token: "YOUR-LICENSE-TOKEN",
254
253
  validityHours: 24,
255
- port: 4204,
256
254
  }),
257
255
  },
258
256
  );
@@ -331,14 +329,13 @@ import type { SignpadConfig } from "@signosoft/signpad-js";
331
329
  async function fetchLease() {
332
330
  try {
333
331
  const response = await fetch(
334
- "https://test.signosoft.com/api/v1/driver/leases",
332
+ "https://test.signosoft.com/api/v1/public/driver-leases/create",
335
333
  {
336
334
  method: "POST",
337
335
  headers: { "Content-Type": "application/json" },
338
336
  body: JSON.stringify({
339
- licenceKey: "YOUR-LICENSE-KEY",
337
+ token: "YOUR-LICENSE-TOKEN",
340
338
  validityHours: 24,
341
- port: 4204,
342
339
  }),
343
340
  },
344
341
  );
@@ -439,13 +436,12 @@ const signpadConfig = ref<SignpadConfig>({ lease: undefined });
439
436
 
440
437
  const fetchLease = async () => {
441
438
  try {
442
- const response = await fetch("https://test.signosoft.com/api/v1/driver/leases", {
439
+ const response = await fetch("https://test.signosoft.com/api/v1/public/driver-leases/create", {
443
440
  method: "POST",
444
441
  headers: { "Content-Type": "application/json" },
445
442
  body: JSON.stringify({
446
- licenceKey: "YOUR-LICENSE-KEY",
443
+ token: "YOUR-LICENSE-TOKEN",
447
444
  validityHours: 24,
448
- port: 4204,
449
445
  }),
450
446
  });
451
447
 
@@ -526,14 +522,13 @@ pad.config = {
526
522
  const fetchLease = async () => {
527
523
  try {
528
524
  const response = await fetch(
529
- "https://test.signosoft.com/api/v1/driver/leases",
525
+ "https://test.signosoft.com/api/v1/public/driver-leases/create",
530
526
  {
531
527
  method: "POST",
532
528
  headers: { "Content-Type": "application/json" },
533
529
  body: JSON.stringify({
534
- licenceKey: "YOUR-LICENSE-KEY",
530
+ token: "YOUR-LICENSE-TOKEN",
535
531
  validityHours: 24,
536
- port: 4204,
537
532
  }),
538
533
  },
539
534
  );
@@ -676,6 +671,7 @@ The complete list of keys that can be translated is maintained in `src/i18n/en.j
676
671
  | `CONNECTION_ERROR` | Connection error. |
677
672
  | `ERROR_DISCONNECTION` | Error during disconnection. |
678
673
  | `ERROR_INSTANTIATING_DRIVER` | Error instantiating driver. |
674
+ | `INSUFFICIENT_TOKENS` | Not enough tokens to sign. Reconnecting… |
679
675
  | `INVALID_LICENSE_KEY` | Invalid license key. |
680
676
  | `READY_TO_CONNECT` | Ready to connect. |
681
677
  | `SIGNPAD_DETECTED` | Signpad detected. Click 'Connect Signpad' to begin. |
@@ -711,10 +707,28 @@ Standard event listeners triggered _after_ specific actions. Useful for observin
711
707
  | `onOk` | `event: CustomEvent<ISignatureConfirmationData>` | Dispatched when signature is confirmed. |
712
708
  | `onClear` | `event: CustomEvent<void>` | Dispatched when the canvas has been cleared. |
713
709
  | `onCancel` | `event: CustomEvent<void>` | Dispatched when the user aborts the session. |
714
- | `onError` | `event: CustomEvent<Error>` | Dispatched on critical failures (lease, driver, connection, etc.). |
710
+ | `onError` | `event: CustomEvent<ISignpadErrorDetail>` | Dispatched on critical failures (lease, driver, connection, billing, etc.). |
715
711
 
716
712
  > `actionHandlers` and `eventCallbacks` are separate hooks and can both be configured.
717
713
 
714
+ #### 🚨 `onError` payload (`ISignpadErrorDetail`)
715
+
716
+ ```typescript
717
+ {
718
+ category: SignpadErrorCategory; // BILLING_DENIED | NETWORK | OTHER
719
+ message: string; // error.message, for convenience
720
+ error: Error; // the original error
721
+ }
722
+ ```
723
+
724
+ `category` also drives automatic recovery:
725
+
726
+ - **`BILLING_DENIED`** — the lease has run out of signing credits/tokens. Signing automatically restarts a few seconds after the error is shown.
727
+ - **`OTHER`** — any other recoverable failure (e.g. a driver hiccup, a cancelled device picker). Signing automatically restarts the same way as `BILLING_DENIED`.
728
+ - **`NETWORK`** — a connectivity problem (lease fetch failed, device physically disconnected, origin validation failed). The error stays shown; signing does **not** auto-restart, since retrying on a timer can't fix a network or configuration problem — the user (or your app) must retry manually, e.g. via `connect()`.
729
+
730
+ > **Migration note (breaking payload shape change):** `event.detail` used to be the raw `Error`. It is now `ISignpadErrorDetail`; use `event.detail.error` for the original `Error` instance. `event.detail.message` still works unchanged.
731
+
718
732
  ---
719
733
 
720
734
  ### 💡 Example Implementation
@@ -923,7 +937,17 @@ The component progresses through a finite set of states, exposed via the `Signpa
923
937
  | `PROCESSING_CANCEL` | `"processing_cancel"` | Cancel action is being processed. |
924
938
  | `DISCONNECTING` | `"disconnecting"` | Disconnect in progress. |
925
939
  | `DISCONNECTED` | `"disconnected"` | Component is idle and disconnected. |
926
- | `ERROR` | `"error"` | An unrecoverable error occurred (see `onError` callback). |
940
+ | `ERROR` | `"error"` | An error occurred (see `onError` callback). Signing automatically restarts a few seconds later unless the error's `category` is `NETWORK`. |
941
+
942
+ ### 🚨 `SignpadErrorCategory`
943
+
944
+ Also importable from `@signosoft/signpad-js`, carried on the `onError` payload (see [`onError` payload](#-onerror-payload-isignpaderrordetail) above):
945
+
946
+ | Value | Value string | Auto-restarts signing? |
947
+ | :--------------- | :------------------ | :---------------------- |
948
+ | `BILLING_DENIED` | `"billing_denied"` | Yes |
949
+ | `NETWORK` | `"network"` | No |
950
+ | `OTHER` | `"other"` | Yes |
927
951
 
928
952
  ---
929
953
 
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { ConnectionMode } from '@signosoft/tablet-driver';
1
2
  import { CSSResult } from 'lit';
2
3
  import { LitElement } from 'lit';
3
4
  import { TemplateResult } from 'lit-html';
@@ -176,11 +177,12 @@ declare class ConnectionManager {
176
177
  /**
177
178
  * Initiates the connection process to a physical device or a mouse fallback.
178
179
  *
179
- * @param autoConnect - If true, attempts to connect without showing a device selection dialog.
180
+ * @param autoConnect - Connect mode: "manual" opens the browser device selection
181
+ * dialog; "auto"/"hotplug" attempt already-authorized devices silently.
180
182
  * @param allowFallback - If true, enables mouse/pointer input if no physical device is found.
181
183
  * @returns A promise resolving to true if connection (or fallback) was successful.
182
184
  */
183
- connect(autoConnect?: boolean, allowFallback?: boolean): Promise<boolean>;
185
+ connect(autoConnect?: ConnectionMode, allowFallback?: boolean): Promise<boolean>;
184
186
  /**
185
187
  * Terminates the connection with the device and cleans up the driver instance.
186
188
  * @returns Resolves when disconnection completes.
@@ -239,6 +241,20 @@ declare class ConnectionManager {
239
241
  * @returns Resolves when the driver is initialized.
240
242
  */
241
243
  initWithLease(lease: any): Promise<void>;
244
+ /**
245
+ * Called by the driver when the lease has run out of signing credits.
246
+ * @param detail - Driver-provided description of the denial.
247
+ * @returns Always false — declines the driver's own retry; signpad-js's
248
+ * auto-restart (triggered by the ERROR transition below) handles recovery.
249
+ */
250
+ private handleBillingDenied;
251
+ /**
252
+ * Called by the driver when the billing check itself fails (e.g. the
253
+ * billing server is unreachable). Treated as a network error.
254
+ * @param detail - Driver-provided description of the failure.
255
+ * @returns Always false — see handleBillingDenied.
256
+ */
257
+ private handleBillingError;
242
258
  isFallback(deviceInfo: any | null, isDeviceConnected: boolean, includeDisconnected: boolean): boolean;
243
259
  /**
244
260
  * Normalizes device info to always include deviceName.
@@ -286,7 +302,7 @@ export declare interface IEventCallbacks {
286
302
  onOk?: (event: CustomEvent<ISignatureConfirmationData>) => void;
287
303
  onClear?: (event: CustomEvent<void>) => void;
288
304
  onCancel?: (event: CustomEvent<void>) => void;
289
- onError?: (event: CustomEvent<Error>) => void;
305
+ onError?: (event: CustomEvent<ISignpadErrorDetail>) => void;
290
306
  }
291
307
 
292
308
  export declare interface ILanguageOptions {
@@ -358,6 +374,12 @@ export declare interface ISignatureTabletMeta {
358
374
  [key: string]: any;
359
375
  }
360
376
 
377
+ export declare interface ISignpadErrorDetail {
378
+ category: SignpadErrorCategory;
379
+ message: string;
380
+ error: Error;
381
+ }
382
+
361
383
  export declare interface ITranslationSet {
362
384
  [key: string]: string;
363
385
  }
@@ -520,7 +542,8 @@ export declare class SignosoftSignpad extends LitElement {
520
542
  dispatch(name: string, detail?: any): void;
521
543
  /**
522
544
  * Attempts to establish a connection with a signature tablet.
523
- * @param autoConnect - If true, tries to connect without showing a device picker.
545
+ * @param autoConnect - Connect mode: "manual" opens the browser HID picker;
546
+ * "auto"/"hotplug" silently try already-authorized devices (see `ConnectionMode`).
524
547
  * @param allowFallback - If true, enables mouse/touch signing if no device is found.
525
548
  * @returns A promise resolving to true if connection (or fallback) succeeded.
526
549
  */
@@ -560,8 +583,24 @@ export declare class SignosoftSignpad extends LitElement {
560
583
  * - if physical is not available, allow fallback as a secondary attempt
561
584
  */
562
585
  connect: () => Promise<void>;
586
+ /**
587
+ * If currently in mouse fallback, tears that session down seamlessly
588
+ * (no DISCONNECTED UI flash) so a physical-device connect attempt can
589
+ * proceed cleanly.
590
+ */
563
591
  private prepareForManualConnect;
592
+ /**
593
+ * First step of the manual `connect()` flow: silently retries an
594
+ * already-authorized device (no HID picker) using "auto" mode.
595
+ * `allowFallback=false` ensures we only treat a real physical reconnect as success.
596
+ */
564
597
  private tryAuthorizedManualConnect;
598
+ /**
599
+ * Second step of the manual `connect()` flow, run only when the silent
600
+ * attempt above fails: opens the browser HID picker ("manual" mode) so
601
+ * the user can grant access to a new device. If the user cancels or no
602
+ * device is selected, falls back to one more silent "auto" attempt.
603
+ */
565
604
  private tryInteractiveManualConnectFallback;
566
605
  /**
567
606
  * UI disconnect action: delegates to the public disconnect method.
@@ -611,6 +650,19 @@ export declare class SignosoftSignpad extends LitElement {
611
650
  private shouldScheduleImmediateRetry;
612
651
  private scheduleAutoConnectRetry;
613
652
  private clearAutoConnectQueue;
653
+ /**
654
+ * Schedules signing to restart automatically after a BILLING_DENIED/OTHER
655
+ * error, so the flow recovers without requiring a manual reconnect.
656
+ * NETWORK errors never reach this — they stay shown until the user retries.
657
+ * @param delayMs - How long to keep the error visible before restarting.
658
+ */
659
+ private scheduleErrorAutoRestart;
660
+ /**
661
+ * Restarts the signing session after an auto-recoverable error, respecting
662
+ * the connect/disconnect reentrancy lock so it never races a concurrent
663
+ * manual connect/disconnect or hotplug transition.
664
+ */
665
+ private restartSigningAfterError;
614
666
  private delay;
615
667
  /**
616
668
  * Disconnects current session without transitioning through DISCONNECTED UI.
@@ -657,6 +709,12 @@ export declare interface SignpadConfig {
657
709
  eventCallbacks?: IEventCallbacks;
658
710
  }
659
711
 
712
+ export declare enum SignpadErrorCategory {
713
+ BILLING_DENIED = "billing_denied",
714
+ NETWORK = "network",
715
+ OTHER = "other"
716
+ }
717
+
660
718
  export declare enum SignpadEventType {
661
719
  SIGN_PEN = "sign-pen",
662
720
  SIGN_OK = "sign-ok",
@@ -683,6 +741,7 @@ export declare enum SignpadMessage {
683
741
  CONNECTION_ERROR = "CONNECTION_ERROR",
684
742
  ERROR_DISCONNECTION = "ERROR_DISCONNECTION",
685
743
  ERROR_INSTANTIATING_DRIVER = "ERROR_INSTANTIATING_DRIVER",
744
+ INSUFFICIENT_TOKENS = "INSUFFICIENT_TOKENS",
686
745
  INVALID_LICENSE_KEY = "INVALID_LICENSE_KEY",
687
746
  READY_TO_CONNECT = "READY_TO_CONNECT",
688
747
  SIGNPAD_DETECTED = "SIGNPAD_DETECTED",
@@ -781,7 +840,15 @@ declare class StateManager {
781
840
  * @param error - Optional error object if transitioning to an ERROR state.
782
841
  * @returns void
783
842
  */
784
- transitionTo(newState: SignpadState, messageKey?: string, error?: Error): void;
843
+ transitionTo(newState: SignpadState, messageKey?: string, error?: Error, category?: SignpadErrorCategory): void;
844
+ /**
845
+ * Heuristically classifies an error for auto-recovery decisions.
846
+ * Explicit categories (e.g. from billing hooks) should be passed to
847
+ * transitionTo directly rather than relying on this fallback.
848
+ * @param error - The error to classify.
849
+ * @returns The inferred error category.
850
+ */
851
+ private classifyError;
785
852
  /**
786
853
  * Updates the internal drawing flag. Triggers a UI update if the value changes.
787
854
  * @param started - Boolean indicating if the user has started drawing.