@novasamatech/host-api 0.10.2 → 0.12.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/dist/hostApi.js CHANGED
@@ -293,6 +293,9 @@ export function createHostApi(transport) {
293
293
  paymentStatusSubscribe(args, callback) {
294
294
  return transport.subscribe('host_payment_status_subscribe', args, callback);
295
295
  },
296
+ paymentTopUpStatusSubscribe(args, callback) {
297
+ return transport.subscribe('host_payment_top_up_status_subscribe', args, callback);
298
+ },
296
299
  requestResourceAllocation(payload) {
297
300
  return makeRequest(transport.request('host_request_resource_allocation', payload), reason => ({
298
301
  tag: payload.tag,
package/dist/index.d.ts CHANGED
@@ -31,7 +31,7 @@ export { NotificationId, PushNotification, PushNotificationError } from './proto
31
31
  export { NavigateToErr } from './protocol/v1/navigation.js';
32
32
  export { PreimageKey, PreimageSubmitErr, PreimageValue } from './protocol/v1/preimage.js';
33
33
  export { AllocatableResource, AllocationOutcome, ResourceAllocationErr } from './protocol/v1/resourceAllocation.js';
34
- export { PaymentBalance, PaymentBalanceErr, PaymentId, PaymentReceipt, PaymentRequestErr, PaymentStatus, PaymentStatusErr, PaymentTopUpErr, PaymentTopUpSource, } from './protocol/v1/payments.js';
34
+ export { PaymentBalance, PaymentBalanceErr, PaymentId, PaymentRequestErr, PaymentStatus, PaymentStatusErr, PaymentTopUpErr, PaymentTopUpId, PaymentTopUpSource, PaymentTopUpStatus, PaymentTopUpStatusErr, } from './protocol/v1/payments.js';
35
35
  export { Arrangement, BorderStyle, ButtonVariant, ColorToken, ContentAlignment, CustomRendererNode, Dimensions, HorizontalAlignment, Modifier, Shape, Size, TypographyStyle, VerticalAlignment, } from './protocol/v1/customRenderer.js';
36
36
  export { ChainHeadEvent, ChainHeadFollowV1_start, ChainIdentifier, ChainInfoErr, OperationStartedResult, RuntimeType, StorageQueryItem, StorageQueryType, StorageResultItem, TransactionBroadcastV1_request, TransactionBroadcastV1_response, TransactionStopV1_request, TransactionStopV1_response, } from './protocol/v1/chainInteraction.js';
37
37
  export { CoinPaymentBalance, CoinPaymentCheque, CoinPaymentErr, CoinPaymentListenForItem, CoinPaymentPurseId, CoinPaymentPurseInfo, CoinPaymentReceivable, CoinPaymentStatus, CoinPaymentTransmissionChannel, } from './protocol/v1/coinPayment.js';
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ export { NotificationId, PushNotification, PushNotificationError } from './proto
23
23
  export { NavigateToErr } from './protocol/v1/navigation.js';
24
24
  export { PreimageKey, PreimageSubmitErr, PreimageValue } from './protocol/v1/preimage.js';
25
25
  export { AllocatableResource, AllocationOutcome, ResourceAllocationErr } from './protocol/v1/resourceAllocation.js';
26
- export { PaymentBalance, PaymentBalanceErr, PaymentId, PaymentReceipt, PaymentRequestErr, PaymentStatus, PaymentStatusErr, PaymentTopUpErr, PaymentTopUpSource, } from './protocol/v1/payments.js';
26
+ export { PaymentBalance, PaymentBalanceErr, PaymentId, PaymentRequestErr, PaymentStatus, PaymentStatusErr, PaymentTopUpErr, PaymentTopUpId, PaymentTopUpSource, PaymentTopUpStatus, PaymentTopUpStatusErr, } from './protocol/v1/payments.js';
27
27
  export { Arrangement, BorderStyle, ButtonVariant, ColorToken, ContentAlignment, CustomRendererNode, Dimensions, HorizontalAlignment, Modifier, Shape, Size, TypographyStyle, VerticalAlignment, } from './protocol/v1/customRenderer.js';
28
28
  export { ChainHeadEvent, ChainHeadFollowV1_start, ChainIdentifier, ChainInfoErr, OperationStartedResult, RuntimeType, StorageQueryItem, StorageQueryType, StorageResultItem, TransactionBroadcastV1_request, TransactionBroadcastV1_response, TransactionStopV1_request, TransactionStopV1_response, } from './protocol/v1/chainInteraction.js';
29
29
  export { CoinPaymentBalance, CoinPaymentCheque, CoinPaymentErr, CoinPaymentListenForItem, CoinPaymentPurseId, CoinPaymentPurseInfo, CoinPaymentReceivable, CoinPaymentStatus, CoinPaymentTransmissionChannel, } from './protocol/v1/coinPayment.js';
@@ -942,25 +942,23 @@ export declare const hostApiProtocol: {
942
942
  tag: "Coins";
943
943
  value: Uint8Array<ArrayBufferLike>[];
944
944
  };
945
+ id: Uint8Array<ArrayBufferLike>;
945
946
  }>, Codec<import("./callError.js").CallResultValue<undefined, import("@novasamatech/scale").CodecError<{
946
947
  reason: string;
947
- }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InsufficientFunds"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<{
948
- credited: bigint;
949
- }, "PaymentTopUpErr::PartialPayment">>>];
948
+ }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::SourceBusy">>>];
950
949
  }>;
951
950
  readonly host_payment_request: VersionedProtocolRequest<{
952
951
  readonly v1: [Codec<{
953
952
  from: number | undefined;
954
953
  amount: bigint;
955
954
  destination: Uint8Array<ArrayBufferLike>;
956
- }>, Codec<import("./callError.js").CallResultValue<{
957
- id: string;
958
- }, import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
955
+ id: Uint8Array<ArrayBufferLike>;
956
+ }>, Codec<import("./callError.js").CallResultValue<undefined, import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
959
957
  reason: string;
960
- }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>>];
958
+ }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>>];
961
959
  }>;
