@peabody-soft/mbs-model-ts 1.5.0 → 1.7.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 (52) hide show
  1. package/dist/Address.js +8 -11
  2. package/dist/Attachment.js +7 -8
  3. package/dist/AttachmentBaseUrl.js +10 -10
  4. package/dist/AuthTokens.js +12 -7
  5. package/dist/Business.js +19 -19
  6. package/dist/BusinessIdentifier.js +2 -2
  7. package/dist/BusinessLink.js +16 -16
  8. package/dist/BusinessProfile.js +4 -4
  9. package/dist/CartEditor.js +137 -166
  10. package/dist/Catalog.js +19 -25
  11. package/dist/Constants.js +10 -10
  12. package/dist/ContainerNames.js +10 -11
  13. package/dist/Entity.js +11 -9
  14. package/dist/Enums.js +2 -2
  15. package/dist/Exceptions.js +2 -2
  16. package/dist/GeneralSettings.js +23 -21
  17. package/dist/HttpStatusCodes.js +10 -11
  18. package/dist/Ids.js +24 -30
  19. package/dist/Item.js +6 -7
  20. package/dist/LatLong.js +3 -3
  21. package/dist/LiveData.js +6 -6
  22. package/dist/Measures.js +2 -2
  23. package/dist/Message.js +6 -6
  24. package/dist/MockDatabase.js +2 -2
  25. package/dist/Model.js +294 -365
  26. package/dist/Order.js +20 -17
  27. package/dist/Package.js +7 -8
  28. package/dist/PackageIdentifier.js +2 -2
  29. package/dist/PaymentMethodDetail.js +4 -4
  30. package/dist/Photo.js +6 -7
  31. package/dist/Price.js +8 -9
  32. package/dist/PriceList.js +2 -2
  33. package/dist/Product.js +17 -22
  34. package/dist/ProductCategory.js +3 -4
  35. package/dist/Profile.js +26 -27
  36. package/dist/ProtoMap.d.ts +3 -0
  37. package/dist/ProtoMap.js +288 -294
  38. package/dist/Routes.js +3 -3
  39. package/dist/ServiceExceptions.js +11 -12
  40. package/dist/ServiceProxy.js +19 -23
  41. package/dist/ShoppingList.js +112 -130
  42. package/dist/SyncCache.d.ts +3 -0
  43. package/dist/SyncCache.js +92 -75
  44. package/dist/SyncKeys.js +8 -8
  45. package/dist/SyncState.js +5 -5
  46. package/dist/Tax.js +16 -21
  47. package/dist/TaxHelper.js +22 -30
  48. package/dist/TaxType.js +8 -9
  49. package/dist/UserProfile.js +4 -4
  50. package/dist/WorkingDays.js +15 -15
  51. package/dist/index.js +9 -9
  52. package/package.json +1 -1
