@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
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sync-peer-http-sender-v1
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
6
|
+
import { SyncPeer_V1 } from '../sync-peer-v1.mjs';
|
|
7
|
+
import { SyncSagaContextIbGib_V1 } from '../../sync-saga-context/sync-saga-context-types.mjs';
|
|
8
|
+
import { IbGibSpaceAny } from '../../../witness/space/space-base-v1.mjs';
|
|
9
|
+
import { GLOBAL_LOG_A_LOT } from '../../../core-constants.mjs';
|
|
10
|
+
import {
|
|
11
|
+
InitializeSyncPeerHttpSenderOpts,
|
|
12
|
+
SyncPeerHttpSenderData_V1,
|
|
13
|
+
SyncPeerHttpSenderRel8ns_V1,
|
|
14
|
+
SyncPeerHttpSenderIbGib_V1
|
|
15
|
+
} from './sync-peer-http-sender-types.mjs';
|
|
16
|
+
|
|
17
|
+
const logalot = GLOBAL_LOG_A_LOT;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Http Sender Peer implementation.
|
|
21
|
+
* Sends Context to a remote server utilizing POST for uplink and SSE for downlink.
|
|
22
|
+
*/
|
|
23
|
+
export class SyncPeerHttpSender_V1
|
|
24
|
+
extends SyncPeer_V1<InitializeSyncPeerHttpSenderOpts>
|
|
25
|
+
implements SyncPeerHttpSenderIbGib_V1 {
|
|
26
|
+
|
|
27
|
+
protected override lc: string = `[${SyncPeerHttpSender_V1.name}]`;
|
|
28
|
+
|
|
29
|
+
override get classname(): string {
|
|
30
|
+
return SyncPeerHttpSender_V1.name;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare data: SyncPeerHttpSenderData_V1 | undefined;
|
|
34
|
+
declare rel8ns: SyncPeerHttpSenderRel8ns_V1 | undefined;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Stored reference to the SSE EventSource connection.
|
|
38
|
+
* Ensure you polyfill EventSource in Node environments if needed.
|
|
39
|
+
*/
|
|
40
|
+
protected eventSource?: EventSource;
|
|
41
|
+
|
|
42
|
+
constructor(
|
|
43
|
+
initialData: SyncPeerHttpSenderData_V1,
|
|
44
|
+
initialRel8ns?: SyncPeerHttpSenderRel8ns_V1,
|
|
45
|
+
) {
|
|
46
|
+
super(initialData, initialRel8ns);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
protected override async sendContextRequest(context: SyncSagaContextIbGib_V1): Promise<SyncSagaContextIbGib_V1 | undefined> {
|
|
52
|
+
const lc = `${this.lc}[${this.sendContextRequest.name}]`;
|
|
53
|
+
try {
|
|
54
|
+
if (logalot) { console.log(`${lc} starting...`); }
|
|
55
|
+
|
|
56
|
+
if (!this.data?.syncEventsRoute) { throw new Error(`data.syncEventsRoute required.`); }
|
|
57
|
+
if (!this.data?.syncRoute) { throw new Error(`data.syncRoute required.`); }
|
|
58
|
+
|
|
59
|
+
// 1. Establish SSE connection to `this.data.syncEventsRoute` if not already open
|
|
60
|
+
// (In a real implementation, you might initialize this elsewhere or ensure it stays reconnecting)
|
|
61
|
+
if (!this.eventSource) {
|
|
62
|
+
if (logalot) { console.log(`${lc} initializing EventSource to ${this.data.syncEventsRoute}`); }
|
|
63
|
+
this.eventSource = new EventSource(this.data.syncEventsRoute);
|
|
64
|
+
this.eventSource.onerror = (err) => console.error(`${lc} EventSource error:`, err);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return new Promise<SyncSagaContextIbGib_V1 | undefined>(async (resolve, reject) => {
|
|
68
|
+
// 2. Setup listeners for SSE incoming context and ibgib payloads
|
|
69
|
+
const onMessage = async (event: MessageEvent) => {
|
|
70
|
+
try {
|
|
71
|
+
const parsedData = JSON.parse(event.data);
|
|
72
|
+
|
|
73
|
+
// TODO [USER]: Determine if `parsedData` is a domain payload ibGib OR the final response context.
|
|
74
|
+
// e.g.:
|
|
75
|
+
// if (parsedData.isDomainIbGib) {
|
|
76
|
+
// // Deserialize to IbGib_V1
|
|
77
|
+
// const ibGib = parsedData;
|
|
78
|
+
// await this.payloadIbGibsDomainReceived$.next(ibGib);
|
|
79
|
+
// } else if (parsedData.isResponseContext) {
|
|
80
|
+
// // Deserialize to SyncSagaContextIbGib_V1
|
|
81
|
+
// const responseContext = parsedData;
|
|
82
|
+
// this.eventSource?.removeEventListener('message', onMessage);
|
|
83
|
+
// resolve(responseContext);
|
|
84
|
+
// }
|
|
85
|
+
} catch (e) {
|
|
86
|
+
console.error(`${lc} failed to parse SSE message`, e);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
this.eventSource!.addEventListener('message', onMessage);
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
// 3. Serialize Context and Control IbGibs
|
|
94
|
+
// TODO [USER]: Serialize the `context` and `controlIbGibs` into your wire format
|
|
95
|
+
const payloadBody = JSON.stringify({
|
|
96
|
+
context: context,
|
|
97
|
+
// controlIbGibs: ...
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// 4. POST the context to `this.data.syncRoute`
|
|
101
|
+
if (!this.data) { throw new Error(`(UNEXPECTED) this.data falsy? (E: 8c6aa9e1aa7869465a26ee3a7d136826)`); }
|
|
102
|
+
const response = await fetch(this.data.syncRoute, {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
headers: {
|
|
105
|
+
'Content-Type': 'application/json',
|
|
106
|
+
// Add Authorization headers here if needed
|
|
107
|
+
},
|
|
108
|
+
body: payloadBody,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
throw new Error(`HTTP Sync Error: ${response.status} ${await response.text()}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 5. Wait for the SSE stream response to resolve with the responseContext
|
|
116
|
+
// The Promise will remain pending until `onMessage` identifies the final response context and calls resolve().
|
|
117
|
+
} catch (e) {
|
|
118
|
+
this.eventSource?.removeEventListener('message', onMessage);
|
|
119
|
+
reject(e);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
124
|
+
throw error;
|
|
125
|
+
} finally {
|
|
126
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module sync-peer-http.respec
|
|
3
|
+
*
|
|
4
|
+
* Verifies SyncSagaCoordinator using a mock HTTP/SSE "thin layer".
|
|
5
|
+
* This utilizes SyncPeerHttpSender_V1 and SyncPeerHttpReceiver_V1 for network synchronization simulations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as cp from 'child_process';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
respecfully, lastOfAll, iReckon, ifWe, ifWeMight
|
|
14
|
+
} from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
|
|
15
|
+
const maam = `[${import.meta.url}]`, sir = maam;
|
|
16
|
+
import { clone, delay, extractErrorMsg, pretty } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
17
|
+
import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
18
|
+
|
|
19
|
+
import { GLOBAL_LOG_A_LOT } from '../../core-constants.mjs';
|
|
20
|
+
import { SyncSagaCoordinator } from '../sync-saga-coordinator.mjs';
|
|
21
|
+
import { getFromSpace, putInSpace, registerNewIbGib } from '../../witness/space/space-helper.mjs';
|
|
22
|
+
import { Metaspace_Innerspace } from '../../witness/space/metaspace/metaspace-innerspace/metaspace-innerspace.mjs';
|
|
23
|
+
import { InnerSpace_V1 } from '../../witness/space/inner-space/inner-space-v1.mjs';
|
|
24
|
+
import { createTimelineRootTestHelper, getTestKeystoneServiceHelper } from '../../test-helpers.mjs';
|
|
25
|
+
import { mut8Timeline, } from '../../timeline/timeline-api.mjs';
|
|
26
|
+
import { DEFAULT_INNER_SPACE_DATA_V1 } from '../../witness/space/inner-space/inner-space-types.mjs';
|
|
27
|
+
import { toDto } from '../../common/other/ibgib-helper.mjs';
|
|
28
|
+
import { getSyncSagaFrameDependencyGraph } from '../sync-helpers.mjs';
|
|
29
|
+
import { SyncIbGib_V1 } from '../sync-types.mjs';
|
|
30
|
+
import { SyncPeerHttpSender_V1 } from './sync-peer-http-sender/sync-peer-http-sender-v1.mjs';
|
|
31
|
+
import { SyncPeerHttpReceiver_V1 } from './sync-peer-http-receiver/sync-peer-http-receiver-v1.mjs';
|
|
32
|
+
import { SyncPeerHttpSenderData_V1 } from './sync-peer-http-sender/sync-peer-http-sender-types.mjs';
|
|
33
|
+
import { SyncPeerHttpReceiverData_V1 } from './sync-peer-http-receiver/sync-peer-http-receiver-types.mjs';
|
|
34
|
+
import { SyncSagaContextIbGib_V1 } from '../sync-saga-context/sync-saga-context-types.mjs';
|
|
35
|
+
import { SyncHttpNodeAdapter_V1 } from './sync-peer-http-receiver/sync-http-node-adapter.mjs';
|
|
36
|
+
|
|
37
|
+
const logalot = GLOBAL_LOG_A_LOT;
|
|
38
|
+
const lc = `[sync-peer-http.respec]`;
|
|
39
|
+
|
|
40
|
+
await respecfully(sir, `Sync HTTP Peers`, async () => {
|
|
41
|
+
|
|
42
|
+
let metaspace: Metaspace_Innerspace;
|
|
43
|
+
let sourceSpace: InnerSpace_V1;
|
|
44
|
+
let destSpace: InnerSpace_V1;
|
|
45
|
+
|
|
46
|
+
// We focus this test initially for development
|
|
47
|
+
await ifWeMight(sir, `Basic Push Sync over Mocked HTTP/SSE`, async () => {
|
|
48
|
+
// 1. Setup Spaces
|
|
49
|
+
metaspace = new Metaspace_Innerspace(undefined);
|
|
50
|
+
await metaspace.initialize({
|
|
51
|
+
getFnAlert: () => async ({ title, msg }) => { console.log(`[Alert] ${title}: ${msg}`); },
|
|
52
|
+
getFnPrompt: () => async ({ title, msg }) => { console.log(`[Prompt] ${title}: ${msg}`); return ''; },
|
|
53
|
+
getFnPromptPassword: () => async (title, msg) => { console.log(`[PromptPwd] ${title}: ${msg}`); return null; },
|
|
54
|
+
});
|
|
55
|
+
while (!metaspace.initialized) { await delay(10); }
|
|
56
|
+
|
|
57
|
+
const defaultLocalUserSpace = await metaspace.getLocalUserSpace({ lock: false });
|
|
58
|
+
if (!defaultLocalUserSpace) { throw new Error(`(UNEXPECTED) defaultLocalUserSpace falsy?`); }
|
|
59
|
+
await defaultLocalUserSpace.initialized;
|
|
60
|
+
|
|
61
|
+
sourceSpace = new InnerSpace_V1({
|
|
62
|
+
...DEFAULT_INNER_SPACE_DATA_V1,
|
|
63
|
+
name: 'source',
|
|
64
|
+
uuid: 'source_uuid',
|
|
65
|
+
description: 'source test space',
|
|
66
|
+
});
|
|
67
|
+
await sourceSpace.initialized;
|
|
68
|
+
|
|
69
|
+
destSpace = new InnerSpace_V1({
|
|
70
|
+
...DEFAULT_INNER_SPACE_DATA_V1,
|
|
71
|
+
name: 'dest',
|
|
72
|
+
uuid: 'dest_uuid',
|
|
73
|
+
description: 'dest test space',
|
|
74
|
+
});
|
|
75
|
+
await destSpace.initialized;
|
|
76
|
+
|
|
77
|
+
// 2. Seed Source Data
|
|
78
|
+
if (logalot) { console.log(`${lc} Creating data in Source...`); }
|
|
79
|
+
const root = await createTimelineRootTestHelper({
|
|
80
|
+
ib: 'timeline_root',
|
|
81
|
+
data: { type: 'root', },
|
|
82
|
+
space: sourceSpace,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const child = await mut8Timeline({
|
|
86
|
+
timeline: root,
|
|
87
|
+
mut8Opts: {
|
|
88
|
+
dataToAddOrPatch: { type: 'child', },
|
|
89
|
+
},
|
|
90
|
+
metaspace,
|
|
91
|
+
space: sourceSpace,
|
|
92
|
+
});
|
|
93
|
+
const childAddr = getIbGibAddr({ ibGib: child });
|
|
94
|
+
|
|
95
|
+
// 3. Setup Coordinators & Peer
|
|
96
|
+
if (logalot) { console.log(`${lc} Setting up Coordinators...`); }
|
|
97
|
+
const mockKeystone = await getTestKeystoneServiceHelper();
|
|
98
|
+
|
|
99
|
+
const senderCoordinator = new SyncSagaCoordinator(mockKeystone);
|
|
100
|
+
const receiverCoordinator = new SyncSagaCoordinator(mockKeystone);
|
|
101
|
+
|
|
102
|
+
// --- Mocking the HTTP "Network" ---
|
|
103
|
+
// Instead of real fetch and EventSource, we wire the Sender's outgoing HTTP
|
|
104
|
+
// calls directly to the Receiver's incoming endpoints.
|
|
105
|
+
|
|
106
|
+
const receiverPeerData: SyncPeerHttpReceiverData_V1 = { classname: SyncPeerHttpReceiver_V1.name };
|
|
107
|
+
const receiverPeer = new SyncPeerHttpReceiver_V1(receiverPeerData);
|
|
108
|
+
await receiverPeer.initialized;
|
|
109
|
+
await receiverPeer.initializeOpts({
|
|
110
|
+
localCoordinator: receiverCoordinator,
|
|
111
|
+
localMetaspace: metaspace,
|
|
112
|
+
localSpace: destSpace,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// We'll subclass/monkey-patch the Sender peer to use mock fetching
|
|
116
|
+
class MockSyncPeerHttpSender extends SyncPeerHttpSender_V1 {
|
|
117
|
+
override async sendContextRequest(context: SyncSagaContextIbGib_V1): Promise<SyncSagaContextIbGib_V1 | undefined> {
|
|
118
|
+
// Mock POST /sync/frame
|
|
119
|
+
// Real sender would serialize and POST. Here we just hand it to receiver:
|
|
120
|
+
const responsePromise = new Promise<SyncSagaContextIbGib_V1 | undefined>(async (resolve, reject) => {
|
|
121
|
+
try {
|
|
122
|
+
const rel8ns = context.rel8ns;
|
|
123
|
+
if (!rel8ns || (rel8ns.sagaFrame || []).length !== 1) { throw new Error(`(UNEXPECTED) context.rel8ns.sagaFrame missing?`); }
|
|
124
|
+
const sagaAddr = rel8ns.sagaFrame![0];
|
|
125
|
+
const getSagaRes = await getFromSpace({ addr: sagaAddr, space: sourceSpace });
|
|
126
|
+
const sagaFrame = getSagaRes.ibGibs![0] as SyncIbGib_V1;
|
|
127
|
+
|
|
128
|
+
const { msgStones, identities } = await getSyncSagaFrameDependencyGraph({
|
|
129
|
+
sagaIbGib: sagaFrame,
|
|
130
|
+
localSpace: sourceSpace,
|
|
131
|
+
});
|
|
132
|
+
const msg = msgStones[0];
|
|
133
|
+
const controlIbGibs = [...identities, msg, sagaFrame, context].filter(x => !!x).map(x => toDto({ ibGib: x }));
|
|
134
|
+
|
|
135
|
+
// The Server Adapter calls receiverPeer.handleIncomingSyncRequest
|
|
136
|
+
const responseContext = await receiverPeer.handleIncomingSyncRequest({
|
|
137
|
+
context,
|
|
138
|
+
controlIbGibs
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (!responseContext) {
|
|
142
|
+
resolve(undefined);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// **Mock the Server Adapter returning data**
|
|
147
|
+
// Real server would stream the newly evolved Control Context ibgibs to SSE,
|
|
148
|
+
// followed by the response domain payload ibgibs.
|
|
149
|
+
// We must MANUALLY persist the control ibgibs to the sender space FIRST,
|
|
150
|
+
// to simulate the client downloading and validating them from the SSE connection.
|
|
151
|
+
await delay(100);
|
|
152
|
+
const responseSagaAddr = responseContext.rel8ns!.sagaFrame![0];
|
|
153
|
+
const getResponseSagaRes = await getFromSpace({ addr: responseSagaAddr, space: destSpace });
|
|
154
|
+
const responseSagaFrame = getResponseSagaRes.ibGibs![0] as SyncIbGib_V1;
|
|
155
|
+
const depGraphResponse = await getSyncSagaFrameDependencyGraph({
|
|
156
|
+
sagaIbGib: responseSagaFrame,
|
|
157
|
+
localSpace: destSpace,
|
|
158
|
+
});
|
|
159
|
+
const responseControlIbGibs = [
|
|
160
|
+
...identities, // ORIGINAL identities, not the receiver's!
|
|
161
|
+
depGraphResponse.msgStones[0],
|
|
162
|
+
responseSagaFrame,
|
|
163
|
+
context
|
|
164
|
+
].filter(x => !!x).map(x => toDto({ ibGib: x }));
|
|
165
|
+
|
|
166
|
+
for (const ibGib of responseControlIbGibs) {
|
|
167
|
+
await putInSpace({ space: sourceSpace, ibGibs: [ibGib] });
|
|
168
|
+
await registerNewIbGib({ ibGib, space: sourceSpace, fnBroadcast: undefined });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
await delay(5); // Simulate end of SSE task event
|
|
172
|
+
// Resolve with the responseContext
|
|
173
|
+
resolve(responseContext);
|
|
174
|
+
|
|
175
|
+
// THEN simulate streaming the domain payload ibgibs to the local subject
|
|
176
|
+
if (responseContext.payloadIbGibsDomain) {
|
|
177
|
+
new Promise<void>(async (resDom) => {
|
|
178
|
+
for (const domainIbGib of responseContext.payloadIbGibsDomain!) {
|
|
179
|
+
await delay(1); // emulate network gap between SSE events
|
|
180
|
+
await this.payloadIbGibsDomainReceived$.next(domainIbGib);
|
|
181
|
+
}
|
|
182
|
+
resDom();
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
} catch (e) {
|
|
187
|
+
reject(e);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return responsePromise;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const senderPeerData: SyncPeerHttpSenderData_V1 = {
|
|
195
|
+
classname: SyncPeerHttpSender_V1.name,
|
|
196
|
+
syncRoute: 'http://mock/sync/frame',
|
|
197
|
+
syncEventsRoute: 'http://mock/sync/events'
|
|
198
|
+
};
|
|
199
|
+
const senderPeer = new MockSyncPeerHttpSender(senderPeerData);
|
|
200
|
+
await senderPeer.initialized;
|
|
201
|
+
|
|
202
|
+
// We configure localSpace and a senderTempSpace for the mock:
|
|
203
|
+
const senderTempSpace = new InnerSpace_V1({
|
|
204
|
+
...DEFAULT_INNER_SPACE_DATA_V1, name: 'sender_temp', uuid: 'sender_temp_uuid'
|
|
205
|
+
});
|
|
206
|
+
await senderTempSpace.initialized;
|
|
207
|
+
|
|
208
|
+
await senderPeer.initializeOpts({
|
|
209
|
+
localSpace: sourceSpace,
|
|
210
|
+
localTempSpace: senderTempSpace
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// 4. Run Sync
|
|
214
|
+
if (logalot) { console.log(`${lc} Running Sync...`); }
|
|
215
|
+
try {
|
|
216
|
+
const resSync = await senderCoordinator.sync({
|
|
217
|
+
peer: senderPeer,
|
|
218
|
+
localSpace: sourceSpace,
|
|
219
|
+
metaspace: metaspace,
|
|
220
|
+
domainIbGibs: [child], // Sync the child
|
|
221
|
+
useSessionIdentity: false, // Testing logic only
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
await resSync.done;
|
|
225
|
+
iReckon(sir, true).asTo('Mocked request ran').isGonnaBeTrue();
|
|
226
|
+
|
|
227
|
+
// We now expect the entire saga to complete because handleIncomingSyncRequest works
|
|
228
|
+
let childInDest = await getFromSpace({ addr: childAddr, space: destSpace });
|
|
229
|
+
iReckon(sir, childInDest.success).asTo('Child is correctly pushed to destination space').isGonnaBeTrue();
|
|
230
|
+
|
|
231
|
+
} catch (error: any) {
|
|
232
|
+
console.error(`${lc}[senderCoordinator.sync] FULL ERROR:`, error.stack || error.message || error);
|
|
233
|
+
// Will fail initially because handleIncomingSyncRequest is not implemented
|
|
234
|
+
iReckon(sir, false).asTo(`Unexpected error: ${extractErrorMsg(error)}`).isGonnaBeTrue();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
await respecfully(sir, `Real Sync via Local HTTP/2 Node Adapter with Self-Signed Certs`, async () => {
|
|
240
|
+
// 1. Generate Self-Signed Certs via OpenSSL or PowerShell
|
|
241
|
+
const tmpDir = path.join(process.cwd(), 'tmp-certs');
|
|
242
|
+
const keyPath = path.join(tmpDir, 'server.key');
|
|
243
|
+
const certPath = path.join(tmpDir, 'server.cert');
|
|
244
|
+
const pfxPath = path.join(tmpDir, 'server.pfx');
|
|
245
|
+
|
|
246
|
+
let hasTlsGenerator = false;
|
|
247
|
+
let isWin = process.platform === 'win32';
|
|
248
|
+
|
|
249
|
+
if (isWin) {
|
|
250
|
+
hasTlsGenerator = true;
|
|
251
|
+
} else {
|
|
252
|
+
try {
|
|
253
|
+
cp.execSync('openssl version', { stdio: 'ignore' });
|
|
254
|
+
hasTlsGenerator = true;
|
|
255
|
+
} catch (e) {
|
|
256
|
+
console.warn(`${lc} OpenSSL not found in PATH. Skipping HTTP/2 Native test.`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (hasTlsGenerator) {
|
|
261
|
+
if (!fs.existsSync(tmpDir)) { fs.mkdirSync(tmpDir, { recursive: true }); }
|
|
262
|
+
|
|
263
|
+
let keyInfo: Buffer | undefined;
|
|
264
|
+
let certInfo: Buffer | undefined;
|
|
265
|
+
let pfxInfo: Buffer | undefined;
|
|
266
|
+
|
|
267
|
+
if (isWin) {
|
|
268
|
+
if (!fs.existsSync(pfxPath)) {
|
|
269
|
+
if (logalot) { console.log(`${lc} Generating self-signed cert via PowerShell...`); }
|
|
270
|
+
const psScript = `
|
|
271
|
+
$cert = New-SelfSignedCertificate -CertStoreLocation "Cert:\\CurrentUser\\My" -Subject "localhost" -KeyExportPolicy Exportable -NotAfter (Get-Date).AddDays(1)
|
|
272
|
+
$pwd = ConvertTo-SecureString -String "testpass" -Force -AsPlainText
|
|
273
|
+
Export-PfxCertificate -Cert $cert -FilePath "${pfxPath.replace(/\\/g, '\\\\')}" -Password $pwd
|
|
274
|
+
Remove-Item -Path $cert.PSPath
|
|
275
|
+
`;
|
|
276
|
+
cp.execSync(`powershell -Command "${psScript.replace(/\n/g, '; ')}"`, { stdio: 'ignore' });
|
|
277
|
+
}
|
|
278
|
+
pfxInfo = fs.readFileSync(pfxPath);
|
|
279
|
+
} else {
|
|
280
|
+
if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) {
|
|
281
|
+
if (logalot) { console.log(`${lc} Generating self-signed cert...`); }
|
|
282
|
+
cp.execSync(`openssl req -x509 -newkey rsa:2048 -nodes -keyout ${keyPath} -out ${certPath} -days 1 -subj "/CN=localhost"`, { stdio: 'ignore' });
|
|
283
|
+
}
|
|
284
|
+
keyInfo = fs.readFileSync(keyPath);
|
|
285
|
+
certInfo = fs.readFileSync(certPath);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Bypass self-signed cert rejection in Node fetch
|
|
289
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
290
|
+
|
|
291
|
+
// 2. Setup Spaces
|
|
292
|
+
metaspace = new Metaspace_Innerspace(undefined);
|
|
293
|
+
await metaspace.initialize({
|
|
294
|
+
getFnAlert: () => async () => { },
|
|
295
|
+
getFnPrompt: () => async () => '',
|
|
296
|
+
getFnPromptPassword: () => async () => null,
|
|
297
|
+
});
|
|
298
|
+
while (!metaspace.initialized) { await delay(10); }
|
|
299
|
+
|
|
300
|
+
const defaultLocalUserSpace = await metaspace.getLocalUserSpace({ lock: false });
|
|
301
|
+
await defaultLocalUserSpace?.initialized;
|
|
302
|
+
|
|
303
|
+
sourceSpace = new InnerSpace_V1({ ...DEFAULT_INNER_SPACE_DATA_V1, name: 'source_h2', uuid: 'source_h2_uuid' });
|
|
304
|
+
await sourceSpace.initialized;
|
|
305
|
+
destSpace = new InnerSpace_V1({ ...DEFAULT_INNER_SPACE_DATA_V1, name: 'dest_h2', uuid: 'dest_h2_uuid' });
|
|
306
|
+
await destSpace.initialized;
|
|
307
|
+
|
|
308
|
+
// 3. Setup Node Adapter & Receiver
|
|
309
|
+
const mockKeystone = await getTestKeystoneServiceHelper();
|
|
310
|
+
const receiverCoordinator = new SyncSagaCoordinator(mockKeystone);
|
|
311
|
+
|
|
312
|
+
const receiverPeer = new SyncPeerHttpReceiver_V1({ classname: SyncPeerHttpReceiver_V1.name });
|
|
313
|
+
await receiverPeer.initialized;
|
|
314
|
+
await receiverPeer.initializeOpts({
|
|
315
|
+
localCoordinator: receiverCoordinator,
|
|
316
|
+
localMetaspace: metaspace,
|
|
317
|
+
localSpace: destSpace,
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
const port = 8443;
|
|
321
|
+
const adapter = new SyncHttpNodeAdapter_V1({
|
|
322
|
+
receiverPeer,
|
|
323
|
+
port,
|
|
324
|
+
key: keyInfo,
|
|
325
|
+
cert: certInfo,
|
|
326
|
+
pfx: pfxInfo,
|
|
327
|
+
passphrase: 'testpass',
|
|
328
|
+
basePath: '/sync'
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
await adapter.start();
|
|
332
|
+
|
|
333
|
+
// 4. Test the Adapter Connection
|
|
334
|
+
if (logalot) { console.log(`${lc} Pinging the HTTP/2 Adapter via POST...`); }
|
|
335
|
+
|
|
336
|
+
// Create a dummy context structure just to appease the parser and prove connection success
|
|
337
|
+
const testContext: any = { classname: 'SyncSagaContextIbGib_V1', rel8ns: {}, data: {} };
|
|
338
|
+
const payloadBody = JSON.stringify({ context: testContext, controlIbGibs: [] });
|
|
339
|
+
|
|
340
|
+
try {
|
|
341
|
+
const res = await fetch(`https://localhost:${port}/sync/frame`, {
|
|
342
|
+
method: 'POST',
|
|
343
|
+
headers: { 'Content-Type': 'application/json', 'x-client-id': 'test-123' },
|
|
344
|
+
body: payloadBody
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
await ifWeMight(sir, 'check http2 adapter', async () => {
|
|
348
|
+
iReckon(sir, res.ok).asTo('Successfully reached HTTP/2 Adapter via POST').isGonnaBeTrue();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
// The receiver peer inside the adapter will throw a normal logged warning about invalid saga formats from our dummy context,
|
|
353
|
+
// but the HTTP transport should respond 200 OK, verifying the http2 server is cleanly bound!
|
|
354
|
+
|
|
355
|
+
} catch (err) {
|
|
356
|
+
console.error(`${lc} HTTP/2 test failed:`, err);
|
|
357
|
+
iReckon(sir, false).asTo('HTTP/2 Adapter POST should not throw').isGonnaBeTrue();
|
|
358
|
+
} finally {
|
|
359
|
+
await adapter.stop();
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
});
|
|
@@ -15,30 +15,30 @@ import { SyncPeerData_V1, SyncPeerRel8ns_V1 } from '../sync-peer-types.mjs';
|
|
|
15
15
|
*/
|
|
16
16
|
export interface SyncPeerInnerspaceOptions {
|
|
17
17
|
/**
|
|
18
|
-
* The "receiver" durable space (not temp).
|
|
19
|
-
*
|
|
18
|
+
* The "receiver" durable space (not temp).
|
|
19
|
+
*
|
|
20
20
|
* ## notes
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
22
|
* when syncing/merging locally, we are working with two spaces and this
|
|
23
23
|
* acts as the "remote" space even though it's technically still local.
|
|
24
24
|
*/
|
|
25
25
|
receiverSpace: IbGibSpaceAny;
|
|
26
26
|
/**
|
|
27
|
-
* Coordinator for the "receiver".
|
|
28
|
-
*
|
|
27
|
+
* Coordinator for the "receiver".
|
|
28
|
+
*
|
|
29
29
|
* @see {@link receiverSpace} notes.
|
|
30
30
|
*/
|
|
31
31
|
receiverCoordinator: SyncSagaCoordinator;
|
|
32
32
|
/**
|
|
33
|
-
* Metaspace for the "receiver".
|
|
34
|
-
*
|
|
33
|
+
* Metaspace for the "receiver".
|
|
34
|
+
*
|
|
35
35
|
* @see {@link receiverSpace} notes.
|
|
36
36
|
*/
|
|
37
37
|
receiverMetaspace: MetaspaceService;
|
|
38
38
|
/**
|
|
39
39
|
* Temporary sync transaction space for the "receiver", for storage of
|
|
40
40
|
* domain ibgibs created/received throughout the sync saga until commit.
|
|
41
|
-
*
|
|
41
|
+
*
|
|
42
42
|
* @see {@link receiverSpace} notes.
|
|
43
43
|
*/
|
|
44
44
|
receiverTempSpace: IbGibSpaceAny;
|
|
@@ -67,7 +67,7 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1<InitializeSyncPeerInnersp
|
|
|
67
67
|
super(initialData, initialRel8ns);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
protected
|
|
70
|
+
protected async ensureReceiverTempSpace(): Promise<IbGibSpaceAny> {
|
|
71
71
|
const lc = `${this.lc}[${this.ensureReceiverTempSpace.name}]`;
|
|
72
72
|
try {
|
|
73
73
|
if (logalot) { console.log(`${lc} starting... (I: bab87f15dea77cd4892bd8a8d2e65826)`); }
|
|
@@ -108,14 +108,17 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1<InitializeSyncPeerInnersp
|
|
|
108
108
|
|
|
109
109
|
if (!this.opts) { throw new Error(`(UNEXPECTED) this.opts falsy? (E: d8b1348e3233810128999596b1fa5826)`); }
|
|
110
110
|
|
|
111
|
+
await this.ensureReceiverTempSpace();
|
|
112
|
+
|
|
111
113
|
const {
|
|
112
|
-
|
|
114
|
+
localSpace, localTempSpace,
|
|
113
115
|
receiverSpace, receiverCoordinator, receiverMetaspace,
|
|
114
116
|
receiverTempSpace
|
|
115
117
|
} = this.opts;
|
|
116
118
|
|
|
117
119
|
if (logalot) { console.log(`${lc} starting...Context: ${getIbGibAddr({ ibGib: context })}`); }
|
|
118
120
|
|
|
121
|
+
|
|
119
122
|
const { sagaFrame } = context;
|
|
120
123
|
|
|
121
124
|
// The context has already been validated, authenticated and authorized at this point.
|
|
@@ -128,7 +131,7 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1<InitializeSyncPeerInnersp
|
|
|
128
131
|
if (!sagaFrame.data) { throw new Error(`(UNEXPECTED) sagaFrame.data falsy? (E: f30e290a8b770e1b387377420ea73a26)`); }
|
|
129
132
|
if (!sagaFrame.rel8ns) { throw new Error(`(UNEXPECTED) sagaFrame.rel8ns falsy? (E: f888caa698b8cf6b4893b7fd6df09726)`); }
|
|
130
133
|
if (!receiverTempSpace) { throw new Error(`(UNEXPECTED) receiverTempSpace falsy? (E: 3b46d838f6fc645c58b29215bfddb826)`); }
|
|
131
|
-
if (!
|
|
134
|
+
if (!localTempSpace) { throw new Error(`(UNEXPECTED) localTempSpace falsy? (E: b187a8f913c2295ae90d7ae2b47b6a26)`); }
|
|
132
135
|
// #endregion sanity validation assertions
|
|
133
136
|
|
|
134
137
|
// let localSpace: IbGibSpaceAny;
|
|
@@ -149,7 +152,7 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1<InitializeSyncPeerInnersp
|
|
|
149
152
|
|
|
150
153
|
const { sagaIbGib: _alreadyHave, msgStones, identities } = await getSyncSagaFrameDependencyGraph({
|
|
151
154
|
sagaIbGib: sagaFrame,
|
|
152
|
-
localSpace:
|
|
155
|
+
localSpace: localSpace,
|
|
153
156
|
});
|
|
154
157
|
if (msgStones.length !== 1) { throw new Error(`(UNEXPECTED) msgStones.length !== 1? we're only geared for a single msg stone that is always present (not 0, not greater than 1) (E: 2d3138ed130f1aca116551889483e826)`); }
|
|
155
158
|
const msg = msgStones[0];
|
|
@@ -238,13 +241,13 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1<InitializeSyncPeerInnersp
|
|
|
238
241
|
// ...put into sender's durable space
|
|
239
242
|
await putInSpace({
|
|
240
243
|
ibGibs: responsePayloadIbGibsControl,
|
|
241
|
-
space:
|
|
244
|
+
space: localSpace,
|
|
242
245
|
});
|
|
243
246
|
// register yet??
|
|
244
247
|
for (const control of responsePayloadIbGibsControl) {
|
|
245
248
|
await registerNewIbGib({
|
|
246
249
|
ibGib: control,
|
|
247
|
-
space:
|
|
250
|
+
space: localSpace,
|
|
248
251
|
fnBroadcast: undefined
|
|
249
252
|
});
|
|
250
253
|
}
|
|
@@ -266,7 +269,7 @@ export class SyncPeerInnerspace_V1 extends SyncPeer_V1<InitializeSyncPeerInnersp
|
|
|
266
269
|
|
|
267
270
|
await putInSpace_dnasThenNonDnas({
|
|
268
271
|
ibGibs: payloadIbGibsDomain_response,
|
|
269
|
-
space:
|
|
272
|
+
space: localTempSpace,
|
|
270
273
|
});
|
|
271
274
|
|
|
272
275
|
for (const payloadDomain of payloadIbGibsDomain_response) {
|
|
@@ -35,20 +35,20 @@ export interface SyncPeerIbGib_V1 extends IbGib_V1<SyncPeerData_V1, SyncPeerRel8
|
|
|
35
35
|
*/
|
|
36
36
|
export interface InitializeSyncPeerOpts {
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
38
|
+
* local durable space.
|
|
39
|
+
*
|
|
40
40
|
* will store control ibgibs (context, sync saga ibgib, control msg stones)
|
|
41
|
-
* here (and in {@link
|
|
41
|
+
* here (and in {@link localTempSpace}) throughout the process for audit trail.
|
|
42
42
|
*/
|
|
43
|
-
|
|
43
|
+
localSpace: IbGibSpaceAny;
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* local temporary space for the entire sync transaction.
|
|
46
|
+
*
|
|
47
47
|
* In addition to control ibgibs which are stored in both temp and durable
|
|
48
48
|
* spaces, this temp space will be where domain ibgibs are stored that are
|
|
49
49
|
* received/created throughout the transaction until commit.
|
|
50
50
|
*/
|
|
51
|
-
|
|
51
|
+
localTempSpace?: IbGibSpaceAny;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -69,9 +69,9 @@ export interface SyncPeerWitness<TInitializeOpts extends InitializeSyncPeerOpts
|
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* sender-specific opts/config
|
|
72
|
-
*
|
|
72
|
+
*
|
|
73
73
|
* ## notes
|
|
74
|
-
*
|
|
74
|
+
*
|
|
75
75
|
* I'm doing this hack because I have to be able to create a peer without
|
|
76
76
|
* being able to fully configure it at construction time. So I can't place
|
|
77
77
|
* this init code in the {@link initialize} method.
|
|
@@ -81,14 +81,14 @@ export interface SyncPeerWitness<TInitializeOpts extends InitializeSyncPeerOpts
|
|
|
81
81
|
/**
|
|
82
82
|
* use this to set the senderTempSpace and any other optional opts that need
|
|
83
83
|
* to be configured just before sending any contexts across the wire.
|
|
84
|
-
*
|
|
84
|
+
*
|
|
85
85
|
* @see {@link opts}
|
|
86
86
|
*/
|
|
87
87
|
setOptionalOpts(arg: Partial<TInitializeOpts>): void;
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
90
|
* Observable for streaming large domain payloads asynchronously.
|
|
91
|
-
*
|
|
91
|
+
*
|
|
92
92
|
* Implementations should publish domain ibgibs to this observable as they are received.
|
|
93
93
|
* The handling code (e.g. SyncSagaCoordinator) will subscribe to this.
|
|
94
94
|
*/
|