962
960
  readonly host_payment_status_subscribe: VersionedProtocolSubscription<{
963
- readonly v1: [Codec<string>, Codec<{
961
+ readonly v1: [import("@novasamatech/scale").BytesCodec<number>, Codec<{
964
962
  tag: "Failed";
965
963
  value: string;
966
964
  } | {
@@ -969,6 +967,9 @@ export declare const hostApiProtocol: {
969
967
  } | {
970
968
  tag: "Completed";
971
969
  value: undefined;
970
+ } | {
971
+ tag: "PartiallyClaimed";
972
+ value: bigint;
972
973
  }>, [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
973
974
  reason: string;
974
975
  }, "PaymentStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentStatusErr::PaymentNotFound">>, import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
@@ -1482,5 +1483,47 @@ export declare const hostApiProtocol: {
1482
1483
  reason: string;
1483
1484
  }, "WorkerErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "WorkerErr::TooManyOpen">>>];
1484
1485
  }>;
1486
+ readonly host_payment_top_up_status_subscribe: VersionedProtocolSubscription<{
1487
+ readonly v1: [import("@novasamatech/scale").BytesCodec<number>, Codec<{
1488
+ tag: "Detecting";
1489
+ value: undefined;
1490
+ } | {
1491
+ tag: "Claiming";
1492
+ value: undefined;
1493
+ } | {
1494
+ tag: "Claimed";
1495
+ value: {
1496
+ finalized: boolean;
1497
+ };
1498
+ } | {
1499
+ tag: "ClaimedPartially";
1500
+ value: {
1501
+ actualClaimed: bigint;
1502
+ };
1503
+ } | {
1504
+ tag: "NotClaimed";
1505
+ value: undefined;
1506
+ }>, [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
1507
+ reason: string;
1508
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>, import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
1509
+ reason: string;
1510
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>] & {
1511
+ enc: import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
1512
+ reason: string;
1513
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>;
1514
+ dec: import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
1515
+ reason: string;
1516
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>;
1517
+ } & {
1518
+ readonly NotFound: import("@novasamatech/scale").ErrCodec<undefined, "PaymentTopUpStatusErr::NotFound">;
1519
+ readonly Unknown: import("@novasamatech/scale").ErrCodec<{
1520
+ reason: string;
1521
+ }, "PaymentTopUpStatusErr::Unknown">;
1522
+ } & {
1523
+ [Symbol.hasInstance](v: unknown): v is import("@novasamatech/scale").CodecError<{
1524
+ reason: string;
1525
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">;
1526
+ }];
1527
+ }>;
1485
1528
  };
1486
1529
  export {};
@@ -14,7 +14,7 @@ import { StorageClearV1_request, StorageClearV1_response, StorageReadV1_request,
14
14
  import { LocaleSubscribeV1_interrupt, LocaleSubscribeV1_receive, LocaleSubscribeV1_start } from './v1/locale.js';
15
15
  import { NavigateToV1_request, NavigateToV1_response } from './v1/navigation.js';
16
16
  import { PushNotificationCancelV1_request, PushNotificationCancelV1_response, PushNotificationV1_request, PushNotificationV1_response, } from './v1/notification.js';
17
- import { PaymentBalanceSubscribeV1_interrupt, PaymentBalanceSubscribeV1_receive, PaymentBalanceSubscribeV1_start, PaymentRequestV1_request, PaymentRequestV1_response, PaymentStatusSubscribeV1_interrupt, PaymentStatusSubscribeV1_receive, PaymentStatusSubscribeV1_start, PaymentTopUpV1_request, PaymentTopUpV1_response, } from './v1/payments.js';
17
+ import { PaymentBalanceSubscribeV1_interrupt, PaymentBalanceSubscribeV1_receive, PaymentBalanceSubscribeV1_start, PaymentRequestV1_request, PaymentRequestV1_response, PaymentStatusSubscribeV1_interrupt, PaymentStatusSubscribeV1_receive, PaymentStatusSubscribeV1_start, PaymentTopUpStatusSubscribeV1_interrupt, PaymentTopUpStatusSubscribeV1_receive, PaymentTopUpStatusSubscribeV1_start, PaymentTopUpV1_request, PaymentTopUpV1_response, } from './v1/payments.js';
18
18
  import { PreimageLookupSubscribeV1_interrupt, PreimageLookupSubscribeV1_receive, PreimageLookupSubscribeV1_start, PreimageSubmitV1_request, PreimageSubmitV1_response, } from './v1/preimage.js';
19
19
  import { RemotePermissionV1_request, RemotePermissionV1_response } from './v1/remotePermission.js';
20
20
  import { RequestResourceAllocationV1_request, RequestResourceAllocationV1_response } from './v1/resourceAllocation.js';
@@ -317,4 +317,14 @@ export const hostApiProtocol = {
317
317
  host_worker_end_operation: versionedRequest(indexer.request(), {
318
318
  v1: [WorkerEndOperationV1_request, WorkerEndOperationV1_response],
319
319
  }),
320
+ // Appended rather than placed next to `host_payment_top_up`: the index is a
321
+ // single running counter, so slotting it into the payment block would shift
322
+ // every id after it.
323
+ host_payment_top_up_status_subscribe: versionedSubscription(indexer.subscription(), {
324
+ v1: [
325
+ PaymentTopUpStatusSubscribeV1_start,
326
+ PaymentTopUpStatusSubscribeV1_receive,
327
+ PaymentTopUpStatusSubscribeV1_interrupt,
328
+ ],
329
+ }),
320
330
  };
@@ -995,27 +995,25 @@ export declare const MessagePayload: EnumCodec<Record<"host_handshake_request",
995
995
  tag: "Coins";
996
996
  value: Uint8Array<ArrayBufferLike>[];
997
997
  };
998
+ id: Uint8Array<ArrayBufferLike>;
998
999
  }>;
999
1000
  }>> & Record<"host_payment_top_up_response", EnumCodec<{
1000
1001
  readonly v1: Codec<import("./callError.js").CallResultValue<undefined, import("@novasamatech/scale").CodecError<{
1001
1002
  reason: string;
1002
- }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InsufficientFunds"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<{
1003
- credited: bigint;
1004
- }, "PaymentTopUpErr::PartialPayment">>>;
1003
+ }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::SourceBusy">>>;
1005
1004
  }>> & Record<"host_payment_request_request", EnumCodec<{
1006
1005
  readonly v1: Codec<{
1007
1006
  from: number | undefined;
1008
1007
  amount: bigint;
1009
1008
  destination: Uint8Array<ArrayBufferLike>;
1009
+ id: Uint8Array<ArrayBufferLike>;
1010
1010
  }>;
1011
1011
  }>> & Record<"host_payment_request_response", EnumCodec<{
1012
- readonly v1: Codec<import("./callError.js").CallResultValue<{
1013
- id: string;
1014
- }, import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
1012
+ readonly v1: Codec<import("./callError.js").CallResultValue<undefined, import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
1015
1013
  reason: string;
1016
- }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>>;
1014
+ }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>>;
1017
1015
  }>> & Record<"host_payment_status_subscribe_start", EnumCodec<{
1018
- readonly v1: Codec<string>;
1016
+ readonly v1: import("@novasamatech/scale").BytesCodec<number>;
1019
1017
  }>> & Record<"host_payment_status_subscribe_receive", EnumCodec<{
1020
1018
  readonly v1: Codec<{
1021
1019
  tag: "Failed";
@@ -1026,6 +1024,9 @@ export declare const MessagePayload: EnumCodec<Record<"host_handshake_request",
1026
1024
  } | {
1027
1025
  tag: "Completed";
1028
1026
  value: undefined;
1027
+ } | {
1028
+ tag: "PartiallyClaimed";
1029
+ value: bigint;
1029
1030
  }>;
1030
1031
  }>> & Record<"host_payment_status_subscribe_interrupt", EnumCodec<{
1031
1032
  readonly v1: [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
@@ -1577,7 +1578,52 @@ export declare const MessagePayload: EnumCodec<Record<"host_handshake_request",
1577
1578
  readonly v1: Codec<import("./callError.js").CallResultValue<undefined, import("@novasamatech/scale").CodecError<{
1578
1579
  reason: string;
1579
1580
  }, "WorkerErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "WorkerErr::TooManyOpen">>>;
1580
- }>>>;
1581
+ }>> & Record<"host_payment_top_up_status_subscribe_start", EnumCodec<{
1582
+ readonly v1: import("@novasamatech/scale").BytesCodec<number>;
1583
+ }>> & Record<"host_payment_top_up_status_subscribe_receive", EnumCodec<{
1584
+ readonly v1: Codec<{
1585
+ tag: "Detecting";
1586
+ value: undefined;
1587
+ } | {
1588
+ tag: "Claiming";
1589
+ value: undefined;
1590
+ } | {
1591
+ tag: "Claimed";
1592
+ value: {
1593
+ finalized: boolean;
1594
+ };
1595
+ } | {
1596
+ tag: "ClaimedPartially";
1597
+ value: {
1598
+ actualClaimed: bigint;
1599
+ };
1600
+ } | {
1601
+ tag: "NotClaimed";
1602
+ value: undefined;
1603
+ }>;
1604
+ }>> & Record<"host_payment_top_up_status_subscribe_interrupt", EnumCodec<{
1605
+ readonly v1: [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
1606
+ reason: string;
1607
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>, import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
1608
+ reason: string;
1609
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>] & {
1610
+ enc: import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
1611
+ reason: string;
1612
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>;
1613
+ dec: import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
1614
+ reason: string;
1615
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>;
1616
+ } & {
1617
+ readonly NotFound: import("@novasamatech/scale").ErrCodec<undefined, "PaymentTopUpStatusErr::NotFound">;
1618
+ readonly Unknown: import("@novasamatech/scale").ErrCodec<{
1619
+ reason: string;
1620
+ }, "PaymentTopUpStatusErr::Unknown">;
1621
+ } & {
1622
+ [Symbol.hasInstance](v: unknown): v is import("@novasamatech/scale").CodecError<{
1623
+ reason: string;
1624
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">;
1625
+ };
1626
+ }>> & Record<"host_payment_top_up_status_subscribe_stop", Codec<undefined>>>;
1581
1627
  export declare const Message: Codec<{
1582
1628
  requestId: string;
1583
1629
  payload: {
@@ -3006,6 +3052,7 @@ export declare const Message: Codec<{
3006
3052
  tag: "Coins";
3007
3053
  value: Uint8Array<ArrayBufferLike>[];
3008
3054
  };
3055
+ id: Uint8Array<ArrayBufferLike>;
3009
3056
  };
3010
3057
  };
3011
3058
  } | {
@@ -3014,9 +3061,7 @@ export declare const Message: Codec<{
3014
3061
  tag: "v1";
3015
3062
  value: import("./callError.js").CallResultValue<undefined, import("@novasamatech/scale").CodecError<{
3016
3063
  reason: string;
3017
- }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InsufficientFunds"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<{
3018
- credited: bigint;
3019
- }, "PaymentTopUpErr::PartialPayment">>;
3064
+ }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::SourceBusy">>;
3020
3065
  };
