@peabody-soft/mbs-model-ts 1.0.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.
Files changed (212) hide show
  1. package/LICENCE +661 -0
  2. package/dist/Address.d.ts +33 -0
  3. package/dist/Address.js +97 -0
  4. package/dist/Attachment.d.ts +16 -0
  5. package/dist/Attachment.js +49 -0
  6. package/dist/AttachmentBaseUrl.d.ts +11 -0
  7. package/dist/AttachmentBaseUrl.js +41 -0
  8. package/dist/AuthTokens.d.ts +13 -0
  9. package/dist/AuthTokens.js +30 -0
  10. package/dist/Business.d.ts +44 -0
  11. package/dist/Business.js +87 -0
  12. package/dist/BusinessIdentifier.d.ts +8 -0
  13. package/dist/BusinessIdentifier.js +14 -0
  14. package/dist/BusinessLink.d.ts +21 -0
  15. package/dist/BusinessLink.js +61 -0
  16. package/dist/BusinessProfile.d.ts +11 -0
  17. package/dist/BusinessProfile.js +27 -0
  18. package/dist/CartEditor.d.ts +59 -0
  19. package/dist/CartEditor.js +324 -0
  20. package/dist/Catalog.d.ts +28 -0
  21. package/dist/Catalog.js +115 -0
  22. package/dist/Constants.d.ts +10 -0
  23. package/dist/Constants.js +43 -0
  24. package/dist/ContainerNames.d.ts +2 -0
  25. package/dist/ContainerNames.js +21 -0
  26. package/dist/Database.d.ts +15 -0
  27. package/dist/Database.js +1 -0
  28. package/dist/Entity.d.ts +27 -0
  29. package/dist/Entity.js +69 -0
  30. package/dist/Enums.d.ts +16 -0
  31. package/dist/Enums.js +18 -0
  32. package/dist/Exceptions.d.ts +4 -0
  33. package/dist/Exceptions.js +8 -0
  34. package/dist/GeneralSettings.d.ts +46 -0
  35. package/dist/GeneralSettings.js +99 -0
  36. package/dist/HttpStatusCodes.d.ts +2 -0
  37. package/dist/HttpStatusCodes.js +34 -0
  38. package/dist/Ids.d.ts +17 -0
  39. package/dist/Ids.js +78 -0
  40. package/dist/Item.d.ts +12 -0
  41. package/dist/Item.js +30 -0
  42. package/dist/LatLong.d.ts +7 -0
  43. package/dist/LatLong.js +17 -0
  44. package/dist/LiveData.d.ts +30 -0
  45. package/dist/LiveData.js +76 -0
  46. package/dist/Measures.d.ts +20 -0
  47. package/dist/Measures.js +34 -0
  48. package/dist/Message.d.ts +16 -0
  49. package/dist/Message.js +32 -0
  50. package/dist/MockDatabase.d.ts +19 -0
  51. package/dist/MockDatabase.js +73 -0
  52. package/dist/Model.d.ts +63 -0
  53. package/dist/Model.js +629 -0
  54. package/dist/Order.d.ts +31 -0
  55. package/dist/Order.js +70 -0
  56. package/dist/Package.d.ts +25 -0
  57. package/dist/Package.js +52 -0
  58. package/dist/PackageIdentifier.d.ts +8 -0
  59. package/dist/PackageIdentifier.js +14 -0
  60. package/dist/PaymentMethodDetail.d.ts +8 -0
  61. package/dist/PaymentMethodDetail.js +17 -0
  62. package/dist/Photo.d.ts +11 -0
  63. package/dist/Photo.js +29 -0
  64. package/dist/Price.d.ts +17 -0
  65. package/dist/Price.js +52 -0
  66. package/dist/PriceList.d.ts +3 -0
  67. package/dist/PriceList.js +5 -0
  68. package/dist/Product.d.ts +33 -0
  69. package/dist/Product.js +84 -0
  70. package/dist/ProductCategory.d.ts +10 -0
  71. package/dist/ProductCategory.js +18 -0
  72. package/dist/Profile.d.ts +20 -0
  73. package/dist/Profile.js +55 -0
  74. package/dist/ProtoMap.d.ts +71 -0
  75. package/dist/ProtoMap.js +1126 -0
  76. package/dist/Routes.d.ts +7 -0
  77. package/dist/Routes.js +12 -0
  78. package/dist/Service.d.ts +16 -0
  79. package/dist/Service.js +1 -0
  80. package/dist/ServiceExceptions.d.ts +40 -0
  81. package/dist/ServiceExceptions.js +84 -0
  82. package/dist/ServiceProxy.d.ts +25 -0
  83. package/dist/ServiceProxy.js +117 -0
  84. package/dist/ShoppingList.d.ts +64 -0
  85. package/dist/ShoppingList.js +188 -0
  86. package/dist/SyncCache.d.ts +28 -0
  87. package/dist/SyncCache.js +137 -0
  88. package/dist/SyncKeys.d.ts +5 -0
  89. package/dist/SyncKeys.js +41 -0
  90. package/dist/SyncState.d.ts +8 -0
  91. package/dist/SyncState.js +30 -0
  92. package/dist/Tax.d.ts +10 -0
  93. package/dist/Tax.js +30 -0
  94. package/dist/UserProfile.d.ts +16 -0
  95. package/dist/UserProfile.js +40 -0
  96. package/dist/WorkingDays.d.ts +33 -0
  97. package/dist/WorkingDays.js +121 -0
  98. package/dist/generated/Address.d.ts +77 -0
  99. package/dist/generated/Address.js +110 -0
  100. package/dist/generated/AddressList.d.ts +39 -0
  101. package/dist/generated/AddressList.js +60 -0
  102. package/dist/generated/AddressType.d.ts +15 -0
  103. package/dist/generated/AddressType.js +20 -0
  104. package/dist/generated/Attachment.d.ts +66 -0
  105. package/dist/generated/Attachment.js +89 -0
  106. package/dist/generated/AttachmentType.d.ts +154 -0
  107. package/dist/generated/AttachmentType.js +159 -0
  108. package/dist/generated/AuthTokens.d.ts +56 -0
  109. package/dist/generated/AuthTokens.js +74 -0
  110. package/dist/generated/AuthenticationMethod.d.ts +24 -0
  111. package/dist/generated/AuthenticationMethod.js +29 -0
  112. package/dist/generated/Business.d.ts +54 -0
  113. package/dist/generated/Business.js +75 -0
  114. package/dist/generated/BusinessIdentifier.d.ts +36 -0
  115. package/dist/generated/BusinessIdentifier.js +60 -0
  116. package/dist/generated/BusinessIdentifierType.d.ts +49 -0
  117. package/dist/generated/BusinessIdentifierType.js +54 -0
  118. package/dist/generated/BusinessLink.d.ts +76 -0
  119. package/dist/generated/BusinessLink.js +99 -0
  120. package/dist/generated/BusinessSyncInRequest.d.ts +42 -0
  121. package/dist/generated/BusinessSyncInRequest.js +60 -0
  122. package/dist/generated/BusinessSyncInResponse.d.ts +42 -0
  123. package/dist/generated/BusinessSyncInResponse.js +60 -0
  124. package/dist/generated/BusinessSyncOutRequest.d.ts +82 -0
  125. package/dist/generated/BusinessSyncOutRequest.js +107 -0
  126. package/dist/generated/BusinessSyncOutResponse.d.ts +106 -0
  127. package/dist/generated/BusinessSyncOutResponse.js +139 -0
  128. package/dist/generated/Configuration.d.ts +48 -0
  129. package/dist/generated/Configuration.js +63 -0
  130. package/dist/generated/Constants.d.ts +474 -0
  131. package/dist/generated/Constants.js +479 -0
  132. package/dist/generated/CreateUserRequest.d.ts +37 -0
  133. package/dist/generated/CreateUserRequest.js +59 -0
  134. package/dist/generated/DimensionUnit.d.ts +28 -0
  135. package/dist/generated/DimensionUnit.js +33 -0
  136. package/dist/generated/Dimensions.d.ts +41 -0
  137. package/dist/generated/Dimensions.js +76 -0
  138. package/dist/generated/Entity.d.ts +62 -0
  139. package/dist/generated/Entity.js +83 -0
  140. package/dist/generated/FulfillmentMode.d.ts +32 -0
  141. package/dist/generated/FulfillmentMode.js +37 -0
  142. package/dist/generated/GeneralSettings.d.ts +141 -0
  143. package/dist/generated/GeneralSettings.js +186 -0
  144. package/dist/generated/Item.d.ts +54 -0
  145. package/dist/generated/Item.js +82 -0
  146. package/dist/generated/LatLong.d.ts +36 -0
  147. package/dist/generated/LatLong.js +59 -0
  148. package/dist/generated/Message.d.ts +80 -0
  149. package/dist/generated/Message.js +114 -0
  150. package/dist/generated/MessageType.d.ts +34 -0
  151. package/dist/generated/MessageType.js +39 -0
  152. package/dist/generated/OrderStatus.d.ts +50 -0
  153. package/dist/generated/OrderStatus.js +55 -0
  154. package/dist/generated/Package.d.ts +63 -0
  155. package/dist/generated/Package.js +92 -0
  156. package/dist/generated/PackageIdentifier.d.ts +36 -0
  157. package/dist/generated/PackageIdentifier.js +60 -0
  158. package/dist/generated/PackageIdentifierType.d.ts +49 -0
  159. package/dist/generated/PackageIdentifierType.js +54 -0
  160. package/dist/generated/PartyPreferencesPayload.d.ts +41 -0
  161. package/dist/generated/PartyPreferencesPayload.js +60 -0
  162. package/dist/generated/PaymentMethod.d.ts +20 -0
  163. package/dist/generated/PaymentMethod.js +25 -0
  164. package/dist/generated/PaymentMethodDetail.d.ts +37 -0
  165. package/dist/generated/PaymentMethodDetail.js +59 -0
  166. package/dist/generated/Price.d.ts +52 -0
  167. package/dist/generated/Price.js +75 -0
  168. package/dist/generated/PriceList.d.ts +34 -0
  169. package/dist/generated/PriceList.js +51 -0
  170. package/dist/generated/Product.d.ts +77 -0
  171. package/dist/generated/Product.js +106 -0
  172. package/dist/generated/ProductCategory.d.ts +32 -0
  173. package/dist/generated/ProductCategory.js +51 -0
  174. package/dist/generated/ProductType.d.ts +42 -0
  175. package/dist/generated/ProductType.js +47 -0
  176. package/dist/generated/ProfileSyncOutRequest.d.ts +51 -0
  177. package/dist/generated/ProfileSyncOutRequest.js +75 -0
  178. package/dist/generated/ProfileSyncOutResponse.d.ts +56 -0
  179. package/dist/generated/ProfileSyncOutResponse.js +77 -0
  180. package/dist/generated/ReservedPackage.d.ts +34 -0
  181. package/dist/generated/ReservedPackage.js +39 -0
  182. package/dist/generated/Role.d.ts +71 -0
  183. package/dist/generated/Role.js +76 -0
  184. package/dist/generated/SalesOrderPayload.d.ts +85 -0
  185. package/dist/generated/SalesOrderPayload.js +123 -0
  186. package/dist/generated/ShoppingList.d.ts +99 -0
  187. package/dist/generated/ShoppingList.js +132 -0
  188. package/dist/generated/ShoppingListItem.d.ts +102 -0
  189. package/dist/generated/ShoppingListItem.js +139 -0
  190. package/dist/generated/TaskStatus.d.ts +20 -0
  191. package/dist/generated/TaskStatus.js +25 -0
  192. package/dist/generated/Tax.d.ts +37 -0
  193. package/dist/generated/Tax.js +60 -0
  194. package/dist/generated/TaxType.d.ts +25 -0
  195. package/dist/generated/TaxType.js +30 -0
  196. package/dist/generated/UrlAndToken.d.ts +54 -0
  197. package/dist/generated/UrlAndToken.js +67 -0
  198. package/dist/generated/User.d.ts +63 -0
  199. package/dist/generated/User.js +89 -0
  200. package/dist/generated/Weight.d.ts +33 -0
  201. package/dist/generated/Weight.js +60 -0
  202. package/dist/generated/WeightUnit.d.ts +28 -0
  203. package/dist/generated/WeightUnit.js +33 -0
  204. package/dist/generated/WorkingDays.d.ts +42 -0
  205. package/dist/generated/WorkingDays.js +68 -0
  206. package/dist/generated/WorkingHours.d.ts +33 -0
  207. package/dist/generated/WorkingHours.js +52 -0
  208. package/dist/generated/WorkingHoursRange.d.ts +42 -0
  209. package/dist/generated/WorkingHoursRange.js +59 -0
  210. package/dist/index.d.ts +48 -0
  211. package/dist/index.js +60 -0
  212. package/package.json +55 -0
