@verdant-web/common 1.11.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 (241) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/EventSubscriber.d.ts +17 -0
  3. package/dist/cjs/EventSubscriber.js +67 -0
  4. package/dist/cjs/EventSubscriber.js.map +1 -0
  5. package/dist/cjs/baseline.d.ts +5 -0
  6. package/dist/cjs/baseline.js +3 -0
  7. package/dist/cjs/baseline.js.map +1 -0
  8. package/dist/cjs/batching.d.ts +41 -0
  9. package/dist/cjs/batching.js +89 -0
  10. package/dist/cjs/batching.js.map +1 -0
  11. package/dist/cjs/files.d.ts +19 -0
  12. package/dist/cjs/files.js +19 -0
  13. package/dist/cjs/files.js.map +1 -0
  14. package/dist/cjs/files.test.d.ts +1 -0
  15. package/dist/cjs/files.test.js +81 -0
  16. package/dist/cjs/files.test.js.map +1 -0
  17. package/dist/cjs/index.d.ts +18 -0
  18. package/dist/cjs/index.js +36 -0
  19. package/dist/cjs/index.js.map +1 -0
  20. package/dist/cjs/indexes.d.ts +14 -0
  21. package/dist/cjs/indexes.js +116 -0
  22. package/dist/cjs/indexes.js.map +1 -0
  23. package/dist/cjs/indexes.test.d.ts +1 -0
  24. package/dist/cjs/indexes.test.js +128 -0
  25. package/dist/cjs/indexes.test.js.map +1 -0
  26. package/dist/cjs/migration.d.ts +98 -0
  27. package/dist/cjs/migration.js +128 -0
  28. package/dist/cjs/migration.js.map +1 -0
  29. package/dist/cjs/oids.d.ts +87 -0
  30. package/dist/cjs/oids.js +375 -0
  31. package/dist/cjs/oids.js.map +1 -0
  32. package/dist/cjs/oids.test.d.ts +1 -0
  33. package/dist/cjs/oids.test.js +282 -0
  34. package/dist/cjs/oids.test.js.map +1 -0
  35. package/dist/cjs/operation.d.ts +139 -0
  36. package/dist/cjs/operation.js +533 -0
  37. package/dist/cjs/operation.js.map +1 -0
  38. package/dist/cjs/operation.test.d.ts +1 -0
  39. package/dist/cjs/operation.test.js +827 -0
  40. package/dist/cjs/operation.test.js.map +1 -0
  41. package/dist/cjs/patch.d.ts +26 -0
  42. package/dist/cjs/patch.js +227 -0
  43. package/dist/cjs/patch.js.map +1 -0
  44. package/dist/cjs/presence.d.ts +27 -0
  45. package/dist/cjs/presence.js +3 -0
  46. package/dist/cjs/presence.js.map +1 -0
  47. package/dist/cjs/protocol.d.ts +145 -0
  48. package/dist/cjs/protocol.js +4 -0
  49. package/dist/cjs/protocol.js.map +1 -0
  50. package/dist/cjs/refs.d.ts +5 -0
  51. package/dist/cjs/refs.js +22 -0
  52. package/dist/cjs/refs.js.map +1 -0
  53. package/dist/cjs/replica.d.ts +28 -0
  54. package/dist/cjs/replica.js +29 -0
  55. package/dist/cjs/replica.js.map +1 -0
  56. package/dist/cjs/schema/defaults.d.ts +4 -0
  57. package/dist/cjs/schema/defaults.js +72 -0
  58. package/dist/cjs/schema/defaults.js.map +1 -0
  59. package/dist/cjs/schema/defaults.test.d.ts +1 -0
  60. package/dist/cjs/schema/defaults.test.js +21 -0
  61. package/dist/cjs/schema/defaults.test.js.map +1 -0
  62. package/dist/cjs/schema/index.d.ts +8 -0
  63. package/dist/cjs/schema/index.js +29 -0
  64. package/dist/cjs/schema/index.js.map +1 -0
  65. package/dist/cjs/schema/indexFilters.d.ts +6 -0
  66. package/dist/cjs/schema/indexFilters.js +31 -0
  67. package/dist/cjs/schema/indexFilters.js.map +1 -0
  68. package/dist/cjs/schema/types/collection.d.ts +51 -0
  69. package/dist/cjs/schema/types/collection.js +3 -0
  70. package/dist/cjs/schema/types/collection.js.map +1 -0
  71. package/dist/cjs/schema/types/compounds.d.ts +12 -0
  72. package/dist/cjs/schema/types/compounds.js +3 -0
  73. package/dist/cjs/schema/types/compounds.js.map +1 -0
  74. package/dist/cjs/schema/types/fields.d.ts +59 -0
  75. package/dist/cjs/schema/types/fields.js +3 -0
  76. package/dist/cjs/schema/types/fields.js.map +1 -0
  77. package/dist/cjs/schema/types/filters.d.ts +29 -0
  78. package/dist/cjs/schema/types/filters.js +3 -0
  79. package/dist/cjs/schema/types/filters.js.map +1 -0
  80. package/dist/cjs/schema/types/shapes.d.ts +21 -0
  81. package/dist/cjs/schema/types/shapes.js +3 -0
  82. package/dist/cjs/schema/types/shapes.js.map +1 -0
  83. package/dist/cjs/schema/types/synthetics.d.ts +28 -0
  84. package/dist/cjs/schema/types/synthetics.js +3 -0
  85. package/dist/cjs/schema/types/synthetics.js.map +1 -0
  86. package/dist/cjs/schema/types.d.ts +18 -0
  87. package/dist/cjs/schema/types.js +23 -0
  88. package/dist/cjs/schema/types.js.map +1 -0
  89. package/dist/cjs/timestamp.d.ts +48 -0
  90. package/dist/cjs/timestamp.js +244 -0
  91. package/dist/cjs/timestamp.js.map +1 -0
  92. package/dist/cjs/timestamp.test.d.ts +1 -0
  93. package/dist/cjs/timestamp.test.js +94 -0
  94. package/dist/cjs/timestamp.test.js.map +1 -0
  95. package/dist/cjs/undo.d.ts +3 -0
  96. package/dist/cjs/undo.js +199 -0
  97. package/dist/cjs/undo.js.map +1 -0
  98. package/dist/cjs/utils.d.ts +15 -0
  99. package/dist/cjs/utils.js +128 -0
  100. package/dist/cjs/utils.js.map +1 -0
  101. package/dist/cjs/utils.test.d.ts +1 -0
  102. package/dist/cjs/utils.test.js +37 -0
  103. package/dist/cjs/utils.test.js.map +1 -0
  104. package/dist/esm/EventSubscriber.d.ts +17 -0
  105. package/dist/esm/EventSubscriber.js +63 -0
  106. package/dist/esm/EventSubscriber.js.map +1 -0
  107. package/dist/esm/baseline.d.ts +5 -0
  108. package/dist/esm/baseline.js +2 -0
  109. package/dist/esm/baseline.js.map +1 -0
  110. package/dist/esm/batching.d.ts +41 -0
  111. package/dist/esm/batching.js +84 -0
  112. package/dist/esm/batching.js.map +1 -0
  113. package/dist/esm/files.d.ts +19 -0
  114. package/dist/esm/files.js +13 -0
  115. package/dist/esm/files.js.map +1 -0
  116. package/dist/esm/files.test.d.ts +1 -0
  117. package/dist/esm/files.test.js +79 -0
  118. package/dist/esm/files.test.js.map +1 -0
  119. package/dist/esm/index.d.ts +18 -0
  120. package/dist/esm/index.js +16 -0
  121. package/dist/esm/index.js.map +1 -0
  122. package/dist/esm/indexes.d.ts +14 -0
  123. package/dist/esm/indexes.js +106 -0
  124. package/dist/esm/indexes.js.map +1 -0
  125. package/dist/esm/indexes.test.d.ts +1 -0
  126. package/dist/esm/indexes.test.js +126 -0
  127. package/dist/esm/indexes.test.js.map +1 -0
  128. package/dist/esm/migration.d.ts +98 -0
  129. package/dist/esm/migration.js +122 -0
  130. package/dist/esm/migration.js.map +1 -0
  131. package/dist/esm/oids.d.ts +87 -0
  132. package/dist/esm/oids.js +348 -0
  133. package/dist/esm/oids.js.map +1 -0
  134. package/dist/esm/oids.test.d.ts +1 -0
  135. package/dist/esm/oids.test.js +280 -0
  136. package/dist/esm/oids.test.js.map +1 -0
  137. package/dist/esm/operation.d.ts +139 -0
  138. package/dist/esm/operation.js +518 -0
  139. package/dist/esm/operation.js.map +1 -0
  140. package/dist/esm/operation.test.d.ts +1 -0
  141. package/dist/esm/operation.test.js +825 -0
  142. package/dist/esm/operation.test.js.map +1 -0
  143. package/dist/esm/patch.d.ts +26 -0
  144. package/dist/esm/patch.js +223 -0
  145. package/dist/esm/patch.js.map +1 -0
  146. package/dist/esm/presence.d.ts +27 -0
  147. package/dist/esm/presence.js +2 -0
  148. package/dist/esm/presence.js.map +1 -0
  149. package/dist/esm/protocol.d.ts +145 -0
  150. package/dist/esm/protocol.js +3 -0
  151. package/dist/esm/protocol.js.map +1 -0
  152. package/dist/esm/refs.d.ts +5 -0
  153. package/dist/esm/refs.js +17 -0
  154. package/dist/esm/refs.js.map +1 -0
  155. package/dist/esm/replica.d.ts +28 -0
  156. package/dist/esm/replica.js +26 -0
  157. package/dist/esm/replica.js.map +1 -0
  158. package/dist/esm/schema/defaults.d.ts +4 -0
  159. package/dist/esm/schema/defaults.js +66 -0
  160. package/dist/esm/schema/defaults.js.map +1 -0
  161. package/dist/esm/schema/defaults.test.d.ts +1 -0
  162. package/dist/esm/schema/defaults.test.js +19 -0
  163. package/dist/esm/schema/defaults.test.js.map +1 -0
  164. package/dist/esm/schema/index.d.ts +8 -0
  165. package/dist/esm/schema/index.js +10 -0
  166. package/dist/esm/schema/index.js.map +1 -0
  167. package/dist/esm/schema/indexFilters.d.ts +6 -0
  168. package/dist/esm/schema/indexFilters.js +23 -0
  169. package/dist/esm/schema/indexFilters.js.map +1 -0
  170. package/dist/esm/schema/types/collection.d.ts +51 -0
  171. package/dist/esm/schema/types/collection.js +2 -0
  172. package/dist/esm/schema/types/collection.js.map +1 -0
  173. package/dist/esm/schema/types/compounds.d.ts +12 -0
  174. package/dist/esm/schema/types/compounds.js +2 -0
  175. package/dist/esm/schema/types/compounds.js.map +1 -0
  176. package/dist/esm/schema/types/fields.d.ts +59 -0
  177. package/dist/esm/schema/types/fields.js +2 -0
  178. package/dist/esm/schema/types/fields.js.map +1 -0
  179. package/dist/esm/schema/types/filters.d.ts +29 -0
  180. package/dist/esm/schema/types/filters.js +2 -0
  181. package/dist/esm/schema/types/filters.js.map +1 -0
  182. package/dist/esm/schema/types/shapes.d.ts +21 -0
  183. package/dist/esm/schema/types/shapes.js +2 -0
  184. package/dist/esm/schema/types/shapes.js.map +1 -0
  185. package/dist/esm/schema/types/synthetics.d.ts +28 -0
  186. package/dist/esm/schema/types/synthetics.js +2 -0
  187. package/dist/esm/schema/types/synthetics.js.map +1 -0
  188. package/dist/esm/schema/types.d.ts +18 -0
  189. package/dist/esm/schema/types.js +7 -0
  190. package/dist/esm/schema/types.js.map +1 -0
  191. package/dist/esm/timestamp.d.ts +48 -0
  192. package/dist/esm/timestamp.js +229 -0
  193. package/dist/esm/timestamp.js.map +1 -0
  194. package/dist/esm/timestamp.test.d.ts +1 -0
  195. package/dist/esm/timestamp.test.js +92 -0
  196. package/dist/esm/timestamp.test.js.map +1 -0
  197. package/dist/esm/undo.d.ts +3 -0
  198. package/dist/esm/undo.js +195 -0
  199. package/dist/esm/undo.js.map +1 -0
  200. package/dist/esm/utils.d.ts +15 -0
  201. package/dist/esm/utils.js +114 -0
  202. package/dist/esm/utils.js.map +1 -0
  203. package/dist/esm/utils.test.d.ts +1 -0
  204. package/dist/esm/utils.test.js +35 -0
  205. package/dist/esm/utils.test.js.map +1 -0
  206. package/dist/tsconfig-cjs.tsbuildinfo +1 -0
  207. package/dist/tsconfig.tsbuildinfo +1 -0
  208. package/package.json +38 -0
  209. package/src/EventSubscriber.ts +81 -0
  210. package/src/baseline.ts +9 -0
  211. package/src/batching.ts +135 -0
  212. package/src/files.ts +34 -0
  213. package/src/index.ts +26 -0
  214. package/src/indexes.test.ts +158 -0
  215. package/src/indexes.ts +151 -0
  216. package/src/migration.ts +391 -0
  217. package/src/oids.test.ts +395 -0
  218. package/src/oids.ts +442 -0
  219. package/src/operation.test.ts +966 -0
  220. package/src/operation.ts +755 -0
  221. package/src/patch.ts +277 -0
  222. package/src/presence.ts +29 -0
  223. package/src/protocol.ts +184 -0
  224. package/src/refs.ts +16 -0
  225. package/src/replica.ts +29 -0
  226. package/src/schema/defaults.test.ts +19 -0
  227. package/src/schema/defaults.ts +72 -0
  228. package/src/schema/index.ts +28 -0
  229. package/src/schema/indexFilters.ts +49 -0
  230. package/src/schema/types/collection.ts +133 -0
  231. package/src/schema/types/compounds.ts +33 -0
  232. package/src/schema/types/fields.ts +85 -0
  233. package/src/schema/types/filters.ts +39 -0
  234. package/src/schema/types/shapes.ts +83 -0
  235. package/src/schema/types/synthetics.ts +45 -0
  236. package/src/schema/types.ts +28 -0
  237. package/src/timestamp.test.ts +113 -0
  238. package/src/timestamp.ts +284 -0
  239. package/src/undo.ts +205 -0
  240. package/src/utils.test.ts +38 -0
  241. package/src/utils.ts +137 -0
