@ibgib/ts-gib 0.4.9

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 (87) hide show
  1. package/.vscode/launch.json +24 -0
  2. package/.vscode/settings.json +34 -0
  3. package/.vscode/tasks.json +37 -0
  4. package/CHANGELOG.md +159 -0
  5. package/README.md +502 -0
  6. package/dist/V1/constants.d.mts +22 -0
  7. package/dist/V1/constants.d.mts.map +1 -0
  8. package/dist/V1/constants.mjs +21 -0
  9. package/dist/V1/constants.mjs.map +1 -0
  10. package/dist/V1/factory.d.mts +23 -0
  11. package/dist/V1/factory.d.mts.map +1 -0
  12. package/dist/V1/factory.mjs +78 -0
  13. package/dist/V1/factory.mjs.map +1 -0
  14. package/dist/V1/index.d.mts +6 -0
  15. package/dist/V1/index.d.mts.map +1 -0
  16. package/dist/V1/index.mjs +6 -0
  17. package/dist/V1/index.mjs.map +1 -0
  18. package/dist/V1/sha256v1.d.mts +19 -0
  19. package/dist/V1/sha256v1.d.mts.map +1 -0
  20. package/dist/V1/sha256v1.mjs +86 -0
  21. package/dist/V1/sha256v1.mjs.map +1 -0
  22. package/dist/V1/transforms/fork.d.mts +16 -0
  23. package/dist/V1/transforms/fork.d.mts.map +1 -0
  24. package/dist/V1/transforms/fork.mjs +111 -0
  25. package/dist/V1/transforms/fork.mjs.map +1 -0
  26. package/dist/V1/transforms/index.d.mts +5 -0
  27. package/dist/V1/transforms/index.d.mts.map +1 -0
  28. package/dist/V1/transforms/index.mjs +5 -0
  29. package/dist/V1/transforms/index.mjs.map +1 -0
  30. package/dist/V1/transforms/mut8.d.mts +50 -0
  31. package/dist/V1/transforms/mut8.d.mts.map +1 -0
  32. package/dist/V1/transforms/mut8.mjs +246 -0
  33. package/dist/V1/transforms/mut8.mjs.map +1 -0
  34. package/dist/V1/transforms/rel8.d.mts +14 -0
  35. package/dist/V1/transforms/rel8.d.mts.map +1 -0
  36. package/dist/V1/transforms/rel8.mjs +176 -0
  37. package/dist/V1/transforms/rel8.mjs.map +1 -0
  38. package/dist/V1/transforms/transform-helper.d.mts +92 -0
  39. package/dist/V1/transforms/transform-helper.d.mts.map +1 -0
  40. package/dist/V1/transforms/transform-helper.mjs +189 -0
  41. package/dist/V1/transforms/transform-helper.mjs.map +1 -0
  42. package/dist/V1/types.d.mts +79 -0
  43. package/dist/V1/types.d.mts.map +1 -0
  44. package/dist/V1/types.mjs +12 -0
  45. package/dist/V1/types.mjs.map +1 -0
  46. package/dist/helper.d.mts +77 -0
  47. package/dist/helper.d.mts.map +1 -0
  48. package/dist/helper.mjs +179 -0
  49. package/dist/helper.mjs.map +1 -0
  50. package/dist/index.cjs +4 -0
  51. package/dist/index.cjs.map +1 -0
  52. package/dist/index.d.cts +4 -0
  53. package/dist/index.d.cts.map +1 -0
  54. package/dist/index.d.mts +4 -0
  55. package/dist/index.d.mts.map +1 -0
  56. package/dist/index.mjs +4 -0
  57. package/dist/index.mjs.map +1 -0
  58. package/dist/types.d.mts +242 -0
  59. package/dist/types.d.mts.map +1 -0
  60. package/dist/types.mjs +2 -0
  61. package/dist/types.mjs.map +1 -0
  62. package/jasmine-browser.json +18 -0
  63. package/jasmine.json +6 -0
  64. package/package.json +61 -0
  65. package/src/V1/constants.mts +23 -0
  66. package/src/V1/factory.mts +110 -0
  67. package/src/V1/factory.spec.mts +162 -0
  68. package/src/V1/index.mts +5 -0
  69. package/src/V1/sha256v1.mts +85 -0
  70. package/src/V1/sha256v1.spec.mts +221 -0
  71. package/src/V1/transforms/fork.mts +100 -0
  72. package/src/V1/transforms/fork.spec.mts +410 -0
  73. package/src/V1/transforms/index.mts +4 -0
  74. package/src/V1/transforms/mut8.mts +239 -0
  75. package/src/V1/transforms/mut8.spec.mts +656 -0
  76. package/src/V1/transforms/rel8.mts +173 -0
  77. package/src/V1/transforms/rel8.spec.mts +556 -0
  78. package/src/V1/transforms/transform-helper.mts +263 -0
  79. package/src/V1/transforms/transform-helper.spec.mts +45 -0
  80. package/src/V1/types.mts +84 -0
  81. package/src/helper.mts +192 -0
  82. package/src/helper.spec.mts +127 -0
  83. package/src/index.cts +3 -0
  84. package/src/index.mts +3 -0
  85. package/src/types.mts +242 -0
  86. package/tsconfig.json +15 -0
  87. package/tsconfig.test.json +10 -0
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Test helper functions.
3
+ */
4
+
5
+ import * as h from './helper.mjs';
6
+ import { HashAlgorithm } from './helper.mjs';
7
+
8
+ const SOME_STRING = "This is some stringy stuff...";
9
+ const SOME_STRING_HASH = "5DC14EA1027B956AD6BA51F11372DF823FCF3429B5F2063F1DDA358E0F4F2992";
10
+ const SOME_STRING_HASH_512 = "C48C780DA7C43EE7047CDAB0D7A2FDF5DC050DF3291D3CAE973FB0F51BE8535668592EB25A730C95A23D3B4D57924893E7E87C86DC0F52C6D5D2E34EE41203E5";
11
+ const SOME_OTHER_STRING = "This is quite a different string of stuff.";
12
+ const TEST_HASHES: { [key: string]: string } = {
13
+ [SOME_STRING + h.HashAlgorithm.sha_256]: SOME_STRING_HASH,
14
+ [SOME_STRING + h.HashAlgorithm.sha_512]: SOME_STRING_HASH_512,
15
+ [SOME_OTHER_STRING + h.HashAlgorithm.sha_256]: 'AE4C18B37B2329770E05EA3F946C6EB6DE56D2DC568E1F5CBB395E2A1556F58A',
16
+ [SOME_OTHER_STRING + h.HashAlgorithm.sha_512]: '2F1A72B21C914ED459319DF4B5D70E81CEE67C4B48BC74CD6BA8F41DCEC20DCD100C914913F370B2782985268D05C590B46F3FE9005A7477BA952935D2454E53',
17
+ }
18
+
19
+ describe(`when cloning`, () => {
20
+
21
+ it(`should copy deep objects`, async () => {
22
+ const objSimple = { a: SOME_STRING };
23
+ const objADeep = {
24
+ levelOne: {
25
+ levelTwo: {
26
+ buckle: "your shoe",
27
+ three: "four",
28
+ objSimple: objSimple,
29
+ }
30
+ }
31
+ };
32
+ const cloneADeep = h.clone(objADeep);
33
+ expect(cloneADeep?.levelOne?.levelTwo?.buckle).toBe("your shoe");
34
+ expect(cloneADeep?.levelOne?.levelTwo?.three).toBe("four");
35
+ expect(cloneADeep?.levelOne?.levelTwo?.objSimple).toEqual(objSimple);
36
+
37
+ cloneADeep.levelOne.levelTwo.objSimple.a = SOME_OTHER_STRING;
38
+
39
+ // original should **still** be the first value
40
+ expect(objSimple.a).toBe(SOME_STRING);
41
+ // clone should be changed.
42
+ expect(cloneADeep.levelOne.levelTwo.objSimple.a).toBe(SOME_OTHER_STRING);
43
+ });
44
+ });
45
+
46
+ describe(`when getting timestamp`, () => {
47
+ it(`should get the current date as UTCString`, async () => {
48
+ // implementation detail hmm....
49
+ const timestamp = h.getTimestamp();
50
+ const date = new Date(timestamp);
51
+ const dateAsUTCString = date.toUTCString();
52
+ expect(timestamp).toBe(dateAsUTCString);
53
+ });
54
+ });
55
+
56
+ describe(`when hashing (helper)`, () => {
57
+ const TEST_ALGORITHMS: h.HashAlgorithm[] = Object.values(h.HashAlgorithm);
58
+
59
+ // implicit is just SHA-256
60
+ it(`should hash consistently with implicit SHA-256`, async () => {
61
+ const hash = await h.hash({ s: SOME_STRING }) || "";
62
+ expect(hash.toUpperCase()).toBe(TEST_HASHES[SOME_STRING + 'SHA-256']);
63
+ });
64
+
65
+ for (let algorithm of TEST_ALGORITHMS) {
66
+ it(`should hash consistently with explicit ${algorithm}`, async () => {
67
+ // const hash = await h.hash({s: SOME_STRING, algorithm: "SHA-256"}) || "";
68
+ let hash = await h.hash({ s: SOME_STRING, algorithm }) || "";
69
+ expect(hash.toUpperCase()).toBe(TEST_HASHES[SOME_STRING + algorithm]);
70
+ hash = await h.hash({ s: SOME_OTHER_STRING, algorithm }) || "";
71
+ expect(hash.toUpperCase()).toBe(TEST_HASHES[SOME_OTHER_STRING + algorithm]);
72
+ });
73
+ it(`should hash without collisions, 1000 times, ${algorithm}`, async () => {
74
+ const hashes: string[] = [];
75
+ const salt = await h.getUUID(1024);
76
+ // console.log(`salt: ${salt}`);
77
+ for (let i = 0; i < 1000; i++) {
78
+ const hash = await h.hash({ s: salt + i.toString(), algorithm }) || "";
79
+ // console.log(hash);
80
+ expect(hashes).not.toContain(hash);
81
+ hashes.push(hash);
82
+ }
83
+ });
84
+ };
85
+ });
86
+
87
+ describe(`when generating UUIDs`, () => {
88
+ it(`shouldn't duplicate UUIDs`, async () => {
89
+ const ids: string[] = [];
90
+ for (let i = 0; i < 100; i++) {
91
+ const id = await h.getUUID();
92
+ expect(ids).not.toContain(id);
93
+ ids.push(id);
94
+ }
95
+ });
96
+ });
97
+
98
+ describe(`when extractErrorMsg`, () => {
99
+ it(`should return canned msg when error is falsy`, () => {
100
+ const defaultMsg = '[error is falsy]'; // duplicate of code in helper.mjs
101
+ [null, undefined, ''].forEach(error => {
102
+ expect(h.extractErrorMsg(error)).withContext(JSON.stringify(error)).toEqual(defaultMsg);
103
+ });
104
+ });
105
+ it(`should return incoming error if it is a string`, () => {
106
+ ['string here', 'undefined', '42', 'ibgib'].forEach(stringError => {
107
+ expect(h.extractErrorMsg(stringError)).withContext(JSON.stringify(stringError)).toEqual(stringError);
108
+ });
109
+ });
110
+ it(`should return error.message if it's a thrown error`, () => {
111
+ ['string here', 'undefined', 'something went wrong', 'danger. out of memory (E: ce86ffd7a0174c1d8ce5e56c807dd4b1)']
112
+ .map(x => new Error(x))
113
+ .forEach(error => {
114
+ expect(h.extractErrorMsg(error)).withContext(error.message).toEqual(error.message);
115
+ });
116
+ });
117
+ it(`should return incoming error stringified if it is a number`, () => {
118
+ [1234, 0, 1_000, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, -5, 1 / 23].forEach(numberError => {
119
+ expect(h.extractErrorMsg(numberError)).withContext(JSON.stringify(numberError)).toEqual(JSON.stringify(numberError));
120
+ });
121
+ });
122
+ it(`should return canned response with type if incoming error is none of the above`, () => {
123
+ let error = { x: 1, y: 2 };
124
+ let msg = h.extractErrorMsg(error);
125
+ expect(msg).withContext(JSON.stringify(error)).toBeTruthy();
126
+ });
127
+ });
package/src/index.cts ADDED
@@ -0,0 +1,3 @@
1
+ export * as V1 from './V1/index.mjs';
2
+ export * from './types.mjs';
3
+ export * from './helper.mjs';
package/src/index.mts ADDED
@@ -0,0 +1,3 @@
1
+ export * as V1 from './V1/index.mjs';
2
+ export * from './types.mjs';
3
+ export * from './helper.mjs';
package/src/types.mts ADDED
@@ -0,0 +1,242 @@
1
+ /**
2
+ * The core of the simplicity of the ibGib protocol is that
3
+ * fundamentally you are taking two ibGibs and producing a third.
4
+ *
5
+ * There are three primary functions: mut8, rel8, fork
6
+ *
7
+ * These are actually different aspects of the single function of
8
+ * relationship and time, either extending or creating a timeline.
9
+ *
10
+ * Mut8 is intrinsic, rel8 is extrinsic, fork is a new timeline.
11
+ * Mut8 changes a timeline, rel8 changes a timeline's link(s),
12
+ * fork creates a new timeline.
13
+ */
14
+ export declare type Ib = '' | string;
15
+ export declare type Gib = '' | 'gib' | string;
16
+ /**
17
+ * Convenient for when destructuring an IbGibAddr
18
+ */
19
+ export interface IbAndGib {
20
+ ib: Ib,
21
+ gib: Gib,
22
+ }
23
+ /**
24
+ * Mostly a marker type of address.
25
+ *
26
+ * Not sure how to enforce schema on demand in TypeScript, but
27
+ * that's to decide for future.
28
+ */
29
+ export declare type IbGibAddr = string;
30
+ export declare type IbGibRel8ns = {
31
+ /**
32
+ * The key is the rel8nName.
33
+ *
34
+ * TS doesnt allow for the indexer to have a non-number/string value
35
+ * even if it's an alias for one of these types to be more readable.
36
+ * Otherwise I would type the `key` here as a `Rel8nName` alias of
37
+ * `string.`
38
+ */
39
+ [key: string]: IbGibAddr[] | null | undefined;
40
+ };
41
+ /**
42
+ * At the base ibGib, the bare minimum is that an ib (data) is required,
43
+ * with an optional gib (metadata).
44
+ */
45
+ export interface IbGib {
46
+ ib: Ib;
47
+ gib?: Gib;
48
+ }
49
+ /**
50
+ * When adding additional structure to an ibGib, the first representation
51
+ * mechanism (from V1) was having explicit Data and Rel8ns keys.
52
+ *
53
+ * This is, however, not the only way to represent this. As just one example,
54
+ * you could also have a prefix for keys that are meant to be the relationships
55
+ * to other ibGibs.
56
+ *
57
+ * I'm including this shape at the core here and not just in V1 because it could
58
+ * be reused for other versions that are different tweaks with different default
59
+ * relationships and data structures but still adhere to this data/rel8ns split
60
+ * (and naming convention).
61
+ */
62
+ export interface IbGibWithDataAndRel8ns<TData = any, TRel8ns extends IbGibRel8ns = IbGibRel8ns> extends IbGib {
63
+ /**
64
+ * Intrinsic data to this ibGib, most likely with primitives e.g. strings or numbers,
65
+ * that will be statically copied from mutation to mutation.
66
+ */
67
+ data?: TData | undefined;
68
+ /**
69
+ * Extrinsic data WRT this ibGib, which can track their own timelines of changes.
70
+ *
71
+ * Note that even if the relationships here point to the same address, i.e. do
72
+ * not change, the other ibGibs can be seen as changing or not. It all depends
73
+ * on how you want to interpret the relationship.
74
+ *
75
+ * For example, if you want to pause/freeze a relationship, then this would be
76
+ * handled by the viewer of the relationship. It just wouldn't check anywhere for
77
+ * the more up-to-date version.
78
+ */
79
+ rel8ns?: TRel8ns | undefined;
80
+ }
81
+ export declare type TransformType = 'fork' | 'mut8' | 'rel8';
82
+ export interface TransformOpts<TSrc extends IbGib = IbGib> {
83
+ /**
84
+ * Fork, mut8, rel8
85
+ */
86
+ type?: TransformType;
87
+ /**
88
+ * If truthy, does NOT add a timestamp to the new ibGib.
89
+ */
90
+ noTimestamp?: boolean;
91
+ /**
92
+ * If truthy, creates dna ibGibs like V1.
93
+ * If falsy, skips the dna and only creates the resultant ibGib.
94
+ */
95
+ dna?: boolean;
96
+ /**
97
+ * Src to apply the transform to.
98
+ *
99
+ * Used at runtime, NOT persisted in space.
100
+ */
101
+ src?: TSrc;
102
+ /**
103
+ * Address of Src. Used in the space persistence.
104
+ */
105
+ srcAddr?: IbGibAddr;
106
+ /**
107
+ * There are two ways of creating rel8ns to other ibgibs:
108
+ *
109
+ * 1) Concat previous ones with new one
110
+ * * e.g. past: ['a^gib'] --> past: ['a^gib', 'b^gib'] --> past: ['a^gib', 'b^gib', 'c^gib']
111
+ * 2) Only have most recent one, linked list style:
112
+ * * e.g. past: ['a^gib'] --> past: ['b^gib'] --> past: ['c^gib']
113
+ *
114
+ * If you choose #1, then you have the advantage of not needing to load up all of the previous
115
+ * records to evaluate. So this will give you minimal runtime requirements, but take up more space.
116
+ * If you choose #2, like in a blockchain e.g., then you will have a smaller space footprint but
117
+ * it takes longer to build the entire list.
118
+ *
119
+ * This gives flexibility for having rel8ns that only wish to have a single value at most.
120
+ *
121
+ */
122
+ linkedRel8ns?: string[];
123
+ /**
124
+ * If truthy, this will include a data['n'] value that acts as an incremented
125
+ * counter for a naive versioning tracker.
126
+ *
127
+ * So A0^123.data.n = 0, A1^456.data.n = 1, etc.
128
+ */
129
+ nCounter?: boolean;
130
+ }
131
+ export interface TemporalJunctionPointOptions {
132
+ timestamp?: boolean;
133
+ uuid?: boolean;
134
+ }
135
+ export interface TransformOpts_Fork<TSrc extends IbGib = IbGib> extends TransformOpts<TSrc> {
136
+ type?: 'fork';
137
+ /**
138
+ * Destination ib for the transform.
139
+ */
140
+ destIb?: string;
141
+ /**
142
+ * If truthy, creates a UUID to encourage local uniqueness of the fork.
143
+ */
144
+ uuid?: boolean;
145
+ /**
146
+ * If truthy, the forked ibGib will be a temporal junction point using
147
+ * the specified
148
+ * This will provide a UUID to encourage local uniqueness of the fork.
149
+ *
150
+ * For what a temporal junction point is, refer to
151
+ * Back to the Future II (or ask me).
152
+ */
153
+ tjp?: TemporalJunctionPointOptions;
154
+ /**
155
+ * If true, retains parent/source's extrinsic rel8ns.
156
+ */
157
+ cloneRel8ns?: boolean;
158
+ /**
159
+ * If true, retains parent/source's intrinsic data.
160
+ */
161
+ cloneData?: boolean;
162
+ }
163
+ export interface TransformOpts_Mut8<TSrc extends IbGib = IbGib, TNewData = any> extends TransformOpts<TSrc> {
164
+ type?: 'mut8';
165
+ /**
166
+ * Info to rename keys. Should be an object where each value should either be
167
+ * a string or an object. If it's a string, then the corresponding key will
168
+ * be renamed to that value. If it's an object, then it will recurse at that
169
+ * key.
170
+ *
171
+ * @example
172
+ * data = { a: 'aaa', b: { rename: 'me', ignore: 'me' }}
173
+ * dataToRemove = { a: 'aRenamed', b: { rename: 'renamed' } }
174
+ * data = { aRenamed: 'aaa', b: { renamed: 'me', ignore: 'me' }}
175
+ */
176
+ dataToRename?: {
177
+ [key: string]: any;
178
+ };
179
+ /**
180
+ * Info to remove keys. Should be an object where each value should either be
181
+ * a string or an object. If it's a string, then the corresponding key will
182
+ * be removed (the value is ignored). If it's an object, then it will recurse at that
183
+ * key.
184
+ *
185
+ * @example
186
+ * data = { a: 'aaa', b: { remove: 'me', ignore: 'me' }}
187
+ * dataToRemove = { b: { remove: '' } }
188
+ * data = { a: 'aaa', b: { ignore: 'me' }}
189
+ */
190
+ dataToRemove?: {
191
+ [key: string]: any;
192
+ };
193
+ /**
194
+ * Data object that contains only additive information for ibGib's intrinsic data.
195
+ */
196
+ dataToAddOrPatch?: TNewData;
197
+ /**
198
+ * If given, will mut8 the ib (without forking the entire ibGib).
199
+ *
200
+ * Often this will act as a 'rename', e.g. (if the ib is acting as the 'name')
201
+ */
202
+ mut8Ib?: string;
203
+ }
204
+ export interface TransformOpts_Rel8<TSrc extends IbGib = IbGib> extends TransformOpts<TSrc> {
205
+ type?: 'rel8';
206
+ /**
207
+ * Relationships to add to an ibGib, either by creating new relationships or by
208
+ * concatenating the arrays to existing ones.
209
+ *
210
+ * NOTES:
211
+ * - Moving relationships can be performed by combining add/remove rel8ns.
212
+ * - How the relations are actually represented in the ibGib record is
213
+ * left to the compiler. The same goes for how this information is
214
+ * recorded in the dna, if generating dna.
215
+ */
216
+ rel8nsToAddByAddr?: IbGibRel8ns;
217
+ /**
218
+ * Relationships to remove from an ibGib.
219
+ *
220
+ * NOTES:
221
+ * - Moving relationships can be performed by combining add/remove rel8ns.
222
+ * - Attempting to remove a non-existing relationship may or may not cause
223
+ * an error, depending on the compiler.
224
+ */
225
+ rel8nsToRemoveByAddr?: IbGibRel8ns;
226
+ }
227
+
228
+ export interface TransformResult<TOut extends IbGib> {
229
+ /**
230
+ * The final result of the transformation
231
+ */
232
+ newIbGib: TOut,
233
+ /**
234
+ * DNA side effects created in the transformation.
235
+ */
236
+ dnas?: TOut[],
237
+ /**
238
+ * If you're performing a transform with multiple steps,
239
+ * then there will be intermediate ibGibs created.
240
+ */
241
+ intermediateIbGibs?: TOut[],
242
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "declaration": true, /* Generates corresponding '.d.ts' file. */
5
+ "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
6
+ "sourceMap": true, /* Generates corresponding '.map' file. */
7
+ "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
8
+ "composite": true, /* Enable project compilation */
9
+ "outDir": "./dist", /* Redirect output structure to the directory. */
10
+ "module": "ESNext", /* https://www.typescriptlang.org/docs/handbook/esm-node.html */
11
+ },
12
+ "exclude": [
13
+ "**/*.spec.mts"
14
+ ]
15
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist", /* Redirect output structure to the directory. */
5
+ "module": "ESNext", /* https://www.typescriptlang.org/docs/handbook/esm-node.html */
6
+ },
7
+ "exclude": [
8
+ // override inherited exclude of spec files
9
+ ]
10
+ }