@shaxpir/duiduidui-models 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 (211) hide show
  1. package/README.md +1 -0
  2. package/decs.d.ts +87 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +20 -0
  5. package/dist/models/OutboundMessage.d.ts +18 -0
  6. package/dist/models/OutboundMessage.js +25 -0
  7. package/dist/models/content/Activity.d.ts +10 -0
  8. package/dist/models/content/Activity.js +2 -0
  9. package/dist/models/content/ArrayView.d.ts +26 -0
  10. package/dist/models/content/ArrayView.js +174 -0
  11. package/dist/models/content/Billing.d.ts +144 -0
  12. package/dist/models/content/Billing.js +418 -0
  13. package/dist/models/content/Book.d.ts +77 -0
  14. package/dist/models/content/Book.js +407 -0
  15. package/dist/models/content/Category.d.ts +16 -0
  16. package/dist/models/content/Category.js +20 -0
  17. package/dist/models/content/Checkpointable.d.ts +21 -0
  18. package/dist/models/content/Checkpointable.js +156 -0
  19. package/dist/models/content/Comment.d.ts +19 -0
  20. package/dist/models/content/Comment.js +53 -0
  21. package/dist/models/content/ConceptArt.d.ts +31 -0
  22. package/dist/models/content/ConceptArt.js +84 -0
  23. package/dist/models/content/Content.d.ts +52 -0
  24. package/dist/models/content/Content.js +61 -0
  25. package/dist/models/content/ContentKind.d.ts +10 -0
  26. package/dist/models/content/ContentKind.js +16 -0
  27. package/dist/models/content/Context.d.ts +28 -0
  28. package/dist/models/content/Context.js +162 -0
  29. package/dist/models/content/DevEnv.d.ts +5 -0
  30. package/dist/models/content/DevEnv.js +9 -0
  31. package/dist/models/content/Device.d.ts +24 -0
  32. package/dist/models/content/Device.js +62 -0
  33. package/dist/models/content/Dictionary.d.ts +31 -0
  34. package/dist/models/content/Dictionary.js +5 -0
  35. package/dist/models/content/DictionaryEntry.d.ts +20 -0
  36. package/dist/models/content/DictionaryEntry.js +2 -0
  37. package/dist/models/content/ElasticModel.d.ts +149 -0
  38. package/dist/models/content/ElasticModel.js +179 -0
  39. package/dist/models/content/Environment.d.ts +61 -0
  40. package/dist/models/content/Environment.js +124 -0
  41. package/dist/models/content/ExportOptions.d.ts +64 -0
  42. package/dist/models/content/ExportOptions.js +213 -0
  43. package/dist/models/content/Folder.d.ts +16 -0
  44. package/dist/models/content/Folder.js +33 -0
  45. package/dist/models/content/Fragment.d.ts +54 -0
  46. package/dist/models/content/Fragment.js +181 -0
  47. package/dist/models/content/GeoLocation.d.ts +4 -0
  48. package/dist/models/content/GeoLocation.js +2 -0
  49. package/dist/models/content/Hanzi.d.ts +21 -0
  50. package/dist/models/content/Hanzi.js +2 -0
  51. package/dist/models/content/HighlightRule.d.ts +9 -0
  52. package/dist/models/content/HighlightRule.js +2 -0
  53. package/dist/models/content/Manifest.d.ts +42 -0
  54. package/dist/models/content/Manifest.js +114 -0
  55. package/dist/models/content/Media.d.ts +32 -0
  56. package/dist/models/content/Media.js +98 -0
  57. package/dist/models/content/Metric.d.ts +46 -0
  58. package/dist/models/content/Metric.js +183 -0
  59. package/dist/models/content/Migration.d.ts +68 -0
  60. package/dist/models/content/Migration.js +155 -0
  61. package/dist/models/content/Model.d.ts +45 -0
  62. package/dist/models/content/Model.js +280 -0
  63. package/dist/models/content/Permissions.d.ts +7 -0
  64. package/dist/models/content/Permissions.js +20 -0
  65. package/dist/models/content/Phrase.d.ts +8 -0
  66. package/dist/models/content/Phrase.js +2 -0
  67. package/dist/models/content/Placeholder.d.ts +8 -0
  68. package/dist/models/content/Placeholder.js +36 -0
  69. package/dist/models/content/Profile.d.ts +30 -0
  70. package/dist/models/content/Profile.js +95 -0
  71. package/dist/models/content/RichText.d.ts +58 -0
  72. package/dist/models/content/RichText.js +79 -0
  73. package/dist/models/content/Session.d.ts +39 -0
  74. package/dist/models/content/Session.js +173 -0
  75. package/dist/models/content/Speech.d.ts +67 -0
  76. package/dist/models/content/Speech.js +97 -0
  77. package/dist/models/content/Stub.d.ts +24 -0
  78. package/dist/models/content/Stub.js +179 -0
  79. package/dist/models/content/Time.d.ts +56 -0
  80. package/dist/models/content/Time.js +295 -0
  81. package/dist/models/content/User.d.ts +36 -0
  82. package/dist/models/content/User.js +95 -0
  83. package/dist/models/content/Workspace.d.ts +71 -0
  84. package/dist/models/content/Workspace.js +237 -0
  85. package/dist/models/content/index.d.ts +36 -0
  86. package/dist/models/content/index.js +53 -0
  87. package/dist/models/index.d.ts +4 -0
  88. package/dist/models/index.js +21 -0
  89. package/dist/models/legacy/LegacyBodyFormat.d.ts +9 -0
  90. package/dist/models/legacy/LegacyBodyFormat.js +2 -0
  91. package/dist/models/legacy/LegacyComment.d.ts +12 -0
  92. package/dist/models/legacy/LegacyComment.js +2 -0
  93. package/dist/models/legacy/LegacyContent.d.ts +53 -0
  94. package/dist/models/legacy/LegacyContent.js +55 -0
  95. package/dist/models/legacy/LegacyConversion.d.ts +55 -0
  96. package/dist/models/legacy/LegacyConversion.js +401 -0
  97. package/dist/models/legacy/LegacyFragment.d.ts +21 -0
  98. package/dist/models/legacy/LegacyFragment.js +2 -0
  99. package/dist/models/legacy/LegacyLocator.d.ts +8 -0
  100. package/dist/models/legacy/LegacyLocator.js +31 -0
  101. package/dist/models/legacy/LegacyOutboundMessage.d.ts +16 -0
  102. package/dist/models/legacy/LegacyOutboundMessage.js +13 -0
  103. package/dist/models/legacy/LegacyPicture.d.ts +14 -0
  104. package/dist/models/legacy/LegacyPicture.js +2 -0
  105. package/dist/models/legacy/LegacyProfile.d.ts +9 -0
  106. package/dist/models/legacy/LegacyProfile.js +2 -0
  107. package/dist/models/legacy/LegacySession.d.ts +41 -0
  108. package/dist/models/legacy/LegacySession.js +35 -0
  109. package/dist/models/legacy/LegacyStory.d.ts +23 -0
  110. package/dist/models/legacy/LegacyStory.js +2 -0
  111. package/dist/models/legacy/LegacyStub.d.ts +15 -0
  112. package/dist/models/legacy/LegacyStub.js +2 -0
  113. package/dist/models/legacy/LegacyTransaction.d.ts +14 -0
  114. package/dist/models/legacy/LegacyTransaction.js +49 -0
  115. package/dist/models/legacy/LegacyUser.d.ts +28 -0
  116. package/dist/models/legacy/LegacyUser.js +32 -0
  117. package/dist/models/legacy/LegacyWorkspace.d.ts +23 -0
  118. package/dist/models/legacy/LegacyWorkspace.js +6 -0
  119. package/dist/models/legacy/index.d.ts +15 -0
  120. package/dist/models/legacy/index.js +32 -0
  121. package/dist/models/markup/BodyFormat.d.ts +14 -0
  122. package/dist/models/markup/BodyFormat.js +190 -0
  123. package/dist/models/markup/ChangeModel.d.ts +22 -0
  124. package/dist/models/markup/ChangeModel.js +107 -0
  125. package/dist/models/markup/DeltaOps.d.ts +5 -0
  126. package/dist/models/markup/DeltaOps.js +74 -0
  127. package/dist/models/markup/HtmlMarkup.d.ts +4 -0
  128. package/dist/models/markup/HtmlMarkup.js +21 -0
  129. package/dist/models/markup/Operation.d.ts +32 -0
  130. package/dist/models/markup/Operation.js +194 -0
  131. package/dist/models/markup/TextEditOps.d.ts +9 -0
  132. package/dist/models/markup/TextEditOps.js +50 -0
  133. package/dist/models/markup/index.d.ts +6 -0
  134. package/dist/models/markup/index.js +23 -0
  135. package/dist/repo/ConnectionListener.d.ts +9 -0
  136. package/dist/repo/ConnectionListener.js +21 -0
  137. package/dist/repo/PermissiveJson1.d.ts +58 -0
  138. package/dist/repo/PermissiveJson1.js +39 -0
  139. package/dist/repo/ShareSync.d.ts +60 -0
  140. package/dist/repo/ShareSync.js +348 -0
  141. package/dist/repo/index.d.ts +3 -0
  142. package/dist/repo/index.js +20 -0
  143. package/dist/util/Async.d.ts +8 -0
  144. package/dist/util/Async.js +18 -0
  145. package/dist/util/Base62.d.ts +6 -0
  146. package/dist/util/Base62.js +47 -0
  147. package/dist/util/BinarySearch.d.ts +7 -0
  148. package/dist/util/BinarySearch.js +46 -0
  149. package/dist/util/CachingHasher.d.ts +8 -0
  150. package/dist/util/CachingHasher.js +41 -0
  151. package/dist/util/Color.d.ts +32 -0
  152. package/dist/util/Color.js +204 -0
  153. package/dist/util/Dispatch.d.ts +15 -0
  154. package/dist/util/Dispatch.js +79 -0
  155. package/dist/util/EditDistance.d.ts +13 -0
  156. package/dist/util/EditDistance.js +184 -0
  157. package/dist/util/Encryption.d.ts +5 -0
  158. package/dist/util/Encryption.js +2 -0
  159. package/dist/util/Logging.d.ts +108 -0
  160. package/dist/util/Logging.js +412 -0
  161. package/dist/util/NumberFormat.d.ts +14 -0
  162. package/dist/util/NumberFormat.js +224 -0
  163. package/dist/util/Struct.d.ts +4 -0
  164. package/dist/util/Struct.js +15 -0
  165. package/dist/util/Template.d.ts +16 -0
  166. package/dist/util/Template.js +128 -0
  167. package/dist/util/Text.d.ts +45 -0
  168. package/dist/util/Text.js +243 -0
  169. package/dist/util/Tuples.d.ts +9 -0
  170. package/dist/util/Tuples.js +135 -0
  171. package/dist/util/Validate.d.ts +4 -0
  172. package/dist/util/Validate.js +11 -0
  173. package/dist/util/Vocabulary.d.ts +3 -0
  174. package/dist/util/Vocabulary.js +35 -0
  175. package/dist/util/index.d.ts +16 -0
  176. package/dist/util/index.js +33 -0
  177. package/lib/models/content/ArrayView.ts +203 -0
  178. package/lib/models/content/Billing.ts +558 -0
  179. package/lib/models/content/Content.ts +110 -0
  180. package/lib/models/content/ContentKind.ts +14 -0
  181. package/lib/models/content/DevEnv.ts +5 -0
  182. package/lib/models/content/Device.ts +86 -0
  183. package/lib/models/content/DictionaryEntry.ts +22 -0
  184. package/lib/models/content/GeoLocation.ts +4 -0
  185. package/lib/models/content/Hanzi.ts +25 -0
  186. package/lib/models/content/Manifest.ts +162 -0
  187. package/lib/models/content/Media.ts +126 -0
  188. package/lib/models/content/Model.ts +327 -0
  189. package/lib/models/content/Permissions.ts +21 -0
  190. package/lib/models/content/Phrase.ts +10 -0
  191. package/lib/models/content/Profile.ts +119 -0
  192. package/lib/models/content/Time.ts +328 -0
  193. package/lib/models/content/User.ts +130 -0
  194. package/lib/models/markup/ChangeModel.ts +95 -0
  195. package/lib/models/markup/DeltaOps.ts +71 -0
  196. package/lib/models/markup/Operation.ts +215 -0
  197. package/lib/models/markup/TextEditOps.ts +50 -0
  198. package/lib/repo/ConnectionListener.ts +25 -0
  199. package/lib/repo/PermissiveJson1.ts +14 -0
  200. package/lib/repo/ShareSync.ts +390 -0
  201. package/lib/util/Base62.ts +47 -0
  202. package/lib/util/CachingHasher.ts +38 -0
  203. package/lib/util/Dispatch.ts +92 -0
  204. package/lib/util/Encryption.ts +5 -0
  205. package/lib/util/Logging.ts +568 -0
  206. package/lib/util/NumberFormat.ts +194 -0
  207. package/lib/util/Struct.ts +14 -0
  208. package/lib/util/Tuples.ts +131 -0
  209. package/package.json +41 -0
  210. package/tsconfig.json +25 -0
  211. package/tslint.json +46 -0
