@ibgib/space-gib 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/Dockerfile +14 -0
  3. package/IMPLEMENTATION.md +484 -0
  4. package/README.md +46 -0
  5. package/dist/client/bootstrap.mjs +58 -0
  6. package/dist/client/bootstrap.mjs.map +7 -0
  7. package/dist/client/chunk-CT47Z5WU.mjs +21 -0
  8. package/dist/client/chunk-CT47Z5WU.mjs.map +7 -0
  9. package/dist/client/chunk-RHEDTRKF.mjs +235 -0
  10. package/dist/client/chunk-RHEDTRKF.mjs.map +7 -0
  11. package/dist/client/index.html +147 -0
  12. package/dist/client/index.mjs +2 -0
  13. package/dist/client/index.mjs.map +7 -0
  14. package/dist/client/script.mjs +2 -0
  15. package/dist/client/script.mjs.map +7 -0
  16. package/dist/client/style.css +605 -0
  17. package/dist/respec-gib.node.mjs +5 -0
  18. package/dist/server/server.mjs +20157 -0
  19. package/dist/server/server.mjs.map +7 -0
  20. package/generate-version-file.js +35 -0
  21. package/package.json +27 -0
  22. package/src/client/AUTO-GENERATED-version.mts +11 -0
  23. package/src/client/README.md +19 -0
  24. package/src/client/api/function-infos.web.mts +38 -0
  25. package/src/client/api/space-gib-api-bridge.mts +85 -0
  26. package/src/client/bootstrap.mts +49 -0
  27. package/src/client/components/keystone-creator/keystone-creator.css +139 -0
  28. package/src/client/components/keystone-creator/keystone-creator.html +26 -0
  29. package/src/client/components/keystone-creator/keystone-creator.mts +229 -0
  30. package/src/client/constants.mts +76 -0
  31. package/src/client/custom.d.ts +11 -0
  32. package/src/client/dev-tools.mts +540 -0
  33. package/src/client/helpers.web.mts +178 -0
  34. package/src/client/index.html +147 -0
  35. package/src/client/index.mts +59 -0
  36. package/src/client/script.mts +13 -0
  37. package/src/client/style.css +605 -0
  38. package/src/client/types.mts +85 -0
  39. package/src/client/ui/shell/space-gib-shell-constants.mts +24 -0
  40. package/src/client/ui/shell/space-gib-shell-service.mts +233 -0
  41. package/src/client/ui/shell/space-gib-shell-types.mts +5 -0
  42. package/src/client/witness/app/space-gib/space-gib-app-v1.mts +160 -0
  43. package/src/client/witness/app/space-gib/space-gib-constants.mts +38 -0
  44. package/src/client/witness/app/space-gib/space-gib-helper.mts +72 -0
  45. package/src/client/witness/app/space-gib/space-gib-types.mts +47 -0
  46. package/src/common/keystone-policies.mts +159 -0
  47. package/src/respec-gib.node.mts +6 -0
  48. package/src/server/README.md +18 -0
  49. package/src/server/bootstrap-helper.mts +141 -0
  50. package/src/server/bootstrap-helper.respec.mts +100 -0
  51. package/src/server/metaspace-nodeindexedspace/metaspace-nodeindexedspace.mts +85 -0
  52. package/src/server/path-constants.mts +89 -0
  53. package/src/server/path-helper.mts +101 -0
  54. package/src/server/path-helper.respec.mts +94 -0
  55. package/src/server/serve-gib/CHANGELOG.md +29 -0
  56. package/src/server/serve-gib/README.md +34 -0
  57. package/src/server/serve-gib/constants.mts +1 -0
  58. package/src/server/serve-gib/handlers/api/debug/ws-echo.handler.mts +104 -0
  59. package/src/server/serve-gib/handlers/api/health.handler.mts +23 -0
  60. package/src/server/serve-gib/handlers/api/health.respec.mts +51 -0
  61. package/src/server/serve-gib/handlers/api/ibgib/ibgib-handler-types.mts +49 -0
  62. package/src/server/serve-gib/handlers/api/ibgib/ibgib.handler.mts +176 -0
  63. package/src/server/serve-gib/handlers/api/keystone/keystone-evolve.handler.mts +261 -0
  64. package/src/server/serve-gib/handlers/api/keystone/keystone-genesis.handler.mts +146 -0
  65. package/src/server/serve-gib/handlers/api/keystone/keystone-get.handler.mts +198 -0
  66. package/src/server/serve-gib/handlers/api/keystone/keystone-get.respec.mts +107 -0
  67. package/src/server/serve-gib/handlers/api/keystone/keystone-handler-types.mts +29 -0
  68. package/src/server/serve-gib/handlers/api/keystone/keystone-post.handler.mts +70 -0
  69. package/src/server/serve-gib/handlers/api/keystone/keystone-post.respec.mts +130 -0
  70. package/src/server/serve-gib/handlers/error-handler.mts +36 -0
  71. package/src/server/serve-gib/handlers/handler-base.mts +383 -0
  72. package/src/server/serve-gib/handlers/static-handler.mts +82 -0
  73. package/src/server/serve-gib/handlers/ws/sync-upgrade.handler.mts +498 -0
  74. package/src/server/serve-gib/handlers/ws/ws-helper.mts +111 -0
  75. package/src/server/serve-gib/handlers/ws/ws-types.mts +53 -0
  76. package/src/server/serve-gib/serve-gib-helpers.mts +32 -0
  77. package/src/server/serve-gib/serve-gib-v1.mts +172 -0
  78. package/src/server/serve-gib/serve-gib.respec.mts +90 -0
  79. package/src/server/serve-gib/types.mts +102 -0
  80. package/src/server/server-constants.mts +2 -0
  81. package/src/server/server.mts +96 -0
  82. package/tsconfig.json +29 -0
  83. package/tsconfig.server.json +29 -0
  84. package/tsconfig.test.json +27 -0
