@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.
- package/.vscode/launch.json +24 -0
- package/.vscode/settings.json +34 -0
- package/.vscode/tasks.json +37 -0
- package/CHANGELOG.md +159 -0
- package/README.md +502 -0
- package/dist/V1/constants.d.mts +22 -0
- package/dist/V1/constants.d.mts.map +1 -0
- package/dist/V1/constants.mjs +21 -0
- package/dist/V1/constants.mjs.map +1 -0
- package/dist/V1/factory.d.mts +23 -0
- package/dist/V1/factory.d.mts.map +1 -0
- package/dist/V1/factory.mjs +78 -0
- package/dist/V1/factory.mjs.map +1 -0
- package/dist/V1/index.d.mts +6 -0
- package/dist/V1/index.d.mts.map +1 -0
- package/dist/V1/index.mjs +6 -0
- package/dist/V1/index.mjs.map +1 -0
- package/dist/V1/sha256v1.d.mts +19 -0
- package/dist/V1/sha256v1.d.mts.map +1 -0
- package/dist/V1/sha256v1.mjs +86 -0
- package/dist/V1/sha256v1.mjs.map +1 -0
- package/dist/V1/transforms/fork.d.mts +16 -0
- package/dist/V1/transforms/fork.d.mts.map +1 -0
- package/dist/V1/transforms/fork.mjs +111 -0
- package/dist/V1/transforms/fork.mjs.map +1 -0
- package/dist/V1/transforms/index.d.mts +5 -0
- package/dist/V1/transforms/index.d.mts.map +1 -0
- package/dist/V1/transforms/index.mjs +5 -0
- package/dist/V1/transforms/index.mjs.map +1 -0
- package/dist/V1/transforms/mut8.d.mts +50 -0
- package/dist/V1/transforms/mut8.d.mts.map +1 -0
- package/dist/V1/transforms/mut8.mjs +246 -0
- package/dist/V1/transforms/mut8.mjs.map +1 -0
- package/dist/V1/transforms/rel8.d.mts +14 -0
- package/dist/V1/transforms/rel8.d.mts.map +1 -0
- package/dist/V1/transforms/rel8.mjs +176 -0
- package/dist/V1/transforms/rel8.mjs.map +1 -0
- package/dist/V1/transforms/transform-helper.d.mts +92 -0
- package/dist/V1/transforms/transform-helper.d.mts.map +1 -0
- package/dist/V1/transforms/transform-helper.mjs +189 -0
- package/dist/V1/transforms/transform-helper.mjs.map +1 -0
- package/dist/V1/types.d.mts +79 -0
- package/dist/V1/types.d.mts.map +1 -0
- package/dist/V1/types.mjs +12 -0
- package/dist/V1/types.mjs.map +1 -0
- package/dist/helper.d.mts +77 -0
- package/dist/helper.d.mts.map +1 -0
- package/dist/helper.mjs +179 -0
- package/dist/helper.mjs.map +1 -0
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +4 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types.d.mts +242 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +2 -0
- package/dist/types.mjs.map +1 -0
- package/jasmine-browser.json +18 -0
- package/jasmine.json +6 -0
- package/package.json +61 -0
- package/src/V1/constants.mts +23 -0
- package/src/V1/factory.mts +110 -0
- package/src/V1/factory.spec.mts +162 -0
- package/src/V1/index.mts +5 -0
- package/src/V1/sha256v1.mts +85 -0
- package/src/V1/sha256v1.spec.mts +221 -0
- package/src/V1/transforms/fork.mts +100 -0
- package/src/V1/transforms/fork.spec.mts +410 -0
- package/src/V1/transforms/index.mts +4 -0
- package/src/V1/transforms/mut8.mts +239 -0
- package/src/V1/transforms/mut8.spec.mts +656 -0
- package/src/V1/transforms/rel8.mts +173 -0
- package/src/V1/transforms/rel8.spec.mts +556 -0
- package/src/V1/transforms/transform-helper.mts +263 -0
- package/src/V1/transforms/transform-helper.spec.mts +45 -0
- package/src/V1/types.mts +84 -0
- package/src/helper.mts +192 -0
- package/src/helper.spec.mts +127 -0
- package/src/index.cts +3 -0
- package/src/index.mts +3 -0
- package/src/types.mts +242 -0
- package/tsconfig.json +15 -0
- package/tsconfig.test.json +10 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { fork } from './transforms/fork.mjs';
|
|
2
|
+
import { mut8 } from './transforms/mut8.mjs';
|
|
3
|
+
import { rel8 } from './transforms/rel8.mjs';
|
|
4
|
+
import { Ib, IbGib, IbGibRel8ns, TransformResult, TemporalJunctionPointOptions } from '../types.mjs';
|
|
5
|
+
import { IbGib_V1 } from './types.mjs';
|
|
6
|
+
import { IB, GIB, ROOT } from './constants.mjs';
|
|
7
|
+
|
|
8
|
+
export class Factory_V1 {
|
|
9
|
+
static root() {
|
|
10
|
+
return Factory_V1.primitive({ ib: IB });
|
|
11
|
+
}
|
|
12
|
+
static primitive({
|
|
13
|
+
ib
|
|
14
|
+
}: {
|
|
15
|
+
ib: Ib
|
|
16
|
+
}): IbGib_V1 {
|
|
17
|
+
return { ib, gib: GIB };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static primitives({
|
|
21
|
+
ibs
|
|
22
|
+
}: {
|
|
23
|
+
ibs: Ib[]
|
|
24
|
+
}) {
|
|
25
|
+
return ibs.map(ib => Factory_V1.primitive({ ib }));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static async firstGen<TData = any>({
|
|
29
|
+
ib = IB,
|
|
30
|
+
parentIbGib = Factory_V1.root(),
|
|
31
|
+
data,
|
|
32
|
+
rel8ns,
|
|
33
|
+
dna,
|
|
34
|
+
tjp,
|
|
35
|
+
linkedRel8ns,
|
|
36
|
+
noTimestamp,
|
|
37
|
+
nCounter,
|
|
38
|
+
}: {
|
|
39
|
+
ib: Ib,
|
|
40
|
+
parentIbGib: IbGib,
|
|
41
|
+
data?: TData,
|
|
42
|
+
rel8ns?: IbGibRel8ns,
|
|
43
|
+
dna?: boolean,
|
|
44
|
+
tjp?: TemporalJunctionPointOptions;
|
|
45
|
+
linkedRel8ns?: string[],
|
|
46
|
+
noTimestamp?: boolean,
|
|
47
|
+
nCounter?: boolean,
|
|
48
|
+
}) {
|
|
49
|
+
const lc = `[firstGen]`;
|
|
50
|
+
/** * Multiple transform steps will create multiple results. */
|
|
51
|
+
const interimResults: TransformResult<IbGib_V1>[] = [];
|
|
52
|
+
let src: IbGib_V1 = parentIbGib || ROOT;
|
|
53
|
+
let resFork = await fork({
|
|
54
|
+
src,
|
|
55
|
+
destIb: ib,
|
|
56
|
+
tjp,
|
|
57
|
+
dna,
|
|
58
|
+
linkedRel8ns,
|
|
59
|
+
noTimestamp,
|
|
60
|
+
nCounter,
|
|
61
|
+
});
|
|
62
|
+
interimResults.push(resFork);
|
|
63
|
+
src = resFork.newIbGib;
|
|
64
|
+
|
|
65
|
+
if (data) {
|
|
66
|
+
let resMut8 = await mut8({
|
|
67
|
+
src,
|
|
68
|
+
dataToAddOrPatch: data,
|
|
69
|
+
dna,
|
|
70
|
+
linkedRel8ns,
|
|
71
|
+
noTimestamp,
|
|
72
|
+
nCounter,
|
|
73
|
+
});
|
|
74
|
+
interimResults.push(resMut8);
|
|
75
|
+
src = resMut8.newIbGib;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
if (rel8ns) {
|
|
79
|
+
let resRel8 = await rel8({
|
|
80
|
+
src,
|
|
81
|
+
rel8nsToAddByAddr: rel8ns,
|
|
82
|
+
dna,
|
|
83
|
+
linkedRel8ns,
|
|
84
|
+
noTimestamp,
|
|
85
|
+
nCounter,
|
|
86
|
+
});
|
|
87
|
+
interimResults.push(resRel8);
|
|
88
|
+
// src = resRel8.newIbGib; // not needed because not used (this is the last step)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (interimResults.length > 1) {
|
|
92
|
+
const newIbGib = interimResults.slice(interimResults.length - 1)[0].newIbGib;
|
|
93
|
+
const result = {
|
|
94
|
+
newIbGib,
|
|
95
|
+
intermediateIbGibs: interimResults.slice(0, interimResults.length - 1).map(x => x.newIbGib),
|
|
96
|
+
} as TransformResult<IbGib_V1>;
|
|
97
|
+
if (dna) {
|
|
98
|
+
let dnas: IbGib_V1[] = [];
|
|
99
|
+
interimResults.forEach(res => { dnas = dnas.concat(res.dnas!); });
|
|
100
|
+
result.dnas = dnas;
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
} else if (interimResults.length === 1) {
|
|
104
|
+
// for some reason the caller just used this as a fork.
|
|
105
|
+
return interimResults[0];
|
|
106
|
+
} else {
|
|
107
|
+
throw new Error(`${lc} hmm, I'm not sure...`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
|
|
2
|
+
import { IbGib_V1, IbGibRel8ns_V1, Rel8n } from './types.mjs';
|
|
3
|
+
import { fork } from './transforms/fork.mjs';
|
|
4
|
+
import { TransformOpts_Fork, IbGibAddr, Ib, TransformResult, IbGibRel8ns } from '../types.mjs';
|
|
5
|
+
import { pretty, clone, delay, getIbGibAddr } from '../helper.mjs';
|
|
6
|
+
import { ROOT, ROOT_ADDR } from './constants.mjs';
|
|
7
|
+
import { Factory_V1 as factory } from './factory.mjs';
|
|
8
|
+
import { mut8 } from './transforms/mut8.mjs';
|
|
9
|
+
import { sha256v1 } from './sha256v1.mjs';
|
|
10
|
+
import { getGib, getGibInfo } from './transforms/transform-helper.mjs';
|
|
11
|
+
|
|
12
|
+
const PRIMITIVE_IBS: string[] = [
|
|
13
|
+
'a', '7', 'tag',
|
|
14
|
+
'any string/value that isnt hashed with a gib is a primitive',
|
|
15
|
+
// e.g. 6 -> 6^ -> 6^gib are all equivalent ib^gib addresses,
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
const DATA_SIMPLE_XY = { x: 1, y: 2 };
|
|
20
|
+
|
|
21
|
+
const SIMPLE_REL8N_NAMES: string[] = [
|
|
22
|
+
// just some possible example rel8n names
|
|
23
|
+
'child', 'container', 'folder', 'identity', 'tag', 'liked'
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
describe(`when using factory`, () => {
|
|
28
|
+
|
|
29
|
+
it(`primitives() should make multiple ibgibs`, async () => {
|
|
30
|
+
const primitiveIbGibs = factory.primitives({ ibs: PRIMITIVE_IBS });
|
|
31
|
+
expect(primitiveIbGibs).toBeTruthy();
|
|
32
|
+
expect(primitiveIbGibs.length).toEqual(PRIMITIVE_IBS.length);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe(`firstGen`, () => {
|
|
36
|
+
it(`should make an ibgib`, async () => {
|
|
37
|
+
const testIb = 'some ib here';
|
|
38
|
+
const { newIbGib } = await factory.firstGen({
|
|
39
|
+
ib: testIb,
|
|
40
|
+
parentIbGib: ROOT,
|
|
41
|
+
});
|
|
42
|
+
expect(newIbGib).toBeTruthy;
|
|
43
|
+
});
|
|
44
|
+
it(`should make ibgibs with initial data`, async () => {
|
|
45
|
+
const testIb = 'some ib here';
|
|
46
|
+
const { newIbGib, intermediateIbGibs } = await factory.firstGen({
|
|
47
|
+
ib: testIb,
|
|
48
|
+
parentIbGib: ROOT,
|
|
49
|
+
data: DATA_SIMPLE_XY,
|
|
50
|
+
noTimestamp: true,
|
|
51
|
+
});
|
|
52
|
+
expect(newIbGib.data).withContext(`newIbGib.data`).toBeTruthy();
|
|
53
|
+
expect(newIbGib.data).toEqual(DATA_SIMPLE_XY);
|
|
54
|
+
|
|
55
|
+
// an intermediate ibGib should be created with
|
|
56
|
+
// the same ib, but not yet mutated with the data.
|
|
57
|
+
expect(intermediateIbGibs).withContext(`intermediateIbGibs`).toBeTruthy();
|
|
58
|
+
expect(intermediateIbGibs!.length).toEqual(1);
|
|
59
|
+
expect(intermediateIbGibs![0].ib).toEqual(testIb);
|
|
60
|
+
expect(intermediateIbGibs![0].data).withContext(`intermediateIbGibs[0].data`).not.toBeTruthy();
|
|
61
|
+
});
|
|
62
|
+
it(`should make ibgibs with initial data & rel8ns`, async () => {
|
|
63
|
+
const primitiveIbgibAddrs =
|
|
64
|
+
factory
|
|
65
|
+
.primitives({ ibs: PRIMITIVE_IBS })
|
|
66
|
+
.map(ibGib => getIbGibAddr({ ibGib }));
|
|
67
|
+
|
|
68
|
+
const testRel8ns: IbGibRel8ns = {};
|
|
69
|
+
SIMPLE_REL8N_NAMES.forEach(rel8nName => {
|
|
70
|
+
testRel8ns[rel8nName] = primitiveIbgibAddrs;
|
|
71
|
+
});
|
|
72
|
+
const testIb = 'some ib here';
|
|
73
|
+
const { newIbGib, intermediateIbGibs } = await factory.firstGen({
|
|
74
|
+
ib: testIb,
|
|
75
|
+
parentIbGib: ROOT,
|
|
76
|
+
data: DATA_SIMPLE_XY,
|
|
77
|
+
noTimestamp: true,
|
|
78
|
+
rel8ns: testRel8ns,
|
|
79
|
+
});
|
|
80
|
+
expect(newIbGib.data).withContext(`newIbGib.data`).toBeTruthy();
|
|
81
|
+
expect(newIbGib.data).toEqual(DATA_SIMPLE_XY);
|
|
82
|
+
expect(newIbGib.rel8ns).withContext(`newIbGib.rel8ns`).toBeTruthy();
|
|
83
|
+
SIMPLE_REL8N_NAMES.forEach(rel8nName => {
|
|
84
|
+
expect(newIbGib.rel8ns![rel8nName]).toEqual(primitiveIbgibAddrs);
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// an intermediate ibGib should be created with
|
|
88
|
+
// the same ib, but not yet mutated with the data.
|
|
89
|
+
expect(intermediateIbGibs).withContext(`intermediateIbGibs`).toBeTruthy();
|
|
90
|
+
expect(intermediateIbGibs!.length).toEqual(2);
|
|
91
|
+
expect(intermediateIbGibs![0].ib).toEqual(testIb);
|
|
92
|
+
expect(intermediateIbGibs![1].ib).toEqual(testIb);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('other stuff here because jasmine is opinionated about no async in describe', () => {
|
|
100
|
+
var allIbGibs: IbGib_V1[];
|
|
101
|
+
beforeAll(async () => {
|
|
102
|
+
// I'm having some weird discrepancies between calling `sha256v1` and
|
|
103
|
+
// `getGib` (which itself calls sha256v1 supposedly).
|
|
104
|
+
//
|
|
105
|
+
// SOLUTION: these "weird" discrepancies were major bugs...how in the
|
|
106
|
+
// world it's been going this long, I don't know. Good God...
|
|
107
|
+
// anyway, I was calculating the gib in the fork and rel8 transforms
|
|
108
|
+
// before adding the dna to the rel8ns. I have no idea how I didn't catch
|
|
109
|
+
// this earlier!
|
|
110
|
+
let badIbGib: IbGib_V1 = {
|
|
111
|
+
"ib": "comment ff1at755",
|
|
112
|
+
"gib": "CA4B24EE80C62A781379B263BCBF1F6C68DDA53D67C9195213635A8C08CDBA45",
|
|
113
|
+
"rel8ns": {
|
|
114
|
+
"ancestor": [
|
|
115
|
+
"comment^gib"
|
|
116
|
+
],
|
|
117
|
+
"dna": [
|
|
118
|
+
"fork^846B2C9498D4AE906D235DFCFA31C8E71089A93AF1950849F67430468FF36B92"
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
"data": {
|
|
122
|
+
"n": 0,
|
|
123
|
+
"timestamp": "Fri, 18 Feb 2022 13:56:01 GMT",
|
|
124
|
+
"uuid": "c4773e052dedc808dcc932d371e724bc4d47410d6833b95b8bd0e403adb6f4b3",
|
|
125
|
+
"isTjp": true
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const text = "ff1 at 755";
|
|
130
|
+
const data: any = { text, textTimestamp: "Fri, 18 Feb 2022 13:56:01 GMT" };
|
|
131
|
+
|
|
132
|
+
// create an ibgib with the filename and ext
|
|
133
|
+
const opts: any = {
|
|
134
|
+
parentIbGib: factory.primitive({ ib: 'comment' }),
|
|
135
|
+
ib: badIbGib.ib,
|
|
136
|
+
data,
|
|
137
|
+
dna: true,
|
|
138
|
+
tjp: { uuid: true, timestamp: true },
|
|
139
|
+
nCounter: true,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const resCommentIbGib = await factory.firstGen(opts);
|
|
143
|
+
allIbGibs = [
|
|
144
|
+
resCommentIbGib!.newIbGib,
|
|
145
|
+
...resCommentIbGib.intermediateIbGibs!,
|
|
146
|
+
...resCommentIbGib.dnas!
|
|
147
|
+
];
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should match up ibGib.gib and getGib & should match up sha256v1 hash and punctiliar hash', async () => {
|
|
151
|
+
for (let i = 0; i < allIbGibs.length; i++) {
|
|
152
|
+
const x = allIbGibs[i];
|
|
153
|
+
let hash_sha256v1Direct = await sha256v1(x, '');
|
|
154
|
+
let hash_getGib = await getGib({ ibGib: x });
|
|
155
|
+
let punctiliarHash = getGibInfo({ gib: hash_getGib }).punctiliarHash;
|
|
156
|
+
expect(hash_getGib).toEqual(x.gib!, 'hash_getGib does not equal x.gib');
|
|
157
|
+
expect(hash_sha256v1Direct).toEqual(punctiliarHash!);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
});
|
package/src/V1/index.mts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
let crypto: any = globalThis.crypto;
|
|
2
|
+
let { subtle } = crypto;
|
|
3
|
+
|
|
4
|
+
import { IbGib_V1, IbGibData_V1, IbGibRel8ns_V1 } from "./types.mjs";
|
|
5
|
+
import { Ib } from "../types.mjs";
|
|
6
|
+
import { extractErrorMsg } from "../helper.mjs";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Performs the gib hash like V1
|
|
10
|
+
*
|
|
11
|
+
* I have it all in one function for smallest, most independent version possible.
|
|
12
|
+
*
|
|
13
|
+
* #thanks https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest
|
|
14
|
+
*
|
|
15
|
+
* @param ibGib ibGib for which to calculate the gib
|
|
16
|
+
*/
|
|
17
|
+
export function sha256v1(ibGib: IbGib_V1, salt: string = ""): Promise<string> {
|
|
18
|
+
// console.log('func_gib_sha256v1 executed');
|
|
19
|
+
if (!salt) { salt = ""; }
|
|
20
|
+
let hashToHex = async (message: string | undefined) => {
|
|
21
|
+
if (!message) { return ""; }
|
|
22
|
+
const msgUint8 = new TextEncoder().encode(message);
|
|
23
|
+
const buffer = await subtle.digest('SHA-256', msgUint8);
|
|
24
|
+
const asArray = Array.from(new Uint8Array(buffer));
|
|
25
|
+
return asArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
26
|
+
};
|
|
27
|
+
let hashFields;
|
|
28
|
+
if (salt) {
|
|
29
|
+
hashFields = async (ib: Ib, data: IbGibData_V1 | undefined, rel8ns: IbGibRel8ns_V1 | undefined) => {
|
|
30
|
+
const hasRel8ns =
|
|
31
|
+
Object.keys(rel8ns || {}).length > 0 &&
|
|
32
|
+
Object.keys(rel8ns || {}).some(k => rel8ns![k] && rel8ns![k]!.length > 0);
|
|
33
|
+
const hasData = Object.keys((data) || {}).length > 0;
|
|
34
|
+
const ibHash = (await hashToHex(salt + ib)).toUpperCase();
|
|
35
|
+
// empty, null, undefined all treated the same at this level.
|
|
36
|
+
const rel8nsHash: string = hasRel8ns ? (await hashToHex(salt + JSON.stringify(rel8ns))).toUpperCase() : "";
|
|
37
|
+
// empty, null, undefined all treated the same at this level (though not farther down in data)
|
|
38
|
+
const dataHash: string = hasData ? (await hashToHex(salt + JSON.stringify(data))).toUpperCase() : "";
|
|
39
|
+
// if the ibgib has no rel8ns or data, the hash should be just of the ib itself.
|
|
40
|
+
const allHash = hasRel8ns || hasData ?
|
|
41
|
+
(await hashToHex(salt + ibHash + rel8nsHash + dataHash)).toUpperCase() :
|
|
42
|
+
(await hashToHex(salt + ibHash)).toUpperCase();
|
|
43
|
+
return allHash;
|
|
44
|
+
};
|
|
45
|
+
} else {
|
|
46
|
+
hashFields = async (ib: Ib, data: IbGibData_V1 | undefined, rel8ns: IbGibRel8ns_V1 | undefined) => {
|
|
47
|
+
const hasRel8ns =
|
|
48
|
+
Object.keys(rel8ns || {}).length > 0 &&
|
|
49
|
+
Object.keys(rel8ns || {}).some(k => rel8ns![k] && rel8ns![k]!.length > 0);
|
|
50
|
+
const hasData = Object.keys((data) || {}).length > 0;
|
|
51
|
+
const ibHash = (await hashToHex(ib)).toUpperCase();
|
|
52
|
+
// empty, null, undefined all treated the same at this level.
|
|
53
|
+
const rel8nsHash: string = hasRel8ns ? (await hashToHex(JSON.stringify(rel8ns))).toUpperCase() : "";
|
|
54
|
+
// empty, null, undefined all treated the same at this level (though not farther down in data)
|
|
55
|
+
const dataHash: string = hasData ? (await hashToHex(JSON.stringify(data))).toUpperCase() : "";
|
|
56
|
+
// if the ibgib has no rel8ns or data, the hash should be just of the ib itself.
|
|
57
|
+
const allHash = hasRel8ns || hasData ?
|
|
58
|
+
(await hashToHex(ibHash + rel8nsHash + dataHash)).toUpperCase() :
|
|
59
|
+
(await hashToHex(ibHash)).toUpperCase();
|
|
60
|
+
return allHash;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return hashFields(ibGib.ib, ibGib?.data, ibGib?.rel8ns);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* I have one large-ish sha256 function for gibbing purposes
|
|
68
|
+
* (dream where metabootstrapping is better)
|
|
69
|
+
* this is just testing a function that is internal to the sha256v1 func.
|
|
70
|
+
* terrible as can be duplicated, but simple for now.
|
|
71
|
+
*/
|
|
72
|
+
export async function hashToHexCopy(
|
|
73
|
+
message: string | undefined
|
|
74
|
+
): Promise<string | undefined> {
|
|
75
|
+
if (!message) { return ""; }
|
|
76
|
+
try {
|
|
77
|
+
const msgUint8 = new TextEncoder().encode(message);
|
|
78
|
+
const buffer = await subtle.digest('SHA-256', msgUint8);
|
|
79
|
+
const asArray = Array.from(new Uint8Array(buffer));
|
|
80
|
+
return asArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
81
|
+
} catch (e) {
|
|
82
|
+
console.error(extractErrorMsg(e.message));
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test basic hashing that is used when calculating V1 gib hashes
|
|
3
|
+
* using sha256.
|
|
4
|
+
*
|
|
5
|
+
* NOTE:
|
|
6
|
+
* This only tests the node implementation, and manual testing
|
|
7
|
+
* is required for browser until I get some kind of browser testing
|
|
8
|
+
* going.
|
|
9
|
+
*/
|
|
10
|
+
import { IbGib_V1, IbGibRel8ns_V1 } from './types.mjs';
|
|
11
|
+
import { sha256v1, hashToHexCopy } from './sha256v1.mjs';
|
|
12
|
+
import { IbGibWithDataAndRel8ns, IbGibRel8ns } from '../types.mjs';
|
|
13
|
+
import { getGib, getGibInfo } from './transforms/transform-helper.mjs';
|
|
14
|
+
|
|
15
|
+
import { Factory_V1 as factory } from './factory.mjs';
|
|
16
|
+
|
|
17
|
+
// #region Test Data
|
|
18
|
+
|
|
19
|
+
const enum TestIbs {
|
|
20
|
+
ib = "ib",
|
|
21
|
+
some_test_string_here = "Some test string here.",
|
|
22
|
+
}
|
|
23
|
+
let testHashes_sha256_strings: { [key: string]: string | undefined } = {
|
|
24
|
+
[TestIbs.ib]: "765DBB8C38A58A5DC019D7B3133DFFB251D643CB291328AD8E86D4F05655E68B",
|
|
25
|
+
[TestIbs.some_test_string_here]: "E9D61315933F1E8ABCEAA51B2CDD711FBF63C82CBF8C359603907E6DED73DB30"
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const ROOT_IBGIB_ADDR = "ib^gib";
|
|
29
|
+
const EMPTY_REL8NS: any = {};
|
|
30
|
+
const EMPTY_DATA: any = {};
|
|
31
|
+
const UNDEFINED_DATA: undefined = undefined;
|
|
32
|
+
const UNDEFINED_REL8NS: undefined = undefined;
|
|
33
|
+
const NULL_DATA: null = null;
|
|
34
|
+
const NULL_REL8NS: null = null;
|
|
35
|
+
|
|
36
|
+
const FALSY_REL8NS = [EMPTY_REL8NS, UNDEFINED_REL8NS, NULL_REL8NS];
|
|
37
|
+
const FALSY_DATA = [EMPTY_DATA, UNDEFINED_DATA, NULL_DATA];
|
|
38
|
+
const FALSY_DATA_REL8NS: { r: IbGibRel8ns, d: any }[] = [];
|
|
39
|
+
FALSY_REL8NS.forEach(r => {
|
|
40
|
+
FALSY_DATA.forEach(d => {
|
|
41
|
+
FALSY_DATA_REL8NS.push({ d, r });
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
interface DATA_FLAT_XY { x: number; y: number; }
|
|
46
|
+
const DATA_FLAT_XY: DATA_FLAT_XY = { x: 1, y: 2 };
|
|
47
|
+
const DATA_FLAT_XY_HASH = "689A8F1DB95402580476E38C264278CE7B1E664320CFB4E9AE8D3A908CF09964";
|
|
48
|
+
interface DATA_FLAT_XS { x: number; s: string; }
|
|
49
|
+
const DATA_FLAT_XS: DATA_FLAT_XS = { x: 1, s: "string here" };
|
|
50
|
+
const DATA_FLAT_XS_HASH = "ACEB0CC65033DD85216F20CB333FA363F4AF5D601B8FBC053F9C0F10A4D6945F";
|
|
51
|
+
const REL8NS_SIMPLE: IbGibRel8ns_V1 = {
|
|
52
|
+
past: [ROOT_IBGIB_ADDR],
|
|
53
|
+
ancestor: [ROOT_IBGIB_ADDR],
|
|
54
|
+
dna: [ROOT_IBGIB_ADDR],
|
|
55
|
+
identity: [ROOT_IBGIB_ADDR],
|
|
56
|
+
}
|
|
57
|
+
const REL8NS_SIMPLE_HASH = "54E74D958F5413212BFD9A5A692B77B5EAC070E82AEAF860D0EE2CCB6113FAFF";
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A little dogfooding interface for testing
|
|
61
|
+
*/
|
|
62
|
+
interface TestData {
|
|
63
|
+
type: "falsy_data_rel8ns" | "simple_data_rel8ns";
|
|
64
|
+
ibgib: IbGibWithDataAndRel8ns;
|
|
65
|
+
ibHash: string;
|
|
66
|
+
dataHash: string;
|
|
67
|
+
rel8nsHash: string;
|
|
68
|
+
salt?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const TEST_IBGIBS: TestData[] = [
|
|
72
|
+
...FALSY_DATA_REL8NS.map(x => {
|
|
73
|
+
return {
|
|
74
|
+
type: "falsy_data_rel8ns",
|
|
75
|
+
ibgib: {
|
|
76
|
+
ib: TestIbs.ib,
|
|
77
|
+
gib: testHashes_sha256_strings.ib,
|
|
78
|
+
rel8ns: x.r,
|
|
79
|
+
},
|
|
80
|
+
ibHash: testHashes_sha256_strings.ib,
|
|
81
|
+
dataHash: "",
|
|
82
|
+
rel8nsHash: "",
|
|
83
|
+
} as TestData;
|
|
84
|
+
}),
|
|
85
|
+
{
|
|
86
|
+
type: "simple_data_rel8ns",
|
|
87
|
+
ibgib: {
|
|
88
|
+
ib: TestIbs.ib,
|
|
89
|
+
gib: "6B4084CBE160723E10DC14E9B3FC5AFCE537BB41FC00150C5403C2A62D6BE759",
|
|
90
|
+
rel8ns: REL8NS_SIMPLE,
|
|
91
|
+
data: DATA_FLAT_XY,
|
|
92
|
+
},
|
|
93
|
+
ibHash: testHashes_sha256_strings[TestIbs.ib]!,
|
|
94
|
+
rel8nsHash: REL8NS_SIMPLE_HASH,
|
|
95
|
+
dataHash: DATA_FLAT_XY_HASH,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: "simple_data_rel8ns",
|
|
99
|
+
ibgib: {
|
|
100
|
+
ib: TestIbs.ib,
|
|
101
|
+
gib: "A11967196EB5E5F1EC95A5BFA7DD9765B9B060DDAE736F597180BF9D6B53F4ED",
|
|
102
|
+
rel8ns: REL8NS_SIMPLE,
|
|
103
|
+
data: DATA_FLAT_XS,
|
|
104
|
+
},
|
|
105
|
+
ibHash: testHashes_sha256_strings[TestIbs.ib]!,
|
|
106
|
+
rel8nsHash: REL8NS_SIMPLE_HASH,
|
|
107
|
+
dataHash: DATA_FLAT_XS_HASH,
|
|
108
|
+
},
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
// #endregion
|
|
112
|
+
|
|
113
|
+
describe(`when hashing sha256v1`, () => {
|
|
114
|
+
|
|
115
|
+
it(`should hash ibgibs with empty/null/undefined data/rel8ns consistently "forever"`, async () => {
|
|
116
|
+
const ib: string = "ib";
|
|
117
|
+
const gib: string = "gib ignored when hashing";
|
|
118
|
+
const ibHash: string = await hashToHexCopy(ib) || "";
|
|
119
|
+
const dataHash: string = "";
|
|
120
|
+
const rel8nsHash: string = "";
|
|
121
|
+
const all = (ibHash + rel8nsHash + dataHash).toUpperCase();
|
|
122
|
+
const manualAllHash = (await hashToHexCopy(all))?.toUpperCase();
|
|
123
|
+
expect(manualAllHash).toEqual("E975776B1A3E4468086E1D8C409116F6E098D13BEEDFE17AF668071B5D11CD55");
|
|
124
|
+
|
|
125
|
+
const equivalents: IbGib_V1[] = [
|
|
126
|
+
// #region empty rel8ns
|
|
127
|
+
{
|
|
128
|
+
ib, gib,
|
|
129
|
+
rel8ns: EMPTY_REL8NS
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
ib, gib,
|
|
133
|
+
rel8ns: EMPTY_REL8NS,
|
|
134
|
+
data: EMPTY_DATA,
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
ib, gib,
|
|
138
|
+
rel8ns: EMPTY_REL8NS,
|
|
139
|
+
data: NULL_DATA,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
ib, gib,
|
|
143
|
+
rel8ns: EMPTY_REL8NS,
|
|
144
|
+
data: UNDEFINED_DATA,
|
|
145
|
+
},
|
|
146
|
+
// #endregion
|
|
147
|
+
// #region null rel8ns
|
|
148
|
+
{
|
|
149
|
+
ib, gib,
|
|
150
|
+
rel8ns: NULL_REL8NS,
|
|
151
|
+
data: EMPTY_DATA,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
ib, gib,
|
|
155
|
+
rel8ns: NULL_REL8NS,
|
|
156
|
+
data: NULL_DATA,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
ib, gib,
|
|
160
|
+
rel8ns: NULL_REL8NS,
|
|
161
|
+
data: UNDEFINED_DATA,
|
|
162
|
+
},
|
|
163
|
+
// #endregion
|
|
164
|
+
// #region undefined rel8ns
|
|
165
|
+
{
|
|
166
|
+
ib, gib,
|
|
167
|
+
rel8ns: UNDEFINED_REL8NS,
|
|
168
|
+
data: EMPTY_DATA,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
ib, gib,
|
|
172
|
+
rel8ns: UNDEFINED_REL8NS,
|
|
173
|
+
data: NULL_DATA,
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
ib, gib,
|
|
177
|
+
rel8ns: UNDEFINED_REL8NS,
|
|
178
|
+
data: UNDEFINED_DATA,
|
|
179
|
+
},
|
|
180
|
+
// #endregion
|
|
181
|
+
]
|
|
182
|
+
// someday change this to use the TEST_IBGIBS
|
|
183
|
+
for (let j = 0; j < equivalents.length; j++) {
|
|
184
|
+
const ibgib = equivalents[j];
|
|
185
|
+
const result = (await sha256v1(ibgib, "")).toUpperCase();
|
|
186
|
+
expect(result).toEqual(manualAllHash!);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it(`should hash ibgibs with non-null data/rel8ns consistently "forever"`, async () => {
|
|
191
|
+
for (const x of TEST_IBGIBS.filter(x => x.type === "simple_data_rel8ns")) {
|
|
192
|
+
const ibHash: string = await hashToHexCopy(x.ibgib.ib) || "";
|
|
193
|
+
const dataHash: string = await hashToHexCopy(JSON.stringify(x.ibgib.data)) || "";
|
|
194
|
+
expect(dataHash.toUpperCase()).toEqual(x.dataHash);
|
|
195
|
+
const rel8nsHash: string = await hashToHexCopy(JSON.stringify(x.ibgib.rel8ns)) || "";
|
|
196
|
+
expect(rel8nsHash.toUpperCase()).toEqual(x.rel8nsHash);
|
|
197
|
+
const all = (ibHash + rel8nsHash + dataHash).toUpperCase();
|
|
198
|
+
const manualAllHash = (await hashToHexCopy(all))?.toUpperCase();
|
|
199
|
+
expect(manualAllHash).toEqual(x.ibgib.gib);
|
|
200
|
+
|
|
201
|
+
const calculatedGibHash = (await sha256v1(x.ibgib, "")).toUpperCase();
|
|
202
|
+
expect(calculatedGibHash).toEqual(x.ibgib.gib!);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// I have one large-ish sha256 function for gibbing purposes instead of my usual
|
|
207
|
+
// breaking down into multiple smaller functions. This is specifically with having
|
|
208
|
+
// function ibgibs in mind, where the textual code is in the ibgib format
|
|
209
|
+
// (ib, gib, data, rel8ns).
|
|
210
|
+
// (dream where metabootstrapping is better)
|
|
211
|
+
// this is testing a function that is internal to the sha256v1 func.
|
|
212
|
+
// terrible as can be duplicated (i.e. not DRY), but simple albeit fragile testing
|
|
213
|
+
// for now.
|
|
214
|
+
Object.keys(testHashes_sha256_strings).forEach(x => {
|
|
215
|
+
it(`test internal hash function ib: ${x}`, async () => {
|
|
216
|
+
const result = await hashToHexCopy(x);
|
|
217
|
+
expect(result?.toUpperCase()).toEqual(testHashes_sha256_strings[x]);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { getIbGibAddr, clone, getUUID, getTimestamp } from '../../helper.mjs';
|
|
2
|
+
import { sha256v1 } from '../sha256v1.mjs';
|
|
3
|
+
import { IbGib_V1, IbGibData_V1, IbGibRel8ns_V1, Rel8n } from '../types.mjs';
|
|
4
|
+
import { TransformOpts_Fork, TransformResult } from '../../types.mjs';
|
|
5
|
+
import { IBGIB_DELIMITER, ROOT_ADDR } from '../constants.mjs';
|
|
6
|
+
import { buildDna } from './transform-helper.mjs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Original-ish V1 transform behavior.
|
|
10
|
+
* Going to create an ibGib containing the fork data.
|
|
11
|
+
* Apply that fork and create a resulting ibGib.
|
|
12
|
+
*
|
|
13
|
+
* Takes the src ibGib, clears its past and adds a link to
|
|
14
|
+
* the src via the 'ancestor' rel8n.
|
|
15
|
+
*
|
|
16
|
+
* NOTE:
|
|
17
|
+
* This is NOT going to do the plan^gib stuff ATM.
|
|
18
|
+
* Also this does NOT add any identity information ATM.
|
|
19
|
+
*/
|
|
20
|
+
export async function fork(opts: TransformOpts_Fork<IbGib_V1>): Promise<TransformResult<IbGib_V1>> {
|
|
21
|
+
const {
|
|
22
|
+
noTimestamp, dna,
|
|
23
|
+
linkedRel8ns,
|
|
24
|
+
destIb, uuid, tjp,
|
|
25
|
+
cloneRel8ns, cloneData,
|
|
26
|
+
type = 'fork',
|
|
27
|
+
} = opts;
|
|
28
|
+
let src = opts.src;
|
|
29
|
+
|
|
30
|
+
const lc = '[fork_v1]';
|
|
31
|
+
// #region validation
|
|
32
|
+
if (type !== 'fork') { throw new Error(`${lc} not a fork transform.`); }
|
|
33
|
+
if (!opts.type) { opts.type = 'fork' }
|
|
34
|
+
|
|
35
|
+
if (!src) { throw new Error(`${lc} src required to fork.`); }
|
|
36
|
+
if (!src!.ib) { throw new Error(`${lc} src.ib required.`); }
|
|
37
|
+
// destIb is not required, as it just reuses src.ib
|
|
38
|
+
if (destIb && destIb.includes(IBGIB_DELIMITER)) {
|
|
39
|
+
throw new Error(`${lc} destIb can't contain (hardcoded) delimiter right now.`);
|
|
40
|
+
}
|
|
41
|
+
if (!src!.gib) { throw new Error(`${lc} src.gib required.`); }
|
|
42
|
+
|
|
43
|
+
// #endregion
|
|
44
|
+
|
|
45
|
+
// we want to forget `src` proper very quickly because it may have other
|
|
46
|
+
// non-IbGib properties that are not relevant to our transform.
|
|
47
|
+
let dto: IbGib_V1 = { ib: src.ib, gib: src.gib, };
|
|
48
|
+
if (src.data && Object.keys(src.data).length > 0) { dto.data = src.data; }
|
|
49
|
+
if (src.rel8ns && Object.keys(src.rel8ns).length > 0) { dto.rel8ns = src.rel8ns; }
|
|
50
|
+
src = dto;
|
|
51
|
+
|
|
52
|
+
const srcAddr = getIbGibAddr({ ib: src!.ib, gib: src.gib });
|
|
53
|
+
opts.srcAddr = srcAddr;
|
|
54
|
+
|
|
55
|
+
const rel8ns: IbGibRel8ns_V1 =
|
|
56
|
+
cloneRel8ns && src.rel8ns && Object.keys(src.rel8ns).length > 0 ?
|
|
57
|
+
clone(src.rel8ns) :
|
|
58
|
+
{};
|
|
59
|
+
const data: any = cloneData && src?.data ? clone(src!.data) : {};
|
|
60
|
+
if (opts.nCounter) { data.n = 0; }
|
|
61
|
+
const ancestor = linkedRel8ns?.includes(Rel8n.ancestor) ?
|
|
62
|
+
[srcAddr] :
|
|
63
|
+
(rel8ns.ancestor || []).concat([srcAddr]);
|
|
64
|
+
rel8ns.ancestor = ancestor;
|
|
65
|
+
|
|
66
|
+
// remove tjp if exists in rel8ns
|
|
67
|
+
if (rel8ns.tjp) { delete rel8ns.tjp; }
|
|
68
|
+
|
|
69
|
+
const newIbGib = clone(src) as IbGib_V1<IbGibData_V1>;
|
|
70
|
+
if (noTimestamp && tjp?.timestamp) {
|
|
71
|
+
throw new Error(`${lc} both noTimestamp and tjp.timestamp selected.`);
|
|
72
|
+
}
|
|
73
|
+
if (!noTimestamp || tjp?.timestamp) { data.timestamp = getTimestamp(); }
|
|
74
|
+
if (tjp?.uuid || uuid) { data.uuid = await getUUID(); }
|
|
75
|
+
if (tjp?.uuid || tjp?.timestamp) {
|
|
76
|
+
data.isTjp = true;
|
|
77
|
+
} else {
|
|
78
|
+
if (data.isTjp) { delete data.isTjp; }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
newIbGib.ib = destIb || 'ib';
|
|
82
|
+
// rel8ns ignored if forking from the root ib^gib
|
|
83
|
+
if (srcAddr !== ROOT_ADDR) { newIbGib.rel8ns = rel8ns; }
|
|
84
|
+
if (Object.keys(data).length > 0) { newIbGib.data = data; }
|
|
85
|
+
|
|
86
|
+
let transformDna: IbGib_V1 | null = null;
|
|
87
|
+
if (dna) {
|
|
88
|
+
transformDna = await buildDna(opts);
|
|
89
|
+
const dnaAddr = getIbGibAddr({ ibGib: transformDna });
|
|
90
|
+
rel8ns.dna = linkedRel8ns?.includes(Rel8n.dna) ?
|
|
91
|
+
rel8ns.dna = [dnaAddr] :
|
|
92
|
+
rel8ns.dna = (rel8ns.dna || []).concat(dnaAddr);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
newIbGib.gib = await sha256v1(newIbGib, '');
|
|
96
|
+
|
|
97
|
+
const result: TransformResult<IbGib_V1> = { newIbGib };
|
|
98
|
+
if (transformDna) { result.dnas = [transformDna!] }
|
|
99
|
+
return result;
|
|
100
|
+
}
|