@ibgib/space-gib 0.0.1 → 0.0.2
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/client/bootstrap.mjs +1 -1
- package/dist/client/bootstrap.mjs.map +1 -1
- package/dist/client/chunk-BL2SGXS4.mjs +18994 -0
- package/dist/client/chunk-RDTAT5G4.mjs +235 -0
- package/dist/client/chunk-RDTAT5G4.mjs.map +7 -0
- package/dist/client/chunk-RE7XSMHH.mjs +31 -0
- package/dist/client/chunk-RE7XSMHH.mjs.map +7 -0
- package/dist/client/chunk-YUSGN3J4.mjs +23119 -0
- package/dist/client/index.html +44 -8
- package/dist/client/index.mjs +1 -1
- package/dist/client/script.mjs +1 -1
- package/dist/client/style.css +26 -0
- package/dist/server/server.mjs +5323 -1011
- package/dist/server/server.mjs.map +4 -4
- package/package.json +1 -1
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/api/space-gib-api-bridge.mts +84 -8
- package/src/client/dev-tools.mts +609 -24
- package/src/client/index.html +44 -8
- package/src/client/style.css +26 -0
- package/src/common/keystone-policies.json +64 -0
- package/src/common/keystone-policies.mts +39 -86
- package/src/server/serve-gib/handlers/api/debug/ws-echo.handler.mts +13 -12
- package/src/server/serve-gib/handlers/api/keystone/keystone-evolve.handler.mts +14 -167
- package/src/server/serve-gib/handlers/api/keystone/keystone-genesis.handler.mts +6 -6
- package/src/server/serve-gib/handlers/api/keystone/keystone-post.handler.mts +10 -25
- package/src/server/serve-gib/handlers/ws/sync-upgrade-handler-base.mts +201 -0
- package/src/server/serve-gib/handlers/ws/sync-upgrade.handler.mts +13 -487
- package/src/server/serve-gib/handlers/ws/ws-helper.mts +80 -3
- package/dist/client/chunk-CT47Z5WU.mjs +0 -21
- package/dist/client/chunk-CT47Z5WU.mjs.map +0 -7
- package/dist/client/chunk-RHEDTRKF.mjs +0 -235
- package/dist/client/chunk-RHEDTRKF.mjs.map +0 -7
- package/dist/respec-gib.node.mjs +0 -5
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
6
|
-
import {
|
|
7
|
-
import { validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
|
|
6
|
+
import { validateAndRegisterPostKeystones } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs';
|
|
8
7
|
|
|
9
8
|
import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
|
|
10
9
|
import { ServeGibHandlerBase } from '../../handler-base.mjs';
|
|
@@ -12,7 +11,7 @@ import { RequestContext, ResponseResult, ServeGibHttpMethod } from '../../../typ
|
|
|
12
11
|
import { API_PATH_REGEXES } from '../../../../path-constants.mjs';
|
|
13
12
|
import { KeystoneParams } from './keystone-handler-types.mjs';
|
|
14
13
|
|
|
15
|
-
const logalot = GLOBAL_LOG_A_LOT;
|
|
14
|
+
const logalot = GLOBAL_LOG_A_LOT || true;
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* POST /api/keystone
|
|
@@ -33,30 +32,16 @@ export class KeystonePostHandler extends ServeGibHandlerBase<KeystoneParams, any
|
|
|
33
32
|
const { ibGibs } = JSON.parse(reqCtx.body) as { ibGibs: any[] };
|
|
34
33
|
if (!Array.isArray(ibGibs)) return this.error(400, 'ibGibs array required');
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const errors = await validateIbGibIntrinsically({ ibGib });
|
|
39
|
-
if (errors) {
|
|
40
|
-
return this.error(422, 'Intrinsic validation failed', { failedAddr: getIbGibAddr({ ibGib }), errors });
|
|
41
|
-
}
|
|
42
|
-
}
|
|
35
|
+
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
36
|
+
if (!space) { throw new Error(`No local user space found`); }
|
|
43
37
|
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
ibGib,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
}
|
|
38
|
+
// Delegate all intrinsic validation, keystone-specific checks, registration, and persistence to core-gib
|
|
39
|
+
await validateAndRegisterPostKeystones({
|
|
40
|
+
ibGibs,
|
|
41
|
+
metaspace,
|
|
42
|
+
space
|
|
43
|
+
});
|
|
54
44
|
|
|
55
|
-
// 3. Persistence
|
|
56
|
-
console.log(`[KeystoneHandler] Persisting ${ibGibs.length} ibGibs...`);
|
|
57
|
-
await metaspace.put({ ibGibs })
|
|
58
|
-
// await spaceSvc.putIbGibGraph(ibGibs);
|
|
59
|
-
console.log(`[KeystoneHandler] Persistence successful.`);
|
|
60
45
|
return { status: 201, body: { success: true }, isJson: true };
|
|
61
46
|
|
|
62
47
|
} catch (error) {
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module handlers/ws/sync-upgrade-handler-base
|
|
3
|
+
*
|
|
4
|
+
* Highly generic, reusable base class in serve-gib for handling WebSocket upgrades,
|
|
5
|
+
* mapping socket streams to isomorphic SyncPeers, and checking upfront connect handshakes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { IncomingMessage } from 'node:http';
|
|
9
|
+
import { Socket } from 'node:net';
|
|
10
|
+
import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
11
|
+
import { getIbGibAddr, getIbAndGib } from '@ibgib/ts-gib/dist/helper.mjs';
|
|
12
|
+
import { validateIbGibAddr } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
|
|
13
|
+
import { parseKeystoneIb } from '@ibgib/core-gib/dist/keystone/keystone-helpers.mjs';
|
|
14
|
+
import { SyncPeerWebSocketReceiver_V1, IWebSocketWrapper } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-peer-websocket-receiver-v1.mjs';
|
|
15
|
+
import { validateUpfrontConnect } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-websocket-receiver/sync-websocket-peer-helpers.mjs';
|
|
16
|
+
import { SyncSagaCoordinator } from '@ibgib/core-gib/dist/sync/sync-saga-coordinator.mjs';
|
|
17
|
+
|
|
18
|
+
import { GLOBAL_LOG_A_LOT } from '../../constants.mjs';
|
|
19
|
+
import {
|
|
20
|
+
encodeTextFrame, decodeTextFrame, encodeCloseFrame, performConnect,
|
|
21
|
+
WebSocketFrameDecoder
|
|
22
|
+
} from './ws-helper.mjs';
|
|
23
|
+
import { ServeGibHandlerWithMetaspaceBase } from '../handler-base.mjs';
|
|
24
|
+
import { ParamsWithDomain, RequestContext, ResponseResult, ServeGibHttpMethod } from '../../types.mjs';
|
|
25
|
+
|
|
26
|
+
const logalot = GLOBAL_LOG_A_LOT;
|
|
27
|
+
|
|
28
|
+
export interface SyncChannelQueryParams {
|
|
29
|
+
sAddr: string;
|
|
30
|
+
solution: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface SyncChannelRequestContext extends RequestContext<ParamsWithDomain, SyncChannelQueryParams> {
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Reusable server-side upgrade handler plumbing.
|
|
38
|
+
* Binds raw node socket streams to platform-agnostic receiver peers.
|
|
39
|
+
*/
|
|
40
|
+
export abstract class SyncUpgradeHandlerBase extends ServeGibHandlerWithMetaspaceBase<ParamsWithDomain, SyncChannelQueryParams> {
|
|
41
|
+
protected override lc: string = `[${SyncUpgradeHandlerBase.name}]`;
|
|
42
|
+
protected override method: ServeGibHttpMethod = 'GET';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Entry point for WebSocket upgrades.
|
|
46
|
+
* Orchestrates the upgrade, upfront validation, and registers the Receiver peer.
|
|
47
|
+
*/
|
|
48
|
+
async handleUpgrade(reqCtx: RequestContext<ParamsWithDomain>, socket: Socket, head: Buffer): Promise<boolean> {
|
|
49
|
+
const lc_fn = `${this.lc}[handleUpgrade]`;
|
|
50
|
+
try {
|
|
51
|
+
if (logalot) { console.log(`${lc_fn} starting...`); }
|
|
52
|
+
|
|
53
|
+
// 1. Initial routing checks
|
|
54
|
+
if (!this.canHandleRoute(reqCtx)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const ctx = reqCtx as SyncChannelRequestContext;
|
|
59
|
+
|
|
60
|
+
// Extract route parameters & query parameters
|
|
61
|
+
ctx.params = await this.parseParams(ctx);
|
|
62
|
+
ctx.queryParams = await this.parseQueryParams(ctx);
|
|
63
|
+
|
|
64
|
+
// 2. Bootstrap multi-tenant domain metaspace context
|
|
65
|
+
await this.initConcreteContext(ctx);
|
|
66
|
+
|
|
67
|
+
const metaspace = ctx.metaspace!;
|
|
68
|
+
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
69
|
+
if (!space) { throw new Error("No default local user space found."); }
|
|
70
|
+
|
|
71
|
+
// 3. Upfront picket-fence pre-filter validation
|
|
72
|
+
const queryParams = ctx.queryParams!;
|
|
73
|
+
await validateUpfrontConnect({
|
|
74
|
+
sAddr: queryParams.sAddr,
|
|
75
|
+
solution: queryParams.solution,
|
|
76
|
+
space,
|
|
77
|
+
metaspace
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// 4. Perform standard RFC 6455 Connect H andshake Upgrade
|
|
81
|
+
const ok = performConnect(ctx as any as IncomingMessage, socket);
|
|
82
|
+
if (!ok) { return true; }
|
|
83
|
+
|
|
84
|
+
// 5. Instantiate and initialize isomorphic WebSocket Receiver Peer
|
|
85
|
+
const receiverPeer = new SyncPeerWebSocketReceiver_V1({
|
|
86
|
+
classname: 'SyncPeerWebSocketReceiver_V1'
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const localCoordinator = new SyncSagaCoordinator();
|
|
90
|
+
await receiverPeer.initializeOpts({
|
|
91
|
+
localCoordinator,
|
|
92
|
+
localMetaspace: metaspace,
|
|
93
|
+
localSpace: space,
|
|
94
|
+
sagaId: undefined, // Resolved dynamically inside runtime turns
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// 6. Map standard Node.js Socket to platform-agnostic IWebSocketWrapper
|
|
98
|
+
const socketWrapper: IWebSocketWrapper = {
|
|
99
|
+
send(data: string): void {
|
|
100
|
+
socket.write(encodeTextFrame(data));
|
|
101
|
+
},
|
|
102
|
+
onMessage(callback: (data: string) => void): void {
|
|
103
|
+
const decoder = new WebSocketFrameDecoder();
|
|
104
|
+
socket.on('data', (buf) => {
|
|
105
|
+
try {
|
|
106
|
+
decoder.addChunk(buf);
|
|
107
|
+
let frameText = decoder.nextFrame();
|
|
108
|
+
while (frameText !== null) {
|
|
109
|
+
callback(frameText);
|
|
110
|
+
frameText = decoder.nextFrame();
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
if (logalot) { console.warn(`[SyncUpgradeHandlerBase] closing connection due to decoder error: ${extractErrorMsg(error)}`); }
|
|
114
|
+
socket.write(encodeCloseFrame());
|
|
115
|
+
socket.end();
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
onClose(callback: () => void): void {
|
|
120
|
+
socket.on('close', callback);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Bind peer receiver to handle all socket messages (connect & runtime)
|
|
125
|
+
await receiverPeer.bindSocket(socketWrapper);
|
|
126
|
+
|
|
127
|
+
return true;
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error(`${lc_fn} upgrade failure: ${extractErrorMsg(error)}`);
|
|
130
|
+
socket.destroy();
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
protected override async parseParamsImpl(reqCtx: RequestContext<ParamsWithDomain>): Promise<ParamsWithDomain | undefined> {
|
|
136
|
+
const match = reqCtx.pathname.match(this.regex);
|
|
137
|
+
if (!match) return undefined;
|
|
138
|
+
const domainIb = decodeURIComponent(match[1]);
|
|
139
|
+
const domainGib = decodeURIComponent(match[2]);
|
|
140
|
+
const domainAddr = getIbGibAddr({ ib: domainIb, gib: domainGib });
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
domainInfo: this.getDomainInfo({ domainAddr })
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
protected override async parseQueryParams(
|
|
148
|
+
reqCtx: RequestContext<ParamsWithDomain, SyncChannelQueryParams>
|
|
149
|
+
): Promise<SyncChannelQueryParams | undefined> {
|
|
150
|
+
const sAddrRaw = reqCtx.url.searchParams.get('sAddr');
|
|
151
|
+
const sAddr = sAddrRaw ? decodeURIComponent(sAddrRaw) : undefined;
|
|
152
|
+
const solution = reqCtx.url.searchParams.get('solution') ?? undefined;
|
|
153
|
+
|
|
154
|
+
const queryParams: Partial<SyncChannelQueryParams> = {};
|
|
155
|
+
if (sAddr !== undefined) { queryParams.sAddr = sAddr; }
|
|
156
|
+
if (solution !== undefined) { queryParams.solution = solution; }
|
|
157
|
+
|
|
158
|
+
if (Object.keys(queryParams).length > 0) {
|
|
159
|
+
const validationErrors = await this.validateQueryParams({ queryParams });
|
|
160
|
+
if (validationErrors.length === 0) {
|
|
161
|
+
return queryParams as SyncChannelQueryParams;
|
|
162
|
+
} else {
|
|
163
|
+
throw new Error(`invalid query params: ${validationErrors.join(', ')}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
protected override async validateQueryParams({ queryParams }: { queryParams: any }): Promise<string[]> {
|
|
170
|
+
const errors: string[] = [];
|
|
171
|
+
if (!queryParams) {
|
|
172
|
+
return ["Missing query parameters: sAddr, solution"];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (!queryParams.sAddr) {
|
|
176
|
+
errors.push("Missing sAddr");
|
|
177
|
+
} else {
|
|
178
|
+
try {
|
|
179
|
+
const decodedSAddr = queryParams.sAddr;
|
|
180
|
+
const addrErrors = validateIbGibAddr({ addr: decodedSAddr }) ?? [];
|
|
181
|
+
if (addrErrors.length > 0) {
|
|
182
|
+
errors.push(`Invalid sAddr: ${addrErrors.join(', ')}`);
|
|
183
|
+
} else {
|
|
184
|
+
const { ib } = getIbAndGib({ ibGibAddr: decodedSAddr });
|
|
185
|
+
parseKeystoneIb({ ib });
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
errors.push(`Invalid sAddr: ${extractErrorMsg(error)}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!queryParams.solution) {
|
|
193
|
+
errors.push("Missing solution");
|
|
194
|
+
}
|
|
195
|
+
return errors;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
protected override async handleRouteImpl(reqCtx: RequestContext<ParamsWithDomain>): Promise<ResponseResult | undefined> {
|
|
199
|
+
return this.error(400, 'WS endpoint requires upgrade');
|
|
200
|
+
}
|
|
201
|
+
}
|