@@ -0,0 +1,418 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Billing = exports.PaymentStatus = exports.ProductCatalog = exports.ProductLevel = exports.Interval = exports.TransactionTopic = void 0;
4
+ const ShareSync_1 = require("../../repo/ShareSync");
5
+ const Struct_1 = require("../../util/Struct");
6
+ const CachingHasher_1 = require("../../util/CachingHasher");
7
+ const NumberFormat_1 = require("../../util/NumberFormat");
8
+ const Operation_1 = require("../markup/Operation");
9
+ const ArrayView_1 = require("./ArrayView");
10
+ const Content_1 = require("./Content");
11
+ const ContentKind_1 = require("./ContentKind");
12
+ const Time_1 = require("./Time");
13
+ var TransactionTopic;
14
+ (function (TransactionTopic) {
15
+ TransactionTopic["START_7_DAY_TRIAL"] = "START_7_DAY_TRIAL";
16
+ TransactionTopic["APPLY_COUPON"] = "APPLY_COUPON";
17
+ TransactionTopic["PAYMENT_SUCCESS"] = "PAYMENT_SUCCESS";
18
+ TransactionTopic["PAYMENT_FAIL"] = "PAYMENT_FAIL";
19
+ TransactionTopic["CANCEL_SUBSCRIPTION"] = "CANCEL_SUBSCRIPTION";
20
+ TransactionTopic["RESTART_SUBSCRIPTION"] = "RESTART_SUBSCRIPTION";
21
+ })(TransactionTopic || (exports.TransactionTopic = TransactionTopic = {}));
22
+ var Interval;
23
+ (function (Interval) {
24
+ Interval["MONTHLY"] = "MONTHLY";
25
+ Interval["ANNUAL"] = "ANNUAL";
26
+ })(Interval || (exports.Interval = Interval = {}));
27
+ ;
28
+ var ProductLevel;
29
+ (function (ProductLevel) {
30
+ ProductLevel["FREE"] = "FREE";
31
+ ProductLevel["BASIC"] = "BASIC";
32
+ ProductLevel["PRO"] = "PRO";
33
+ })(ProductLevel || (exports.ProductLevel = ProductLevel = {}));
34
+ ;
35
+ ;
36
+ class ProductCatalog {
37
+ constructor(config) {
38
+ this.productsById = new Map();
39
+ this.pricesById = new Map();
40
+ this.plansById = new Map();
41
+ for (const product of config.products) {
42
+ this.productsById.set(product.id, product);
43
+ }
44
+ for (const price of config.prices) {
45
+ this.pricesById.set(price.id, price);
46
+ }
47
+ for (const plan of config.plans) {
48
+ this.plansById.set(plan.id, plan);
49
+ }
50
+ }
51
+ getProductById(id) {
52
+ return this.productsById.get(id);
53
+ }
54
+ getPriceById(id) {
55
+ return this.pricesById.get(id);
56
+ }
57
+ getPlanById(id) {
58
+ return this.plansById.get(id);
59
+ }
60
+ getProductsByPredicate(predicate) {
61
+ const products = [];
62
+ for (const product of this.productsById.values()) {
63
+ if (predicate(product)) {
64
+ products.push(product);
65
+ }
66
+ }
67
+ return products;
68
+ }
69
+ getPricesByPredicate(predicate) {
70
+ const prices = [];
71
+ for (const price of this.pricesById.values()) {
72
+ if (predicate(price)) {
73
+ prices.push(price);
74
+ }
75
+ }
76
+ return prices;
77
+ }
78
+ getPlansByPredicate(predicate) {
79
+ const plans = [];
80
+ for (const plan of this.plansById.values()) {
81
+ if (predicate(plan)) {
82
+ plans.push(plan);
83
+ }
84
+ }
85
+ return plans;
86
+ }
87
+ }
88
+ exports.ProductCatalog = ProductCatalog;
89
+ // TODO: cleanup "PRE_TRIAL" status, and update all users who have this status
90
+ var PaymentStatus;
91
+ (function (PaymentStatus) {
92
+ PaymentStatus["PRE_TRIAL"] = "PRE_TRIAL";
93
+ PaymentStatus["IN_TRIAL"] = "IN_TRIAL";
94
+ PaymentStatus["PAID"] = "PAID";
95
+ PaymentStatus["UNPAID"] = "UNPAID";
96
+ PaymentStatus["CANCELLED"] = "CANCELLED";
97
+ })(PaymentStatus || (exports.PaymentStatus = PaymentStatus = {}));
98
+ class Billing extends Content_1.Content {
99
+ constructor(doc, shouldAcquire, shareSync) {
100
+ super(doc, shouldAcquire, shareSync);
101
+ this._transactionsView = new ArrayView_1.ArrayView(this, ['payload', 'transactions']);
102
+ }
103
+ get payload() {
104
+ this.checkDisposed("Billing.payload");
105
+ return this.doc.data.payload;
106
+ }
107
+ static makeBillingId(userId) {
108
+ return CachingHasher_1.CachingHasher.makeMd5ContentId(userId + "-" + ContentKind_1.ContentKind.BILLING);
109
+ }
110
+ static create(userId, payload, createdAt) {
111
+ // Billing creation always happens in UTC time
112
+ const now = Time_1.MultiClock.utcNow();
113
+ // If the createdAt time is not provided, use the current time
114
+ createdAt ??= now;
115
+ const billingId = Billing.makeBillingId(userId);
116
+ return ShareSync_1.ShareSyncFactory.get().createContent({
117
+ meta: {
118
+ ref: billingId,
119
+ is_head: true,
120
+ kind: ContentKind_1.ContentKind.BILLING,
121
+ id: billingId,
122
+ owner: userId,
123
+ created_at: createdAt,
124
+ updated_at: now,
125
+ },
126
+ payload: payload
127
+ });
128
+ }
129
+ isSubscribedToPricedProduct() {
130
+ this.checkDisposed("Billing.isSubscribedToPricedProduct");
131
+ return this.priceId != null && this.productId != null;
132
+ }
133
+ get priceId() {
134
+ this.checkDisposed("Billing.priceId");
135
+ return this.payload.price_id || null;
136
+ }
137
+ setPriceId(value) {
138
+ this.checkDisposed("Billing.setPriceId");
139
+ if (this.payload.price_id !== value) {
140
+ const batch = new Operation_1.BatchOperation(this);
141
+ batch.setPathValue(['payload', 'price_id'], value);
142
+ batch.commit();
143
+ }
144
+ }
145
+ get productId() {
146
+ this.checkDisposed("Billing.productId");
147
+ return this.payload.product_id || null;
148
+ }
149
+ setProductId(value) {
150
+ this.checkDisposed("Billing.setProductId");
151
+ if (this.payload.product_id !== value) {
152
+ const batch = new Operation_1.BatchOperation(this);
153
+ batch.setPathValue(['payload', 'product_id'], value);
154
+ batch.commit();
155
+ }
156
+ }
157
+ get paidUntil() {
158
+ this.checkDisposed("Billing.paidUntil");
159
+ return this.payload.paid_until;
160
+ }
161
+ setPaidUntil(value) {
162
+ this.checkDisposed("Billing.setPaidUntil");
163
+ if (this.paidUntil !== value) {
164
+ const batch = new Operation_1.BatchOperation(this);
165
+ batch.setPathValue(['payload', 'paid_until'], value);
166
+ batch.commit();
167
+ }
168
+ }
169
+ get paymentStatus() {
170
+ this.checkDisposed("Billing.paymentStatus");
171
+ return this.payload.payment_status;
172
+ }
173
+ setPaymentStatus(value) {
174
+ this.checkDisposed("Billing.setPaymentStatus");
175
+ if (this.paymentStatus !== value) {
176
+ const batch = new Operation_1.BatchOperation(this);
177
+ batch.setPathValue(['payload', 'payment_status'], value);
178
+ batch.commit();
179
+ }
180
+ }
181
+ get stripeCustomerId() {
182
+ this.checkDisposed("Billing.stripeCustomerId");
183
+ return this.payload.stripe_customer_id;
184
+ }
185
+ setStripeCustomerId(value) {
186
+ this.checkDisposed("Billing.setStripeCustomerId");
187
+ if (this.stripeCustomerId !== value) {
188
+ const batch = new Operation_1.BatchOperation(this);
189
+ batch.setPathValue(['payload', 'stripe_customer_id'], value);
190
+ batch.commit();
191
+ }
192
+ }
193
+ get stripePaymentMethodId() {
194
+ this.checkDisposed("Billing.stripePaymentMethodId");
195
+ return this.payload.stripe_payment_method_id;
196
+ }
197
+ setStripePaymentMethodId(value) {
198
+ this.checkDisposed("Billing.setStripePaymentMethodId");
199
+ if (this.stripeCustomerId !== value) {
200
+ const batch = new Operation_1.BatchOperation(this);
201
+ batch.setPathValue(['payload', 'stripe_payment_method_id'], value);
202
+ batch.commit();
203
+ }
204
+ }
205
+ get stripePaymentMethodType() {
206
+ this.checkDisposed("Billing.stripePaymentMethodType");
207
+ return this.payload.stripe_payment_method_id;
208
+ }
209
+ setStripePaymentMethodType(value) {
210
+ this.checkDisposed("Billing.setStripePaymentMethodType");
211
+ if (this.stripeCustomerId !== value) {
212
+ const batch = new Operation_1.BatchOperation(this);
213
+ batch.setPathValue(['payload', 'stripe_payment_method_type'], value);
214
+ batch.commit();
215
+ }
216
+ }
217
+ get creditCard() {
218
+ this.checkDisposed("Billing.creditCard");
219
+ return this.payload.credit_card;
220
+ }
221
+ setCreditCard(value) {
222
+ this.checkDisposed("Billing.setCreditCard");
223
+ if (this.creditCard != value) {
224
+ const batch = new Operation_1.BatchOperation(this);
225
+ batch.setPathValue(['payload', 'credit_card'], value);
226
+ batch.commit();
227
+ }
228
+ }
229
+ get transactions() {
230
+ this.checkDisposed("Billing.transactions");
231
+ return this._transactionsView;
232
+ }
233
+ // Somehow, the transactions array on many users is not in the correct order. Some users have
234
+ // transactions in reverse order, and some have transactions in random order. Eventually, we
235
+ // will correct the stored data, but for now, we will clone the transactions array and sort it
236
+ // by the transaction time, so that we can correctly iterate through the transactions.
237
+ get sortedTransactions() {
238
+ this.checkDisposed("Billing.sortedTransactions");
239
+ return Struct_1.Struct.clone(this._transactionsView.values).sort((a, b) => {
240
+ return Time_1.Time.compareDateTime(a.at_utc_time, b.at_utc_time);
241
+ });
242
+ }
243
+ getLastTransaction() {
244
+ this.checkDisposed("Billing.getLastTransaction");
245
+ if (this._transactionsView.length > 0) {
246
+ const transactions = this.sortedTransactions;
247
+ return transactions[transactions.length - 1];
248
+ }
249
+ else {
250
+ return null;
251
+ }
252
+ }
253
+ getLastPaymentTransaction() {
254
+ this.checkDisposed("Billing.getLastPaymentTransaction");
255
+ // Starts iterating from the most-recent transaction, so this function will
256
+ // return only the most-recent matching transaction.
257
+ const transactions = this.sortedTransactions;
258
+ for (let i = transactions.length - 1; i >= 0; i--) {
259
+ const transaction = transactions[i];
260
+ const topic = transaction.topic;
261
+ if (topic === TransactionTopic.PAYMENT_FAIL || topic === TransactionTopic.PAYMENT_SUCCESS) {
262
+ return transaction;
263
+ }
264
+ }
265
+ return null;
266
+ }
267
+ getActiveUserCoupon() {
268
+ this.checkDisposed("Billing.getActiveUserCoupon");
269
+ const nowInSeconds = (new Date()).getTime() / 1000;
270
+ // Coupons with a duration of "once" or "forever" have a null "end" value. We treat "once" coupons
271
+ // as being still-in-effect until a payment on the next invoice is attempted (either a pass or fail
272
+ // tells us that the billing period has completed).
273
+ const transactions = this.sortedTransactions;
274
+ for (let i = transactions.length - 1; i >= 0; i--) {
275
+ const transaction = transactions[i];
276
+ const topic = transaction.topic;
277
+ if (topic === TransactionTopic.CANCEL_SUBSCRIPTION) {
278
+ return null;
279
+ }
280
+ if (topic === TransactionTopic.APPLY_COUPON) {
281
+ const discount = transaction.details;
282
+ const coupon = discount.coupon;
283
+ if (coupon.duration === "forever" || (nowInSeconds >= discount.start && nowInSeconds <= discount.end)) {
284
+ return coupon;
285
+ }
286
+ else {
287
+ return null;
288
+ }
289
+ }
290
+ }
291
+ return null;
292
+ }
293
+ daysPastDue() {
294
+ this.checkDisposed("Billing.daysPastDue");
295
+ const daysSincePaidUntil = Time_1.Time.timeSince(this.paidUntil, 'days');
296
+ return daysSincePaidUntil < 0 ? 0 : daysSincePaidUntil;
297
+ }
298
+ didLastPaymentFail() {
299
+ this.checkDisposed("Billing.didLastPaymentFail");
300
+ const t = this.getLastPaymentTransaction();
301
+ return t != null && t.topic === TransactionTopic.PAYMENT_FAIL;
302
+ }
303
+ didLastPaymentSucceed() {
304
+ this.checkDisposed("Billing.didLastPaymentSucceed");
305
+ const t = this.getLastPaymentTransaction();
306
+ return t != null && t.topic === TransactionTopic.PAYMENT_SUCCESS;
307
+ }
308
+ findTransactionByTopic(topic) {
309
+ this.checkDisposed("Billing.findTransactionByTopic");
310
+ const transactions = this.sortedTransactions;
311
+ // Starts iterating from the most-recent transaction, so this function will
312
+ // return only the most-recent matching transaction.
313
+ for (let i = transactions.length - 1; i >= 0; i--) {
314
+ const transaction = transactions[i];
315
+ if (transaction.topic === topic) {
316
+ return transaction;
317
+ }
318
+ }
319
+ return null;
320
+ }
321
+ cancel() {
322
+ this.checkDisposed("Billing.cancel");
323
+ const now = Time_1.MultiClock.utcNow();
324
+ const transaction = {
325
+ at_utc_time: now.utc_time,
326
+ topic: TransactionTopic.CANCEL_SUBSCRIPTION
327
+ };
328
+ const batch = new Operation_1.BatchOperation(this, now);
329
+ // Add a transaction to the billing model for this cancellation
330
+ batch.pushIntoArray(['payload', 'transactions'], transaction);
331
+ batch.setPathValue(['payload', 'plan'], null);
332
+ batch.setPathValue(['payload', 'price_id'], null);
333
+ batch.setPathValue(['payload', 'product_id'], null);
334
+ batch.setPathValue(['payload', 'paid_until'], null);
335
+ batch.setPathValue(['payload', 'payment_status'], PaymentStatus.CANCELLED);
336
+ batch.commit();
337
+ }
338
+ restartPlan(plan, paidUntilEpochSeconds) {
339
+ this.checkDisposed("Billing.restartPlan");
340
+ const now = Time_1.MultiClock.utcNow();
341
+ const transaction = {
342
+ at_utc_time: now.utc_time,
343
+ topic: TransactionTopic.RESTART_SUBSCRIPTION
344
+ };
345
+ const batch = new Operation_1.BatchOperation(this, now);
346
+ // Add a transaction to the billing model for this cancellation
347
+ batch.pushIntoArray(['payload', 'transactions'], transaction);
348
+ batch.setPathValue(['payload', 'plan'], plan);
349
+ batch.setPathValue(['payload', 'product_id'], null);
350
+ batch.setPathValue(['payload', 'price_id'], null);
351
+ batch.setPathValue(['payload', 'paid_until'], Time_1.Time.utcFromEpochSeconds(paidUntilEpochSeconds));
352
+ batch.setPathValue(['payload', 'payment_status'], PaymentStatus.PAID);
353
+ batch.commit();
354
+ }
355
+ restartPricedProduct(productId, priceId, paidUntilEpochSeconds) {
356
+ this.checkDisposed("Billing.restartPricedProduct");
357
+ const now = Time_1.MultiClock.utcNow();
358
+ const transaction = {
359
+ at_utc_time: now.utc_time,
360
+ topic: TransactionTopic.RESTART_SUBSCRIPTION
361
+ };
362
+ const batch = new Operation_1.BatchOperation(this, now);
363
+ // Add a transaction to the billing model for this cancellation
364
+ batch.pushIntoArray(['payload', 'transactions'], transaction);
365
+ batch.setPathValue(['payload', 'plan'], null);
366
+ batch.setPathValue(['payload', 'product_id'], productId);
367
+ batch.setPathValue(['payload', 'price_id'], priceId);
368
+ batch.setPathValue(['payload', 'paid_until'], Time_1.Time.utcFromEpochSeconds(paidUntilEpochSeconds));
369
+ batch.setPathValue(['payload', 'payment_status'], PaymentStatus.PAID);
370
+ batch.commit();
371
+ }
372
+ static async findByStripeCustomerId(stripeCustomerId) {
373
+ const shareSync = ShareSync_1.ShareSyncFactory.get();
374
+ return shareSync.findAndAcquire(ContentKind_1.ContentKind.BILLING, { "payload.stripe_customer_id": stripeCustomerId });
375
+ }
376
+ static describeCoupon(coupon) {
377
+ let description = "";
378
+ if (coupon.hasOwnProperty("percent_off") && coupon.percent_off !== null) {
379
+ description = coupon.percent_off + "% OFF";
380
+ }
381
+ else if (coupon.hasOwnProperty("amount_off") && coupon.amount_off !== null) {
382
+ description = NumberFormat_1.NumberFormat.dollarsFromCents(coupon.amount_off) + " OFF";
383
+ }
384
+ if (coupon.duration === "forever") {
385
+ description += ", FOREVER";
386
+ }
387
+ else if (coupon.duration === "once") {
388
+ description += " YOUR NEXT INVOICE";
389
+ }
390
+ else if (coupon.duration === "repeating") {
391
+ description += " FOR " + coupon.duration_in_months + " MONTHS";
392
+ }
393
+ return description;
394
+ }
395
+ static normalizeCreditCardBrand(brand) {
396
+ const lowerCaseNoSpaces = brand.toLowerCase().replace(/\s/g, '');
397
+ if (lowerCaseNoSpaces.startsWith("visa")) {
398
+ return "VISA";
399
+ }
400
+ else if (lowerCaseNoSpaces.startsWith("mastercard")) {
401
+ return "MC";
402
+ }
403
+ else if (lowerCaseNoSpaces.startsWith("americanexpress")) {
404
+ return "AMEX";
405
+ }
406
+ else if (lowerCaseNoSpaces.startsWith("diners")) {
407
+ return "DINERS";
408
+ }
409
+ else if (lowerCaseNoSpaces.startsWith("jcb")) {
410
+ return "JCB";
411
+ }
412
+ else if (lowerCaseNoSpaces.startsWith("discover")) {
413
+ return "DISC";
414
+ }
415
+ return brand;
416
+ }
417
+ }
418
+ exports.Billing = Billing;
@@ -0,0 +1,77 @@
1
+ /// <reference path="../../../decs.d.ts" />
2
+ import { Doc } from '@shaxpir/sharedb/lib/client';
3
+ import { ShareSync } from "../../repo/ShareSync";
4
+ import { ArrayView } from './ArrayView';
5
+ import { ContentBody, ContentId, ContentMeta, ContentRef } from './Content';
6
+ import { Context } from './Context';
7
+ import { ExportOptions } from "./ExportOptions";
8
+ import { Fragment } from "./Fragment";
9
+ import { ContentStub, Stub } from "./Stub";
10
+ export declare enum BookType {
11
+ FICTION = "fiction",
12
+ NONFICTION = "non-fiction",
13
+ EMPTY = "empty"
14
+ }
15
+ export declare enum BookStubArrayKey {
16
+ MANUSCRIPT = "manuscript",
17
+ NOTEBOOK = "notebook",
18
+ TRASH = "trash"
19
+ }
20
+ export interface BookPayload {
21
+ name: string;
22
+ subtitle: string;
23
+ synopsis_ref: ContentRef;
24
+ cover_media_ref: ContentId;
25
+ author: string;
26
+ contributors: ContentId[];
27
+ copyright: string;
28
+ publisher: string;
29
+ isbn: string;
30
+ manuscript: Stub[];
31
+ notebook: Stub[];
32
+ export_options: ExportOptions;
33
+ trash: Stub[];
34
+ total_word_count: number;
35
+ }
36
+ export interface BookBody extends ContentBody {
37
+ meta: ContentMeta;
38
+ payload: BookPayload;
39
+ }
40
+ export declare class Book extends Context {
41
+ private _manuscriptView;
42
+ private _notebookView;
43
+ constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
44
+ get payload(): BookPayload;
45
+ static create(userId: ContentId, template: BookType): Book;
46
+ get coverMediaRef(): ContentId;
47
+ setCoverMediaRef(value: ContentId): void;
48
+ get synopsisRef(): ContentRef;
49
+ setSynopsisId(value: ContentRef): void;
50
+ get name(): string;
51
+ setName(value: string): void;
52
+ get subtitle(): string;
53
+ setSubtitle(value: string): void;
54
+ get author(): string;
55
+ setAuthor(value: string): void;
56
+ get copyright(): string;
57
+ setCopyright(value: string): void;
58
+ get publisher(): string;
59
+ setPublisher(value: string): void;
60
+ get isbn(): string;
61
+ setIsbn(value: string): void;
62
+ get totalWordCount(): number;
63
+ get manuscript(): ArrayView<Stub>;
64
+ get notebook(): ArrayView<Stub>;
65
+ get exportOptions(): ExportOptions;
66
+ replaceExportOptions(newOptions: ExportOptions): void;
67
+ getStubArrayKeys(): BookStubArrayKey[];
68
+ getStubArrayView(key: BookStubArrayKey): ArrayView<Stub>;
69
+ addFragmentToManuscript(fragment: Fragment, activeId: ContentId): void;
70
+ addFragmentToNotebook(fragment: Fragment, activeId?: ContentId): void;
71
+ updateWordCount(): Promise<void>;
72
+ getAllCategories(context: BookStubArrayKey): string[];
73
+ getPlaceholder(): string;
74
+ asStub(): ContentStub;
75
+ static harvestUniqueCategories(bookPayload: BookPayload, context: BookStubArrayKey): string[];
76
+ mergeIncomingContext(incomingBook: BookBody): boolean;
77
+ }