3021
3066
  } | {
3022
3067
  tag: "host_payment_request_request";
@@ -3026,23 +3071,22 @@ export declare const Message: Codec<{
3026
3071
  from: number | undefined;
3027
3072
  amount: bigint;
3028
3073
  destination: Uint8Array<ArrayBufferLike>;
3074
+ id: Uint8Array<ArrayBufferLike>;
3029
3075
  };
3030
3076
  };
3031
3077
  } | {
3032
3078
  tag: "host_payment_request_response";
3033
3079
  value: {
3034
3080
  tag: "v1";
3035
- value: import("./callError.js").CallResultValue<{
3036
- id: string;
3037
- }, import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
3081
+ value: import("./callError.js").CallResultValue<undefined, import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
3038
3082
  reason: string;
3039
- }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>;
3083
+ }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>;
3040
3084
  };
3041
3085
  } | {
3042
3086
  tag: "host_payment_status_subscribe_start";
3043
3087
  value: {
3044
3088
  tag: "v1";
3045
- value: string;
3089
+ value: Uint8Array<ArrayBufferLike>;
3046
3090
  };
3047
3091
  } | {
3048
3092
  tag: "host_payment_status_subscribe_receive";
@@ -3057,6 +3101,9 @@ export declare const Message: Codec<{
3057
3101
  } | {
3058
3102
  tag: "Completed";
3059
3103
  value: undefined;
3104
+ } | {
3105
+ tag: "PartiallyClaimed";
3106
+ value: bigint;
3060
3107
  };
3061
3108
  };
3062
3109
  } | {
@@ -3756,6 +3803,48 @@ export declare const Message: Codec<{
3756
3803
  reason: string;
3757
3804
  }, "WorkerErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "WorkerErr::TooManyOpen">>;
3758
3805
  };
3806
+ } | {
3807
+ tag: "host_payment_top_up_status_subscribe_start";
3808
+ value: {
3809
+ tag: "v1";
3810
+ value: Uint8Array<ArrayBufferLike>;
3811
+ };
3812
+ } | {
3813
+ tag: "host_payment_top_up_status_subscribe_receive";
3814
+ value: {
3815
+ tag: "v1";
3816
+ value: {
3817
+ tag: "Detecting";
3818
+ value: undefined;
3819
+ } | {
3820
+ tag: "Claiming";
3821
+ value: undefined;
3822
+ } | {
3823
+ tag: "Claimed";
3824
+ value: {
3825
+ finalized: boolean;
3826
+ };
3827
+ } | {
3828
+ tag: "ClaimedPartially";
3829
+ value: {
3830
+ actualClaimed: bigint;
3831
+ };
3832
+ } | {
3833
+ tag: "NotClaimed";
3834
+ value: undefined;
3835
+ };
3836
+ };
3837
+ } | {
3838
+ tag: "host_payment_top_up_status_subscribe_interrupt";
3839
+ value: {
3840
+ tag: "v1";
3841
+ value: import("@novasamatech/scale").CodecError<{
3842
+ reason: string;
3843
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">;
3844
+ };
3845
+ } | {
3846
+ tag: "host_payment_top_up_status_subscribe_stop";
3847
+ value: undefined;
3759
3848
  };
3760
3849
  }>;
