@ibgib/core-gib 0.1.48 → 0.1.50
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/dist/common/comment/comment-constants.d.mts +5 -0
- package/dist/common/comment/comment-constants.d.mts.map +1 -1
- package/dist/common/comment/comment-constants.mjs +5 -0
- package/dist/common/comment/comment-constants.mjs.map +1 -1
- package/dist/common/comment/comment-helper.d.mts +9 -1
- package/dist/common/comment/comment-helper.d.mts.map +1 -1
- package/dist/common/comment/comment-helper.mjs +7 -5
- package/dist/common/comment/comment-helper.mjs.map +1 -1
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs +1 -1
- package/dist/sync/sync-conflict-adv-multitimelines.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-basic-divergence.respec.mjs +1 -1
- package/dist/sync/sync-conflict-basic-divergence.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs +1 -1
- package/dist/sync/sync-conflict-basic-multitimelines.respec.mjs.map +1 -1
- package/dist/sync/sync-conflict-text-merge.respec.mjs +1 -1
- package/dist/sync/sync-conflict-text-merge.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-constants.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-constants.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-deep-updates.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs +13 -13
- package/dist/sync/sync-innerspace-dest-ahead-withid.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-dest-ahead.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-dest-ahead.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-multiple-timelines.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace-partial-update.respec.mjs +1 -1
- package/dist/sync/sync-innerspace-partial-update.respec.mjs.map +1 -1
- package/dist/sync/sync-innerspace.respec.mjs +1 -1
- package/dist/sync/sync-innerspace.respec.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-http-node-adapter.d.mts +57 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-http-node-adapter.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-http-node-adapter.mjs +310 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-http-node-adapter.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-types.d.mts +27 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-types.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-types.mjs +2 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-types.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.d.mts +29 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mjs +122 -0
- package/dist/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-types.d.mts +27 -0
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-types.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-types.mjs +2 -0
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-types.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.d.mts +24 -0
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mjs +111 -0
- package/dist/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http.respec.d.mts +8 -0
- package/dist/sync/sync-peer/sync-peer-http.respec.d.mts.map +1 -0
- package/dist/sync/sync-peer/sync-peer-http.respec.mjs +333 -0
- package/dist/sync/sync-peer/sync-peer-http.respec.mjs.map +1 -0
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs +8 -7
- package/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs.map +1 -1
- package/dist/sync/sync-peer/sync-peer-types.d.mts +5 -5
- package/dist/sync/sync-peer/sync-peer-types.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.d.mts +0 -2
- package/dist/sync/sync-peer/sync-peer-v1.d.mts.map +1 -1
- package/dist/sync/sync-peer/sync-peer-v1.mjs +21 -5
- package/dist/sync/sync-peer/sync-peer-v1.mjs.map +1 -1
- package/dist/sync/sync-saga-coordinator.mjs +1 -1
- package/dist/sync/sync-saga-coordinator.mjs.map +1 -1
- package/ibgib-foundations.md +109 -89
- package/package.json +1 -1
- package/src/common/comment/comment-constants.mts +6 -0
- package/src/common/comment/comment-helper.mts +13 -4
- package/src/sync/sync-conflict-adv-multitimelines.respec.mts +1 -1
- package/src/sync/sync-conflict-basic-divergence.respec.mts +1 -1
- package/src/sync/sync-conflict-basic-multitimelines.respec.mts +1 -1
- package/src/sync/sync-conflict-text-merge.respec.mts +1 -1
- package/src/sync/sync-innerspace-constants.respec.mts +1 -1
- package/src/sync/sync-innerspace-deep-updates.respec.mts +1 -1
- package/src/sync/sync-innerspace-dest-ahead-withid.respec.mts +12 -12
- package/src/sync/sync-innerspace-dest-ahead.respec.mts +1 -1
- package/src/sync/sync-innerspace-multiple-timelines.respec.mts +1 -1
- package/src/sync/sync-innerspace-partial-update.respec.mts +1 -1
- package/src/sync/sync-innerspace.respec.mts +1 -1
- package/src/sync/sync-peer/sync-peer-http-receiver/sync-http-node-adapter.mts +319 -0
- package/src/sync/sync-peer/sync-peer-http-receiver/sync-http-node-adapter.mts.metadata.md +72 -0
- package/src/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-types.mts +30 -0
- package/src/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mts +146 -0
- package/src/sync/sync-peer/sync-peer-http-receiver/sync-peer-http-receiver-v1.mts.metadata.md +71 -0
- package/src/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-types.mts +32 -0
- package/src/sync/sync-peer/sync-peer-http-sender/sync-peer-http-sender-v1.mts +129 -0
- package/src/sync/sync-peer/sync-peer-http.respec.mts +364 -0
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-types.mts +8 -8
- package/src/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mts +10 -7
- package/src/sync/sync-peer/sync-peer-types.mts +11 -11
- package/src/sync/sync-peer/sync-peer-v1.mts +5 -7
- package/src/sync/sync-saga-coordinator.mts +1 -1
- package/tmp-certs/server.pfx +0 -0
package/ibgib-foundations.md
CHANGED
|
@@ -6,102 +6,120 @@ This document serves as an onboarding guide and technical reference for the **ib
|
|
|
6
6
|
|
|
7
7
|
At its lowest level, anything in the system is an **ibGib**.
|
|
8
8
|
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* **ib**: The "Metadata". Often a string like "comment", "pic", or "link". It can be descriptive or functional (e.g., class names).
|
|
10
|
+
* **gib**: The "Hash". A cryptographic hash (SHA-256 in V1) of the entire ibGib record.
|
|
11
|
+
* **ib^gib**: The content address. Uniquely identifies a record in the universe.
|
|
12
12
|
|
|
13
13
|
### `gib` Nuances: Punctiliar vs. TJP
|
|
14
14
|
The `gib` is more than a single hash; it encodes timeline context.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
* **Punctiliar Hash**: The hash of *just* the current frame's content. Every ibgib has this.
|
|
16
|
+
* **TJP Gib (Timeline ID)**: The `gib` of the **Temporal Junction Point (TJP)**—the very first frame (Genesis/Fork) of the timeline.
|
|
17
|
+
* **Composite Address**: Use `ib^[punctiliar_hash].[tjp_gib]`.
|
|
18
|
+
* Example: `comment^<CURRENT_HASH>.<GENESIS_HASH>`
|
|
19
|
+
* This allows us to identify *which* timeline a frame belongs to simply by looking at its address.
|
|
20
|
+
* The `tjp` frame itself has a single hash (since its punctiliar hash IS the tjp gib).
|
|
21
21
|
|
|
22
22
|
### Structure
|
|
23
23
|
An `IbGib_V1` object has two primary payload containers:
|
|
24
|
-
1.
|
|
25
|
-
2.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
1. **data**: Intrinsic, immutable properties. (e.g., text content, configuration flags).
|
|
25
|
+
2. **rel8ns**: Extrinsic, Directed Acyclic Graph (DAG) links to other ibGibs.
|
|
26
|
+
* Named edges (e.g., `past`, `ancestor`, `pic`).
|
|
27
|
+
* Always stored as an array of addresses (`IbGibAddr[]`).
|
|
28
28
|
|
|
29
29
|
### Transforms (The "Verbs")
|
|
30
30
|
State is never mutated in place; it is evolved via transforms.
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
31
|
+
* **[fork](file:../libs/ts-gib/src/V1/transforms/fork.mts)**: Creates a new timeline.
|
|
32
|
+
* **Crucial**: Appends to `ancestor` but **CLEARS** the `past` rel8n. This is what births a new timeline.
|
|
33
|
+
* **[mut8](file:../libs/ts-gib/src/V1/transforms/mut8.mts)** (Mutate): Evolves intrinsic data.
|
|
34
|
+
* **Accretive**: By default, it *appends* the new address to the `past` array. It does **not** create a linked list unless `linkedRel8ns` is explicitly used.
|
|
35
|
+
* Access the immediate past via `ibgib.rel8ns.past.at(-1)`.
|
|
36
|
+
* **[rel8](file:../libs/ts-gib/src/V1/transforms/rel8.mts)** (Relate): Evolves extrinsic relationships.
|
|
37
|
+
* Also accretive by default.
|
|
38
38
|
|
|
39
39
|
### DNA (The "How")
|
|
40
40
|
The **`dna`** rel8n is a critical component for distributed consistency.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
41
|
+
* **Memoization**: It stores the *arguments* used to create a transform (e.g., the specific `dataToAddOrPatch` in a `mut8`).
|
|
42
|
+
* **In-Structure History**: These arguments are embedded directly in the ibGib structure via the `dna` rel8n.
|
|
43
|
+
* **Merge Strategy**: When resolving divergent timelines, we don't just compare the final state. We examine the `dna` to understand the *intent* of the divergence.
|
|
44
|
+
* *Example*: Two users edit a comment. One fixes a typo, one adds a sentence. By examining the `dna` (the `mut8` args), we can construct a new transform that applies both changes, rather than one overwriting the other.
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
## 2. Higher-Level Architecture (`core-gib`)
|
|
48
48
|
|
|
49
49
|
### Witness Pattern
|
|
50
50
|
The **[Witness](file:src/witness/witness-types.mts)** is the core functional paradigm.
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
51
|
+
* **Concept**: An ibGib that "observes" (witnesses) another ibGib and produces a result.
|
|
52
|
+
* **Benefits**:
|
|
53
|
+
* **Memoization**: Enables memoizing inputs, outputs, and parameters of the witness class itself.
|
|
54
|
+
* **Aspect-Oriented Composeability**: Provides a single interaction point for easy composition of behaviors (logging, security, permissions).
|
|
55
|
+
* **Interface**: `witness(arg: IbGib) -> Promise<IbGib>`
|
|
56
56
|
|
|
57
57
|
### Space Paradigm & Metaspace
|
|
58
58
|
**[Space](file:src/witness/space/space-types.mts)** is a specialized Witness responsible for storage and retrieval.
|
|
59
|
-
*
|
|
60
|
-
*
|
|
59
|
+
* **Commands**: `put`, `get`, `delete`.
|
|
60
|
+
* **Locations**: `local`, `sync`, `innerspace` (memory-only/test).
|
|
61
61
|
|
|
62
62
|
**[Metaspace](file:src/witness/space/metaspace/metaspace-types.mts)**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
63
|
+
* **Role**: Currently acts as a **Singleton Facade** for the runtime context.
|
|
64
|
+
* Does NOT yet actively route "get from any space" requests (though planned).
|
|
65
|
+
* Initializes default local spaces.
|
|
66
|
+
* **Persistence vs. Indexing**:
|
|
67
|
+
* `metaspace.put`: Persists the ibGib to the underlying space(s) via `putInSpace`.
|
|
68
|
+
* `metaspace.registerNewIbGib`: Updates the *index* (e.g., "Latest" pointers for timelines) and broadcasts the event via `registerNewIbGib` with the pre-configured `fnBroadcast` when metaspace is initialized.
|
|
69
|
+
* *Usage*: put first, then register (skipping register only in rare cases).
|
|
70
70
|
|
|
71
71
|
### Timeline Facade (`timeline-api`)
|
|
72
72
|
**[Timeline API](file:src/timeline/timeline-api.mts)** acts as a consumer-friendly facade over the raw Witness/Transform calls.
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
|
|
76
|
-
### respec-gib Test Framework
|
|
77
|
-
|
|
78
|
-
`
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
*
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
73
|
+
* **Purpose**: Simplifies common operations like "Update this timeline with new data" (`mut8Timeline`).
|
|
74
|
+
* **Abstraction**: Hides the complexity of TJP lookup, generic transforms, and graph traversal.
|
|
75
|
+
|
|
76
|
+
### *respec-gib* Test Framework
|
|
77
|
+
|
|
78
|
+
Since `ibgib` has unique execution environment requirements and a high need for custom asynchronous block handling, it uses a custom testing framework located in `@ibgib/helper-gib/dist/respec-gib`. Each lib/app has its own test runner script located in [lib/app]/src/respec-gib.node.mts, e.g., libs/helper-gib/src/respec-gib.node.mts or libs/core-gib/src/respec-gib.node.mts.
|
|
79
|
+
|
|
80
|
+
Key features include:
|
|
81
|
+
* **`respecfully`**: The equivalent of `describe` or an outer test suite block.
|
|
82
|
+
* async call, MUST USE await
|
|
83
|
+
* organizational block
|
|
84
|
+
* YES can be nested
|
|
85
|
+
* **`ifWe`**: The equivalent of `it`, used for defining a specific test case block.
|
|
86
|
+
* async call, MUST USE await
|
|
87
|
+
* can NOT be nested
|
|
88
|
+
* **`ifWeMight`**: A focused test case (equivalent to `fit` or `it.only`). Using this will restrict execution to only the `ifWeMight` block(s) and skip all others.
|
|
89
|
+
* async call, MUST USE await
|
|
90
|
+
* can NOT be nested
|
|
91
|
+
* **`iReckon`**: The assertion fluent API (equivalent to `expect`).
|
|
92
|
+
* sync call, do NOT await
|
|
93
|
+
* Only specific assertion methods are available compared to other bigger (and funded/helped) testing frameworks:
|
|
94
|
+
* *Assertions*:
|
|
95
|
+
* `willEqual(expected)` - Tests deep equality or reference equality.
|
|
96
|
+
* `isGonnaBe(expected)` - Tests equality.
|
|
97
|
+
* `isGonnaBeTruthy()` / `isGonnaBeFalsy()` - Tests truthiness.
|
|
98
|
+
* `isGonnaBeTrue()` / `isGonnaBeFalse()` - Strict equality to true/false.
|
|
99
|
+
* `isGonnaBeUndefined()` - Strict equality to undefined.
|
|
100
|
+
* `includes(expected)` - Tests array or substring inclusion.
|
|
101
|
+
* *Modifiers*:
|
|
102
|
+
* **`.not`**: Can precede any assertion (e.g., `iReckon(sir, x).not.isGonnaBe(true)`).
|
|
103
|
+
* **`.asTo(label)`**: Used to add context to the error message (e.g., `iReckon(sir, x).asTo("Checking user ID").willEqual(5)`).
|
|
104
|
+
* Setup and Teardown methods run dynamically per suite context:
|
|
105
|
+
* `firstOfAll` / `lastOfAll` - Runs once per outer suite.
|
|
106
|
+
* `firstOfEach` / `lastOfEach` - Runs before/after each inner child (`respecfully` or `ifWe/Might`), or modify the `ifWeMight` regex in `src/respec-gib.node.mts` to focus specific test files.
|
|
89
107
|
|
|
90
108
|
### Timelines & Temporal Junction Points (TJPs)
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
*
|
|
109
|
+
* **Accretion vs. Linked List**: Timelines are typically **accretive**. We carry the full history of addresses in the `past` array (`past: [h1, h2, h3...]`).
|
|
110
|
+
* *Tradeoff*: Increases metadata size but avoids O(N) network fetches required to traverse a linked list history.
|
|
111
|
+
* *Optimization*: Future storage engines will compress this redundancy.
|
|
112
|
+
* **TJP**: The stable identifier. In code, the TJP's `gib` is often used as the **Lock Scope** to serialize transforms on that timeline.
|
|
95
113
|
|
|
96
114
|
### IMPORTANT: Ancestor vs. Previous Frame
|
|
97
115
|
It is critical to distinguish between these two relationships:
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
116
|
+
* **Previous Frame (`past`)**: Points to the immediate predecessor in the *same* timeline. This is the "parent" in the Git commit sense.
|
|
117
|
+
* *Usage*: `mut8`, `rel8`.
|
|
118
|
+
* *Meaning*: "I am the next step in this timeline."
|
|
119
|
+
* **Ancestor (`ancestor`)**: Points to the source from which a *new* timeline was spawned.
|
|
120
|
+
* *Usage*: **ONLY** `fork`.
|
|
121
|
+
* *Meaning*: "I am the beginning of a *new* timeline that came from that timeline."
|
|
122
|
+
* *Constraint*: A `fork` transform clears the `past` array and adds the source to `ancestor`.
|
|
105
123
|
|
|
106
124
|
> [!IMPORTANT]
|
|
107
125
|
> Never use "ancestor" to refer to the previous frame in a timeline history. That is the "past". Ancestor implies a fork.
|
|
@@ -112,36 +130,38 @@ The Sync Protocol is a **Symmetric, Peer-to-Peer** protocol modeled as a "Saga".
|
|
|
112
130
|
See: **[Sync README](file:src/sync/README.md)**
|
|
113
131
|
|
|
114
132
|
### Core Components
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
133
|
+
* **[SyncSagaIbGib](file:src/sync/sync-types.mts)**: The timeline tracking the sync session itself. Acts as an audit trail.
|
|
134
|
+
* **[SyncSagaCoordinator](file:src/sync/sync-saga-coordinator.mts)**: The State Machine driver. Code is identical on both "Alice" (Source) and "Bob" (Destination) nodes.
|
|
135
|
+
* **Message Stones**: Immutable data packets passed between peers (Init, Ack, Delta, Commit).
|
|
118
136
|
|
|
119
137
|
### Protocol Flow
|
|
120
|
-
1.
|
|
121
|
-
2.
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
3.
|
|
126
|
-
4.
|
|
127
|
-
5.
|
|
138
|
+
1. **Init**: Sender generates a **Knowledge Vector** (KV) summary.
|
|
139
|
+
2. **Gap Analysis**: Receiver compares KVs.
|
|
140
|
+
* Sender behind -> **Push Offer**.
|
|
141
|
+
* Sender ahead -> **Delta Request**.
|
|
142
|
+
* Diverged -> **Conflict**.
|
|
143
|
+
3. **Ack**: Receiver sends back lists of needs/offers.
|
|
144
|
+
4. **Delta/Push**: Data exchange.
|
|
145
|
+
5. **Commit**: Session finalized.
|
|
128
146
|
|
|
129
147
|
## 4. Identity (Keystone)
|
|
130
148
|
|
|
131
149
|
**[Keystone](file:src/keystone/README.md)** is a novel, graph-native identity mechanism using **Hash-Based Cryptography** (Post-Quantum ready).
|
|
132
150
|
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
151
|
+
* **Concept**: An identity is not a public key; it is a **Timeline** (Keystone). Verification is **Auditability**. To verify "Alice", you replay her Keystone timeline from Genesis to now, verifying proofs at each step.
|
|
152
|
+
* **Mechanisms**:
|
|
153
|
+
* **Hash-Reveal**: Uses schemes similar to **Lamport Signatures** or **Winternitz OTS**, but adapted for the ibGib graph.
|
|
154
|
+
* **Merkle DAGs**: Efficiently communicates identity state by only syncing missing graph nodes.
|
|
155
|
+
* **Sigma Protocols**: Can support zero-knowledge proofs for authentication without revealing private keys.
|
|
156
|
+
* Only partially implemented
|
|
157
|
+
* **Session Identity**: In Sync, we use ephemeral "Session Keystones" to sign the Saga, ensuring the integrity of the sync session without exposing long-term Master Identity keys.
|
|
158
|
+
* Only partially implemented
|
|
139
159
|
|
|
140
160
|
## Reference Links
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
161
|
+
* **Core Types**: [libs/ts-gib/src/types.mts](file:../libs/ts-gib/src/types.mts)
|
|
162
|
+
* **Transforms**: [libs/ts-gib/src/V1/transforms/](file:../libs/ts-gib/src/V1/transforms/)
|
|
163
|
+
* **Witness**: [libs/core-gib/src/witness/witness-types.mts](file:src/witness/witness-types.mts)
|
|
164
|
+
* **Space**: [libs/core-gib/src/witness/space/space-types.mts](file:src/witness/space/space-types.mts)
|
|
165
|
+
* **Timeline API**: [libs/core-gib/src/timeline/timeline-api.mts](file:src/timeline/timeline-api.mts)
|
|
166
|
+
* **Sync Coordinator**: [libs/core-gib/src/sync/sync-saga-coordinator.mts](file:src/sync/sync-saga-coordinator.mts)
|
|
167
|
+
* **Keystone**: [libs/core-gib/src/keystone/README.md](file:src/keystone/README.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ibgib/core-gib",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.50",
|
|
4
4
|
"description": "ibgib core functionality, including base architecture for witnesses, spaces, apps, robbots, etc., as well as shared utility functions. Node v19+ needed for heavily-used isomorphic webcrypto hashing consumed in both node and browsers.",
|
|
5
5
|
"funding": {
|
|
6
6
|
"type": "individual",
|
|
@@ -8,3 +8,9 @@ export const DEFAULT_COMMENT_TEXT_IB_SUBSTRING_LENGTH = 20;
|
|
|
8
8
|
* @example "comment thisisacomm here_is_addl_metadata"
|
|
9
9
|
*/
|
|
10
10
|
export const DEFAULT_COMMENT_METADATA_IB_SUBSTRING_LENGTH = 128;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* if whitespace-only comment ibgib is enabled, the ib will contain this in
|
|
14
|
+
* place of the whitespace text.
|
|
15
|
+
*/
|
|
16
|
+
export const COMMENT_IB_WHITESPACE_ONLY_TEXT = '___whitespace___';
|
|
@@ -6,7 +6,7 @@ import { GLOBAL_LOG_A_LOT } from '../../core-constants.mjs';
|
|
|
6
6
|
import { IbGibSpaceAny } from '../../witness/space/space-base-v1.mjs';
|
|
7
7
|
import { persistTransformResult } from '../../witness/space/space-helper.mjs';
|
|
8
8
|
import { CommentData_V1, CommentIbGib_V1 } from './comment-types.mjs';
|
|
9
|
-
import { DEFAULT_COMMENT_METADATA_IB_SUBSTRING_LENGTH, DEFAULT_COMMENT_TEXT_IB_SUBSTRING_LENGTH } from './comment-constants.mjs';
|
|
9
|
+
import { COMMENT_IB_WHITESPACE_ONLY_TEXT, DEFAULT_COMMENT_METADATA_IB_SUBSTRING_LENGTH, DEFAULT_COMMENT_TEXT_IB_SUBSTRING_LENGTH } from './comment-constants.mjs';
|
|
10
10
|
|
|
11
11
|
const logalot = GLOBAL_LOG_A_LOT || false;
|
|
12
12
|
|
|
@@ -100,6 +100,7 @@ export async function createCommentIbGib({
|
|
|
100
100
|
addlMetadataText,
|
|
101
101
|
saveInSpace,
|
|
102
102
|
space,
|
|
103
|
+
dontTrimText,
|
|
103
104
|
}: {
|
|
104
105
|
/**
|
|
105
106
|
* comment text
|
|
@@ -121,6 +122,14 @@ export async function createCommentIbGib({
|
|
|
121
122
|
* this space.
|
|
122
123
|
*/
|
|
123
124
|
space?: IbGibSpaceAny,
|
|
125
|
+
/**
|
|
126
|
+
* If true, stores `text` verbatim without trimming leading/trailing
|
|
127
|
+
* whitespace. Required for lossless chunking where rawTexts must tile the
|
|
128
|
+
* parent source exactly.
|
|
129
|
+
*
|
|
130
|
+
* Default: false (existing behaviour — trims whitespace).
|
|
131
|
+
*/
|
|
132
|
+
dontTrimText?: boolean,
|
|
124
133
|
}): Promise<TransformResult<CommentIbGib_V1>> {
|
|
125
134
|
const lc = `[${createCommentIbGib.name}]`;
|
|
126
135
|
|
|
@@ -128,16 +137,16 @@ export async function createCommentIbGib({
|
|
|
128
137
|
try {
|
|
129
138
|
if (!text) { throw new Error(`text required (E: 3e3d0f555e1a83771a6548eb10943522)`); }
|
|
130
139
|
|
|
131
|
-
text = text.trim();
|
|
140
|
+
if (!dontTrimText) { text = text.trim(); }
|
|
132
141
|
|
|
133
|
-
if (!text) { throw new Error(`text cannot be only whitespace (E: d6db3537b9834294836aeb70987c908e)`); }
|
|
142
|
+
if (!text) { throw new Error(`text cannot be only whitespace when dontTrimText is falsy. (E: d6db3537b9834294836aeb70987c908e)`); }
|
|
134
143
|
|
|
135
144
|
const data: CommentData_V1 = { text, textTimestamp: getTimestamp() };
|
|
136
145
|
|
|
137
146
|
// create an ibgib with the filename and ext
|
|
138
147
|
const opts: any = {
|
|
139
148
|
parentIbGib: factory.primitive({ ib: 'comment' }),
|
|
140
|
-
ib: getCommentIb({ commentText: text, addlMetadataText }),
|
|
149
|
+
ib: getCommentIb({ commentText: text.trim() || COMMENT_IB_WHITESPACE_ONLY_TEXT, addlMetadataText }),
|
|
141
150
|
data,
|
|
142
151
|
dna: true,
|
|
143
152
|
tjp: { uuid: true, timestamp: true },
|
|
@@ -86,7 +86,7 @@ await respecfully(sir, `Multi-round/timeline permutations`, async () => {
|
|
|
86
86
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
87
87
|
await peer.initialized;
|
|
88
88
|
await peer.initializeOpts({
|
|
89
|
-
|
|
89
|
+
localSpace: sourceSpace,
|
|
90
90
|
receiverSpace: destSpace,
|
|
91
91
|
receiverCoordinator: receiverCoordinator,
|
|
92
92
|
receiverMetaspace: metaspace,
|
|
@@ -222,7 +222,7 @@ await respecfully(sir, `Two different fields`, async () => {
|
|
|
222
222
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
223
223
|
await peer.initialized;
|
|
224
224
|
await peer.initializeOpts({
|
|
225
|
-
|
|
225
|
+
localSpace: sourceSpace, // "Client"
|
|
226
226
|
receiverSpace: destSpace, // "Server"
|
|
227
227
|
receiverCoordinator,
|
|
228
228
|
receiverMetaspace: metaspace,
|
|
@@ -208,7 +208,7 @@ await respecfully(sir, `Two different fields and rel8d`, async () => {
|
|
|
208
208
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
209
209
|
await peer.initialized;
|
|
210
210
|
await peer.initializeOpts({
|
|
211
|
-
|
|
211
|
+
localSpace: sourceSpace, // "Client"
|
|
212
212
|
receiverSpace: destSpace, // "Server"
|
|
213
213
|
receiverCoordinator,
|
|
214
214
|
receiverMetaspace: metaspace,
|
|
@@ -88,7 +88,7 @@ await respecfully(sir, `Text merge (LCS) conflict resolution`, async () => {
|
|
|
88
88
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
89
89
|
await peer.initialized;
|
|
90
90
|
await peer.initializeOpts({
|
|
91
|
-
|
|
91
|
+
localSpace: sourceSpace,
|
|
92
92
|
receiverSpace: destSpace,
|
|
93
93
|
receiverCoordinator: receiverCoordinator,
|
|
94
94
|
receiverMetaspace: metaspace,
|
|
@@ -73,7 +73,7 @@ await respecfully(sir, `Sync Constants (No TJP)`, async () => {
|
|
|
73
73
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
74
74
|
await peer.initialized;
|
|
75
75
|
await peer.initializeOpts({
|
|
76
|
-
|
|
76
|
+
localSpace: sourceSpace, // "Client"
|
|
77
77
|
receiverSpace: destSpace, // "Server"
|
|
78
78
|
receiverCoordinator,
|
|
79
79
|
receiverMetaspace: metaspace,
|
|
@@ -104,7 +104,7 @@ await respecfully(sir, `Sync InnerSpaces (Deep Updates)`, async () => {
|
|
|
104
104
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
105
105
|
await peer.initialized;
|
|
106
106
|
await peer.initializeOpts({
|
|
107
|
-
|
|
107
|
+
localSpace: sourceSpace, // "Client"
|
|
108
108
|
receiverSpace: destSpace, // "Server"
|
|
109
109
|
receiverCoordinator,
|
|
110
110
|
receiverMetaspace: metaspace,
|
|
@@ -124,7 +124,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
124
124
|
return resGet.success && resGet.ibGibs && resGet.ibGibs.length === 1;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
await
|
|
127
|
+
await ifWe(sir, 'verify setup', async () => {
|
|
128
128
|
// Ensure V2 is ONLY in Dest (it is, per `space: destSpace`)
|
|
129
129
|
// Ensure Source does NOT have V2
|
|
130
130
|
iReckon(sir, await fnAddrExistsInSpace(addrV0, sourceSpace)).asTo('source has V0').isGonnaBeTrue();
|
|
@@ -143,7 +143,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
143
143
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
144
144
|
await peer.initialized;
|
|
145
145
|
await peer.initializeOpts({
|
|
146
|
-
|
|
146
|
+
localSpace: sourceSpace, // "Client"
|
|
147
147
|
receiverSpace: destSpace, // "Server"
|
|
148
148
|
receiverCoordinator,
|
|
149
149
|
receiverMetaspace: metaspace,
|
|
@@ -193,7 +193,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
193
193
|
// 5. Verify Sync (v2 should be in both source and dest now)
|
|
194
194
|
console.log(`${lc} Verifying Sync...`);
|
|
195
195
|
|
|
196
|
-
await
|
|
196
|
+
await ifWe(sir, `verify v2 now also in source`, async () => {
|
|
197
197
|
// Verify Tip (V2)
|
|
198
198
|
|
|
199
199
|
iReckon(sir, await fnAddrExistsInSpace(addrV0, sourceSpace)).asTo('source has V0').isGonnaBeTrue();
|
|
@@ -205,7 +205,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
205
205
|
|
|
206
206
|
});
|
|
207
207
|
|
|
208
|
-
await
|
|
208
|
+
await ifWe(sir, `dependency graphs the same`, async () => {
|
|
209
209
|
|
|
210
210
|
const sourceDepGraph = await getDependencyGraph({
|
|
211
211
|
ibGibAddr: addrV2,
|
|
@@ -234,7 +234,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
234
234
|
// For now, we'll retrieve from spaces after sync completes
|
|
235
235
|
let sessionKeystoneAddr: IbGibAddr | undefined;
|
|
236
236
|
|
|
237
|
-
await
|
|
237
|
+
await ifWe(sir, 'IDENTITY: session keystone exists in sender space', async () => {
|
|
238
238
|
// TODO: Get saga IbGib and access sessionKeystones rel8n
|
|
239
239
|
// Once saga access is implemented (per Bill's guidance), retrieve keystone addr from:
|
|
240
240
|
// const keystoneAddrs = sagaIbGib.rel8ns?.sessionKeystones;
|
|
@@ -258,7 +258,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
258
258
|
.isGonnaBeTrue();
|
|
259
259
|
});
|
|
260
260
|
|
|
261
|
-
await
|
|
261
|
+
await ifWe(sir, 'IDENTITY: session keystone exists in receiver space', async () => {
|
|
262
262
|
// Session keystone should be transferred to receiver's durable space
|
|
263
263
|
iReckon(sir, sessionKeystoneAddr)
|
|
264
264
|
.asTo('session keystone address was captured')
|
|
@@ -272,7 +272,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
272
272
|
}
|
|
273
273
|
});
|
|
274
274
|
|
|
275
|
-
await
|
|
275
|
+
await ifWe(sir, 'IDENTITY: saga frames are signed', async () => {
|
|
276
276
|
// TODO: Get saga frames and check each has a proof
|
|
277
277
|
// This will FAIL when we actually check - that's the point (TDD RED)
|
|
278
278
|
|
|
@@ -281,7 +281,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
281
281
|
.isGonnaBeTrue();
|
|
282
282
|
});
|
|
283
283
|
|
|
284
|
-
await
|
|
284
|
+
await ifWe(sir, 'IDENTITY: frame signatures are valid', async () => {
|
|
285
285
|
// TODO: For each saga frame, validate proof against session keystone
|
|
286
286
|
// const isValid = await validateProofWithKeystone({
|
|
287
287
|
// proof: frame.proof,
|
|
@@ -296,7 +296,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
296
296
|
.isGonnaBeTrue();
|
|
297
297
|
});
|
|
298
298
|
|
|
299
|
-
await
|
|
299
|
+
await ifWe(sir, 'IDENTITY: session keystone challenges are depleted', async () => {
|
|
300
300
|
// TODO: Session keystone should evolve after signing frames
|
|
301
301
|
// This will FAIL because keystone evolution not implemented yet
|
|
302
302
|
|
|
@@ -305,7 +305,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
305
305
|
.isGonnaBeTrue();
|
|
306
306
|
});
|
|
307
307
|
|
|
308
|
-
await
|
|
308
|
+
await ifWe(sir, 'IDENTITY: frame timestamps are present and fresh', async () => {
|
|
309
309
|
// TODO: Check each frame has timestamp in proof claim
|
|
310
310
|
// const claim = JSON.parse(frame.proof.claim.scope);
|
|
311
311
|
// iReckon(sir, claim.timestamp).asTo('has timestamp').isGonnaBeTruthy();
|
|
@@ -318,7 +318,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
318
318
|
.isGonnaBeTrue();
|
|
319
319
|
});
|
|
320
320
|
|
|
321
|
-
await
|
|
321
|
+
await ifWe(sir, 'IDENTITY: keystone has no hard links to domain ibgibs', async () => {
|
|
322
322
|
if (sessionKeystoneAddr) {
|
|
323
323
|
const keystoneResult = await getFromSpace({
|
|
324
324
|
addr: sessionKeystoneAddr,
|
|
@@ -343,7 +343,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
343
343
|
}
|
|
344
344
|
});
|
|
345
345
|
|
|
346
|
-
await
|
|
346
|
+
await ifWe(sir, 'IDENTITY: saga frames have no hard links to domain ibgibs', async () => {
|
|
347
347
|
// Saga frames should NOT have hard links to domain ibgibs
|
|
348
348
|
// This currently PASSES but will expose issues if hard links exist
|
|
349
349
|
|
|
@@ -135,7 +135,7 @@ await respecfully(sir, `Sync InnerSpaces (Dest Ahead)`, async () => {
|
|
|
135
135
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
136
136
|
await peer.initialized;
|
|
137
137
|
await peer.initializeOpts({
|
|
138
|
-
|
|
138
|
+
localSpace: sourceSpace, // "Client"
|
|
139
139
|
receiverSpace: destSpace, // "Server"
|
|
140
140
|
receiverCoordinator,
|
|
141
141
|
receiverMetaspace: metaspace,
|
|
@@ -108,7 +108,7 @@ await respecfully(sir, `Sync InnerSpaces (Multiple Timelines)`, async () => {
|
|
|
108
108
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
109
109
|
await peer.initialized;
|
|
110
110
|
await peer.initializeOpts({
|
|
111
|
-
|
|
111
|
+
localSpace: sourceSpace, // "Client"
|
|
112
112
|
receiverSpace: destSpace, // "Server"
|
|
113
113
|
receiverCoordinator,
|
|
114
114
|
receiverMetaspace: metaspace,
|
|
@@ -116,7 +116,7 @@ await respecfully(sir, `Sync InnerSpaces (Partial Update)`, async () => {
|
|
|
116
116
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
117
117
|
await peer.initialized;
|
|
118
118
|
await peer.initializeOpts({
|
|
119
|
-
|
|
119
|
+
localSpace: sourceSpace, // "Client"
|
|
120
120
|
receiverSpace: destSpace, // "Server"
|
|
121
121
|
receiverCoordinator,
|
|
122
122
|
receiverMetaspace: metaspace,
|
|
@@ -108,7 +108,7 @@ await respecfully(sir, `Sync InnerSpaces`, async () => {
|
|
|
108
108
|
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
109
109
|
await peer.initialized;
|
|
110
110
|
await peer.initializeOpts({
|
|
111
|
-
|
|
111
|
+
localSpace: sourceSpace, // "Client"
|
|
112
112
|
receiverSpace: destSpace, // "Server"
|
|
113
113
|
receiverCoordinator,
|
|
114
114
|
receiverMetaspace: metaspace,
|