@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,179 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Stubs = void 0;
7
+ const pluralize_1 = __importDefault(require("pluralize"));
8
+ const Struct_1 = require("../../util/Struct");
9
+ const Content_1 = require("./Content");
10
+ const ContentKind_1 = require("./ContentKind");
11
+ class Stubs {
12
+ static idFromStub(stub) {
13
+ let id = null;
14
+ if (typeof (stub) === "string") {
15
+ // The array entry is a bare string... either a locator or an ID.
16
+ id = Content_1.Content.parseContentRef(stub).id;
17
+ }
18
+ else if (stub.hasOwnProperty("id")) {
19
+ id = stub.id;
20
+ }
21
+ else if (stub.hasOwnProperty("ref")) {
22
+ id = Content_1.Content.parseContentRef(stub.ref).id;
23
+ }
24
+ return id;
25
+ }
26
+ static refFromStub(stub) {
27
+ let ref = null;
28
+ if (typeof (stub) === "string") {
29
+ ref = stub;
30
+ }
31
+ else if (stub.hasOwnProperty("ref")) {
32
+ ref = stub.ref;
33
+ }
34
+ else if (stub.hasOwnProperty("id")) {
35
+ ref = stub.id;
36
+ }
37
+ return ref;
38
+ }
39
+ static unflatten(stubs) {
40
+ const nodesById = new Map();
41
+ const unflattened = [];
42
+ for (let i = 0, len = stubs.length; i < len; i++) {
43
+ const stub = Struct_1.Struct.clone(stubs[i]);
44
+ const id = Stubs.idFromStub(stub);
45
+ nodesById.set(id, stub);
46
+ if (stub.parent && nodesById.has(stub.parent)) {
47
+ const parentNode = nodesById.get(stub.parent);
48
+ if (!parentNode.hasOwnProperty("children")) {
49
+ parentNode.children = [];
50
+ }
51
+ parentNode.children.push(stub);
52
+ }
53
+ else {
54
+ unflattened.push(stub);
55
+ }
56
+ }
57
+ return unflattened;
58
+ }
59
+ static isFolderStub(stub) {
60
+ return stub && stub.hasOwnProperty('kind') && stub.kind == ContentKind_1.ContentKind.FOLDER;
61
+ }
62
+ static isContentStub(stub) {
63
+ return stub && stub.hasOwnProperty('ref');
64
+ }
65
+ // Given an array of fragment stubs (like you'd find in 'book.payload.manuscript',
66
+ // 'book.payload.notebook', or 'book.payload.ideas'), this function adds the
67
+ // designated stub to the array at the correct index. This is based in part on
68
+ // whether a fragment is already 'active' (selected by the user in the workspace
69
+ // tree) and whether the default insertion point is at the beginning or end of
70
+ // the array. When the correct insertion point has been found the function
71
+ // automatically injects the correct tree-parent ID into the stub.
72
+ static insertStubAtActivePoint(stub, stubArrayView, category, activeId, defaultAtBeginning) {
73
+ // Build a parentage map of all the stubs in the array.
74
+ const parentage = new Map();
75
+ const indexesById = new Map();
76
+ // Try to find a folder whose label matches the pluralization of the category for this stub.
77
+ // For example, if the stub has a category of "character", then a matching folder would be
78
+ // named "CHARACTERS" or "Characters". If we find such a folder, then the new stub will be
79
+ // added within the matching folder's hierarchy.
80
+ let categoryFolderStubIdx = -1;
81
+ if (category !== null) {
82
+ const singularCategory = pluralize_1.default.singular(category.toLowerCase());
83
+ for (let i = 0, len = stubArrayView.length; i < len; i++) {
84
+ const currentStub = stubArrayView.get(i);
85
+ const stubId = Stubs.idFromStub(currentStub);
86
+ indexesById.set(stubId, i);
87
+ if (currentStub.parent) {
88
+ parentage.set(stubId, currentStub.parent);
89
+ }
90
+ if (Stubs.isFolderStub(currentStub)) {
91
+ const folderLabel = currentStub.label.toLowerCase();
92
+ const singularLabel = pluralize_1.default.singular(folderLabel);
93
+ if (singularLabel === singularCategory) {
94
+ categoryFolderStubIdx = i;
95
+ }
96
+ }
97
+ }
98
+ }
99
+ // Find the active ID (i.e., whatever is currently selected in the menu) in the stub array
100
+ let activeIdx = stubArrayView.firstIndexWhere(stub => Stubs.idFromStub(stub) === activeId);
101
+ // If there isn't an active ID (because nothing is currently selected in the menu), or if
102
+ // the active ID doesn't seem to be within this particular stub array (manuscript vs notebook),
103
+ // then treat any category folder we might have found ("Characters" or "Themes", etc) as the
104
+ // as an active ID.
105
+ if (activeIdx === -1) {
106
+ activeIdx = categoryFolderStubIdx;
107
+ }
108
+ else if (categoryFolderStubIdx !== -1) {
109
+ // If the active stub and the category folder stub both exist, then we need to figure out
110
+ // which of them takes priority. Matching a category folder is more important, so generally,
111
+ // we will just use the category folder. But if the active index is WITHIN the category
112
+ // folder, then we'll use the active ID instead.
113
+ let activeIdIsWithinCategoryFolder = false;
114
+ let currentStub = stubArrayView.get(activeIdx);
115
+ while (currentStub) {
116
+ const currentStubId = Stubs.idFromStub(currentStub);
117
+ if (parentage.has(currentStubId)) {
118
+ const parentId = parentage.get(currentStubId);
119
+ if (indexesById.has(parentId)) {
120
+ const parentStubIndex = indexesById.get(parentId);
121
+ if (parentStubIndex === categoryFolderStubIdx) {
122
+ activeIdIsWithinCategoryFolder = true;
123
+ break;
124
+ }
125
+ currentStub = stubArrayView.get(parentStubIndex);
126
+ }
127
+ else {
128
+ // NOTE: It should be impossible to get here, because we've already built a map of all the
129
+ // stubs in the array, and we've already checked that the parentage map contains the parent ID.
130
+ throw new Error(`Parent ID ${parentId} not found in stub array`);
131
+ }
132
+ }
133
+ else {
134
+ currentStub = undefined;
135
+ }
136
+ }
137
+ if (!activeIdIsWithinCategoryFolder) {
138
+ activeIdx = categoryFolderStubIdx;
139
+ }
140
+ }
141
+ // Insert the new stub into the array at the index of the active stub (which
142
+ // may have been adjusted above to point to the category folder index).
143
+ let idx;
144
+ if (activeIdx === -1) {
145
+ // Couldn't find the active ID in the array of stubs. Add the stub at either
146
+ // the beginning or end of the array, depending on the designated default.
147
+ if (defaultAtBeginning) {
148
+ stubArrayView.unshift(stub);
149
+ idx = 0;
150
+ }
151
+ else {
152
+ idx = stubArrayView.length;
153
+ stubArrayView.push(stub);
154
+ }
155
+ }
156
+ else {
157
+ // Find the stub at the active index. If it's a folder, then use it as the parent of the new stub. Otherwise,
158
+ // if the stub at the active index has a parent, then the new stub should assume the same parent as its sibling.
159
+ const activeStub = stubArrayView.get(activeIdx);
160
+ if (Stubs.isFolderStub(activeStub)) {
161
+ const folderStub = activeStub;
162
+ stub.parent = folderStub.id;
163
+ }
164
+ else if (activeStub.parent) {
165
+ stub.parent = activeStub.parent;
166
+ }
167
+ // Insert the new stub immediately after the active stub.
168
+ idx = activeIdx + 1;
169
+ if (idx >= stubArrayView.length) {
170
+ stubArrayView.push(stub);
171
+ }
172
+ else {
173
+ stubArrayView.insert(idx, stub);
174
+ }
175
+ }
176
+ return idx;
177
+ }
178
+ }
179
+ exports.Stubs = Stubs;
@@ -0,0 +1,56 @@
1
+ import dayjs from 'dayjs';
2
+ declare enum CompactDateTimeBrand {
3
+ }
4
+ declare enum CompactDateBrand {
5
+ }
6
+ export type CompactDateTime = string & CompactDateTimeBrand;
7
+ export type CompactDate = string & CompactDateBrand;
8
+ export interface SingleTime {
9
+ utc_time: CompactDateTime;
10
+ }
11
+ export interface MultiTime {
12
+ utc_time: CompactDateTime;
13
+ local_time: CompactDateTime;
14
+ }
15
+ export declare class MultiClock {
16
+ static utcNow(): MultiTime;
17
+ static now(): MultiTime;
18
+ }
19
+ export declare class Time {
20
+ static readonly DATETIME_FORMAT_LEGACY: string;
21
+ static readonly DATE_FORMAT: string;
22
+ static readonly DATETIME_FORMAT_COMPACT: string;
23
+ static readonly DATE_NO_YEAR: string;
24
+ static readonly DATE_BEAUTIFIED: string;
25
+ static readonly DATE_FULLY_BEAUTIFIED: string;
26
+ static readonly YEAR_ONLY: string;
27
+ static asCompactDateTime(text: string): CompactDateTime;
28
+ static asCompactDate(text: string): CompactDate | null;
29
+ static isDateBefore(a: CompactDate, b: CompactDate): boolean;
30
+ static isDateAfter(a: CompactDate, b: CompactDate): boolean;
31
+ static compareDate(a: CompactDate, b: CompactDate): number;
32
+ static isDateTimeBefore(a: CompactDateTime, b: CompactDateTime): boolean;
33
+ static isDateTimeAfter(a: CompactDateTime, b: CompactDateTime): boolean;
34
+ static compareDateTime(a: CompactDateTime, b: CompactDateTime): number;
35
+ static sortByUtcTime(array: MultiTime[]): MultiTime[];
36
+ static dateFrom(timestamp: CompactDateTime): CompactDate;
37
+ static datesBetween(minDate: CompactDate, maxDate: CompactDate): CompactDate[];
38
+ static plus(timestamp: CompactDateTime, amount: number, units: dayjs.ManipulateType): CompactDateTime;
39
+ static todayLocal(): CompactDate;
40
+ static todayUtc(): CompactDate;
41
+ static startOfMonth(date: CompactDate): CompactDate;
42
+ static local(utc?: CompactDateTime): CompactDateTime;
43
+ static utcFromEpochSeconds(seconds: number): CompactDateTime;
44
+ static utc(local?: CompactDateTime): CompactDateTime;
45
+ static format(timestamp: CompactDateTime, pattern: string, isLocal: boolean): CompactDateTime;
46
+ static formatFromDate(date: Date, pattern: string): string;
47
+ static beautify(timestamp: CompactDateTime, isLocal?: boolean, amount?: number, units?: string): string;
48
+ static absDiffMinutes(a: CompactDateTime, b: CompactDateTime): number;
49
+ static elapsed(timestamp: CompactDateTime, isLocal: boolean): string;
50
+ static timeUntil(utcTime: CompactDateTime, units: dayjs.UnitType): number;
51
+ static timeSince(utcTime: CompactDateTime, units: dayjs.UnitType): number;
52
+ static currentYear(): string;
53
+ static humanizedDatePacific(epochSeconds: number): string;
54
+ static humanizedTimePacific(epochSeconds: number): string;
55
+ }
56
+ export {};
@@ -0,0 +1,295 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Time = exports.MultiClock = void 0;
7
+ const dayjs_1 = __importDefault(require("dayjs"));
8
+ const utc_1 = __importDefault(require("dayjs/plugin/utc"));
9
+ const timezone_1 = __importDefault(require("dayjs/plugin/timezone"));
10
+ const dayOfYear_1 = __importDefault(require("dayjs/plugin/dayOfYear"));
11
+ dayjs_1.default.extend(utc_1.default);
12
+ dayjs_1.default.extend(timezone_1.default);
13
+ dayjs_1.default.extend(dayOfYear_1.default);
14
+ var CompactDateTimeBrand;
15
+ (function (CompactDateTimeBrand) {
16
+ })(CompactDateTimeBrand || (CompactDateTimeBrand = {}));
17
+ var CompactDateBrand;
18
+ (function (CompactDateBrand) {
19
+ })(CompactDateBrand || (CompactDateBrand = {}));
20
+ class MultiClock {
21
+ static utcNow() {
22
+ const localtime = Time.local();
23
+ const utcTime = Time.utc(localtime);
24
+ return {
25
+ local_time: utcTime,
26
+ utc_time: utcTime
27
+ };
28
+ }
29
+ static now() {
30
+ const localtime = Time.local();
31
+ return {
32
+ local_time: localtime,
33
+ utc_time: Time.utc(localtime)
34
+ };
35
+ }
36
+ }
37
+ exports.MultiClock = MultiClock;
38
+ class Time {
39
+ static asCompactDateTime(text) {
40
+ // A compact datetime is always 17 digits long and starts with '20'
41
+ if (text.startsWith("20") && /^\d{17}$/.test(text)) {
42
+ return text;
43
+ }
44
+ return null;
45
+ }
46
+ static asCompactDate(text) {
47
+ // A compact date is always 8 digits long and starts with '20'
48
+ if (text.startsWith("20") && /^\d{8}$/.test(text)) {
49
+ return text;
50
+ }
51
+ return null;
52
+ }
53
+ static isDateBefore(a, b) {
54
+ return Time.compareDate(a, b) < 0;
55
+ }
56
+ static isDateAfter(a, b) {
57
+ return Time.compareDate(a, b) > 0;
58
+ }
59
+ static compareDate(a, b) {
60
+ if (a == null && b == null) {
61
+ return 0;
62
+ }
63
+ else if (a == null) {
64
+ return -1;
65
+ }
66
+ else if (b == null) {
67
+ return 1;
68
+ }
69
+ return a.localeCompare(b);
70
+ }
71
+ static isDateTimeBefore(a, b) {
72
+ return Time.compareDateTime(a, b) < 0;
73
+ }
74
+ static isDateTimeAfter(a, b) {
75
+ return Time.compareDateTime(a, b) > 0;
76
+ }
77
+ static compareDateTime(a, b) {
78
+ if (a == null && b == null) {
79
+ return 0;
80
+ }
81
+ else if (a == null) {
82
+ return -1;
83
+ }
84
+ else if (b == null) {
85
+ return 1;
86
+ }
87
+ return a.localeCompare(b);
88
+ }
89
+ static sortByUtcTime(array) {
90
+ return array.sort((a, b) => Time.compareDateTime(a.utc_time, b.utc_time));
91
+ }
92
+ static dateFrom(timestamp) {
93
+ const timestampText = timestamp;
94
+ if (timestampText.length >= 8 && /^\d{8}.*/.test(timestampText)) {
95
+ return timestampText.substring(0, 8);
96
+ }
97
+ if (typeof (timestamp) === "string") {
98
+ throw new Error("can\x27t parse date from malformed timestamp: " + timestamp);
99
+ }
100
+ else {
101
+ throw new Error("can\x27t parse date from malformed timestamp: " + JSON.stringify(timestamp));
102
+ }
103
+ }
104
+ static datesBetween(minDate, maxDate) {
105
+ const dates = new Array();
106
+ let d = minDate;
107
+ while (d.localeCompare(minDate) >= 0 && d.localeCompare(maxDate) <= 0) {
108
+ dates.push(d);
109
+ d = (0, dayjs_1.default)(d, Time.DATE_FORMAT).add(1, 'days').format(Time.DATE_FORMAT);
110
+ }
111
+ return dates;
112
+ }
113
+ static plus(timestamp, amount, units) {
114
+ const time = (0, dayjs_1.default)(timestamp, Time.DATETIME_FORMAT_COMPACT);
115
+ return time.add(amount, units).format(Time.DATETIME_FORMAT_COMPACT);
116
+ }
117
+ static todayLocal() {
118
+ return Time.dateFrom(Time.local());
119
+ }
120
+ static todayUtc() {
121
+ return Time.dateFrom(Time.utc());
122
+ }
123
+ static startOfMonth(date) {
124
+ let text = date;
125
+ if (text.startsWith("20") && /^\d{8}$/.test(text)) {
126
+ text = text.substring(0, 6) + "01;";
127
+ }
128
+ return text;
129
+ }
130
+ static local(utc) {
131
+ let result;
132
+ if (typeof (utc) === "undefined") {
133
+ result = (0, dayjs_1.default)().format(Time.DATETIME_FORMAT_COMPACT);
134
+ }
135
+ else {
136
+ const timestamp = dayjs_1.default.utc(utc, Time.DATETIME_FORMAT_COMPACT)
137
+ .local();
138
+ result = timestamp.format(Time.DATETIME_FORMAT_COMPACT);
139
+ }
140
+ return result;
141
+ }
142
+ // TODO: Should this actually be called localFromEpochSeconds? Passing zero
143
+ // returns timestamp that is local-timezone hours offset from UTC epoch time.
144
+ static utcFromEpochSeconds(seconds) {
145
+ return dayjs_1.default.unix(seconds).utc().format(Time.DATETIME_FORMAT_COMPACT);
146
+ }
147
+ static utc(local) {
148
+ let result;
149
+ if (typeof (local) === "undefined") {
150
+ result = dayjs_1.default.utc().format(Time.DATETIME_FORMAT_COMPACT);
151
+ }
152
+ else {
153
+ const timestamp = (0, dayjs_1.default)(local, Time.DATETIME_FORMAT_COMPACT)
154
+ .utc();
155
+ result = timestamp.format(Time.DATETIME_FORMAT_COMPACT);
156
+ }
157
+ return result;
158
+ }
159
+ static format(timestamp, pattern, isLocal) {
160
+ let time = null;
161
+ if (isLocal) {
162
+ time = (0, dayjs_1.default)(timestamp, Time.DATETIME_FORMAT_COMPACT);
163
+ }
164
+ else {
165
+ time = dayjs_1.default.utc(timestamp, Time.DATETIME_FORMAT_COMPACT)
166
+ .local();
167
+ }
168
+ return time.format(pattern);
169
+ }
170
+ static formatFromDate(date, pattern) {
171
+ const time = (0, dayjs_1.default)(date);
172
+ return time.format(pattern);
173
+ }
174
+ static beautify(timestamp, isLocal = false, amount, units) {
175
+ const now = (0, dayjs_1.default)();
176
+ let time = null;
177
+ if (isLocal) {
178
+ time = (0, dayjs_1.default)(timestamp, Time.DATETIME_FORMAT_COMPACT);
179
+ }
180
+ else {
181
+ time = dayjs_1.default.utc(timestamp, Time.DATETIME_FORMAT_COMPACT)
182
+ .local();
183
+ }
184
+ // If the 'num' and 'units' params exist, then use them to manipulate the timestamp
185
+ if (typeof (amount) === "number" && typeof (units) === "string") {
186
+ time = time.add(amount, units);
187
+ }
188
+ let datePart = "", timePart = "";
189
+ const timeDayOfYear = time.dayOfYear();
190
+ const nowDayOfYear = now.dayOfYear();
191
+ const timeYear = time.year();
192
+ const nowYear = now.year();
193
+ if (nowDayOfYear === timeDayOfYear && nowYear === timeYear) {
194
+ datePart = "Today";
195
+ }
196
+ else if (nowDayOfYear - timeDayOfYear === 1 && nowYear === timeYear) {
197
+ datePart = "Yesterday";
198
+ }
199
+ else if (nowDayOfYear === 1 && timeDayOfYear === 365 && timeYear % 4 !== 0 && nowYear - timeYear === 1) {
200
+ datePart = "Yesterday";
201
+ }
202
+ else if (nowDayOfYear === 1 && timeDayOfYear === 366 && timeYear % 4 === 0 && nowYear - timeYear === 1) {
203
+ datePart = "Yesterday";
204
+ }
205
+ else if (timeDayOfYear - nowDayOfYear === 1 && timeYear === nowYear) {
206
+ datePart = "Tomorrow";
207
+ }
208
+ else if (timeDayOfYear === 1 && nowDayOfYear === 365 && nowYear % 4 !== 0 && timeYear - nowYear === 1) {
209
+ datePart = "Tomorrow";
210
+ }
211
+ else if (timeDayOfYear === 1 && nowDayOfYear === 366 && nowYear % 4 === 0 && timeYear - nowYear === 1) {
212
+ datePart = "Tomorrow";
213
+ }
214
+ else if (Math.abs(now.diff(time, "days")) <= 30) {
215
+ datePart = time.format(Time.DATE_FULLY_BEAUTIFIED);
216
+ }
217
+ else {
218
+ datePart = time.format(Time.DATE_BEAUTIFIED);
219
+ }
220
+ if (Math.abs(now.diff(time, "days")) <= 7) {
221
+ timePart = time.format("h:mm a");
222
+ timePart = timePart.replace(" am", "a");
223
+ timePart = timePart.replace(" pm", "p");
224
+ }
225
+ if (timePart.length === 0) {
226
+ return datePart;
227
+ }
228
+ else {
229
+ return datePart + ", " + timePart;
230
+ }
231
+ }
232
+ static absDiffMinutes(a, b) {
233
+ const aMoment = (0, dayjs_1.default)(a, Time.DATETIME_FORMAT_COMPACT);
234
+ const bMoment = (0, dayjs_1.default)(b, Time.DATETIME_FORMAT_COMPACT);
235
+ return Math.abs(aMoment.diff(bMoment, 'minutes', true));
236
+ }
237
+ static elapsed(timestamp, isLocal) {
238
+ let time = null;
239
+ if (isLocal) {
240
+ time = (0, dayjs_1.default)(timestamp, Time.DATETIME_FORMAT_COMPACT);
241
+ }
242
+ else {
243
+ time = dayjs_1.default.utc(timestamp, Time.DATETIME_FORMAT_COMPACT)
244
+ .local();
245
+ }
246
+ const difference = (0, dayjs_1.default)().diff(time, 'seconds');
247
+ if (difference < 60) {
248
+ return difference === 1 ? "1 second ago" : difference + " seconds ago";
249
+ }
250
+ else if (difference < 3 * 60) {
251
+ const minutes = Math.floor(difference / 60);
252
+ const seconds = Math.floor(difference % 60);
253
+ const minText = minutes === 1 ? "1 minute" : minutes + " minutes";
254
+ const secText = seconds === 1 ? "1 second" : seconds + " seconds";
255
+ return minText + ", " + secText + " ago";
256
+ }
257
+ else if (difference < 60 * 60) {
258
+ const minutes = Math.round(difference / 60);
259
+ return "about " + minutes + " minutes ago";
260
+ }
261
+ else if (difference < 24 * 60 * 60) {
262
+ const hours = Math.round(difference / (60 * 60));
263
+ return "about " + hours + " hours ago";
264
+ }
265
+ else {
266
+ return Time.beautify(timestamp, isLocal);
267
+ }
268
+ }
269
+ static timeUntil(utcTime, units) {
270
+ return -Time.timeSince(utcTime, units);
271
+ }
272
+ static timeSince(utcTime, units) {
273
+ const then = dayjs_1.default.utc(utcTime, Time.DATETIME_FORMAT_COMPACT);
274
+ const now = (0, dayjs_1.default)().utc();
275
+ return now.diff(then, units, true);
276
+ }
277
+ static currentYear() {
278
+ return (0, dayjs_1.default)().format(Time.YEAR_ONLY);
279
+ }
280
+ static humanizedDatePacific(epochSeconds) {
281
+ return dayjs_1.default.unix(epochSeconds).tz("America/Los_Angeles").format("MMMM D, YYYY");
282
+ }
283
+ // TODO: Should this actually expect seconds instead of milliseconds?
284
+ static humanizedTimePacific(epochSeconds) {
285
+ return (0, dayjs_1.default)(epochSeconds).tz("America/Los_Angeles").format("h:mm:ss a") + " (Pacific)";
286
+ }
287
+ }
288
+ exports.Time = Time;
289
+ Time.DATETIME_FORMAT_LEGACY = "YYYY-MM-DDTHH:mm:ss.SSSZ";
290
+ Time.DATE_FORMAT = "YYYYMMDD";
291
+ Time.DATETIME_FORMAT_COMPACT = "YYYYMMDDHHmmssSSS";
292
+ Time.DATE_NO_YEAR = "MMMM D";
293
+ Time.DATE_BEAUTIFIED = "MMMM D, YYYY";
294
+ Time.DATE_FULLY_BEAUTIFIED = "dddd, MMMM D, YYYY";
295
+ Time.YEAR_ONLY = "YYYY";
@@ -0,0 +1,36 @@
1
+ /// <reference path="../../../decs.d.ts" />
2
+ import { Doc } from '@shaxpir/sharedb/lib/client';
3
+ import { ShareSync } from '../../repo/ShareSync';
4
+ import { Content, ContentId, ContentMeta } from "./Content";
5
+ import { MultiTime } from "./Time";
6
+ export interface UserPayload {
7
+ email: string;
8
+ phone: string;
9
+ force_password_reset: boolean;
10
+ pass_md5_salt_md5: string;
11
+ salt: string;
12
+ }
13
+ export interface ModernUserBody {
14
+ meta: ContentMeta;
15
+ payload: UserPayload;
16
+ }
17
+ export declare class ModernUser extends Content {
18
+ static readonly MIN_PASSWORD_LENGTH: number;
19
+ constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
20
+ get payload(): UserPayload;
21
+ static create(userId: ContentId, payload: UserPayload, createdAt?: MultiTime): ModernUser;
22
+ get email(): string;
23
+ setEmail(value: string): void;
24
+ get forcePasswordReset(): boolean;
25
+ setForcePasswordReset(value: boolean): void;
26
+ get passMd5SaltMd5(): string;
27
+ setPassMd5SaltMd5(value: string): void;
28
+ get salt(): string;
29
+ hasValidPassword(password: string): boolean;
30
+ hasValidPassMd5(passMd5: string): boolean;
31
+ static makePassMd5SaltMd5(salt: string, password: string): string;
32
+ static addSaltToPassMd5(salt: string, passMd5: string): string;
33
+ static makePassMd5(password: string): string;
34
+ static isValidPassMd5(passMd5: string, userPayload: UserPayload): boolean;
35
+ static findByEmail(email: string): Promise<ModernUser[]>;
36
+ }
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ModernUser = void 0;
4
+ const ShareSync_1 = require("../../repo/ShareSync");
5
+ const CachingHasher_1 = require("../../util/CachingHasher");
6
+ const Operation_1 = require("../markup/Operation");
7
+ const Content_1 = require("./Content");
8
+ const ContentKind_1 = require("./ContentKind");
9
+ const Time_1 = require("./Time");
10
+ class ModernUser extends Content_1.Content {
11
+ constructor(doc, shouldAcquire, shareSync) {
12
+ super(doc, shouldAcquire, shareSync);
13
+ }
14
+ get payload() {
15
+ return this.doc.data.payload;
16
+ }
17
+ static create(userId, payload, createdAt) {
18
+ // User creation always happens in UTC time
19
+ const now = Time_1.MultiClock.utcNow();
20
+ // If the createdAt time is not provided, use the current time
21
+ createdAt ??= now;
22
+ return ShareSync_1.ShareSyncFactory.get().createContent({
23
+ meta: {
24
+ ref: userId,
25
+ is_head: true,
26
+ kind: ContentKind_1.ContentKind.USER,
27
+ id: userId,
28
+ owner: userId,
29
+ created_at: createdAt,
30
+ updated_at: now
31
+ },
32
+ payload: payload
33
+ });
34
+ }
35
+ get email() {
36
+ return this.payload.email;
37
+ }
38
+ setEmail(value) {
39
+ if (this.email != value) {
40
+ const batch = new Operation_1.BatchOperation(this);
41
+ batch.setPathValue(['payload', 'email'], value);
42
+ batch.commit();
43
+ }
44
+ }
45
+ get forcePasswordReset() {
46
+ return this.payload.force_password_reset;
47
+ }
48
+ setForcePasswordReset(value) {
49
+ if (this.forcePasswordReset != value) {
50
+ const batch = new Operation_1.BatchOperation(this);
51
+ batch.setPathValue(['payload', 'force_password_reset'], value);
52
+ batch.commit();
53
+ }
54
+ }
55
+ get passMd5SaltMd5() {
56
+ return this.payload.pass_md5_salt_md5;
57
+ }
58
+ setPassMd5SaltMd5(value) {
59
+ if (this.passMd5SaltMd5 != value) {
60
+ const batch = new Operation_1.BatchOperation(this);
61
+ batch.setPathValue(['payload', 'pass_md5_salt_md5'], value);
62
+ batch.commit();
63
+ }
64
+ }
65
+ get salt() {
66
+ return this.payload.salt;
67
+ }
68
+ hasValidPassword(password) {
69
+ const passMd5 = ModernUser.makePassMd5(password);
70
+ return this.hasValidPassMd5(passMd5);
71
+ }
72
+ hasValidPassMd5(passMd5) {
73
+ return ModernUser.isValidPassMd5(passMd5, this.payload);
74
+ }
75
+ static makePassMd5SaltMd5(salt, password) {
76
+ const passMd5 = ModernUser.makePassMd5(password);
77
+ return ModernUser.addSaltToPassMd5(salt, passMd5);
78
+ }
79
+ static addSaltToPassMd5(salt, passMd5) {
80
+ return CachingHasher_1.CachingHasher.makeMd5Hash(passMd5 + salt);
81
+ }
82
+ static makePassMd5(password) {
83
+ return CachingHasher_1.CachingHasher.makeMd5Hash(password);
84
+ }
85
+ static isValidPassMd5(passMd5, userPayload) {
86
+ const passMd5SaltMd5 = ModernUser.addSaltToPassMd5(userPayload.salt, passMd5);
87
+ return passMd5SaltMd5 === userPayload.pass_md5_salt_md5;
88
+ }
89
+ static async findByEmail(email) {
90
+ const shareSync = ShareSync_1.ShareSyncFactory.get();
91
+ return shareSync.findAndAcquire(ContentKind_1.ContentKind.USER, { "payload.email": email });
92
+ }
93
+ }
94
+ exports.ModernUser = ModernUser;
95
+ ModernUser.MIN_PASSWORD_LENGTH = 8;