@@ -0,0 +1,7 @@
1
+ export default class Routes {
2
+ static readonly BUSINESS_SYNC_OUT: string;
3
+ static readonly BUSINESS_SYNC_IN: string;
4
+ static readonly PROFILE_SYNC_OUT: string;
5
+ static readonly CREATE_USER: string;
6
+ static readonly UPDATE_USER: string;
7
+ }
package/dist/Routes.js ADDED
@@ -0,0 +1,12 @@
1
+ // The last path segment of each call this library makes, appended to the base url a ServiceProxy is
2
+ // built with. Named after the server method the segment reaches, in the kebab case Java Routes.java
3
+ // uses, and prefixed to keep the storefront methods clear of the merchant ones that share the host.
4
+ // No route takes an id: every one of these calls says everything it needs to in its request message.
5
+ class Routes {
6
+ }
7
+ Routes.BUSINESS_SYNC_OUT = "shop-business-sync-out";
8
+ Routes.BUSINESS_SYNC_IN = "shop-business-sync-in";
9
+ Routes.PROFILE_SYNC_OUT = "shop-profile-sync-out";
10
+ Routes.CREATE_USER = "shop-create-user";
11
+ Routes.UPDATE_USER = "shop-update-user";
12
+ export default Routes;
@@ -0,0 +1,16 @@
1
+ import { AuthTokens as proto_AuthTokens } from "./generated/AuthTokens";
2
+ import { BusinessSyncInRequest as proto_BusinessSyncInRequest } from "./generated/BusinessSyncInRequest";
3
+ import { BusinessSyncInResponse as proto_BusinessSyncInResponse } from "./generated/BusinessSyncInResponse";
4
+ import { BusinessSyncOutRequest as proto_BusinessSyncOutRequest } from "./generated/BusinessSyncOutRequest";
5
+ import { BusinessSyncOutResponse as proto_BusinessSyncOutResponse } from "./generated/BusinessSyncOutResponse";
6
+ import { CreateUserRequest as proto_CreateUserRequest } from "./generated/CreateUserRequest";
7
+ import { ProfileSyncOutRequest as proto_ProfileSyncOutRequest } from "./generated/ProfileSyncOutRequest";
8
+ import { ProfileSyncOutResponse as proto_ProfileSyncOutResponse } from "./generated/ProfileSyncOutResponse";
9
+ import { User as proto_User } from "./generated/User";
10
+ export default interface Service {
11
+ businessSyncOut(request: proto_BusinessSyncOutRequest, authTokens: proto_AuthTokens | null): Promise<proto_BusinessSyncOutResponse>;
12
+ businessSyncIn(request: proto_BusinessSyncInRequest, authTokens: proto_AuthTokens): Promise<proto_BusinessSyncInResponse>;
13
+ profileSyncOut(request: proto_ProfileSyncOutRequest, authTokens: proto_AuthTokens): Promise<proto_ProfileSyncOutResponse>;
14
+ createUser(request: proto_CreateUserRequest, authTokens: proto_AuthTokens): Promise<proto_ProfileSyncOutResponse>;
15
+ updateUser(user: proto_User, authTokens: proto_AuthTokens): Promise<proto_ProfileSyncOutResponse>;
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ export declare class ServiceException extends Error {
2
+ readonly httpStatusCode: number;
3
+ constructor(httpStatusCode: number, message?: string);
4
+ }
5
+ export declare class BadRequestException extends ServiceException {
6
+ constructor(message?: string);
7
+ static readonly STATUS_CODE: number;
8
+ }
9
+ export declare class UnauthorizedException extends ServiceException {
10
+ constructor(message?: string);
11
+ static readonly STATUS_CODE: number;
12
+ }
13
+ export declare class NotFoundException extends ServiceException {
14
+ constructor(message?: string);
15
+ static readonly STATUS_CODE: number;
16
+ }
17
+ export declare class MethodNotAllowedException extends ServiceException {
18
+ constructor(message?: string);
19
+ static readonly STATUS_CODE: number;
20
+ }
21
+ export declare class ConflictException extends ServiceException {
22
+ constructor(message?: string);
23
+ static readonly STATUS_CODE: number;
24
+ }
25
+ export declare class UpgradeRequiredException extends ServiceException {
26
+ constructor(message?: string);
27
+ static readonly STATUS_CODE: number;
28
+ }
29
+ export declare class InternalServerException extends ServiceException {
30
+ constructor(message?: string);
31
+ static readonly STATUS_CODE: number;
32
+ }
33
+ export declare class ServiceUnavailableException extends ServiceException {
34
+ constructor(message?: string);
35
+ static readonly STATUS_CODE: number;
36
+ }
37
+ export declare class NetworkConnectionException extends Error {
38
+ readonly reason?: unknown;
39
+ constructor(message?: string, reason?: unknown);
40
+ }
@@ -0,0 +1,84 @@
1
+ // What a Service call fails with. Unlike the two in Exceptions.ts these are not programming errors:
2
+ // a caller is expected to catch them and decide what to do - sign in again, retry, or show the shop
3
+ // it already has cached. They mirror Java com.merabills.repository.client.exception so that the two
4
+ // clients of this server describe the same failure the same way.
5
+ // Each carries the status code rather than being told apart by a string, and the derived classes
6
+ // exist so a caller can catch the one case it can actually handle without testing a number.
7
+ // A call reached the server and the server refused it. Thrown directly for a status code none of the
8
+ // classes below names, so an unrecognised failure is still a ServiceException and not something else.
9
+ export class ServiceException extends Error {
10
+ constructor(httpStatusCode, message) {
11
+ super(message);
12
+ this.httpStatusCode = httpStatusCode;
13
+ // Otherwise every one of these reports itself as a bare "Error" when logged
14
+ this.name = new.target.name;
15
+ }
16
+ }
17
+ // HTTP 400 - the request was not one the server could act on
18
+ export class BadRequestException extends ServiceException {
19
+ constructor(message) {
20
+ super(BadRequestException.STATUS_CODE, message);
21
+ }
22
+ }
23
+ BadRequestException.STATUS_CODE = 400;
24
+ // HTTP 401 - the credentials were missing, expired or not the caller's to present
25
+ export class UnauthorizedException extends ServiceException {
26
+ constructor(message) {
27
+ super(UnauthorizedException.STATUS_CODE, message);
28
+ }
29
+ }
30
+ UnauthorizedException.STATUS_CODE = 401;
31
+ // HTTP 404 - no such business, user or route
32
+ export class NotFoundException extends ServiceException {
33
+ constructor(message) {
34
+ super(NotFoundException.STATUS_CODE, message);
35
+ }
36
+ }
37
+ NotFoundException.STATUS_CODE = 404;
38
+ // HTTP 405 - the route exists but not for this method
39
+ export class MethodNotAllowedException extends ServiceException {
40
+ constructor(message) {
41
+ super(MethodNotAllowedException.STATUS_CODE, message);
42
+ }
43
+ }
44
+ MethodNotAllowedException.STATUS_CODE = 405;
45
+ // HTTP 409 - the change collided with one the server already had
46
+ export class ConflictException extends ServiceException {
47
+ constructor(message) {
48
+ super(ConflictException.STATUS_CODE, message);
49
+ }
50
+ }
51
+ ConflictException.STATUS_CODE = 409;
52
+ // HTTP 426 - this client is too old for the server to answer
53
+ export class UpgradeRequiredException extends ServiceException {
54
+ constructor(message) {
55
+ super(UpgradeRequiredException.STATUS_CODE, message);
56
+ }
57
+ }
58
+ UpgradeRequiredException.STATUS_CODE = 426;
59
+ // HTTP 500 - the server failed while answering. Worth retrying, unlike the 4xx cases above.
60
+ export class InternalServerException extends ServiceException {
61
+ constructor(message) {
62
+ super(InternalServerException.STATUS_CODE, message);
63
+ }
64
+ }
65
+ InternalServerException.STATUS_CODE = 500;
66
+ // HTTP 503 - the server is up but cannot answer yet
67
+ export class ServiceUnavailableException extends ServiceException {
68
+ constructor(message) {
69
+ super(ServiceUnavailableException.STATUS_CODE, message);
70
+ }
71
+ }
72
+ ServiceUnavailableException.STATUS_CODE = 503;
73
+ // The call never got an answer at all - offline, DNS, TLS, a refused connection or one cut short.
74
+ // Not a ServiceException, because there is no status code and the server may well have acted on the
75
+ // request: a caller that retries has to be prepared for the first attempt to have succeeded.
76
+ export class NetworkConnectionException extends Error {
77
+ constructor(message, reason) {
78
+ super(message);
79
+ this.reason = reason;
80
+ this.name = new.target.name;
81
+ }
82
+ }
83
+ // Which status code each of these stands for is HttpStatusCodes.ts, the way Java keeps the classes
84
+ // in its exception package and the mapping in HttpStatusCodes.
@@ -0,0 +1,25 @@
1
+ import { AuthTokens as proto_AuthTokens } from "./generated/AuthTokens";
2
+ import { BusinessSyncInRequest as proto_BusinessSyncInRequest } from "./generated/BusinessSyncInRequest";
3
+ import { BusinessSyncInResponse as proto_BusinessSyncInResponse } from "./generated/BusinessSyncInResponse";
4
+ import { BusinessSyncOutRequest as proto_BusinessSyncOutRequest } from "./generated/BusinessSyncOutRequest";
5
+ import { BusinessSyncOutResponse as proto_BusinessSyncOutResponse } from "./generated/BusinessSyncOutResponse";
6
+ import { CreateUserRequest as proto_CreateUserRequest } from "./generated/CreateUserRequest";
7
+ import { ProfileSyncOutRequest as proto_ProfileSyncOutRequest } from "./generated/ProfileSyncOutRequest";
8
+ import { ProfileSyncOutResponse as proto_ProfileSyncOutResponse } from "./generated/ProfileSyncOutResponse";
9
+ import { User as proto_User } from "./generated/User";
10
+ import Service from "./Service";
11
+ export type FetchFunction = (url: string, init: RequestInit) => Promise<Response>;
12
+ export default class ServiceProxy implements Service {
13
+ constructor(serviceBaseUrl: string, fetchFunction?: FetchFunction | null);
14
+ businessSyncOut(request: proto_BusinessSyncOutRequest, authTokens: proto_AuthTokens | null): Promise<proto_BusinessSyncOutResponse>;
15
+ businessSyncIn(request: proto_BusinessSyncInRequest, authTokens: proto_AuthTokens): Promise<proto_BusinessSyncInResponse>;
16
+ profileSyncOut(request: proto_ProfileSyncOutRequest, authTokens: proto_AuthTokens): Promise<proto_ProfileSyncOutResponse>;
17
+ createUser(request: proto_CreateUserRequest, authTokens: proto_AuthTokens): Promise<proto_ProfileSyncOutResponse>;
18
+ updateUser(user: proto_User, authTokens: proto_AuthTokens): Promise<proto_ProfileSyncOutResponse>;
19
+ private post;
20
+ private send;
21
+ private getFetchFunction;
22
+ private static readErrorMessage;
23
+ private readonly _serviceBaseUrl;
24
+ private readonly _fetchFunction;
25
+ }
@@ -0,0 +1,117 @@
1
+ import { BusinessSyncInRequest as proto_BusinessSyncInRequest } from "./generated/BusinessSyncInRequest";
2
+ import { BusinessSyncInResponse as proto_BusinessSyncInResponse } from "./generated/BusinessSyncInResponse";
3
+ import { BusinessSyncOutRequest as proto_BusinessSyncOutRequest } from "./generated/BusinessSyncOutRequest";
4
+ import { BusinessSyncOutResponse as proto_BusinessSyncOutResponse } from "./generated/BusinessSyncOutResponse";
5
+ import { CreateUserRequest as proto_CreateUserRequest } from "./generated/CreateUserRequest";
6
+ import { ProfileSyncOutRequest as proto_ProfileSyncOutRequest } from "./generated/ProfileSyncOutRequest";
7
+ import { ProfileSyncOutResponse as proto_ProfileSyncOutResponse } from "./generated/ProfileSyncOutResponse";
8
+ import { User as proto_User } from "./generated/User";
9
+ import { IllegalOperationException } from "./Exceptions";
10
+ import { isError, throwOnError } from "./HttpStatusCodes";
11
+ import { buildAuthTokensBytes } from "./ProtoMap";
12
+ import Routes from "./Routes";
13
+ import { NetworkConnectionException } from "./ServiceExceptions";
14
+ // A Service that reaches a real MeraBills server. Every call is one POST to the route named after
15
+ // it, carrying its request message encoded, and answering with the response message encoded - so
16
+ // this class translates nothing and reads no field of either.
17
+ // One call is one page: a sync out is paged, and the loop belongs to whoever is caching what comes
18
+ // back, so that each page is written as it arrives - see Model.businessSyncIn.
19
+ export default class ServiceProxy {
20
+ // The base url is everything before the route, with or without a trailing slash and with or
21
+ // without a path of its own - both are joined onto rather than replaced, so a server reached
22
+ // under a prefix works without the caller having to know how a route is built.
23
+ constructor(serviceBaseUrl, fetchFunction = null) {
24
+ this._serviceBaseUrl = serviceBaseUrl.replace(TRAILING_SLASHES, "");
25
+ this._fetchFunction = fetchFunction;
26
+ }
27
+ async businessSyncOut(request, authTokens) {
28
+ return this.post(Routes.BUSINESS_SYNC_OUT, proto_BusinessSyncOutRequest, request, proto_BusinessSyncOutResponse, authTokens);
29
+ }
30
+ async businessSyncIn(request, authTokens) {
31
+ return this.post(Routes.BUSINESS_SYNC_IN, proto_BusinessSyncInRequest, request, proto_BusinessSyncInResponse, authTokens);
32
+ }
33
+ async profileSyncOut(request, authTokens) {
34
+ return this.post(Routes.PROFILE_SYNC_OUT, proto_ProfileSyncOutRequest, request, proto_ProfileSyncOutResponse, authTokens);
35
+ }
36
+ async createUser(request, authTokens) {
37
+ return this.post(Routes.CREATE_USER, proto_CreateUserRequest, request, proto_ProfileSyncOutResponse, authTokens);
38
+ }
39
+ // The User is the whole request, there being no wrapper message for one
40
+ async updateUser(user, authTokens) {
41
+ return this.post(Routes.UPDATE_USER, proto_User, user, proto_ProfileSyncOutResponse, authTokens);
42
+ }
43
+ // One call: encode, send, turn a refusal into the exception it stands for, decode. The message
44
+ // types are passed in rather than named per call so that every route is sent and read identically.
45
+ async post(route, requestType, request, responseType, authTokens) {
46
+ const response = await this.send(route, requestType.toBinary(request), authTokens);
47
+ // The body of a failure is not a response message, so it has to be dealt with before decoding
48
+ if (isError(response.status))
49
+ throwOnError(response.status, await ServiceProxy.readErrorMessage(route, response));
50
+ return responseType.fromBinary(new Uint8Array(await response.arrayBuffer()));
51
+ }
52
+ async send(route, body, authTokens) {
53
+ const headers = { [CONTENT_TYPE_HEADER]: CONTENT_TYPE_PROTOBUF };
54
+ // An anonymous visitor is given no header at all rather than an empty one - the protocol has no
55
+ // anonymous form of the message, so the absence is what says nobody is claiming to be calling.
56
+ if (authTokens !== null)
57
+ headers[AUTHORIZATION_HEADER] = toBase64(buildAuthTokensBytes(authTokens));
58
+ try {
59
+ return await this.getFetchFunction()(`${this._serviceBaseUrl}/${route}`, {
60
+ method: POST,
61
+ headers: headers,
62
+ body: body,
63
+ });
64
+ }
65
+ catch (reason) {
66
+ // fetch rejects only when no answer arrived at all; a server that refused the call answers
67
+ // with a status code and resolves. So the request may still have been acted on, and a caller
68
+ // that retries has to be prepared for the first attempt to have succeeded.
69
+ throw new NetworkConnectionException(`The call to ${route} could not be completed`, reason);
70
+ }
71
+ }
72
+ // Resolved per call rather than at construction, so a platform that installs fetch after this
73
+ // object is built still works and an absent one fails where it is actually needed.
74
+ getFetchFunction() {
75
+ const supplied = this._fetchFunction;
76
+ if (supplied !== null)
77
+ return supplied;
78
+ const platform = globalThis.fetch;
79
+ if (platform === undefined)
80
+ throw new IllegalOperationException("This platform has no fetch, so a ServiceProxy cannot reach a server");
81
+ // Bound, because fetch called detached from globalThis is refused by browsers
82
+ return platform.bind(globalThis);
83
+ }
84
+ // What the response says went wrong, if anything. This protocol has no error message of its own
85
+ // yet, so the body of a failure can be anything at all - a stack trace, an HTML page - and only
86
+ // the start of one is worth carrying; a body that cannot be read says nothing the status code
87
+ // does not already.
88
+ static async readErrorMessage(route, response) {
89
+ let body;
90
+ try {
91
+ body = (await response.text()).trim();
92
+ }
93
+ catch {
94
+ body = "";
95
+ }
96
+ if (body.length > MAX_ERROR_MESSAGE_LENGTH)
97
+ body = `${body.slice(0, MAX_ERROR_MESSAGE_LENGTH)}...`;
98
+ return body.length === 0 ? route : `${route}: ${body}`;
99
+ }
100
+ }
101
+ // A header carries text, so the encoded credentials travel as base64. No scheme prefix: the server
102
+ // reads the whole value as one encoded AuthTokens, exactly as the Java client sends the whole value
103
+ // as one serialized AuthTokens.
104
+ function toBase64(bytes) {
105
+ // Built a character at a time rather than by spreading the array into String.fromCharCode, which
106
+ // passes it as an argument list and overflows the stack once it is long enough
107
+ let binary = "";
108
+ for (const byte of bytes)
109
+ binary += String.fromCharCode(byte);
110
+ return btoa(binary);
111
+ }
112
+ const AUTHORIZATION_HEADER = "authorization";
113
+ const CONTENT_TYPE_HEADER = "content-type";
114
+ const CONTENT_TYPE_PROTOBUF = "application/octet-stream";
115
+ const POST = "POST";
116
+ const MAX_ERROR_MESSAGE_LENGTH = 512;
117
+ const TRAILING_SLASHES = /\/+$/;
@@ -0,0 +1,64 @@
1
+ import Tax from "./Tax";
2
+ export default class ShoppingList {
3
+ private readonly _isFinal;
4
+ private readonly _autoAddDeliveryCharge;
5
+ private readonly _autoAddServiceCharge;
6
+ private readonly _inventoryLocationId;
7
+ private readonly _priceListId;
8
+ private readonly _totalAmountBeforeDiscount;
9
+ private readonly _discount;
10
+ private readonly _existingItemCount;
11
+ private readonly _deletedItemCount;
12
+ private readonly _existingItems;
13
+ private readonly _deletedItems;
14
+ static fromScaledValues(isFinal: boolean, autoAddDeliveryCharge: boolean, autoAddServiceCharge: boolean, inventoryLocationId: number, priceListId: bigint, scaledTotalAmountBeforeDiscount: bigint, scaledDiscount: bigint, existingItemCount: number, deletedItemCount: number, existingItems: ReadonlyArray<ShoppingListItem>, deletedItems: ReadonlyArray<ShoppingListItem>): ShoppingList;
15
+ constructor(_isFinal: boolean, _autoAddDeliveryCharge: boolean, _autoAddServiceCharge: boolean, _inventoryLocationId: number, _priceListId: bigint, _totalAmountBeforeDiscount: number, _discount: number, _existingItemCount: number, _deletedItemCount: number, _existingItems: ReadonlyArray<ShoppingListItem>, _deletedItems: ReadonlyArray<ShoppingListItem>);
16
+ get isFinal(): boolean;
17
+ get autoAddDeliveryCharge(): boolean;
18
+ get autoAddServiceCharge(): boolean;
19
+ get inventoryLocationId(): number;
20
+ get priceListId(): bigint;
21
+ get totalAmountBeforeDiscount(): number;
22
+ get discount(): number;
23
+ get totalAmount(): number;
24
+ get existingItemCount(): number;
25
+ get deletedItemCount(): number;
26
+ get itemCount(): number;
27
+ get existingItems(): ReadonlyArray<ShoppingListItem>;
28
+ get deletedItems(): ReadonlyArray<ShoppingListItem>;
29
+ get computedTotal(): number;
30
+ get computedTotalTax(): number;
31
+ static readonly EMPTY: ShoppingList;
32
+ }
33
+ export declare class ShoppingListItem {
34
+ private readonly _packageId;
35
+ private readonly _quantity;
36
+ private readonly _unitPrice;
37
+ private readonly _shoppingListOrder;
38
+ private readonly _isOriginal;
39
+ private readonly _isModified;
40
+ private readonly _isStockKeepingRequired;
41
+ private readonly _priceDiscount;
42
+ private readonly _discount;
43
+ private readonly _taxes;
44
+ private readonly _expiryMinutes;
45
+ private readonly _description;
46
+ static fromScaledValues(packageId: bigint, scaledQuantity: number, scaledUnitPrice: bigint, shoppingListOrder: number, isOriginal: boolean, isModified: boolean, isStockKeepingRequired: boolean, scaledPriceDiscount: bigint, scaledDiscount: bigint, taxes: ReadonlyArray<Tax>, expiryMinutes: number, description: string | null): ShoppingListItem;
47
+ constructor(_packageId: bigint, _quantity: number, _unitPrice: number, _shoppingListOrder: number, _isOriginal: boolean, _isModified: boolean, _isStockKeepingRequired: boolean, _priceDiscount: number, _discount: number, _taxes: ReadonlyArray<Tax>, _expiryMinutes: number, _description: string | null);
48
+ get packageId(): bigint;
49
+ get isReservedPackage(): boolean;
50
+ get quantity(): number;
51
+ get unitPrice(): number;
52
+ get shoppingListOrder(): number;
53
+ get isOriginal(): boolean;
54
+ get isModified(): boolean;
55
+ get isStockKeepingRequired(): boolean;
56
+ get priceDiscount(): number;
57
+ get discount(): number;
58
+ get taxes(): ReadonlyArray<Tax>;
59
+ get expiryMinutes(): number;
60
+ get description(): string | null;
61
+ get amount(): number;
62
+ get totalTax(): number;
63
+ get finalPrice(): number;
64
+ }
@@ -0,0 +1,188 @@
1
+ import { MERABILLS_ONLINE_PRICE_LIST_ID, amountFromScaledValue, quantityFromScaledValue, } from "./Constants";
2
+ import Ids from "./Ids";
3
+ // A list of packages being bought: a shopping cart, or what an order contains.
4
+ // Wire totals are authoritative; computed ones (below) use different rounding than Java
5
+ // PriceCalculation, so a UI shows totalAmount, not computedTotal.
6
+ class ShoppingList {
7
+ // Only ProtoMap calls this: it is the one place that sees a total still multiplied by
8
+ // Constants.AMOUNT_FACTOR.
9
+ static fromScaledValues(isFinal, autoAddDeliveryCharge, autoAddServiceCharge, inventoryLocationId, priceListId, scaledTotalAmountBeforeDiscount, scaledDiscount, existingItemCount, deletedItemCount, existingItems, deletedItems) {
10
+ return new ShoppingList(isFinal, autoAddDeliveryCharge, autoAddServiceCharge, inventoryLocationId, priceListId, amountFromScaledValue(scaledTotalAmountBeforeDiscount), amountFromScaledValue(scaledDiscount), existingItemCount, deletedItemCount, existingItems, deletedItems);
11
+ }
12
+ constructor(_isFinal, _autoAddDeliveryCharge, _autoAddServiceCharge, _inventoryLocationId, _priceListId, _totalAmountBeforeDiscount, _discount, _existingItemCount, _deletedItemCount, _existingItems, _deletedItems) {
13
+ this._isFinal = _isFinal;
14
+ this._autoAddDeliveryCharge = _autoAddDeliveryCharge;
15
+ this._autoAddServiceCharge = _autoAddServiceCharge;
16
+ this._inventoryLocationId = _inventoryLocationId;
17
+ this._priceListId = _priceListId;
18
+ this._totalAmountBeforeDiscount = _totalAmountBeforeDiscount;
19
+ this._discount = _discount;
20
+ this._existingItemCount = _existingItemCount;
21
+ this._deletedItemCount = _deletedItemCount;
22
+ this._existingItems = _existingItems;
23
+ this._deletedItems = _deletedItems;
24
+ }
25
+ // True once the customer is done editing, after which the business may edit it instead. Only a
26
+ // final list can have deleted items, and this is never unset.
27
+ get isFinal() {
28
+ return this._isFinal;
29
+ }
30
+ // True when the delivery charge is a line of its own, carrying the reserved package id
31
+ // ReservedPackage.DELIVERY_CHARGE_PACKAGE, rather than being added to the total
32
+ get autoAddDeliveryCharge() {
33
+ return this._autoAddDeliveryCharge;
34
+ }
35
+ // The same, for ReservedPackage.SERVICE_CHARGE_PACKAGE
36
+ get autoAddServiceCharge() {
37
+ return this._autoAddServiceCharge;
38
+ }
39
+ // Zero is the default location
40
+ get inventoryLocationId() {
41
+ return this._inventoryLocationId;
42
+ }
43
+ // The price list these prices came from, which is the one a storefront sells from: a cart with
44
+ // none uses Constants.MERABILLS_ONLINE_PRICE_LIST_ID, the list Catalog.priceList holds.
45
+ get priceListId() {
46
+ return this._priceListId;
47
+ }
48
+ get totalAmountBeforeDiscount() {
49
+ return this._totalAmountBeforeDiscount;
50
+ }
51
+ // The discount on the whole list, as opposed to a discount on one line of it
52
+ get discount() {
53
+ return this._discount;
54
+ }
55
+ // What the customer owes. Derived rather than sent, but derived from the authoritative totals
56
+ // above, so this is the number to display.
57
+ get totalAmount() {
58
+ return this._totalAmountBeforeDiscount - this._discount;
59
+ }
60
+ // Read from the wire and not from the length of the array below, because the protocol sends the
61
+ // count even when it does not send the items themselves
62
+ get existingItemCount() {
63
+ return this._existingItemCount;
64
+ }
65
+ get deletedItemCount() {
66
+ return this._deletedItemCount;
67
+ }
68
+ get itemCount() {
69
+ return this._existingItemCount + this._deletedItemCount;
70
+ }
71
+ get existingItems() {
72
+ return this._existingItems;
73
+ }
74
+ // The items that were in this list when it was made final and have since been deleted or
75
+ // replaced. Always empty until then.
76
+ get deletedItems() {
77
+ return this._deletedItems;
78
+ }
79
+ // Sum of finalPrice over existingItems. Not authoritative (rounded here, not by the server), and
80
+ // only covers the whole list when existingItems.length equals existingItemCount.
81
+ get computedTotal() {
82
+ let result = 0;
83
+ for (const item of this._existingItems)
84
+ result += item.finalPrice;
85
+ return result;
86
+ }
87
+ // The sum of the taxes of the items that are here, with the same caveat as computedTotal
88
+ get computedTotalTax() {
89
+ let result = 0;
90
+ for (const item of this._existingItems)
91
+ result += item.totalTax;
92
+ return result;
93
+ }
94
+ }
95
+ // An empty cart, for a customer who has not put anything in one yet
96
+ ShoppingList.EMPTY = new ShoppingList(false, false, false, 0, MERABILLS_ONLINE_PRICE_LIST_ID, 0, 0, 0, 0, Object.freeze([]), Object.freeze([]));
97
+ export default ShoppingList;
98
+ // One line of a shopping list: the package being bought, how much of it, and at what price.
99
+ export class ShoppingListItem {
100
+ // Only ProtoMap calls this: it is the one place that sees a quantity multiplied by
101
+ // Constants.QUANTITY_FACTOR and prices multiplied by Constants.AMOUNT_FACTOR.
102
+ static fromScaledValues(packageId, scaledQuantity, scaledUnitPrice, shoppingListOrder, isOriginal, isModified, isStockKeepingRequired, scaledPriceDiscount, scaledDiscount, taxes, expiryMinutes, description) {
103
+ return new ShoppingListItem(packageId, quantityFromScaledValue(scaledQuantity), amountFromScaledValue(scaledUnitPrice), shoppingListOrder, isOriginal, isModified, isStockKeepingRequired, amountFromScaledValue(scaledPriceDiscount), amountFromScaledValue(scaledDiscount), taxes, expiryMinutes, description);
104
+ }
105
+ constructor(_packageId, _quantity, _unitPrice, _shoppingListOrder, _isOriginal, _isModified, _isStockKeepingRequired, _priceDiscount, _discount, _taxes, _expiryMinutes, _description) {
106
+ this._packageId = _packageId;
107
+ this._quantity = _quantity;
108
+ this._unitPrice = _unitPrice;
109
+ this._shoppingListOrder = _shoppingListOrder;
110
+ this._isOriginal = _isOriginal;
111
+ this._isModified = _isModified;
112
+ this._isStockKeepingRequired = _isStockKeepingRequired;
113
+ this._priceDiscount = _priceDiscount;
114
+ this._discount = _discount;
115
+ this._taxes = _taxes;
116
+ this._expiryMinutes = _expiryMinutes;
117
+ this._description = _description;
118
+ }
119
+ // The package being bought. Four ids are reserved for charge and summary lines rather than
120
+ // catalog packages and will not be found in the catalog - see isReservedPackage below.
121
+ get packageId() {
122
+ return this._packageId;
123
+ }
124
+ // True when this line is a charge/summary (delivery, service charge, discount, or total) rather
125
+ // than a catalog package. A UI must label such lines itself.
126
+ get isReservedPackage() {
127
+ return Ids.isReservedPackageId(this._packageId);
128
+ }
129
+ get quantity() {
130
+ return this._quantity;
131
+ }
132
+ // What one unit costs, which is the offer price when the package is on offer
133
+ get unitPrice() {
134
+ return this._unitPrice;
135
+ }
136
+ // Where this line sits in the list, from zero
137
+ get shoppingListOrder() {
138
+ return this._shoppingListOrder;
139
+ }
140
+ // True when this line was created before the list was made final
141
+ get isOriginal() {
142
+ return this._isOriginal;
143
+ }
144
+ // True when this line has been deleted or replaced since the list was made final
145
+ get isModified() {
146
+ return this._isModified;
147
+ }
148
+ get isStockKeepingRequired() {
149
+ return this._isStockKeepingRequired;
150
+ }
151
+ // What the offer takes off the unit price - the regular price of the package less its offer
152
+ // price - and not a discount on this line
153
+ get priceDiscount() {
154
+ return this._priceDiscount;
155
+ }
156
+ // The discount on this whole line, taxes included
157
+ get discount() {
158
+ return this._discount;
159
+ }
160
+ get taxes() {
161
+ return this._taxes;
162
+ }
163
+ // Minutes after purchase when this item expires, and zero when it does not
164
+ get expiryMinutes() {
165
+ return this._expiryMinutes;
166
+ }
167
+ get description() {
168
+ return this._description;
169
+ }
170
+ // What this line costs before tax and before its discount
171
+ get amount() {
172
+ return this._unitPrice * this._quantity;
173
+ }
174
+ // Tax on this line at the rates it was bought with. Computed here since the protocol sends
175
+ // rates, not amounts, and left unrounded (unlike the server's authoritative total).
176
+ get totalTax() {
177
+ const amount = this.amount;
178
+ let result = 0;
179
+ for (const tax of this._taxes)
180
+ result += (amount * tax.rate) / 100;
181
+ return result;
182
+ }
183
+ // What this line adds to the list: what it costs, plus the tax on it, less its discount. This is
184
+ // the definition ShoppingListItem.proto gives.
185
+ get finalPrice() {
186
+ return this.amount + this.totalTax - this._discount;
187
+ }
188
+ }
@@ -0,0 +1,28 @@
1
+ import { BusinessSyncOutResponse as proto_BusinessSyncOutResponse } from "./generated/BusinessSyncOutResponse";
2
+ import { Message as proto_Message } from "./generated/Message";
3
+ import { ProfileSyncOutResponse as proto_ProfileSyncOutResponse } from "./generated/ProfileSyncOutResponse";
4
+ import AuthTokens from "./AuthTokens";
5
+ import Database from "./Database";
6
+ export default class SyncCache {
7
+ private readonly _database;
8
+ constructor(_database: Database);
9
+ readBusiness(containerName: string): Promise<proto_BusinessSyncOutResponse | null>;
10
+ writeBusiness(containerName: string, response: proto_BusinessSyncOutResponse): Promise<number>;
11
+ readProfile(containerName: string): Promise<proto_ProfileSyncOutResponse | null>;
12
+ writeProfile(containerName: string, response: proto_ProfileSyncOutResponse): Promise<number>;
13
+ readAuthTokens(containerName: string): Promise<AuthTokens | null>;
14
+ writeAuthTokens(containerName: string, authTokens: AuthTokens): Promise<void>;
15
+ readOrders(containerName: string): Promise<ReadonlyArray<proto_Message>>;
16
+ readMessageUpdateNumber(containerName: string): Promise<bigint>;
17
+ writeOrder(containerName: string, order: proto_Message): Promise<number>;
18
+ readCart(containerName: string): Promise<proto_Message | null>;
19
+ writeCart(containerName: string, cart: proto_Message): Promise<number>;
20
+ deleteCart(containerName: string): Promise<number>;
21
+ writeMessages(containerName: string, messages: ReadonlyArray<proto_Message>): Promise<number>;
22
+ private readAll;
23
+ private writeBlobs;
24
+ private write;
25
+ private getContainer;
26
+ private readonly _containers;
27
+ }
28
+ export declare const NO_DELETES: ReadonlyArray<bigint>;