package/dist/Address.js CHANGED
@@ -1,9 +1,7 @@
1
- // A postal address: a delivery address of a customer, or an address of a business. Not an entity -
2
- // its id is unique only within the AddressList that holds it.
1
+ // A postal address of a customer or a business. Not an entity: its id is unique only within the
2
+ // AddressList that holds it.
3
3
  export default class Address {
4
- constructor(
5
- // Unique only within the list that holds it, unlike an entity id
6
- id, _addressType, _unitNumber, _community, _line2, _city, _state, _pinCode, _countryCode) {
4
+ constructor(id, _addressType, _unitNumber, _community, _line2, _city, _state, _pinCode, _countryCode) {
7
5
  this.id = id;
8
6
  this._addressType = _addressType;
9
7
  this._unitNumber = _unitNumber;
@@ -42,8 +40,8 @@ export default class Address {
42
40
  get countryCode() {
43
41
  return this._countryCode;
44
42
  }
45
- // The set parts, in envelope order, joined with commas; empty when none are set. Country is
46
- // deliberately excluded - turning a code into a name is a UI decision, not this library's.
43
+ // The non-empty parts in envelope order, joined with commas. Country is left out, since naming
44
+ // it is a UI decision.
47
45
  get formattedAddress() {
48
46
  const parts = [];
49
47
  for (const part of [
@@ -75,8 +73,8 @@ export class AddressList {
75
73
  get size() {
76
74
  return this._addresses.length;
77
75
  }
78
- // The address named by defaultAddressId, or the first address if that id names none (default was
79
- // deleted). Null only when the list is empty.
76
+ // The address named by defaultAddressId, or the first one if that id names none (the default was
77
+ // deleted). Null when the list is empty.
80
78
  get defaultAddress() {
81
79
  if (this._addresses.length === 0)
82
80
  return null;
@@ -92,6 +90,5 @@ export class AddressList {
92
90
  return null;
93
91
  }
94
92
  }
95
- // An empty list, for a user or a business that has no addresses at all. Frozen and shared,
96
- // because an AddressList holds nothing that can change.
93
+ // The shared empty list. Frozen, since an AddressList cannot change.
97
94
  AddressList.EMPTY = new AddressList(0n, Object.freeze([]));
@@ -1,7 +1,7 @@
1
1
  import Entity from "./Entity";
2
2
  import Ids from "./Ids";
3
- // A file attached to an entity - a photo of a business, a product or a package. Not part of this
4
- // library's public surface; a UI is given a Photo (attachment type + url) built from this instead.
3
+ // A file attached to an entity: a photo of a business, product or package. Not public. A UI is given
4
+ // a Photo (attachment type and url) built from it.
5
5
  export default class Attachment extends Entity {
6
6
  constructor(header, _attachmentType, _owningEntityId, _fileHash, _fileExtension, _fileName) {
7
7
  super(header);
@@ -11,21 +11,20 @@ export default class Attachment extends Entity {
11
11
  this._fileExtension = _fileExtension;
12
12
  this._fileName = _fileName;
13
13
  }
14
- // Which photo of the owning entity this is: the main catalog image, one of the lifestyle images,
15
- // a photo of the store, and so on
14
+ // Which photo of the owning entity this is, such as the main catalog image or a store photo
16
15
  get attachmentType() {
17
16
  return this._attachmentType;
18
17
  }
19
- // The business, product or package this file is attached to. Nothing nests on the wire, so this
20
- // is how the sync layer finds which entity a photo belongs to.
18
+ // The business, product or package this file is attached to. Nothing nests on the wire, so the
19
+ // sync layer uses this to place the photo.
21
20
  get owningEntityId() {
22
21
  return this._owningEntityId;
23
22
  }
24
23
  get fileName() {
25
24
  return this._fileName;
26
25
  }
27
- // Storage file name, or null if this attachment has no file (deleted). Must exactly match Java
28
- // Attachment.getStorageFileName: UTC date with zero-based month, upper-hex id/hash, no 0x prefix.
26
+ // Storage file name, or null if the attachment has no file (deleted). Must match Java
27
+ // Attachment.getStorageFileName: UTC date with zero-based month, upper-hex id and hash, no 0x prefix.
29
28
  get storageFileName() {
30
29
  if (this._fileHash === null || this._fileExtension === null)
31
30
  return null;
@@ -1,40 +1,40 @@
1
1
  import { Constants as proto_Constants } from "./generated/Constants";
2
2
  import { InvalidArgumentException } from "./Exceptions";
3
3
  // Where a business's attachment files live, the signature that reads them, and when both expire.
4
- // Signature has no getter (only createFileUrl exposes it) - safe in a url only because it is
5
- // scoped, read-only and short-lived, unlike AuthTokens' userToken/linkToken.
4
+ // The signature has no getter, only createFileUrl exposes it. It is safe in a url because it is
5
+ // scoped, read-only and short-lived, unlike AuthTokens' userToken and linkToken.
6
6
  export default class AttachmentBaseUrl {
7
7
  constructor(_resourceUrl, _sasToken, expiry) {
8
8
  this._resourceUrl = _resourceUrl;
9
9
  this._sasToken = _sasToken;
10
- // The protobuf promises no trailing slash and no query string; checked rather than trusted,
11
- // since violating either silently produces a url that fetches nothing.
10
+ // The protobuf promises no trailing slash and no query string. Checked, since either would
11
+ // silently build a url that fetches nothing.
12
12
  if (_resourceUrl.length === 0 || _resourceUrl.endsWith("/"))
13
13
  throw new InvalidArgumentException(`Not a container url: ${_resourceUrl}`);
14
14
  if (_resourceUrl.includes("?"))
15
15
  throw new InvalidArgumentException("A container url cannot carry a query string");
16
16
  this._expiry = Number(expiry);
17
17
  }
18
- // The url of the container the files are in, always https and never with a trailing slash
18
+ // The url of the container the files are in. Https, no trailing slash.
19
19
  get resourceUrl() {
20
20
  return this._resourceUrl;
21
21
  }
22
22
  get expiry() {
23
23
  return new Date(this._expiry);
24
24
  }
25
- // True once too close to expiry to be worth using (margin: ATTACHMENT_BASE_URL_EXPIRY_MARGIN),
26
- // compared against the client's own clock so a url can't expire between being built and fetched.
25
+ // True once within ATTACHMENT_BASE_URL_EXPIRY_MARGIN of expiry, by the client's clock, so a url
26
+ // cannot expire between being built and fetched.
27
27
  get hasExpired() {
28
28
  return Date.now() + proto_Constants.ATTACHMENT_BASE_URL_EXPIRY_MARGIN >= this._expiry;
29
29
  }
30
- // The url of one file: storage file name as the path, signature as the query string. Name must
31
- // be a flat path segment - a container is not a directory tree.
30
+ // The url of one file: storage file name as the path, signature as the query string. The name
31
+ // must be a single path segment, as a container has no directories.
32
32
  createFileUrl(storageFileName) {
33
33
  if (storageFileName.length === 0 || storageFileName.includes("/"))
34
34
  throw new InvalidArgumentException(`Not a storage file name: ${storageFileName}`);
35
35
  return new URL(`${this._resourceUrl}/${storageFileName}?${this._sasToken}`);
36
36
  }
37
- // Redacts the signature, so that logging one of these cannot leak it
37
+ // Redacts the signature so logging cannot leak it
38
38
  toString() {
39
39
  return `AttachmentBaseUrl(resourceUrl=${this._resourceUrl}, expiry=${this.expiry.toISOString()}, sasToken=<redacted>)`;
40
40
  }
@@ -1,5 +1,6 @@
1
- // The credentials one request is signed with: exactly the fields of the AuthTokens message and nothing derived, so that what this library holds and what the wire carries cannot drift.
2
- // A class of its own rather than the generated message because these are held and cached rather than only sent; ProtoMap turns one into the message a Service is handed. Every value is a bearer credential - never log one.
1
+ // The credentials a request is signed with: the fields of the AuthTokens message, nothing derived.
2
+ // A class of its own because it is held and cached. ProtoMap turns one into the message a Service
3
+ // is handed. Every value is a bearer credential, so never log one.
3
4
  export default class AuthTokens {
4
5
  constructor(_authenticationMethod, _authenticationToken, _userToken, _linkToken) {
5
6
  this._authenticationMethod = _authenticationMethod;
@@ -7,23 +8,27 @@ export default class AuthTokens {
7
8
  this._userToken = _userToken;
8
9
  this._linkToken = _linkToken;
9
10
  }
10
- // Which identity provider issued the authentication token, and so how a server parses it. Always set: zero is FIREBASE, not "unspecified".
11
+ // The identity provider that issued the authentication token, which tells the server how to
12
+ // parse it. Always set. Zero is FIREBASE.
11
13
  get authenticationMethod() {
12
14
  return this._authenticationMethod;
13
15
  }
14
- // Which person is calling, as their identity provider says. Empty on one read back out of the cache, which deliberately keeps no copy of it - see ProtoMap.authTokensToBlob.
16
+ // Who is calling, as their identity provider states it. Empty when read back from the cache, which
17
+ // keeps no copy. See ProtoMap.authTokensToBlob.
15
18
  get authenticationToken() {
16
19
  return this._authenticationToken;
17
20
  }
18
- // Which MeraBills user that person is, issued by this server. Null until a profile sync out has been made once, which is the call that earns one.
21
+ // The MeraBills user, issued by this server. Null until the first profile sync out, which is the
22
+ // call that returns one.
19
23
  get userToken() {
20
24
  return this._userToken;
21
25
  }
22
- // Which business the caller may act against, from the BusinessLink of that business. Null on a call that names none, which the protocol allows.
26
+ // Authorizes the caller against one business, from that business's BusinessLink. Null on a call
27
+ // that names no business.
23
28
  get linkToken() {
24
29
  return this._linkToken;
25
30
  }
26
- // Redacts all three, so that logging one of these cannot leak a credential
31
+ // Redacts all three tokens so logging cannot leak them
27
32
  toString() {
28
33
  return `AuthTokens(authenticationMethod=${this._authenticationMethod}, authenticationToken=<redacted>, userToken=<${this._userToken === null ? "none" : "redacted"}>, linkToken=<${this._linkToken === null ? "none" : "redacted"}>)`;
29
34
  }
package/dist/Business.js CHANGED
@@ -3,9 +3,9 @@ import CartEditor from "./CartEditor";
3
3
  import Catalog from "./Catalog";
4
4
  import Entity from "./Entity";
5
5
  import GeneralSettings from "./GeneralSettings";
6
- // The business a customer is browsing: its name, settings, photos, catalog, orders, and cart.
7
- // Rebuilt by the sync layer from flat wire entities and set via UpdatableBusiness, not a public
8
- // setter - a UI holding a Business can read all of it and change none of it.
6
+ // The business a customer is browsing: name, settings, photos, catalog, orders and cart. The sync
7
+ // layer rebuilds it from flat wire entities and sets it through UpdatableBusiness. A UI can read
8
+ // all of it and change none.
9
9
  export default class Business extends Entity {
10
10
  constructor(header, _businessId, _displayName, _countryCode) {
11
11
  super(header);
@@ -20,8 +20,8 @@ export default class Business extends Entity {
20
20
  this._catalog = Catalog.EMPTY;
21
21
  this._attachmentBaseUrl = null;
22
22
  }
23
- // The unique, lower case, url friendly id this storefront was reached by - not the entity id
24
- // (see the warning on BusinessLink.businessId, which is this business's entity id)
23
+ // The unique, lower case, url friendly id the storefront is reached by. The entity id is
24
+ // BusinessLink.businessId.
25
25
  get businessId() {
26
26
  return this._businessId;
27
27
  }
@@ -47,28 +47,28 @@ export default class Business extends Entity {
47
47
  set photos(value) {
48
48
  this._photos = value;
49
49
  }
50
- // The orders this customer has placed
50
+ // The orders this customer has placed, open and completed (fulfilled or cancelled). Order.status
51
+ // says how far the business got, and Order.isDeleted that it has completed the order. The library
52
+ // does not sort them.
51
53
  get orders() {
52
54
  return this._orders;
53
55
  }
54
56
  set orders(value) {
55
57
  this._orders = value;
56
58
  }
57
- // What this customer has picked and not yet ordered. Null until they have put something in a
58
- // cart, and null again once they have ordered what was in it - the message the cart travels in
59
- // outlives being emptied, but nothing of it is a customer's business, so what is exposed is the
60
- // list alone. The fulfillment mode is not part of it: that is chosen when an order is placed, and
61
- // is a field of the Order - see defaultFulfillmentMode for the one other place it is read.
59
+ // What this customer has picked and not yet ordered. Null until something is put in a cart, and
60
+ // null again once it is ordered, although the message carrying the cart outlives that. Only the
61
+ // list is exposed. The fulfillment mode is chosen when an order is placed and is a field of the
62
+ // Order (see defaultFulfillmentMode).
62
63
  get cart() {
63
64
  return this._cart;
64
65
  }
65
66
  set cart(value) {
66
67
  this._cart = value;
67
68
  }
68
- // What to preselect for this customer's next order: whatever the party preferences message
69
- // already carries, which createOrder stamps with the mode an order was just placed under - so
70
- // this is that order's own choice, not necessarily today's cart's. DELIVERY when there has never
71
- // been a party preferences message to read one from.
69
+ // What to preselect for the next order. It is the mode in the party preferences message, which
70
+ // createOrder stamps with the mode of the order just placed, so it is the last order's choice.
71
+ // DELIVERY when there is no party preferences message.
72
72
  get defaultFulfillmentMode() {
73
73
  return this._defaultFulfillmentMode;
74
74
  }
@@ -82,14 +82,14 @@ export default class Business extends Entity {
82
82
  set catalog(value) {
83
83
  this._catalog = value;
84
84
  }
85
- // A scratch copy of the cart to edit, priced off this business's catalog and charged to its
86
- // settings - see CartEditor. It reads all three once, here, so a Business republished mid-edit
87
- // needs a fresh one; nothing an editor does touches this business until its built list reaches
85
+ // A scratch copy of the cart to edit, priced from this business's catalog and settings (see
86
+ // CartEditor). It reads catalog, settings and cart once, so a Business republished mid-edit needs
87
+ // a new editor. Nothing it does touches this business until its built list reaches
88
88
  // Model.updateCartLocalOnly.
89
89
  createCartEditor() {
90
90
  return new CartEditor(this._catalog, this._settings, this._cart);
91
91
  }
92
- // Where this business's photo files live; renewed on its own schedule independent of the rest
92
+ // Where this business's photo files live. Renewed on its own schedule.
93
93
  get attachmentBaseUrl() {
94
94
  return this._attachmentBaseUrl;
95
95
  }
@@ -1,5 +1,5 @@
1
- // An identifier of a business - a GSTIN, for example - and its kind. Same pair-not-a-map reason as
2
- // PackageIdentifier: Java identifies kinds by string id, so this numbering is protocol-only.
1
+ // An identifier of a business, such as a GSTIN, and its kind. A pair rather than a map, as in
2
+ // PackageIdentifier: Java identifies kinds by string id, so the numbering is protocol-only.
3
3
  export default class BusinessIdentifier {
4
4
  constructor(_type, _value) {
5
5
  this._type = _type;
@@ -1,7 +1,7 @@
1
1
  import { Constants as proto_Constants } from "./generated/Constants";
2
2
  import Entity from "./Entity";
3
- // What links a customer to a business and authorizes them to act against it. businessId is an
4
- // entity id (not the url-friendly Business.businessId); never log or url-embed linkToken.
3
+ // Links a customer to a business and authorizes them to act against it. businessId is an entity
4
+ // id, unlike the url-friendly Business.businessId.
5
5
  class BusinessLink extends Entity {
6
6
  constructor(header, _linkedEntityId, _businessId, _role, _partyId, _linkToken, expiry) {
7
7
  super(header);
@@ -12,46 +12,46 @@ class BusinessLink extends Entity {
12
12
  this._linkToken = _linkToken;
13
13
  this._expiry = Number(expiry);
14
14
  }
15
- // The entity this link is for - the User of the customer, in a storefront. Its entity type is
16
- // the most significant byte of the id, which is how a client tells a user from a business.
15
+ // The entity this link is for, in a storefront the customer's User. The entity type is the most
16
+ // significant byte of the id, which tells a user from a business.
17
17
  get linkedEntityId() {
18
18
  return this._linkedEntityId;
19
19
  }
20
- // The entity id of the business, matching Business.entity.id - see the comment on this class
20
+ // The entity id of the business, matching Business.entity.id. See the class comment.
21
21
  get businessId() {
22
22
  return this._businessId;
23
23
  }
24
- // What the customer may do, normally Role.CUSTOMER. Group is (role >> 6); actual permissions are
25
- // not on the wire, so a UI cannot grey out disallowed actions.
24
+ // What the customer may do, normally Role.CUSTOMER. The group is role >> 6. Permissions are not
25
+ // on the wire, so a UI cannot grey out disallowed actions.
26
26
  get role() {
27
27
  return this._role;
28
28
  }
29
- // The party record of this customer, or Constants.ENTITY_ID_NULL when none. Party is not part of
30
- // this protocol, so a storefront cannot resolve it - exposed only because the server needs it.
29
+ // The customer's party record, or Constants.ENTITY_ID_NULL when none. Party is not part of this
30
+ // protocol, so a storefront cannot resolve it. Exposed because the server needs it.
31
31
  get partyId() {
32
32
  return this._partyId;
33
33
  }
34
- // The credential that goes into AuthTokens.linkToken of every later request naming this
35
- // business. Never log this and never put it in a url.
34
+ // The credential for AuthTokens.linkToken on later requests that name this business. Never log
35
+ // it or put it in a url.
36
36
  get linkToken() {
37
37
  return this._linkToken;
38
38
  }
39
39
  get expiry() {
40
40
  return new Date(this._expiry);
41
41
  }
42
- // False when this link never expires, which is what BusinessLink.NO_EXPIRY means. That constant
43
- // is not in Constants.proto - it is zero, and it is the only meaning zero has for this field.
42
+ // False when the link never expires (expiry is NO_EXPIRY). NO_EXPIRY is zero and is not in
43
+ // Constants.proto.
44
44
  get isExpirySet() {
45
45
  return this._expiry !== BusinessLink.NO_EXPIRY;
46
46
  }
47
- // True once past expiry by more than Constants.MAX_CLOCK_SKEW - applied opposite to
48
- // AttachmentBaseUrl.hasExpired, so a false positive can't lock out a still-entitled customer.
47
+ // True once past expiry by more than Constants.MAX_CLOCK_SKEW. Applied the opposite way to
48
+ // AttachmentBaseUrl.hasExpired, so a false positive cannot lock out an entitled customer.
49
49
  get hasExpired() {
50
50
  if (!this.isExpirySet)
51
51
  return false;
52
52
  return Date.now() - proto_Constants.MAX_CLOCK_SKEW > this._expiry;
53
53
  }
54
- // Redacts the link token, so that logging a link cannot leak it
54
+ // Redacts the link token so logging cannot leak it
55
55
  toString() {
56
56
  return `BusinessLink(id=${this.id}, businessId=${this._businessId}, role=${this._role}, linkToken=<redacted>)`;
57
57
  }
@@ -1,6 +1,6 @@
1
1
  import Entity from "./Entity";
2
2
  // One business the customer is linked to, as the profile database holds it: url-friendly id, name
3
- // and country only - deliberately not a Business, which carries data a profile sync can't provide.
3
+ // and country. A Business carries more than a profile sync provides.
4
4
  export default class BusinessProfile extends Entity {
5
5
  constructor(header, _businessId, _displayName, _countryCode) {
6
6
  super(header);
@@ -8,8 +8,8 @@ export default class BusinessProfile extends Entity {
8
8
  this._displayName = _displayName;
9
9
  this._countryCode = _countryCode;
10
10
  }
11
- // The unique, lower case, url-friendly id a storefront is reached by; what Model.setBusinessId
12
- // takes. Not the entity id - BusinessLink.businessId is the entity id of the same business.
11
+ // The unique, lower case, url-friendly id a storefront is reached by. It is what
12
+ // Model.setBusinessId takes. The entity id is BusinessLink.businessId.
13
13
  get businessId() {
14
14
  return this._businessId;
15
15
  }
@@ -17,7 +17,7 @@ export default class BusinessProfile extends Entity {
17
17
  get displayName() {
18
18
  return this._displayName;
19
19
  }
20
- // ISO 3166-1 numeric; the only thing that says what currency this business's amounts are in
20
+ // ISO 3166-1 numeric; the only source of currency for this business's amounts
21
21
  get countryCode() {
22
22
  return this._countryCode;
23
23
  }