@@ -0,0 +1,133 @@
1
+ import { CollectionCompoundIndices } from './compounds.js';
2
+ import {
3
+ NestedStorageFieldSchema,
4
+ StorageFieldSchema,
5
+ StorageFieldsSchema,
6
+ StorageIndexableFields,
7
+ } from './fields.js';
8
+ import { StorageDocument } from './shapes.js';
9
+ import {
10
+ StorageSyntheticIndexSchema,
11
+ StorageSyntheticIndices,
12
+ } from './synthetics.js';
13
+
14
+ /**
15
+ * The main collection schema
16
+ */
17
+ export type StorageCollectionSchema<
18
+ Fields extends StorageFieldsSchema = StorageFieldsSchema,
19
+ Synthetics extends StorageSyntheticIndices<Fields> = StorageSyntheticIndices<Fields>,
20
+ Compounds extends CollectionCompoundIndices<
21
+ Fields,
22
+ Synthetics
23
+ > = CollectionCompoundIndices<Fields, Synthetics>,
24
+ > = {
25
+ name: string;
26
+ /**
27
+ * Optionally provide a plural name. Useful for some code generation purposes.
28
+ */
29
+ pluralName?: string;
30
+ fields: Fields;
31
+ synthetics?: Synthetics;
32
+ compounds?: Compounds;
33
+ primaryKey: StorageIndexablePropertyName<Fields, Synthetics>;
34
+ };
35
+
36
+ export type NamedSchema<
37
+ Schemas extends StorageCollectionSchema<any, any, any>,
38
+ Name extends string,
39
+ > = Schemas extends { name: Name } ? Schemas : never;
40
+
41
+ export type IndexedSchemaProperties<
42
+ Schema extends StorageCollectionSchema<any, any, any>,
43
+ > = {
44
+ [K in keyof CollectionSchemaFields<Schema> as CollectionSchemaFields<Schema>[K] extends {
45
+ indexed: true;
46
+ }
47
+ ? K
48
+ : never]: CollectionSchemaFields<Schema>[K];
49
+ } & CollectionSchemaComputedIndexes<Schema> &
50
+ CollectionSchemaCompoundIndexes<Schema>;
51
+
52
+ export type CollectionIndexName<
53
+ Collection extends StorageCollectionSchema<any, any, any>,
54
+ > = Extract<keyof IndexedSchemaProperties<Collection>, string>;
55
+
56
+ export type CollectionProperties<
57
+ Collection extends StorageCollectionSchema<any, any, any>,
58
+ > = Collection['fields'] & Collection['synthetics'];
59
+
60
+ export type CollectionPropertyName<
61
+ Collection extends StorageCollectionSchema<any, any, any>,
62
+ > = Exclude<keyof CollectionProperties<Collection>, number | symbol>;
63
+
64
+ export type CollectionEvents<
65
+ Collection extends StorageCollectionSchema<any, any, any>,
66
+ > = {
67
+ put: (value: StorageDocument<Collection>) => void;
68
+ delete: (id: string) => void;
69
+ [key: `put:${string}`]: (value: StorageDocument<Collection>) => void;
70
+ [key: `delete:${string}`]: () => void;
71
+ };
72
+
73
+ export type SchemaForCollection<
74
+ Collection extends StorageCollectionSchema<any, any, any>,
75
+ > = Collection;
76
+
77
+ export type CollectionSchemaFields<
78
+ Schema extends StorageCollectionSchema<any, any, any>,
79
+ > = Schema extends StorageCollectionSchema<infer F, any, any> ? F : never;
80
+ export type CollectionSchemaComputedIndexes<
81
+ Schema extends StorageCollectionSchema<any, any, any>,
82
+ > = Schema extends StorageCollectionSchema<any, infer S, any> ? S : never;
83
+ export type CollectionSchemaCompoundIndexes<
84
+ Schema extends StorageCollectionSchema<any, any, any>,
85
+ > = Schema extends StorageCollectionSchema<any, any, infer C> ? C : never;
86
+
87
+ export type StorageIndexableProperties<
88
+ Schema extends StorageCollectionSchema<any, any, any>,
89
+ > = {
90
+ [K in keyof CollectionSchemaFields<Schema>]: CollectionSchemaFields<Schema>[K] extends {
91
+ indexed: boolean;
92
+ }
93
+ ? CollectionSchemaFields<Schema>[K]
94
+ : never;
95
+ } & CollectionSchemaComputedIndexes<Schema>;
96
+
97
+ export type StorageSchemaProperty<
98
+ Schema extends StorageCollectionSchema<any, any, any>,
99
+ > = StorageSchemaProperties<Schema>[keyof StorageSchemaProperties<Schema>];
100
+
101
+ export type StorageSchemaPropertyName<
102
+ Schema extends StorageCollectionSchema<any, any, any>,
103
+ > = Extract<keyof StorageSchemaProperties<Schema>, string>;
104
+
105
+ export type GetSchemaProperty<
106
+ Schema extends StorageCollectionSchema<any, any, any>,
107
+ Key extends StorageSchemaPropertyName<Schema>,
108
+ > = StorageSchemaProperties<Schema>[Key];
109
+
110
+ export type StoragePropertySchema<BaseFields extends StorageFieldsSchema> =
111
+ | StorageFieldSchema
112
+ | NestedStorageFieldSchema
113
+ | StorageSyntheticIndexSchema<BaseFields>;
114
+
115
+ export type StoragePropertyName<
116
+ Fields extends StorageFieldsSchema,
117
+ Synthetics extends StorageSyntheticIndices<Fields>,
118
+ > =
119
+ | Exclude<keyof Fields, number | symbol>
120
+ | Exclude<keyof Synthetics, number | symbol>;
121
+
122
+ export type StorageIndexablePropertyName<
123
+ Fields extends StorageFieldsSchema,
124
+ Synthetics extends StorageSyntheticIndices<Fields>,
125
+ > =
126
+ | Extract<keyof StorageIndexableFields<Fields>, string>
127
+ | Extract<keyof Synthetics, string>;
128
+
129
+ export type StorageSchemaProperties<
130
+ Schema extends StorageCollectionSchema<any, any, any>,
131
+ > = Schema extends StorageCollectionSchema<infer F, infer S, infer C>
132
+ ? F & S & C
133
+ : never;
@@ -0,0 +1,33 @@
1
+ import {
2
+ CollectionSchemaCompoundIndexes,
3
+ StorageCollectionSchema,
4
+ StoragePropertyName,
5
+ } from './collection.js';
6
+ import { StorageFieldsSchema, StorageObjectFieldSchema } from './fields.js';
7
+ import { StorageSyntheticIndices } from './synthetics.js';
8
+
9
+ type OmitObjectFields<T extends StorageFieldsSchema> = {
10
+ [K in keyof T]: T[K] extends StorageObjectFieldSchema ? never : T[K];
11
+ };
12
+
13
+ export type CollectionCompoundIndex<
14
+ Fields extends StorageFieldsSchema,
15
+ Synthetics extends StorageSyntheticIndices<Fields>,
16
+ > = {
17
+ // object fields cannot be compound index inputs
18
+ of: StoragePropertyName<OmitObjectFields<Fields>, Synthetics>[];
19
+ };
20
+ type CompoundFieldNameTuple<Name extends string> =
21
+ | [Name, Name]
22
+ | [Name, Name, Name]
23
+ | [Name, Name, Name, Name]
24
+ | [Name, Name, Name, Name, Name];
25
+
26
+ export type CollectionCompoundIndices<
27
+ Fields extends StorageFieldsSchema,
28
+ Synthetics extends StorageSyntheticIndices<Fields>,
29
+ > = Record<string, CollectionCompoundIndex<Fields, Synthetics>>;
30
+
31
+ export type CollectionCompoundIndexName<
32
+ Collection extends StorageCollectionSchema<any, any, any>,
33
+ > = Exclude<keyof CollectionSchemaCompoundIndexes<Collection>, number | symbol>;
@@ -0,0 +1,85 @@
1
+ export type StorageStringFieldSchema = {
2
+ type: 'string';
3
+ indexed?: boolean;
4
+ nullable?: boolean;
5
+ default?: string | (() => string);
6
+ };
7
+ export type StorageNumberFieldSchema = {
8
+ type: 'number';
9
+ indexed?: boolean;
10
+ nullable?: boolean;
11
+ default?: number | (() => number);
12
+ };
13
+ export type StorageBooleanFieldSchema = {
14
+ type: 'boolean';
15
+ nullable?: boolean;
16
+ default?: boolean | (() => boolean);
17
+ indexed?: boolean;
18
+ };
19
+ export type StorageArrayFieldSchema = {
20
+ type: 'array';
21
+ items: NestedStorageFieldSchema;
22
+ nullable?: boolean;
23
+ };
24
+ export type StorageObjectFieldSchema = {
25
+ type: 'object';
26
+ properties: NestedStorageFieldsSchema;
27
+ nullable?: boolean;
28
+ };
29
+ export type StorageAnyFieldSchema = {
30
+ type: 'any';
31
+ default?: any;
32
+ };
33
+ export type StorageMapFieldSchema<V extends NestedStorageFieldSchema> = {
34
+ type: 'map';
35
+ values: V;
36
+ };
37
+ export type StorageFileFieldSchema = {
38
+ type: 'file';
39
+ nullable?: boolean;
40
+ // downloadRemote?: boolean; TODO: is this a good feature? maybe later.
41
+ };
42
+
43
+ export type StorageFieldSchema =
44
+ | StorageStringFieldSchema
45
+ | StorageNumberFieldSchema
46
+ | StorageBooleanFieldSchema
47
+ | StorageArrayFieldSchema
48
+ | StorageObjectFieldSchema
49
+ | StorageAnyFieldSchema
50
+ | StorageMapFieldSchema<any>
51
+ | StorageFileFieldSchema;
52
+
53
+ // nested versions don't have index info
54
+ export type NestedStorageStringFieldSchema = {
55
+ type: 'string';
56
+ nullable?: boolean;
57
+ default?: string | (() => string);
58
+ };
59
+ export type NestedStorageNumberFieldSchema = {
60
+ type: 'number';
61
+ nullable?: boolean;
62
+ default?: number | (() => number);
63
+ };
64
+
65
+ export type NestedStorageFieldSchema =
66
+ | NestedStorageStringFieldSchema
67
+ | NestedStorageNumberFieldSchema
68
+ | StorageBooleanFieldSchema
69
+ | StorageArrayFieldSchema
70
+ | StorageObjectFieldSchema
71
+ | StorageAnyFieldSchema
72
+ | StorageMapFieldSchema<any>
73
+ | StorageFileFieldSchema;
74
+
75
+ export type StorageFieldsSchema = Record<string, StorageFieldSchema>;
76
+
77
+ export type NestedStorageFieldsSchema = Record<
78
+ string,
79
+ NestedStorageFieldSchema
80
+ >;
81
+
82
+ // filters to only fields which can be indexed
83
+ export type StorageIndexableFields<Fields extends StorageFieldsSchema> = {
84
+ [K in keyof Fields]: Fields[K] extends { indexed: boolean } ? K : never;
85
+ };
@@ -0,0 +1,39 @@
1
+ export type MatchCollectionIndexFilter = {
2
+ where: string;
3
+ equals: any;
4
+ order?: 'asc' | 'desc';
5
+ };
6
+
7
+ export type RangeCollectionIndexFilter = {
8
+ where: string;
9
+ gte?: any;
10
+ lte?: any;
11
+ gt?: any;
12
+ lt?: any;
13
+ order?: 'asc' | 'desc';
14
+ };
15
+
16
+ export type CollectionCompoundIndexFilter = {
17
+ where: string;
18
+ match: Record<string, any>;
19
+ order: 'asc' | 'desc';
20
+ };
21
+
22
+ export type SortIndexFilter = {
23
+ where: string;
24
+ order: 'asc' | 'desc';
25
+ };
26
+
27
+ export type StartsWithIndexFilter = {
28
+ where: string;
29
+ startsWith: string;
30
+ order?: 'asc' | 'desc';
31
+ };
32
+
33
+ export type CollectionIndexFilter =
34
+ | MatchCollectionIndexFilter
35
+ | RangeCollectionIndexFilter
36
+ | CollectionCompoundIndexFilter
37
+ | StartsWithIndexFilter
38
+ | SortIndexFilter;
39
+ export type CollectionFilter = CollectionIndexFilter;
@@ -0,0 +1,83 @@
1
+ import {
2
+ StorageCollectionSchema,
3
+ StoragePropertySchema,
4
+ } from './collection.js';
5
+ import {
6
+ NestedStorageFieldsSchema,
7
+ StorageArrayFieldSchema,
8
+ StorageFieldsSchema,
9
+ StorageMapFieldSchema,
10
+ StorageObjectFieldSchema,
11
+ } from './fields.js';
12
+
13
+ type StoragePropertyIsNullable<T extends StoragePropertySchema<any>> =
14
+ T extends { nullable?: boolean }
15
+ ? T['nullable'] extends boolean
16
+ ? true
17
+ : false
18
+ : T['type'] extends 'any'
19
+ ? true
20
+ : false;
21
+
22
+ export type BaseShapeFromProperty<T extends StoragePropertySchema<any>> =
23
+ T['type'] extends 'string'
24
+ ? string
25
+ : T['type'] extends 'number'
26
+ ? number
27
+ : T['type'] extends 'boolean'
28
+ ? boolean
29
+ : T extends StorageArrayFieldSchema
30
+ ? ShapeFromProperty<T['items']>[]
31
+ : T extends StorageObjectFieldSchema
32
+ ? ShapeFromFields<T['properties']>
33
+ : T extends StorageMapFieldSchema<any>
34
+ ? Record<string, ShapeFromProperty<T['values']>>
35
+ : T['type'] extends 'any'
36
+ ? any
37
+ : T['type'] extends 'file'
38
+ ? File
39
+ : never;
40
+
41
+ export type ShapeFromProperty<T extends StoragePropertySchema<any>> =
42
+ StoragePropertyIsNullable<T> extends true
43
+ ? BaseShapeFromProperty<T> | null
44
+ : BaseShapeFromProperty<T>;
45
+
46
+ export type ShapeFromFields<
47
+ T extends StorageFieldsSchema | NestedStorageFieldsSchema,
48
+ > = {
49
+ [K in keyof T]: ShapeFromProperty<T[K]>;
50
+ };
51
+
52
+ export type StorageDocument<
53
+ Collection extends StorageCollectionSchema<any, any, any>,
54
+ > = ShapeFromFields<Collection['fields']>;
55
+
56
+ type StoragePropertyIsOptional<T extends StoragePropertySchema<any>> =
57
+ StoragePropertyIsNullable<T> extends true
58
+ ? true
59
+ : T extends { default?: any }
60
+ ? true
61
+ : T['type'] extends 'any'
62
+ ? true
63
+ : T['type'] extends 'array'
64
+ ? true
65
+ : T['type'] extends 'map'
66
+ ? true
67
+ : false;
68
+
69
+ type ShapeFromFieldsWithDefaults<
70
+ T extends StorageFieldsSchema | NestedStorageFieldsSchema,
71
+ > = {
72
+ [K in keyof T as StoragePropertyIsOptional<T[K]> extends true
73
+ ? K
74
+ : never]?: ShapeFromProperty<T[K]>;
75
+ } & {
76
+ [K in keyof T as StoragePropertyIsOptional<T[K]> extends true
77
+ ? never
78
+ : K]: ShapeFromProperty<T[K]>;
79
+ };
80
+
81
+ export type StorageDocumentInit<
82
+ Collection extends StorageCollectionSchema<any, any, any>,
83
+ > = ShapeFromFieldsWithDefaults<Collection['fields']>;
@@ -0,0 +1,45 @@
1
+ import { StorageFieldsSchema } from './fields.js';
2
+ import { ShapeFromFields } from './shapes.js';
3
+
4
+ export type StorageStringSyntheticSchema<Fields extends StorageFieldsSchema> = {
5
+ type: 'string';
6
+ compute: (value: ShapeFromFields<Fields>) => string | null;
7
+ };
8
+ export type StorageNumberSyntheticSchema<Fields extends StorageFieldsSchema> = {
9
+ type: 'number';
10
+ compute: (value: ShapeFromFields<Fields>) => number | null;
11
+ };
12
+ export type StorageBooleanSyntheticSchema<Fields extends StorageFieldsSchema> =
13
+ {
14
+ type: 'boolean';
15
+ compute: (value: ShapeFromFields<Fields>) => boolean | null;
16
+ };
17
+ export type StorageStringArraySyntheticSchema<
18
+ Fields extends StorageFieldsSchema,
19
+ > = {
20
+ type: 'string[]';
21
+ compute: (value: ShapeFromFields<Fields>) => string[];
22
+ };
23
+ export type StorageNumberArraySyntheticSchema<
24
+ Fields extends StorageFieldsSchema,
25
+ > = {
26
+ type: 'number[]';
27
+ compute: (value: ShapeFromFields<Fields>) => number[];
28
+ };
29
+ export type StorageBooleanArraySyntheticSchema<
30
+ Fields extends StorageFieldsSchema,
31
+ > = {
32
+ type: 'boolean[]';
33
+ compute: (value: ShapeFromFields<Fields>) => boolean[];
34
+ };
35
+
36
+ export type StorageSyntheticIndices<Fields extends StorageFieldsSchema> =
37
+ Record<string, StorageSyntheticIndexSchema<Fields>>;
38
+
39
+ export type StorageSyntheticIndexSchema<Fields extends StorageFieldsSchema> =
40
+ | StorageStringSyntheticSchema<Fields>
41
+ | StorageNumberSyntheticSchema<Fields>
42
+ | StorageBooleanSyntheticSchema<Fields>
43
+ | StorageStringArraySyntheticSchema<Fields>
44
+ | StorageNumberArraySyntheticSchema<Fields>
45
+ | StorageBooleanArraySyntheticSchema<Fields>;
@@ -0,0 +1,28 @@
1
+ import { StorageCollectionSchema } from './types/collection.js';
2
+
3
+ export * from './types/collection.js';
4
+ export * from './types/compounds.js';
5
+ export * from './types/fields.js';
6
+ export * from './types/filters.js';
7
+ export * from './types/shapes.js';
8
+ export * from './types/synthetics.js';
9
+
10
+ export interface StorageInit<Schemas extends StorageCollectionSchema> {
11
+ collections: Record<string, Schemas>;
12
+ }
13
+
14
+ export type StorageSchema<
15
+ Collections extends {
16
+ [k: string]: StorageCollectionSchema;
17
+ } = any,
18
+ > = { version: number; collections: Collections };
19
+
20
+ export type SchemaCollectionName<Schema extends StorageSchema<any>> =
21
+ Schema extends StorageSchema<infer Cs>
22
+ ? Exclude<keyof Cs, number | symbol>
23
+ : never;
24
+
25
+ export type SchemaCollection<
26
+ Schema extends StorageSchema<any>,
27
+ Name extends SchemaCollectionName<Schema>,
28
+ > = Schema extends StorageSchema<infer Cs> ? Cs[Name] : never;
@@ -0,0 +1,113 @@
1
+ import { describe, expect, it, vitest } from 'vitest';
2
+ import {
3
+ convertOldHlcTimestamp,
4
+ deserializeHlcTimestamp,
5
+ HybridLogicalClockTimestampProvider,
6
+ OLD_encodeVersion,
7
+ OLD_serializeHlcTimestamp,
8
+ serializeHlcTimestamp,
9
+ } from './timestamp.js';
10
+
11
+ describe('the hybrid logical clock', () => {
12
+ it('always produces incrementing timestamps', async () => {
13
+ const clock = new HybridLogicalClockTimestampProvider();
14
+ let prev = clock.now(1);
15
+
16
+ clock.update(prev);
17
+ let now;
18
+ for (let i = 0; i < 1000; i++) {
19
+ now = clock.now(1);
20
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
21
+ clock.update(now);
22
+ prev = now;
23
+ }
24
+
25
+ let time = new Date().getTime();
26
+ for (let i = 0; i < 1000; i++) {
27
+ vitest.setSystemTime(time++);
28
+ now = clock.now(1);
29
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
30
+ clock.update(now);
31
+ prev = now;
32
+ }
33
+ });
34
+
35
+ it('groups blocks of time by version', () => {
36
+ const clock = new HybridLogicalClockTimestampProvider();
37
+ let prev = clock.now(1);
38
+ clock.update(prev);
39
+ let now: string;
40
+ for (let i = 0; i < 10; i++) {
41
+ now = clock.now(1);
42
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
43
+ clock.update(now);
44
+ prev = now;
45
+ }
46
+ for (let i = 0; i < 10; i++) {
47
+ now = clock.now(2);
48
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
49
+ clock.update(now);
50
+ prev = now;
51
+ }
52
+ const startOfVersion2 = now!;
53
+ // jump back to 1
54
+ prev = clock.now(1);
55
+ clock.update(prev);
56
+
57
+ for (let i = 0; i < 10; i++) {
58
+ now = clock.now(1);
59
+ expect(now > prev, `${now} not later than ${prev}`).toBe(true);
60
+ expect(
61
+ now < startOfVersion2,
62
+ `${now} not earlier than ${startOfVersion2}`,
63
+ ).toBe(true);
64
+ clock.update(now);
65
+ prev = now;
66
+ }
67
+ });
68
+
69
+ it('is shorter than the previous format', () => {
70
+ const clock = new HybridLogicalClockTimestampProvider();
71
+
72
+ expect(clock.now(1).length).toBeLessThan(clock.OLD_now(1).length);
73
+ });
74
+
75
+ it('correctly converts old to new format', () => {
76
+ const clock = new HybridLogicalClockTimestampProvider();
77
+ const oldFormat = clock.OLD_now(1);
78
+ const value = clock.timerState();
79
+ const converted = convertOldHlcTimestamp(oldFormat);
80
+ const newFormat = clock.get(1, value);
81
+ expect(converted).toEqual(newFormat);
82
+ });
83
+
84
+ // this is mostly to verify as I move to the new format.
85
+ // instead of attempting a distributed migration of timestamps, it
86
+ // will be easier that the new format just acts as always in the
87
+ // future of the old one. this will only mess with offline clients,
88
+ // but nobody is using verdant but me yet at time of this change (2022-12-19)
89
+ // which is kind of why I'm doing it now anyway.
90
+ it('old format always comes before new format', () => {
91
+ const clock = new HybridLogicalClockTimestampProvider();
92
+ const newFormat = clock.now(1);
93
+ const oldFormat = clock.OLD_now(1);
94
+ expect(oldFormat < newFormat).toBe(true);
95
+
96
+ // even far-future old timestamps are before new timestamps
97
+ const oldFormat2 = OLD_serializeHlcTimestamp({
98
+ counter: 999,
99
+ node: '9876543210',
100
+ time: new Date(3000, 1, 1).getTime(),
101
+ });
102
+ expect(OLD_encodeVersion(1) + oldFormat2 < newFormat).toBe(true);
103
+ });
104
+
105
+ it('decodes timestamps', () => {
106
+ const time = new Date();
107
+ vitest.setSystemTime(time);
108
+
109
+ const clock = new HybridLogicalClockTimestampProvider();
110
+ const now = clock.now(1);
111
+ expect(clock.getWallClockTime(now)).toEqual(time.getTime());
112
+ });
113
+ });