3761
3850
  export type MessageAction = MessagePayloadSchema['tag'];
@@ -1,5 +1,8 @@
1
1
  export declare const Sr25519SecretKey: import("@novasamatech/scale").BytesCodec<number>;
2
- export declare const PaymentId: import("scale-ts").Codec<string>;
2
+ /** Product-supplied, opaque 32-byte idempotency key for a payment request. */
3
+ export declare const PaymentId: import("@novasamatech/scale").BytesCodec<number>;
4
+ /** Product-supplied, opaque 32-byte idempotency key for a top up. */
5
+ export declare const PaymentTopUpId: import("@novasamatech/scale").BytesCodec<number>;
3
6
  export declare const CoinPaymentPurseId: import("scale-ts").Codec<number>;
4
7
  export declare const PaymentTopUpSource: import("scale-ts").Codec<{
5
8
  tag: "ProductAccount";
@@ -20,9 +23,6 @@ export declare const PaymentTopUpSource: import("scale-ts").Codec<{
20
23
  export declare const PaymentBalance: import("scale-ts").Codec<{
21
24
  available: bigint;
22
25
  }>;
23
- export declare const PaymentReceipt: import("scale-ts").Codec<{
24
- id: string;
25
- }>;
26
26
  export declare const PaymentStatus: import("scale-ts").Codec<{
27
27
  tag: "Failed";
28
28
  value: string;
@@ -32,6 +32,29 @@ export declare const PaymentStatus: import("scale-ts").Codec<{
32
32
  } | {
33
33
  tag: "Completed";
34
34
  value: undefined;
35
+ } | {
36
+ tag: "PartiallyClaimed";
37
+ value: bigint;
38
+ }>;
39
+ export declare const PaymentTopUpStatus: import("scale-ts").Codec<{
40
+ tag: "Detecting";
41
+ value: undefined;
42
+ } | {
43
+ tag: "Claiming";
44
+ value: undefined;
45
+ } | {
46
+ tag: "Claimed";
47
+ value: {
48
+ finalized: boolean;
49
+ };
50
+ } | {
51
+ tag: "ClaimedPartially";
52
+ value: {
53
+ actualClaimed: bigint;
54
+ };
55
+ } | {
56
+ tag: "NotClaimed";
57
+ value: undefined;
35
58
  }>;
36
59
  export declare const PaymentBalanceErr: [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
37
60
  reason: string;
@@ -54,56 +77,63 @@ export declare const PaymentBalanceErr: [import("scale-ts").Encoder<import("@nov
54
77
  reason: string;
55
78
  }, "PaymentBalanceErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentBalanceErr::PermissionDenied">;
56
79
  };
57
- export declare const PartialPaymentErr: import("scale-ts").Codec<{
58
- credited: bigint;
59
- }>;
60
80
  export declare const PaymentTopUpErr: [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
61
81
  reason: string;
62
- }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InsufficientFunds"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<{
63
- credited: bigint;
64
- }, "PaymentTopUpErr::PartialPayment">>, import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
82
+ }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::SourceBusy">>, import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
65
83
  reason: string;
66
- }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InsufficientFunds"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<{
67
- credited: bigint;
68
- }, "PaymentTopUpErr::PartialPayment">>] & {
84
+ }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::SourceBusy">>] & {
69
85
  enc: import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
70
86
  reason: string;
71
- }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InsufficientFunds"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<{
72
- credited: bigint;
73
- }, "PaymentTopUpErr::PartialPayment">>;
87
+ }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::SourceBusy">>;
74
88
  dec: import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
75
89
  reason: string;
76
- }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InsufficientFunds"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<{
77
- credited: bigint;
78
- }, "PaymentTopUpErr::PartialPayment">>;
90
+ }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::SourceBusy">>;
79
91
  } & {
80
- readonly InsufficientFunds: import("@novasamatech/scale").ErrCodec<undefined, "PaymentTopUpErr::InsufficientFunds">;
81
92
  readonly InvalidSource: import("@novasamatech/scale").ErrCodec<undefined, "PaymentTopUpErr::InvalidSource">;
82
- readonly PartialPayment: import("@novasamatech/scale").ErrCodec<{
83
- credited: bigint;
84
- }, "PaymentTopUpErr::PartialPayment">;
93
+ readonly AlreadyExists: import("@novasamatech/scale").ErrCodec<undefined, "PaymentTopUpErr::AlreadyExists">;
94
+ readonly SourceBusy: import("@novasamatech/scale").ErrCodec<undefined, "PaymentTopUpErr::SourceBusy">;
85
95
  readonly Unknown: import("@novasamatech/scale").ErrCodec<{
86
96
  reason: string;
87
97
  }, "PaymentTopUpErr::Unknown">;
88
98
  } & {
89
99
  [Symbol.hasInstance](v: unknown): v is import("@novasamatech/scale").CodecError<{
90
100
  reason: string;
91
- }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InsufficientFunds"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<{
92
- credited: bigint;
93
- }, "PaymentTopUpErr::PartialPayment">;
101
+ }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::SourceBusy">;
102
+ };
103
+ export declare const PaymentTopUpStatusErr: [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
104
+ reason: string;
105
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>, import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
106
+ reason: string;
107
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>] & {
108
+ enc: import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
109
+ reason: string;
110
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>;
111
+ dec: import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
112
+ reason: string;
113
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>;
114
+ } & {
115
+ readonly NotFound: import("@novasamatech/scale").ErrCodec<undefined, "PaymentTopUpStatusErr::NotFound">;
116
+ readonly Unknown: import("@novasamatech/scale").ErrCodec<{
117
+ reason: string;
118
+ }, "PaymentTopUpStatusErr::Unknown">;
119
+ } & {
120
+ [Symbol.hasInstance](v: unknown): v is import("@novasamatech/scale").CodecError<{
121
+ reason: string;
122
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">;
94
123
  };
95
124
  export declare const PaymentRequestErr: [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
96
125
  reason: string;
97
- }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>, import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
126
+ }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>, import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
98
127
  reason: string;
99
- }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>] & {
128
+ }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>] & {
100
129
  enc: import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
101
130
  reason: string;
102
- }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>;
131
+ }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>;
103
132
  dec: import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