@@ -0,0 +1,107 @@
1
+ import { join } from 'node:path';
2
+ import { existsSync, rmSync, mkdirSync } from 'node:fs';
3
+
4
+ import {
5
+ respecfully, iReckon, ifWe, ifWeMight
6
+ } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
7
+ const sir = `[${import.meta.url}]`;
8
+
9
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
10
+ import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
11
+ import { createStandardPoolConfig } from '@ibgib/core-gib/dist/keystone/keystone-config-builder.mjs';
12
+ import { POOL_ID_DEFAULT } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs';
13
+
14
+ import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
15
+ import { ServeGib_V1 } from '../../../serve-gib-v1.mjs';
16
+ import { KeystonePostHandler } from './keystone-post.handler.mjs';
17
+ import { KeystoneGetHandler } from './keystone-get.handler.mjs';
18
+ import { ErrorHandler } from '../../error-handler.mjs';
19
+
20
+ const logalot = GLOBAL_LOG_A_LOT;
21
+
22
+ class MockMetaspace {
23
+ async getLocalUserSpace() { return new MockSpace(); }
24
+ async put() { }
25
+ async registerNewIbGib() { }
26
+ }
27
+ class MockSpace {
28
+ async witness() { return { data: { success: true } }; }
29
+ }
30
+
31
+ await respecfully(sir, 'Keystone GET Integration', async () => {
32
+ const testDataDir = './test-data-get';
33
+ const port = 3003;
34
+
35
+ // Clean test data
36
+ if (existsSync(testDataDir)) {
37
+ rmSync(testDataDir, { recursive: true, force: true });
38
+ }
39
+ mkdirSync(testDataDir, { recursive: true });
40
+
41
+ await ifWeMight(sir, 'retrieve a keystone chain via GET /api/keystone/:addr', async () => {
42
+ const keystoneService = new KeystoneService_V1();
43
+ const config = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: POOL_ID_DEFAULT });
44
+
45
+ // 1. Setup ServeGib_V1 with both POST and GET handlers
46
+ const serveGib = new ServeGib_V1({
47
+ port,
48
+ dataDir: testDataDir,
49
+ handlers: [
50
+ new KeystonePostHandler(),
51
+ new KeystoneGetHandler(),
52
+ ],
53
+ errorHandler: new ErrorHandler()
54
+ });
55
+
56
+ // 2. Generate and POST genesis
57
+ const genesis = await keystoneService.genesis({
58
+ masterSecret: 'AliceSecret',
59
+ configs: [config],
60
+ metaspace: new MockMetaspace() as any,
61
+ space: new MockSpace() as any,
62
+ });
63
+ const addr = getIbGibAddr({ ibGib: genesis });
64
+
65
+ const postReq: any = {
66
+ url: '/api/keystone',
67
+ method: 'POST',
68
+ headers: { 'ibgib-domain': addr, 'content-type': 'application/json' },
69
+ on: (event: string, cb: any) => {
70
+ if (event === 'data') cb(Buffer.from(JSON.stringify({ ibGibs: [genesis] })));
71
+ if (event === 'end') cb();
72
+ }
73
+ };
74
+ const postRes: any = {
75
+ writeHead: () => { },
76
+ end: () => { },
77
+ };
78
+ await serveGib.handleRequest(postReq, postRes);
79
+
80
+ // 3. Mock GET Request
81
+ const getReq: any = {
82
+ url: `/api/keystone/${encodeURIComponent(addr)}`,
83
+ method: 'GET',
84
+ headers: { 'ibgib-domain': addr },
85
+ on: (event: string, cb: any) => {
86
+ if (event === 'end') cb();
87
+ }
88
+ };
89
+
90
+ let capturedStatus: number = 0;
91
+ let capturedBody: any = null;
92
+ const getRes: any = {
93
+ writeHead: (status: number) => { capturedStatus = status; },
94
+ end: (body: string) => { capturedBody = JSON.parse(body); },
95
+ };
96
+
97
+ // 4. Handle GET
98
+ await serveGib.handleRequest(getReq, getRes);
99
+
100
+ // 5. Verify
101
+ iReckon(sir, capturedStatus).asTo('captured status code').isGonnaBe(200);
102
+ iReckon(sir, capturedBody.chain).asTo('captured body chain').isGonnaBeTruthy();
103
+ iReckon(sir, Array.isArray(capturedBody.chain)).asTo('chain is array').isGonnaBe(true);
104
+ iReckon(sir, capturedBody.chain.length).asTo('chain length').isGonnaBe(1);
105
+ iReckon(sir, capturedBody.chain[0].gib).asTo('genesis gib matches').isGonnaBe(genesis.gib);
106
+ });
107
+ });
@@ -0,0 +1,29 @@
1
+ import { DomainInfo } from "../../../types.mjs";
2
+
3
+ export interface KeystoneParams {
4
+ domainInfo: DomainInfo;
5
+ }
6
+
7
+ // #region KeystoneGetQueryParams
8
+ export const DEFAULT_QUERY_PARAMS_GET_KEYSTONE = {
9
+ /**
10
+ * If true, will get the latest keystone frame.
11
+ */
12
+ getLatest: true,
13
+ /**
14
+ * If true, will get the keystone's entire dependency graph
15
+ */
16
+ getGraph: true,
17
+ };
18
+ /**
19
+ * @see {@link DEFAULT_QUERY_PARAMS_GET_KEYSTONE} key/values for jsdocs
20
+ */
21
+ export type KeystoneGetQueryParams = Partial<typeof DEFAULT_QUERY_PARAMS_GET_KEYSTONE>;
22
+ export type KNOWN_QUERY_PARAMS_KEYSTONE_GET = keyof KeystoneGetQueryParams;
23
+ export const KNOWN_QUERY_PARAMS_KEYSTONE_GET = Object.keys(DEFAULT_QUERY_PARAMS_GET_KEYSTONE) as KNOWN_QUERY_PARAMS_KEYSTONE_GET[];
24
+ export function isKnownQueryParamsKey_KeystoneGet(key: any): key is KNOWN_QUERY_PARAMS_KEYSTONE_GET {
25
+ return !!key && typeof key === 'string' ?
26
+ KNOWN_QUERY_PARAMS_KEYSTONE_GET.includes(key as any) :
27
+ false;
28
+ }
29
+ // #endregion KeystoneGetQueryParams
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @module serve-gib/handlers/api/keystone
3
+ */
4
+
5
+ import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
6
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
7
+ import { validateIbGibIntrinsically } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
8
+
9
+ import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
10
+ import { ServeGibHandlerBase } from '../../handler-base.mjs';
11
+ import { RequestContext, ResponseResult, ServeGibHttpMethod } from '../../../types.mjs';
12
+ import { API_PATH_REGEXES } from '../../../../path-constants.mjs';
13
+ import { KeystoneParams } from './keystone-handler-types.mjs';
14
+
15
+ const logalot = GLOBAL_LOG_A_LOT;
16
+
17
+ /**
18
+ * POST /api/keystone
19
+ */
20
+ export class KeystonePostHandler extends ServeGibHandlerBase<KeystoneParams, any> { // todo: keystone post query params if needed?
21
+ protected override lc: string = `[${KeystonePostHandler.name}]`;
22
+ protected override method: ServeGibHttpMethod = 'POST';
23
+ protected override regex = API_PATH_REGEXES.KEYSTONE;
24
+
25
+ protected async handleRouteImpl(reqCtx: RequestContext<KeystoneParams, any>): Promise<ResponseResult | undefined> {
26
+ const lc = `[${this.handleRouteImpl.name}]`;
27
+ try {
28
+ if (logalot) { console.log(`${lc} starting... (I: 63bab8214834cb6e383e0fc364ee8826)`); }
29
+
30
+ const { metaspace } = reqCtx;
31
+ if (!metaspace) { throw new Error(`(UNEXPECTED) reqCtx.metaspace falsy? (E: 3d03027ea7f6f237980e511801255826)`); }
32
+
33
+ const { ibGibs } = JSON.parse(reqCtx.body) as { ibGibs: any[] };
34
+ if (!Array.isArray(ibGibs)) return this.error(400, 'ibGibs array required');
35
+
36
+ // 1. Intrinsic Validation
37
+ for (const ibGib of ibGibs) {
38
+ const errors = await validateIbGibIntrinsically({ ibGib });
39
+ if (errors) {
40
+ return this.error(422, 'Intrinsic validation failed', { failedAddr: getIbGibAddr({ ibGib }), errors });
41
+ }
42
+ }
43
+
44
+ // 2. Keystone-specific checks
45
+ for (const ibGib of ibGibs) {
46
+ if (ibGib.ib?.startsWith('keystone')) {
47
+ if (!reqCtx.metaspace) { return this.error(500, 'Metaspace not initialized'); }
48
+ // Registration handles genesis vs evolution internally via metastones
49
+ await reqCtx.metaspace.registerNewIbGib({
50
+ ibGib,
51
+ });
52
+ }
53
+ }
54
+
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
+ return { status: 201, body: { success: true }, isJson: true };
61
+
62
+ } catch (error) {
63
+ const emsg = `${lc} ${extractErrorMsg(error)}`;
64
+ console.error(emsg);
65
+ return this.error(500, emsg);
66
+ } finally {
67
+ if (logalot) { console.log(`${lc} complete.`); }
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,130 @@
1
+ import { join } from 'node:path';
2
+ import { existsSync, rmSync, mkdirSync, readdirSync } from 'node:fs';
3
+
4
+ import {
5
+ respecfully, iReckon, ifWe, ifWeMight
6
+ } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
7
+ const sir = `[${import.meta.url}]`;
8
+
9
+ import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
10
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
11
+ import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
12
+ import { createStandardPoolConfig } from '@ibgib/core-gib/dist/keystone/keystone-config-builder.mjs';
13
+ import { POOL_ID_DEFAULT } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs';
14
+
15
+ import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
16
+ import { ServeGib_V1 } from '../../../serve-gib-v1.mjs';
17
+ import { KeystonePostHandler } from './keystone-post.handler.mjs';
18
+ import { ErrorHandler } from '../../error-handler.mjs';
19
+ import { getDomainRootPath } from '../../../../bootstrap-helper.mjs';
20
+
21
+ const logalot = GLOBAL_LOG_A_LOT;
22
+ if (logalot) { console.log(`[test] keystone-post.respec.mts top-level entry`); }
23
+
24
+ class MockMetaspace {
25
+ async getLocalUserSpace() { return new MockSpace(); }
26
+ async put() { }
27
+ async registerNewIbGib() { }
28
+ }
29
+ class MockSpace {
30
+ async witness() { return { data: { success: true } }; }
31
+ }
32
+
33
+ await respecfully(sir, 'Keystone POST Integration', async () => {
34
+ const testDataDir = './test-data-post';
35
+ const port = 3001;
36
+
37
+ // Clean test data
38
+ if (existsSync(testDataDir)) {
39
+ rmSync(testDataDir, { recursive: true, force: true });
40
+ }
41
+ mkdirSync(testDataDir, { recursive: true });
42
+
43
+ await ifWe(sir, 'bootstrap a new domain via POST /api/keystone', async () => {
44
+ const keystoneService = new KeystoneService_V1();
45
+ const config = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: POOL_ID_DEFAULT });
46
+
47
+ // 1. Generate real genesis
48
+ const genesis = await keystoneService.genesis({
49
+ masterSecret: 'AliceSecret',
50
+ configs: [config],
51
+ metaspace: new MockMetaspace() as any,
52
+ space: new MockSpace() as any,
53
+ });
54
+ const addr = getIbGibAddr({ ibGib: genesis });
55
+
56
+ if (logalot) { console.log(`[test] Generated genesis: ${addr}`); }
57
+
58
+ // 2. Setup ServeGib_V1
59
+ const serveGib = new ServeGib_V1({
60
+ port,
61
+ dataDir: testDataDir,
62
+ handlers: [new KeystonePostHandler()],
63
+ errorHandler: new ErrorHandler()
64
+ });
65
+
66
+ if (logalot) { console.log(`[test] ServeGib_V1 setup. Posting to /api/keystone...`); }
67
+
68
+ // 3. Mock POST Request
69
+ const req: any = {
70
+ url: '/api/keystone',
71
+ method: 'POST',
72
+ headers: {
73
+ 'ibgib-domain': addr,
74
+ 'content-type': 'application/json'
75
+ },
76
+ on: (event: string, cb: any) => {
77
+ if (event === 'data') {
78
+ if (logalot) { console.log(`[test] sending data chunk...`); }
79
+ cb(Buffer.from(JSON.stringify({ ibGibs: [genesis] })));
80
+ }
81
+ if (event === 'end') {
82
+ if (logalot) { console.log(`[test] end of request.`); }
83
+ cb();
84
+ }
85
+ }
86
+ };
87
+
88
+ let capturedStatus: number = 0;
89
+ let capturedBody: any = null;
90
+ const res: any = {
91
+ writeHead: (status: number) => {
92
+ if (logalot) { console.log(`[test] writeHead: ${status}`); }
93
+ capturedStatus = status;
94
+ },
95
+ end: (body: string) => {
96
+ if (logalot) { console.log(`[test] res.end called with body length: ${body?.length}`); }
97
+ capturedBody = JSON.parse(body);
98
+ },
99
+ statusCode: 0
100
+ };
101
+
102
+ // 4. Handle
103
+ if (logalot) { console.log(`[test] Calling handleRequest...`); }
104
+ await serveGib.handleRequest(req, res);
105
+ if (logalot) { console.log(`[test] handleRequest completed.`); }
106
+
107
+ // 5. Verify
108
+ iReckon(sir, capturedStatus).asTo('captured status code').isGonnaBe(201);
109
+ iReckon(sir, capturedBody.success).asTo(`Handler failed: ${capturedBody.message || 'no message'}`).isGonnaBe(true);
110
+
111
+ const domainPath = getDomainRootPath(genesis.gib!, testDataDir);
112
+ iReckon(sir, existsSync(domainPath)).asTo('domain path exists').isGonnaBe(true);
113
+
114
+ // Verify the ibgib actually exists in the new domain's storage
115
+ // With indexed storage, it's in a bucketed subpath: ibgib/default/ibgibs/B1/B2/
116
+ const bucket1 = genesis.gib!.substring(0, 3).toUpperCase();
117
+ const bucket2 = genesis.gib!.substring(3, 6).toUpperCase();
118
+ const bucketPath = join(domainPath, 'ibgib', 'default', 'ibgibs', bucket1, bucket2);
119
+
120
+ iReckon(sir, existsSync(bucketPath)).asTo(`Bucket path does not exist: ${bucketPath}`).isGonnaBe(true);
121
+
122
+ // We don't know the random filename, but we know it's a .json file in that bucket
123
+ try {
124
+ const files = readdirSync(bucketPath).filter(f => f.endsWith('.json'));
125
+ iReckon(sir, files.length > 0).asTo(`No .json files found in bucket: ${bucketPath}`).isGonnaBe(true);
126
+ } catch (error) {
127
+ iReckon(sir, true).asTo(`error trying to readdir ${bucketPath}: ${extractErrorMsg(error)}`).isGonnaBe(true);
128
+ }
129
+ });
130
+ });
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @module serve-gib/handlers/error-handler
3
+ *
4
+ * Default error handler for serve-gib.
5
+ */
6
+
7
+ import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
8
+
9
+ import { GLOBAL_LOG_A_LOT } from '../constants.mjs';
10
+ import { ServeGibHandlerBase } from './handler-base.mjs';
11
+ import { RequestContext, ResponseResult, ServeGibHttpMethod } from '../types.mjs';
12
+
13
+ const logalot = GLOBAL_LOG_A_LOT;
14
+
15
+ export class ErrorHandler extends ServeGibHandlerBase {
16
+ protected override lc: string = `[${ErrorHandler.name}]`;
17
+ protected override method: ServeGibHttpMethod = 'ALL';
18
+ protected override regex = /.*/;
19
+
20
+ async handleRouteImpl(reqCtx: RequestContext): Promise<ResponseResult | undefined> {
21
+ const lc = `${this.lc}[${this.handleRouteImpl.name}]`;
22
+ try {
23
+ if (logalot) { console.log(`${lc} starting...`); }
24
+
25
+ const { rawUrl, pathname, method, } = reqCtx;
26
+
27
+ // This is the fallback handler
28
+ return this.error(404, 'Not Found', { method, rawUrl, pathname });
29
+ } catch (error: any) {
30
+ console.log(`${lc} ${extractErrorMsg(error)}`);
31
+ throw error;
32
+ } finally {
33
+ if (logalot) { console.log(`${lc} complete.`); }
34
+ }
35
+ }
36
+ }