104
133
  reason: string;
105
- }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>;
134
+ }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>;
106
135
  } & {
136
+ readonly AlreadyExists: import("@novasamatech/scale").ErrCodec<undefined, "PaymentRequestErr::AlreadyExists">;
107
137
  readonly Rejected: import("@novasamatech/scale").ErrCodec<undefined, "PaymentRequestErr::Rejected">;
108
138
  readonly InsufficientBalance: import("@novasamatech/scale").ErrCodec<undefined, "PaymentRequestErr::InsufficientBalance">;
109
139
  readonly Unknown: import("@novasamatech/scale").ErrCodec<{
@@ -112,7 +142,7 @@ export declare const PaymentRequestErr: [import("scale-ts").Encoder<import("@nov
112
142
  } & {
113
143
  [Symbol.hasInstance](v: unknown): v is import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
114
144
  reason: string;
115
- }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">;
145
+ }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">;
116
146
  };
117
147
  export declare const PaymentStatusErr: [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
118
148
  reason: string;
@@ -181,23 +211,21 @@ export declare const PaymentTopUpV1_request: import("scale-ts").Codec<{
181
211
  tag: "Coins";
182
212
  value: Uint8Array<ArrayBufferLike>[];
183
213
  };
214
+ id: Uint8Array<ArrayBufferLike>;
184
215
  }>;
185
216
  export declare const PaymentTopUpV1_response: import("scale-ts").Codec<import("../callError.js").CallResultValue<undefined, import("@novasamatech/scale").CodecError<{
186
217
  reason: string;
187
- }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InsufficientFunds"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<{
188
- credited: bigint;
189
- }, "PaymentTopUpErr::PartialPayment">>>;
218
+ }, "PaymentTopUpErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::InvalidSource"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpErr::SourceBusy">>>;
190
219
  export declare const PaymentRequestV1_request: import("scale-ts").Codec<{
191
220
  from: number | undefined;
192
221
  amount: bigint;
193
222
  destination: Uint8Array<ArrayBufferLike>;
223
+ id: Uint8Array<ArrayBufferLike>;
194
224
  }>;
195
- export declare const PaymentRequestV1_response: import("scale-ts").Codec<import("../callError.js").CallResultValue<{
196
- id: string;
197
- }, import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
225
+ export declare const PaymentRequestV1_response: import("scale-ts").Codec<import("../callError.js").CallResultValue<undefined, import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::Rejected"> | import("@novasamatech/scale").CodecError<{
198
226
  reason: string;
199
- }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>>;
200
- export declare const PaymentStatusSubscribeV1_start: import("scale-ts").Codec<string>;
227
+ }, "PaymentRequestErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::AlreadyExists"> | import("@novasamatech/scale").CodecError<undefined, "PaymentRequestErr::InsufficientBalance">>>;
228
+ export declare const PaymentStatusSubscribeV1_start: import("@novasamatech/scale").BytesCodec<number>;
201
229
  export declare const PaymentStatusSubscribeV1_receive: import("scale-ts").Codec<{
202
230
  tag: "Failed";
203
231
  value: string;
@@ -207,6 +235,9 @@ export declare const PaymentStatusSubscribeV1_receive: import("scale-ts").Codec<
207
235
  } | {
208
236
  tag: "Completed";
209
237
  value: undefined;
238
+ } | {
239
+ tag: "PartiallyClaimed";
240
+ value: bigint;
210
241
  }>;
211
242
  export declare const PaymentStatusSubscribeV1_interrupt: [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
212
243
  reason: string;
@@ -229,3 +260,45 @@ export declare const PaymentStatusSubscribeV1_interrupt: [import("scale-ts").Enc
229
260
  reason: string;
230
261
  }, "PaymentStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentStatusErr::PaymentNotFound">;
231
262
  };
263
+ export declare const PaymentTopUpStatusSubscribeV1_start: import("@novasamatech/scale").BytesCodec<number>;
264
+ export declare const PaymentTopUpStatusSubscribeV1_receive: import("scale-ts").Codec<{
265
+ tag: "Detecting";
266
+ value: undefined;
267
+ } | {
268
+ tag: "Claiming";
269
+ value: undefined;
270
+ } | {
271
+ tag: "Claimed";
272
+ value: {
273
+ finalized: boolean;
274
+ };
275
+ } | {
276
+ tag: "ClaimedPartially";
277
+ value: {
278
+ actualClaimed: bigint;
279
+ };
280
+ } | {
281
+ tag: "NotClaimed";
282
+ value: undefined;
283
+ }>;
284
+ export declare const PaymentTopUpStatusSubscribeV1_interrupt: [import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
285
+ reason: string;
286
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>, import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
287
+ reason: string;
288
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>] & {
289
+ enc: import("scale-ts").Encoder<import("@novasamatech/scale").CodecError<{
290
+ reason: string;
291
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>;
292
+ dec: import("scale-ts").Decoder<import("@novasamatech/scale").CodecError<{
293
+ reason: string;
294
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">>;
295
+ } & {
296
+ readonly NotFound: import("@novasamatech/scale").ErrCodec<undefined, "PaymentTopUpStatusErr::NotFound">;
297
+ readonly Unknown: import("@novasamatech/scale").ErrCodec<{
298
+ reason: string;
299
+ }, "PaymentTopUpStatusErr::Unknown">;
300
+ } & {
301
+ [Symbol.hasInstance](v: unknown): v is import("@novasamatech/scale").CodecError<{
302
+ reason: string;
303
+ }, "PaymentTopUpStatusErr::Unknown"> | import("@novasamatech/scale").CodecError<undefined, "PaymentTopUpStatusErr::NotFound">;
304
+ };
@@ -1,11 +1,14 @@
1
1
  import { Bytes, Enum, ErrEnum } from '@novasamatech/scale';
2
- import { Option, Struct, Vector, _void, str, u128, u32 } from 'scale-ts';
2
+ import { Option, Struct, Vector, _void, bool, str, u128, u32 } from 'scale-ts';
3
3
  import { CallResult } from '../callError.js';
4
4
  import { GenericErr } from '../commonCodecs.js';
5
5
  import { DerivationIndex } from './accounts.js';
6
6
  // common types
7
7
  export const Sr25519SecretKey = Bytes(64);
8
- export const PaymentId = str;
8
+ /** Product-supplied, opaque 32-byte idempotency key for a payment request. */
9
+ export const PaymentId = Bytes(32);
10
+ /** Product-supplied, opaque 32-byte idempotency key for a top up. */
11
+ export const PaymentTopUpId = Bytes(32);
9
12
  // Optional purse selector (RFC 0017). `undefined` (None) targets MAIN_PURSE.
10
13
  export const CoinPaymentPurseId = u32;
11
14
  export const PaymentTopUpSource = Enum({
@@ -17,30 +20,56 @@ export const PaymentTopUpSource = Enum({
17
20
  export const PaymentBalance = Struct({
18
21
  available: u128,
19
22
  });
20
- export const PaymentReceipt = Struct({
21
- id: PaymentId,
22
- });
23
+ // A status never advances once it reaches a terminal variant (`Completed`,
24
+ // `Failed`, `PartiallyClaimed`); the host takes no further action and keeps the
25
+ // status readable indefinitely.
23
26
  export const PaymentStatus = Enum({
24
27
  Processing: _void,
28
+ // Terminal: the full amount reached the destination.
25
29
  Completed: _void,
30
+ // Terminal: the payment did not go through; carries the reason.
26
31
  Failed: str,
32
+ // Terminal: only this amount reached the destination, less than requested.
33
+ PartiallyClaimed: u128,
34
+ });
35
+ // A status never advances once it reaches a terminal variant (`Claimed` with
36
+ // `finalized`, `ClaimedPartially`, `NotClaimed`); the host takes no further
37
+ // action and keeps the status readable indefinitely.
38
+ export const PaymentTopUpStatus = Enum({
39
+ // Waiting for the requested amount to appear on the source.
40
+ Detecting: _void,
41
+ Claiming: _void,
42
+ // At least the requested amount was claimed. Terminal once `finalized`.
43
+ Claimed: Struct({ finalized: bool }),
44
+ // Terminal: the host could only claim `actualClaimed`, less than requested.
45
+ // Usually means the source never held enough balance to cover the request —
46
+ // e.g. a re-orged pre-funding transfer. Requesting an amount below the
47
+ // smallest coinage denomination lands here too: the host claims
48
+ // `amount - amount % 2^min_coinage_exponent`.
49
+ ClaimedPartially: Struct({ actualClaimed: u128 }),
50
+ // Terminal: nothing could be claimed, most likely because the host never
51
+ // observed any balance at the source.
52
+ NotClaimed: _void,
27
53
  });
28
54
  // errors
29
55
  export const PaymentBalanceErr = ErrEnum('PaymentBalanceErr', {
30
56
  PermissionDenied: [_void, 'permission denied'],
31
57
  Unknown: [GenericErr, 'unknown error'],
32
58
  });
33
- // Carries the amount that was credited when only some coins could be claimed.
34
- export const PartialPaymentErr = Struct({
35
- credited: u128,
36
- });
37
59
  export const PaymentTopUpErr = ErrEnum('PaymentTopUpErr', {
38
- InsufficientFunds: [_void, 'insufficient funds'],
39
60
  InvalidSource: [_void, 'invalid source'],
40
- PartialPayment: [PartialPaymentErr, ({ credited }) => `partial payment: credited ${credited}`],
61
+ AlreadyExists: [_void, 'a top up with this id already exists'],
62
+ // Only one top up can be live per source; the source frees up once the
63
+ // previous top up reaches a terminal status.
64
+ SourceBusy: [_void, 'source already has a top up in progress'],
65
+ Unknown: [GenericErr, 'unknown error'],
66
+ });
67
+ export const PaymentTopUpStatusErr = ErrEnum('PaymentTopUpStatusErr', {
68
+ NotFound: [_void, 'top up not found'],
41
69
  Unknown: [GenericErr, 'unknown error'],
42
70
  });
43
71
  export const PaymentRequestErr = ErrEnum('PaymentRequestErr', {
72
+ AlreadyExists: [_void, 'a payment with this id already exists'],
44
73
  Rejected: [_void, 'rejected'],
45
74
  InsufficientBalance: [_void, 'insufficient balance'],
46
75
  Unknown: [GenericErr, 'unknown error'],
@@ -60,6 +89,7 @@ export const PaymentTopUpV1_request = Struct({
60
89
  into: Option(CoinPaymentPurseId),
61
90
  amount: u128,
62
91
  source: PaymentTopUpSource,
92
+ id: PaymentTopUpId,
63
93
  });
64
94
  export const PaymentTopUpV1_response = CallResult(_void, PaymentTopUpErr);
65
95
  // host_payment_request
@@ -67,9 +97,14 @@ export const PaymentRequestV1_request = Struct({
67
97
  from: Option(CoinPaymentPurseId),
68
98
  amount: u128,
69
99
  destination: Bytes(32),
100
+ id: PaymentId,
70
101
  });
71
- export const PaymentRequestV1_response = CallResult(PaymentReceipt, PaymentRequestErr);
102
+ export const PaymentRequestV1_response = CallResult(_void, PaymentRequestErr);
72
103
  // host_payment_status_subscribe
73
104
  export const PaymentStatusSubscribeV1_start = PaymentId;
74
105
  export const PaymentStatusSubscribeV1_receive = PaymentStatus;
75
106
  export const PaymentStatusSubscribeV1_interrupt = PaymentStatusErr;
107
+ // host_payment_top_up_status_subscribe
108
+ export const PaymentTopUpStatusSubscribeV1_start = PaymentTopUpId;
109
+ export const PaymentTopUpStatusSubscribeV1_receive = PaymentTopUpStatus;
110
+ export const PaymentTopUpStatusSubscribeV1_interrupt = PaymentTopUpStatusErr;
package/dist/transport.js CHANGED
@@ -80,6 +80,56 @@ export function createTransport(provider) {
80
80
  const messageProvider = createMessageProvider(provider);
81
81
  // subscriptions management (multiplexing)
82
82
  const activeSubscriptions = new Map();
83
+ // Wires a real subscription on the transport; later subscribers with the same
84
+ // start payload join it through `listeners` instead of opening another. The
85
+ // first listener is registered before `start` is posted: an in-process host
86
+ // may send its first value synchronously while handling it.
87
+ function openSubscription(method, subscriptionKey, startPayload, listener) {
88
+ const requestId = createRequestId();
89
+ const stopAction = composeAction(method, 'stop');
90
+ const interruptAction = composeAction(method, 'interrupt');
91
+ const receiveAction = composeAction(method, 'receive');
92
+ const unsubscribeReceive = transport.listenMessages(receiveAction, (receivedId, data) => {
93
+ if (receivedId === requestId) {
94
+ for (const listener of subscription.listeners) {
95
+ try {
96
+ listener.call(data.value);
97
+ }
98
+ catch (e) {
99
+ provider.logger.error(`subscription "${method}" listener threw`, e);
100
+ }
101
+ }
102
+ }
103
+ });
104
+ const unsubscribeInterrupt = transport.listenMessages(interruptAction, (receivedId, data) => {
105
+ if (receivedId === requestId) {
106
+ // The host has dropped this subscription. Tear it down first so a
107
+ // re-subscribe with the same payload, even from inside onInterrupt,
108
+ // opens a fresh one instead of joining this dead entry.
109
+ stopSubscription();
110
+ subscription.latchedInterrupt = { payload: data.value };
111
+ subscription.interruptEvents.emit('interrupt', data.value);
112
+ }
113
+ });
114
+ const stopSubscription = () => {
115
+ activeSubscriptions.delete(subscriptionKey);
116
+ unsubscribeReceive();
117
+ unsubscribeInterrupt();
118
+ };
119
+ const subscription = {
120
+ requestId,
121
+ listeners: [listener],
122
+ interruptEvents: createNanoEvents(),
123
+ kill: () => {
124
+ stopSubscription();
125
+ const stopPayload = enumValue(stopAction, undefined);
126
+ transport.postMessage(requestId, stopPayload);
127
+ },
128
+ };
129
+ activeSubscriptions.set(subscriptionKey, subscription);
130
+ transport.postMessage(requestId, startPayload);
131
+ return subscription;
132
+ }
83
133
  // Lazy provider subscription — zero per-message decode cost while no
84
134
  // debug listener is attached.
85
135
  let debugListenerCount = 0;
@@ -208,17 +258,14 @@ export function createTransport(provider) {
208
258
  },
209
259
  subscribe(method, payload, callback) {
210
260
  checks();
211
- const events = createNanoEvents();
212
261
  const startAction = composeAction(method, 'start');
213
262
  const startPayload = enumValue(startAction, payload);
214
263
  const subscriptionKey = getSubscriptionKey(method, startPayload);
215
- let subscription = activeSubscriptions.get(subscriptionKey);
216
264
  function unsubscribeListener() {
217
265
  const subscription = activeSubscriptions.get(subscriptionKey);
218
266
  if (subscription) {
219
267
  const newListeners = subscription.listeners.filter(listener => listener.call !== callback);
220
268
  if (newListeners.length === 0) {
221
- activeSubscriptions.delete(subscriptionKey);
222
269
  subscription.kill();
223
270
  }
224
271
  else {
@@ -230,61 +277,21 @@ export function createTransport(provider) {
230
277
  call: callback,
231
278
  unsubscribe: unsubscribeListener,
232
279
  };
233
- const publicSubscription = {
280
+ const existing = activeSubscriptions.get(subscriptionKey);
281
+ existing?.listeners.push(listener);
282
+ const subscription = existing ?? openSubscription(method, subscriptionKey, startPayload, listener);
283
+ return {
234
284
  unsubscribe: unsubscribeListener,
235
285
  onInterrupt(callback) {
236
- return events.on('interrupt', callback);
286
+ if (subscription.latchedInterrupt) {
287
+ callback(subscription.latchedInterrupt.payload);
288
+ return () => {
289
+ /* already delivered */
290
+ };
291
+ }
292
+ return subscription.interruptEvents.on('interrupt', callback);
237
293
  },
238
294
  };
239
- // wiring up a real subscription
240
- if (!subscription) {
241
- const requestId = createRequestId();
242
- const stopAction = composeAction(method, 'stop');
243
- const interruptAction = composeAction(method, 'interrupt');
244
- const receiveAction = composeAction(method, 'receive');
245
- const unsubscribeReceive = transport.listenMessages(receiveAction, (receivedId, data) => {
246
- if (receivedId === requestId) {
247
- const subscription = activeSubscriptions.get(subscriptionKey);
248
- if (subscription) {
249
- for (const listener of subscription.listeners) {
250
- try {
251
- listener.call(data.value);
252
- }
253
- catch (e) {
254
- provider.logger.error(`subscription "${method}" listener threw`, e);
255
- }
256
- }
257
- }
258
- }
259
- });
260
- const unsubscribeInterrupt = transport.listenMessages(interruptAction, (receivedId, data) => {
261
- if (receivedId === requestId) {
262
- events.emit('interrupt', data.value);
263
- stopSubscription();
264
- }
265
- });
266
- const stopSubscription = () => {
267
- unsubscribeReceive();
268
- unsubscribeInterrupt();
269
- events.events = {};
270
- };
271
- // creating subscription
272
- subscription = {
273
- requestId,
274
- kill: () => {
275
- stopSubscription();
276
- const stopPayload = enumValue(stopAction, undefined);
277
- transport.postMessage(requestId, stopPayload);
278
- },
279
- listeners: [listener],
280
- };
281
- activeSubscriptions.set(subscriptionKey, subscription);
282
- transport.postMessage(requestId, startPayload);
283
- }
284
- else {
285
- subscription.listeners.push(listener);
286
- }
287
- return publicSubscription;
288
295
  },
289
296
  handleSubscription(method, handler) {
290
297
  checks();
@@ -302,8 +309,12 @@ export function createTransport(provider) {
302
309
  transport.postMessage(requestId, receivePayload);
303
310
  }, value => {
304
311
  interrupted = true;
312
+ // Undefined while the handler is still running; then the handler's
313
+ // own cleanup, which must run since no `stop` will ever arrive.
314
+ const cleanup = subscriptions.get(requestId);
305
315
  subscriptions.delete(requestId);
306
316
  transport.postMessage(requestId, enumValue(interruptAction, value));
317
+ cleanup?.();
307
318
  });
308
319
  if (interrupted) {
309
320
  unsubscribe();
@@ -57,6 +57,134 @@ describe('transport', () => {
57
57
  expect(s1Handler).toHaveBeenCalledTimes(1);
58
58
  expect(s2Handler).toHaveBeenCalledTimes(2);
59
59
  });
60
+ it('starts a fresh host subscription when re-subscribing with the same payload after an interrupt', () => {
61
+ const providers = createProviders();
62
+ const events = createNanoEvents();
63
+ const host = createTransport(providers.host);
64
+ const sdk = createTransport(providers.sdk);
65
+ const containerHandler = vi.fn((_, send, interrupt) => {
66
+ const unsubPush = events.on('push', () => send({ tag: 'v1', value: 'connected' }));
67
+ const unsubInterrupt = events.on('interrupt', () => interrupt({ tag: 'v1', value: undefined }));
68
+ return () => {
69
+ unsubPush();
70
+ unsubInterrupt();
71
+ };
72
+ });
73
+ host.handleSubscription('host_account_connection_status_subscribe', containerHandler);
74
+ const first = vi.fn();
75
+ sdk.subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, first);
76
+ expect(containerHandler).toHaveBeenCalledTimes(1);
77
+ events.emit('interrupt');
78
+ const second = vi.fn();
79
+ sdk.subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, second);
80
+ // The interrupted subscription is gone: the second subscribe must open a
81
+ // new one on the host rather than joining the dead entry.
82
+ expect(containerHandler).toHaveBeenCalledTimes(2);
83
+ events.emit('push');
84
+ expect(first).not.toHaveBeenCalled();
85
+ expect(second).toHaveBeenCalledTimes(1);
86
+ });
87
+ it('delivers an interrupt raised synchronously from the host handler to a later onInterrupt listener', () => {
88
+ const providers = createProviders();
89
+ const host = createTransport(providers.host);
90
+ const sdk = createTransport(providers.sdk);
91
+ host.handleSubscription('host_account_connection_status_subscribe', (_, _send, interrupt) => {
92
+ interrupt({ tag: 'v1', value: undefined });
93
+ return vi.fn();
94
+ });
95
+ const subscription = sdk.subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, vi.fn());
96
+ // With an in-process host the interrupt arrives before subscribe() has
97
+ // returned, so onInterrupt is necessarily attached afterwards.
98
+ const interrupted = vi.fn();
99
+ subscription.onInterrupt(interrupted);
100
+ expect(interrupted).toHaveBeenCalledExactlyOnceWith({ tag: 'v1', value: undefined });
101
+ });
102
+ it('delivers an interrupt to every subscriber sharing a multiplexed subscription', () => {
103
+ const providers = createProviders();
104
+ const events = createNanoEvents();
105
+ const host = createTransport(providers.host);
106
+ const sdk = createTransport(providers.sdk);
107
+ host.handleSubscription('host_account_connection_status_subscribe', (_, _send, interrupt) => events.on('interrupt', () => interrupt({ tag: 'v1', value: undefined })));
108
+ const first = vi.fn();
109
+ const second = vi.fn();
110
+ sdk
111
+ .subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, vi.fn())
112
+ .onInterrupt(first);
113
+ sdk
114
+ .subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, vi.fn())
115
+ .onInterrupt(second);
116
+ events.emit('interrupt');
117
+ expect(first).toHaveBeenCalledExactlyOnceWith({ tag: 'v1', value: undefined });
118
+ expect(second).toHaveBeenCalledExactlyOnceWith({ tag: 'v1', value: undefined });
119
+ });
120
+ it('delivers a later interrupt to a listener attached before it', () => {
121
+ const providers = createProviders();
122
+ const events = createNanoEvents();
123
+ const host = createTransport(providers.host);
124
+ const sdk = createTransport(providers.sdk);
125
+ host.handleSubscription('host_account_connection_status_subscribe', (_, _send, interrupt) => events.on('interrupt', () => interrupt({ tag: 'v1', value: undefined })));
126
+ const interrupted = vi.fn();
127
+ sdk
128
+ .subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, vi.fn())
129
+ .onInterrupt(interrupted);
130
+ events.emit('interrupt');
131
+ expect(interrupted).toHaveBeenCalledExactlyOnceWith({ tag: 'v1', value: undefined });
132
+ });
133
+ it('drops receive frames and makes unsubscribe a no-op once interrupted', () => {
134
+ const providers = createProviders();
135
+ const events = createNanoEvents();
136
+ const host = createTransport(providers.host);
137
+ const sdk = createTransport(providers.sdk);
138
+ const hostCleanup = vi.fn();
139
+ host.handleSubscription('host_account_connection_status_subscribe', (_, send, interrupt) => {
140
+ events.on('interrupt', () => interrupt({ tag: 'v1', value: undefined }));
141
+ events.on('push', () => send({ tag: 'v1', value: 'connected' }));
142
+ return hostCleanup;
143
+ });
144
+ const callback = vi.fn();
145
+ const subscription = sdk.subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, callback);
146
+ events.emit('interrupt');
147
+ // The host-side handler is already torn down by the interrupt itself.
148
+ expect(hostCleanup).toHaveBeenCalledTimes(1);
149
+ events.emit('push');
150
+ expect(callback).not.toHaveBeenCalled();
151
+ // Nothing is left to stop on the host, so no second cleanup.
152
+ subscription.unsubscribe();
153
+ expect(hostCleanup).toHaveBeenCalledTimes(1);
154
+ });
155
+ it('opens a fresh host subscription when re-subscribing from inside onInterrupt', () => {
156
+ const providers = createProviders();
157
+ const events = createNanoEvents();
158
+ const host = createTransport(providers.host);
159
+ const sdk = createTransport(providers.sdk);
160
+ const containerHandler = vi.fn((_, send, interrupt) => {
161
+ events.on('interrupt', () => interrupt({ tag: 'v1', value: undefined }));
162
+ return events.on('push', () => send({ tag: 'v1', value: 'connected' }));
163
+ });
164
+ host.handleSubscription('host_account_connection_status_subscribe', containerHandler);
165
+ const retried = vi.fn();
166
+ sdk
167
+ .subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, vi.fn())
168
+ .onInterrupt(() => {
169
+ sdk.subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, retried);
170
+ });
171
+ events.emit('interrupt');
172
+ expect(containerHandler).toHaveBeenCalledTimes(2);
173
+ events.emit('push');
174
+ expect(retried).toHaveBeenCalledTimes(1);
175
+ });
176
+ it('delivers a value the host sends synchronously while handling start', () => {
177
+ const providers = createProviders();
178
+ const host = createTransport(providers.host);
179
+ const sdk = createTransport(providers.sdk);
180
+ host.handleSubscription('host_account_connection_status_subscribe', (_, send) => {
181
+ send({ tag: 'v1', value: 'connected' });
182
+ return vi.fn();
183
+ });
184
+ const callback = vi.fn();
185
+ sdk.subscribe('host_account_connection_status_subscribe', { tag: 'v1', value: undefined }, callback);
186
+ expect(callback).toHaveBeenCalledExactlyOnceWith({ tag: 'v1', value: 'connected' });
187
+ });
60
188
  it('isolates a throwing subscriber so siblings on the same subscription still receive', () => {
61
189
  const providers = createProviders();
62
190
  const events = createNanoEvents();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/host-api",
3
3
  "type": "module",
4
- "version": "0.10.2",
4
+ "version": "0.12.0",
5
5
  "description": "Host API: transport implementation for host - product integration.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -22,7 +22,7 @@
22
22
  "README.md"
23
23
  ],
24
24
  "dependencies": {
25
- "@novasamatech/scale": "0.10.2",
25
+ "@novasamatech/scale": "0.12.0",
26
26
  "nanoevents": "10.0.0",
27
27
  "nanoid": "6.0.1",
28
28
  "neverthrow": "^8.2.0",