@ibgib/space-gib 0.0.8 → 0.0.12

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 (83) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +1 -0
  3. package/dist/client/bootstrap.mjs +33 -33
  4. package/dist/client/bootstrap.mjs.map +3 -3
  5. package/dist/client/chunk-GCWH3SH4.mjs +21 -0
  6. package/dist/client/chunk-GCWH3SH4.mjs.map +7 -0
  7. package/dist/client/chunk-I7KNBFG3.mjs +2329 -0
  8. package/dist/client/chunk-I7KNBFG3.mjs.map +7 -0
  9. package/dist/client/index.mjs +22 -1
  10. package/dist/client/index.mjs.map +4 -4
  11. package/dist/client/script.mjs +1 -1
  12. package/dist/server/server.mjs +18815 -17778
  13. package/dist/server/server.mjs.map +4 -4
  14. package/package.json +4 -4
  15. package/space-gib.localhost-1785337158142.log +75 -0
  16. package/src/client/AUTO-GENERATED-version.mts +1 -1
  17. package/src/client/README.md +1 -1
  18. package/src/client/api/space-gib-api-bridge.mts +8 -195
  19. package/src/client/dev-tools/common.mts +4 -4
  20. package/src/client/ui/shell/space-gib-shell-service.mts +68 -18
  21. package/src/common/keystone-policies.mts +1 -1
  22. package/src/server/README.md +3 -2
  23. package/src/server/server.mts +13 -32
  24. package/src/server/test.json +0 -0
  25. package/dist/client/chunk-DBHMHCGD.mjs +0 -2341
  26. package/dist/client/chunk-DBHMHCGD.mjs.map +0 -7
  27. package/dist/client/chunk-SUQ5QJH4.mjs +0 -42
  28. package/dist/client/chunk-SUQ5QJH4.mjs.map +0 -7
  29. package/space-gib.localhost-1783713259760.log +0 -45
  30. package/src/client/components/identity-header/IMPLEMENTATION.md +0 -45
  31. package/src/client/components/identity-header/identity-header.css +0 -112
  32. package/src/client/components/identity-header/identity-header.html +0 -11
  33. package/src/client/components/identity-header/identity-header.mts +0 -439
  34. package/src/client/components/identity-manager/IMPLEMENTATION.md +0 -100
  35. package/src/client/components/identity-manager/identity-manager.css +0 -171
  36. package/src/client/components/identity-manager/identity-manager.html +0 -19
  37. package/src/client/components/identity-manager/identity-manager.mts +0 -639
  38. package/src/client/components/keystone-creator/keystone-creator.css +0 -65
  39. package/src/client/components/keystone-creator/keystone-creator.html +0 -41
  40. package/src/client/components/keystone-creator/keystone-creator.mts +0 -443
  41. package/src/client/components/keystone-details/keystone-details.css +0 -569
  42. package/src/client/components/keystone-details/keystone-details.html +0 -127
  43. package/src/client/components/keystone-details/keystone-details.mts +0 -1013
  44. package/src/client/components/keystone-scrubber/SCRUBBER_IMPLEMENTATION.md +0 -33
  45. package/src/client/components/keystone-scrubber/keystone-scrubber.css +0 -46
  46. package/src/client/components/keystone-scrubber/keystone-scrubber.html +0 -15
  47. package/src/client/components/keystone-scrubber/keystone-scrubber.mts +0 -356
  48. package/src/server/bootstrap-helper.mts +0 -141
  49. package/src/server/bootstrap-helper.respec.mts +0 -100
  50. package/src/server/metaspace-nodeindexedspace/metaspace-nodeindexedspace.mts +0 -85
  51. package/src/server/path-constants.mts +0 -101
  52. package/src/server/path-helper.mts +0 -101
  53. package/src/server/path-helper.respec.mts +0 -99
  54. package/src/server/serve-gib/CHANGELOG.md +0 -29
  55. package/src/server/serve-gib/README.md +0 -43
  56. package/src/server/serve-gib/constants.mts +0 -1
  57. package/src/server/serve-gib/handlers/api/debug/ws-echo.handler.mts +0 -105
  58. package/src/server/serve-gib/handlers/api/health.handler.mts +0 -23
  59. package/src/server/serve-gib/handlers/api/health.respec.mts +0 -51
  60. package/src/server/serve-gib/handlers/api/ibgib/ibgib-handler-types.mts +0 -49
  61. package/src/server/serve-gib/handlers/api/ibgib/ibgib.handler.mts +0 -176
  62. package/src/server/serve-gib/handlers/api/keystone/keystone-evolve.handler.mts +0 -141
  63. package/src/server/serve-gib/handlers/api/keystone/keystone-genesis.handler.mts +0 -146
  64. package/src/server/serve-gib/handlers/api/keystone/keystone-get.handler.mts +0 -198
  65. package/src/server/serve-gib/handlers/api/keystone/keystone-get.respec.mts +0 -107
  66. package/src/server/serve-gib/handlers/api/keystone/keystone-handler-types.mts +0 -29
  67. package/src/server/serve-gib/handlers/api/keystone/keystone-post.handler.mts +0 -55
  68. package/src/server/serve-gib/handlers/api/keystone/keystone-post.respec.mts +0 -130
  69. package/src/server/serve-gib/handlers/api/keystone/sso-config.handler.mts +0 -66
  70. package/src/server/serve-gib/handlers/api/keystone/sso-link.handler.mts +0 -140
  71. package/src/server/serve-gib/handlers/api/keystone/sso-login.handler.mts +0 -190
  72. package/src/server/serve-gib/handlers/error-handler.mts +0 -36
  73. package/src/server/serve-gib/handlers/handler-base.mts +0 -383
  74. package/src/server/serve-gib/handlers/static-handler.mts +0 -82
  75. package/src/server/serve-gib/handlers/ws/sync-upgrade-handler-base.mts +0 -233
  76. package/src/server/serve-gib/handlers/ws/sync-upgrade.handler.mts +0 -24
  77. package/src/server/serve-gib/handlers/ws/ws-helper.mts +0 -216
  78. package/src/server/serve-gib/handlers/ws/ws-types.mts +0 -53
  79. package/src/server/serve-gib/serve-gib-helpers.mts +0 -32
  80. package/src/server/serve-gib/serve-gib-v1.mts +0 -172
  81. package/src/server/serve-gib/serve-gib.respec.mts +0 -90
  82. package/src/server/serve-gib/types.mts +0 -102
  83. package/src/server/server-constants.mts +0 -2
@@ -1,100 +0,0 @@
1
- import { join } from 'node:path';
2
- import { existsSync, mkdirSync, rmSync } from 'node:fs';
3
-
4
- import { respecfully, iReckon, ifWe } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
5
- const sir = `[${import.meta.url}]`;
6
- import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
7
- import { KeystoneService_V1 } from '@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs';
8
- import { createStandardPoolConfig } from '@ibgib/core-gib/dist/keystone/keystone-config-builder.mjs';
9
- import { POOL_ID_DEFAULT } from '@ibgib/core-gib/dist/keystone/keystone-constants.mjs';
10
-
11
- import { GLOBAL_LOG_A_LOT } from './server-constants.mjs';
12
- import { getDomainRootPath, bootstrapDomainMetaspace } from './bootstrap-helper.mjs';
13
-
14
- const logalot = GLOBAL_LOG_A_LOT;
15
-
16
-
17
- /**
18
- * Minimal mock to satisfy KeystoneService requirements during genesis.
19
- */
20
- class MockMetaspace {
21
- async getLocalUserSpace() { return new MockSpace(); }
22
- async put() { }
23
- async registerNewIbGib() { }
24
- }
25
- class MockSpace {
26
- async witness() { return { data: { success: true } }; }
27
- }
28
-
29
- await respecfully(sir, 'bootstrap-helper', async () => {
30
- const lc = `[bootstrap-helper.respec.mts][bootstrap-helper]`;
31
- const testDataDir = './test-data';
32
- console.log(`${lc} testDataDir: ${testDataDir} (I: c9f39853a57a5af97ab8ff7882c49826)`);
33
-
34
- // Clean and recreate test-data directory
35
- if (existsSync(testDataDir)) {
36
- rmSync(testDataDir, { recursive: true, force: true });
37
- }
38
- mkdirSync(testDataDir, { recursive: true });
39
-
40
- await ifWe(sir, 'calculate balanced domain root paths', async () => {
41
- const tjpGib = 'abcde1234567890';
42
- const root = getDomainRootPath(tjpGib, testDataDir);
43
-
44
- // Should be: testDataDir/domains/ab/cd/abcde1234567890
45
- iReckon(sir, root).includes(join('domains', 'ab', 'cd', tjpGib));
46
- });
47
-
48
- await ifWe(sir, 'bootstrap a domain metaspace and create the directory', async () => {
49
- const keystoneAddr = 'keystone_alice^abcde1234567890';
50
- const metaspace = await bootstrapDomainMetaspace(keystoneAddr, testDataDir);
51
-
52
- iReckon(sir, metaspace).isGonnaBe(metaspace);
53
- iReckon(sir, metaspace.initialized).isGonnaBe(true);
54
-
55
- const expectedPath = getDomainRootPath('abcde1234567890', testDataDir);
56
- iReckon(sir, existsSync(expectedPath)).isGonnaBe(true);
57
-
58
- // The ibgib framework uses a specific subdirectory structure for the bootstrap
59
- const bootstrapFile = join(expectedPath, 'ibgib', '000_zerospace', 'gib', 'bootstrap.json');
60
- iReckon(sir, existsSync(bootstrapFile)).isGonnaBe(true);
61
-
62
- // Also check that the default space was created
63
- const defaultSpaceDir = join(expectedPath, 'ibgib', 'default');
64
- iReckon(sir, existsSync(defaultSpaceDir)).isGonnaBe(true);
65
- });
66
-
67
- await ifWe(sir, 'integrate with KeystoneService and bootstrap 5 unique domains', async () => {
68
- const keystoneService = new KeystoneService_V1();
69
- const mockMetaspace = new MockMetaspace() as any;
70
- const mockSpace = new MockSpace() as any;
71
- const config = createStandardPoolConfig({ id: POOL_ID_DEFAULT, salt: POOL_ID_DEFAULT });
72
-
73
- const identities = ['Alice', 'Bob', 'Charlie', 'Dave', 'Eve'];
74
-
75
- for (const name of identities) {
76
- // 1. Generate an actual genesis keystone for this identity
77
- const keystone = await keystoneService.genesis({
78
- masterSecret: `SecretFor_${name}`,
79
- configs: [config],
80
- metaspace: mockMetaspace,
81
- space: mockSpace,
82
- });
83
- const addr = getIbGibAddr({ ibGib: keystone });
84
- const tjpGib = keystone.gib!;
85
-
86
- if (logalot) { console.log(`[test] Bootstrapping domain for ${name}: ${addr} (I: 7ba45828f2719ca578a1f078ff16e126)`); }
87
-
88
- // 2. Drive the bootstrap logic
89
- const metaspace = await bootstrapDomainMetaspace(addr, testDataDir);
90
- iReckon(sir, metaspace.initialized).isGonnaBe(true);
91
-
92
- // 3. Verify the unique path
93
- const expectedPath = getDomainRootPath(tjpGib, testDataDir);
94
- iReckon(sir, existsSync(expectedPath)).isGonnaBe(true);
95
-
96
- const bootstrapFile = join(expectedPath, 'ibgib', '000_zerospace', 'gib', 'bootstrap.json');
97
- iReckon(sir, existsSync(bootstrapFile)).isGonnaBe(true);
98
- }
99
- });
100
- });
@@ -1,85 +0,0 @@
1
- /**
2
- * @module node-metaspace driven by a node+fs storage substrate
3
- *
4
- * a metaspace is a space of spaces. it adds/removes spaces and does
5
- * inter-spatial composition related things. it's similar to what people think
6
- * of in terms of a node in a p2p network.
7
- */
8
-
9
- import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
10
- import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
11
- import { IbGibCacheService } from '@ibgib/core-gib/dist/common/cache/cache-types.mjs';
12
- import { MetaspaceBase } from '@ibgib/core-gib/dist/witness/space/metaspace/metaspace-base.mjs';
13
- import { MetaspaceFactory } from '@ibgib/core-gib/dist/witness/space/metaspace/metaspace-types.mjs';
14
-
15
- import { GLOBAL_LOG_A_LOT, GLOBAL_TIMER_NAME } from '../server-constants.mjs';
16
-
17
- const logalot = GLOBAL_LOG_A_LOT;
18
-
19
- /**
20
- *
21
- */
22
- export class Metaspace_Nodeindexedspace extends MetaspaceBase {
23
-
24
- // we won't get an object back, only a DTO ibGib essentially
25
- protected lc: string = `[${Metaspace_Nodeindexedspace.name}]`;
26
-
27
- get zeroSpace(): IbGibSpaceAny {
28
- const lc = `[${this.lc}][get zeroSpace]`;
29
- if (this.metaspaceFactory.fnZeroSpaceFactory) {
30
- return this.metaspaceFactory.fnZeroSpaceFactory();
31
- } else {
32
- throw new Error(`${lc} (UNEXPECTED) this.metaspaceFactory.fnZeroSpaceFactory falsy. not initialized? (E: 9e6c6954dacd868b18c9f34a71e63523)`);
33
- }
34
- }
35
-
36
- constructor(
37
- // public modalController: ModalController,
38
- // public alertController: AlertController,
39
- protected cacheSvc: IbGibCacheService | undefined,
40
- // private latestCacheSvc: IonicStorageLatestIbgibCacheService,
41
- ) {
42
- super(cacheSvc);
43
- const lc = `${this.lc}[ctor]`;
44
- if (logalot) {
45
- console.log(`${lc}${GLOBAL_TIMER_NAME}`);
46
- console.timeLog(GLOBAL_TIMER_NAME);
47
- console.log(`${lc} created. (I: 5690dc2ebf774df3a442bd463dee7455)`);
48
- }
49
-
50
- }
51
-
52
- protected async initializeMetaspaceFactory({ metaspaceFactory }: {
53
- metaspaceFactory: MetaspaceFactory,
54
- }): Promise<void> {
55
- const lc = `[${this.initializeMetaspaceFactory.name}]`;
56
- try {
57
- if (logalot) { console.log(`${lc} starting... (I: 5a29670439ac47634dcdfe25225c8223)`); }
58
- if (!metaspaceFactory) { throw new Error(`(UNEXPECTED) metaspaceFactory falsy? space-gib server initialization should have guaranteed this to be truthy (E: f305356c2978cf0ee8062fd818940826)`); }
59
- if (!metaspaceFactory.fnDefaultLocalSpaceFactory) { throw new Error(`(UNEXPECTED) !metaspaceFactory.fnDefaultLocalSpaceFactory? space-gib server initialization should have guaranteed this to be truthy (E: 884281e5251bd65528eb7b3f48737826)`); }
60
- if (!metaspaceFactory.fnDtoToSpace) { throw new Error(`(UNEXPECTED) !metaspaceFactory.fnDtoToSpace? space-gib server initialization should have guaranteed this to be truthy (E: 885b7828606f36f9183bb9e687e25826)`); }
61
- if (!metaspaceFactory.fnZeroSpaceFactory) { throw new Error(`(UNEXPECTED) !metaspaceFactory.fnZeroSpaceFactory? space-gib server initialization should have guaranteed this to be truthy (E: 336cf6655758bad4aaeea8ce08d8c826)`); }
62
-
63
- await super.initializeMetaspaceFactory({ metaspaceFactory });
64
- } catch (error) {
65
- console.error(`${lc} ${extractErrorMsg(error)}`);
66
- throw error;
67
- } finally {
68
- if (logalot) { console.log(`${lc} complete.`); }
69
- }
70
- }
71
-
72
- // async initializeZeroSpace(): Promise<void> {
73
- // const lc = `[${this.initializeZeroSpace.name}]`;
74
- // try {
75
- // if (logalot) { console.log(`${lc} starting... (I: a3364e9601c70c8163e67868e5d67723)`); }
76
-
77
- // } catch (error) {
78
- // console.error(`${lc} ${extractErrorMsg(error)}`);
79
- // throw error;
80
- // } finally {
81
- // if (logalot) { console.log(`${lc} complete.`); }
82
- // }
83
- // }
84
-
85
- }
@@ -1,101 +0,0 @@
1
- /** Maximum allowed path length to prevent DoS. */
2
- export const MAX_PATH_LENGTH = 2048;
3
-
4
- /**
5
- * Blacklisted patterns for any incoming path.
6
- * We iterate through these for a quick security check.
7
- */
8
- export const FORBIDDEN_PATTERNS = [
9
- /\.\./, // No directory traversal
10
- /\/\//, // No redundant slashes
11
- /\0/, // No null bytes
12
- /(^|\/)\./, // No hidden/dot-files (e.g. .env, .git)
13
- ];
14
-
15
- /**
16
- * Regex for valid API paths.
17
- *
18
- * IMPORTANT: See IMPLEMENTATION.md for overall path schema documentation.
19
- *
20
- * Paths are URL encoded. The `ib` and `gib` portions of addresses are captured explicitly
21
- * by splitting on `%5E` or `^`.
22
- */
23
- export const API_PATH_REGEXES = {
24
- /**
25
- * /api/health
26
- */
27
- HEALTH: /^\/api\/health\/?$/,
28
-
29
- /**
30
- * /api/ibgib/graph/:domainAddr/:ibgibAddr
31
- */
32
- IBGIB_GRAPH: /^\/api\/ibgib\/graph\/([^\/]+?)(?:%5E|\^)([^\/]+)\/([^\/]+?)(?:%5E|\^)([^\/]+)\/?$/,
33
-
34
- /**
35
- * /api/ibgib/:domainAddr/:ibgibAddr
36
- */
37
- IBGIB_ADDR: /^\/api\/ibgib\/([^\/]+?)(?:%5E|\^)([^\/]+)\/([^\/]+?)(?:%5E|\^)([^\/]+)\/?$/,
38
-
39
- /**
40
- * /api/keystone
41
- */
42
- KEYSTONE: /^\/api\/keystone\/?$/,
43
-
44
- /**
45
- * /api/keystone/:domainAddr
46
- */
47
- KEYSTONE_ADDR: /^\/api\/keystone\/([^\/]+?)(?:%5E|\^)([^\/]+)\/?$/,
48
-
49
- /**
50
- * /api/ibgib
51
- */
52
- IBGIB_BASE: /^\/api\/ibgib\/?$/,
53
-
54
- /**
55
- * /api/keystone/evolve/:domainAddr
56
- */
57
- KEYSTONE_EVOLVE: /^\/api\/keystone\/evolve\/([^\/]+?)(?:%5E|\^)([^\/]+)\/?$/,
58
-
59
- /**
60
- * /api/keystone/genesis
61
- *
62
- * Accepts a single genesis-frame keystone ibgib and creates a new
63
- * domain-isolated metaspace for it. No `:domainAddr` in the URL because
64
- * the server derives the domain from the incoming keystone ibgib itself.
65
- *
66
- * Parallel to /api/keystone/evolve.
67
- */
68
- KEYSTONE_GENESIS: /^\/api\/keystone\/genesis\/?$/,
69
-
70
- /**
71
- * /api/debug/ws-echo
72
- *
73
- * Minimal WebSocket echo endpoint for validating WS plumbing (Traefik
74
- * passthrough, server upgrade handling, client connectivity) before
75
- * integrating real sync logic.
76
- *
77
- * ## intent
78
- *
79
- * NOT for production use. Remove or gate behind a flag once WS sync is
80
- * confirmed working end-to-end.
81
- */
82
- DEBUG_WS_ECHO: /^\/api\/debug\/ws-echo\/?$/,
83
- /**
84
- * /api/sync/ws/:domainAddr
85
- */
86
- SYNC_WS: /^\/api\/sync\/ws\/([^\/]+?)(?:%5E|\^)([^\/]+)\/?$/,
87
- /**
88
- * /api/identity/sso/link
89
- */
90
- IDENTITY_SSO_LINK: /^\/api\/identity\/sso\/link\/?$/,
91
- /**
92
- * /api/identity/sso/login
93
- */
94
- IDENTITY_SSO_LOGIN: /^\/api\/identity\/sso\/login\/?$/,
95
- /**
96
- * /api/identity/sso/config
97
- */
98
- IDENTITY_SSO_CONFIG: /^\/api\/identity\/sso\/config\/?$/,
99
- };
100
-
101
- export const VALID_STATIC_PATH_REGEX = /^\/[a-zA-Z0-9\-_\.\/]*$/;
@@ -1,101 +0,0 @@
1
- import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
2
- import { validateIbGibAddr } from '@ibgib/ts-gib/dist/V1/validate-helper.mjs';
3
-
4
- import { GLOBAL_LOG_A_LOT } from './server-constants.mjs';
5
- import { FORBIDDEN_PATTERNS, MAX_PATH_LENGTH, VALID_STATIC_PATH_REGEX } from './path-constants.mjs';
6
-
7
- const logalot = GLOBAL_LOG_A_LOT;
8
-
9
- /**
10
- * little helper function just to DRY out code.
11
- */
12
- export function runtimeErrorValidationStrings(lc: string, error: any): string[] {
13
- const emsg = `${lc} ${extractErrorMsg(error)}`;
14
- console.error(emsg);
15
- return [`runtime error: ${emsg}`];
16
- }
17
-
18
- /**
19
- * Validates that a path is safe from common attacks and under max length.
20
- */
21
- export function validateRawPath(rawPath: string): string[] {
22
- const lc = `[${validateRawPath.name}]`;
23
- try {
24
- if (logalot) { console.log(`${lc} starting... (I: 80bd6f63e6c83b8e943b90383e044826)`); }
25
-
26
- const errors: string[] = [];
27
-
28
- if (!rawPath || rawPath.length > MAX_PATH_LENGTH) {
29
- errors.push(`path too long. MAX_PATH_LENGTH: ${MAX_PATH_LENGTH}, incoming path length: ${rawPath.length}`);
30
- }
31
-
32
- for (const pattern of FORBIDDEN_PATTERNS) {
33
- if (pattern.test(rawPath)) {
34
- errors.push(`invalid path. contains forbidden pattern.source: ${pattern.source} (E: 56a228fb9473a086b83d0088b5af1826)`);
35
- }
36
- }
37
-
38
- return errors;
39
- } catch (error) {
40
- return runtimeErrorValidationStrings(lc, error);
41
- } finally {
42
- if (logalot) { console.log(`${lc} complete.`); }
43
- }
44
- }
45
-
46
- /**
47
- * simple boolean wrapper for {@link validateRawPath}
48
- */
49
- export function isSafePath(path: string): boolean {
50
- const errors = validateRawPath(path);
51
- return errors.length === 0;
52
- }
53
-
54
- export function validateStaticPath(path: string): string[] {
55
- const lc = `[${validateStaticPath.name}]`;
56
- try {
57
- if (logalot) { console.log(`${lc} starting... (I: 4f9cf8ffd528c7dd88324529528eeb26)`); }
58
-
59
- const errors: string[] = [];
60
-
61
- if (!VALID_STATIC_PATH_REGEX.test(path)) {
62
- errors.push(`static path fails to match VALID_STATIC_PATH_REGEX of ${VALID_STATIC_PATH_REGEX} (E: dfdf38a0439d4d09186e6fa81ab66826) `);
63
- }
64
-
65
- return errors;
66
- } catch (error) {
67
- return runtimeErrorValidationStrings(lc, error);
68
- } finally {
69
- if (logalot) { console.log(`${lc} complete.`); }
70
- }
71
- }
72
-
73
- /**
74
- * Validates a static file path.
75
- */
76
- export function isValidStaticPath(path: string): boolean {
77
- if (!isSafePath(path)) { return false; }
78
- const errors = validateStaticPath(path);
79
- return errors.length === 0;
80
- }
81
-
82
- /**
83
- * Decodes and validates a single ibGib address segment from a URL path.
84
- * Uses the library's internal validateIbGibAddr for deep checking.
85
- */
86
- export function validateAddressSegment(encodedAddr: string): string[] {
87
- const lc = `[${validateAddressSegment.name}]`;
88
- try {
89
- if (logalot) { console.log(`${lc} starting... (I: 1bb9ff7e1aefb77b670b2519658cc126)`); }
90
- if (!encodedAddr) {
91
- throw new Error(`(UNEXPECTED) falsy encodedAddr? We're expecting to have already guaranteed there are no double-slashes (i.e. no empty segments) (E: 7be7668e7b8c9fbbdf56f0fe19f92e26)`);
92
- }
93
- const addr = decodeURIComponent(encodedAddr);
94
- const errors = validateIbGibAddr({ addr });
95
- return errors ?? [];
96
- } catch (error) {
97
- return runtimeErrorValidationStrings(lc, error);
98
- } finally {
99
- if (logalot) { console.log(`${lc} complete.`); }
100
- }
101
- }
@@ -1,99 +0,0 @@
1
- // import { respecfully, iReckon, ifWe } from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
2
- // import {
3
- // isSafePath, isValidStaticPath,
4
- // // API_PATHS, getPathParams, MAX_PATH_LENGTH,
5
- // validateAddressSegment
6
- // } from './path-helper.mjs';
7
- // import { MAX_PATH_LENGTH } from './path-constants.mts';
8
-
9
- // const sir = `[${import.meta.url}]`;
10
-
11
- // await respecfully(sir, 'Path Helper Validation', async () => {
12
-
13
- // await respecfully(sir, 'isSafePath', async () => {
14
- // await ifWe(sir, 'valid simple paths', async () => {
15
- // iReckon(sir, isSafePath('/api/health')).isGonnaBeTrue();
16
- // iReckon(sir, isSafePath('/index.html')).isGonnaBeTrue();
17
- // });
18
-
19
- // await ifWe(sir, 'too long paths', async () => {
20
- // const longPath = '/'.repeat(MAX_PATH_LENGTH + 1);
21
- // iReckon(sir, isSafePath(longPath)).isGonnaBeFalse();
22
- // });
23
-
24
- // await ifWe(sir, 'directory traversal attempts', async () => {
25
- // iReckon(sir, isSafePath('/../etc/passwd')).isGonnaBeFalse();
26
- // iReckon(sir, isSafePath('/api/../../etc/passwd')).isGonnaBeFalse();
27
- // });
28
-
29
- // await ifWe(sir, 'null bytes', async () => {
30
- // iReckon(sir, isSafePath('/api/health\0')).isGonnaBeFalse();
31
- // });
32
-
33
- // await ifWe(sir, 'redundant slashes', async () => {
34
- // iReckon(sir, isSafePath('/api//health')).isGonnaBeFalse();
35
- // });
36
-
37
- // await ifWe(sir, 'dot-file access', async () => {
38
- // iReckon(sir, isSafePath('/.env')).isGonnaBeFalse();
39
- // iReckon(sir, isSafePath('/scripts/.hidden')).isGonnaBeFalse();
40
- // iReckon(sir, isSafePath('/.git/config')).isGonnaBeFalse();
41
- // });
42
- // });
43
-
44
- // await respecfully(sir, 'validateAddressSegment', async () => {
45
- // await ifWe(sir, 'valid encoded addresses', async () => {
46
- // const validGib = 'a'.repeat(64);
47
- // iReckon(sir, validateAddressSegment(`someib%5E${validGib}`)).isGonnaBeTrue();
48
- // // gib with dots (common in sha256.sha256)
49
- // const dotGib = `${validGib}.${validGib}`;
50
- // iReckon(sir, validateAddressSegment(`someib%5E${dotGib}`)).isGonnaBeTrue();
51
- // });
52
-
53
- // await ifWe(sir, 'invalid encoded addresses', async () => {
54
- // iReckon(sir, validateAddressSegment('no_delim')).isGonnaBeFalse();
55
- // iReckon(sir, validateAddressSegment('%5Estarts_with_delim')).isGonnaBeFalse();
56
- // iReckon(sir, validateAddressSegment('too%5Emany%5Edelims')).isGonnaBeFalse();
57
- // iReckon(sir, validateAddressSegment('too%5Emany..dots')).isGonnaBeFalse();
58
- // iReckon(sir, validateAddressSegment('invalid_chars_!%5Eabc')).isGonnaBeFalse();
59
- // });
60
- // });
61
-
62
- // await respecfully(sir, 'API_PATHS Regexes', async () => {
63
- // await ifWe(sir, 'HEALTH regex', async () => {
64
- // iReckon(sir, API_PATHS.HEALTH.test('/api/health')).isGonnaBeTrue();
65
- // iReckon(sir, API_PATHS.HEALTH.test('/api/health/')).isGonnaBeTrue();
66
- // iReckon(sir, API_PATHS.HEALTH.test('/api/health/more')).isGonnaBeFalse();
67
- // });
68
-
69
- // await ifWe(sir, 'IBGIB_ADDR regex', async () => {
70
- // // valid encoded addr: someib%5Esomegib
71
- // const addr = '/api/ibgib/someib%5Esomegib';
72
- // iReckon(sir, API_PATHS.IBGIB_ADDR.test(addr)).isGonnaBeTrue();
73
-
74
- // const params = getPathParams(addr, API_PATHS.IBGIB_ADDR);
75
- // iReckon(sir, params?.[0]).isGonnaBe('someib%5Esomegib');
76
- // });
77
-
78
- // await ifWe(sir, 'IBGIB_GRAPH regex', async () => {
79
- // const path = '/api/ibgib/graph/someib%5Esomegib';
80
- // iReckon(sir, API_PATHS.IBGIB_GRAPH.test(path)).isGonnaBeTrue();
81
-
82
- // const params = getPathParams(path, API_PATHS.IBGIB_GRAPH);
83
- // iReckon(sir, params?.[0]).isGonnaBe('someib%5Esomegib');
84
- // });
85
-
86
- // await ifWe(sir, 'KEYSTONE regex', async () => {
87
- // iReckon(sir, API_PATHS.KEYSTONE.test('/api/keystone')).isGonnaBeTrue();
88
- // iReckon(sir, API_PATHS.KEYSTONE.test('/api/keystone/')).isGonnaBeTrue();
89
- // });
90
-
91
- // await ifWe(sir, 'KEYSTONE_EVOLVE regex', async () => {
92
- // const path = '/api/keystone/evolve/someib%5Esomegib';
93
- // iReckon(sir, API_PATHS.KEYSTONE_EVOLVE.test(path)).isGonnaBeTrue();
94
-
95
- // const params = getPathParams(path, API_PATHS.KEYSTONE_EVOLVE);
96
- // iReckon(sir, params?.[0]).isGonnaBe('someib%5Esomegib');
97
- // });
98
- // });
99
- // });
@@ -1,29 +0,0 @@
1
- # serve-gib changelog
2
-
3
- _note: as you implement features/fixes/etc., please document them here under the "Working Version" section._
4
-
5
- ## Working Version
6
-
7
- * impl: initial core infrastructure
8
- * defined `RouteInfo`, `ResponseResult`, and `ServeGibHandler` foundational types.
9
- * implemented `ServeGib_V1` with pipeline-based request processing.
10
- * added robust `try..catch..finally` pattern with built-in access logging and timing.
11
- * impl: handler "pit of success" plumbing
12
- * implemented `ServeGibHandlerBase` abstract class to reduce boilerplate.
13
- * automated route matching via `canHandleRoute` and `regex` properties.
14
- * implemented `handleRouteImpl` pattern to separate plumbing from business logic.
15
- * added generic `TQueryParams` support with automated parsing via `parseQueryParams`.
16
- * feat: hierarchical handler organization
17
- * established folder-based grouping mirroring URL paths (e.g., `handlers/api/ibgib/`).
18
- * enforced "one handler per hard route" and "one handler per file" architectural guidelines.
19
- * feat: concrete core handlers
20
- * `HealthHandler`: Simple liveness probe.
21
- * `IbGibHandler`: Single ibGib address resolution.
22
- * `IbGibGraphHandler`: Complex graph/BFS retrieval.
23
- * `KeystoneHandler`: Genesis and evolution turn persistence.
24
- * `StaticFileHandler`: High-performance asset serving with SPA history fallback.
25
- * `ErrorHandler`: Standardized 404 and fatal error reporting.
26
- * docs: architectural guidance
27
- * created `README.md` with detailed guidance on handler philosophy and plumbing usage.
28
- * test: validation suite
29
- * implemented `serve-gib.respec.mts` verifying orchestrator pipeline and `RouteInfo` construction.
@@ -1,43 +0,0 @@
1
- # serve-gib Microframework
2
-
3
- A minimalist, high-observability HTTP microframework for ibgib servers.
4
-
5
- ## Architecture & Guidance
6
-
7
- ### 1. Handler Philosophy
8
- * **One handler per "hard" route**: A handler should correspond to a unique URL path pattern, disregarding query parameters.
9
- * **One regex per handler**: Concrete handlers should ideally define a single `regex` property for routing.
10
- * **One handler per file**: Each route handler should live in its own file within the `handlers/` directory (e.g., `handlers/api/health.handler.mts`).
11
- * The subfolders should match the hard route of the handler, e.g., `api/ibgib` route should be in the `handlers/api/ibgib` subfolder.
12
-
13
- ### 2. The "Pit of Success" Plumbing
14
- The `ServeGibHandlerBase` class provides built-in plumbing to reduce boilerplate:
15
- * **`handleRoute` (Plumbing)**: Automatically checks `canHandleRoute`, parses query parameters, and provides a top-level `try..catch` block for logging and error reporting.
16
- * **`handleRouteImpl` (Implementation)**: This is where the core logic of the handler resides.
17
- * **`canHandleRoute`**: Defaults to a regex match on `info.pathname`. Override this for more complex routing logic.
18
-
19
- ### 3. Query Parameters
20
- Query parameters are handled via the `parseQueryParams` method in the base class.
21
- * By default, it parses URL search params into a key-value object.
22
- * Handlers can override this method to perform custom parsing or validation (e.g., parsing JSON strings from query params).
23
- * The base class is generic: `ServeGibHandlerBase<TQueryParams = any>`.
24
-
25
- ### 4. RouteInfo
26
- The `RouteInfo` object provides an enriched view of the incoming request:
27
- * `decodedPathSegments`: Pre-split and decoded path parts.
28
- * `protocol`, `method`, `body`: Basic HTTP info.
29
- * `queryParams`: The result of the handler's `parseQueryParams` call.
30
-
31
- ## Pipeline Order
32
- The `ServeGib_V1` executes handlers in the order they are provided in the `handlers` array. The first handler to return a non-undefined `ResponseResult` wins.
33
- * **Tip**: Order specific routes (like `/api/ibgib/graph`) before more general ones (like `/api/ibgib`).
34
- * **Fallback**: The `ErrorHandler` is used as a final catch-all for 404s and fatal errors.
35
-
36
- ## Docker / Server Resilience Note
37
- When deploying or running this service (or any downstream applications) within a Docker Compose environment, ensure that the `docker-compose.yml` configuration specifies a restart policy such as:
38
- ```yaml
39
- services:
40
- space-gib:
41
- restart: unless-stopped
42
- ```
43
- This ensures that the container auto-recovers and restarts if the node process crashes due to unhandled events (such as raw TCP socket `ECONNRESET` exceptions from client refreshes).
@@ -1 +0,0 @@
1
- export const GLOBAL_LOG_A_LOT = false;
@@ -1,105 +0,0 @@
1
- /**
2
- * @module handlers/api/debug/ws-echo.handler
3
- *
4
- * Minimal WebSocket echo handler for validating end-to-end WebSocket
5
- * plumbing: Traefik passthrough → Node.js upgrade event → browser client.
6
- *
7
- * ## intent
8
- *
9
- * This is a diagnostic-only endpoint. The goal is to confirm that:
10
- * 1. Traefik correctly forwards WS upgrade requests to the container
11
- * 2. The Node.js `upgrade` event fires and we can accept the connect handshake
12
- * 3. The browser client can open a wss:// connection and exchange frames
13
- *
14
- * Once WS sync is confirmed end-to-end, this handler can be removed or
15
- * gated behind an env flag.
16
- *
17
- * ## endpoint
18
- *
19
- * `GET /api/debug/ws-echo` (with Upgrade: websocket header)
20
- *
21
- * On connect: server sends `{"status":"connected","msg":"ws-echo ready"}`
22
- * On message: server echoes `{"echo":<original message>}`
23
- * On close: server logs and cleans up
24
- */
25
-
26
- import { IncomingMessage } from 'node:http';
27
- import { Socket } from 'node:net';
28
-
29
- import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
30
-
31
- import { GLOBAL_LOG_A_LOT } from '../../../constants.mjs';
32
- import {
33
- encodeTextFrame, decodeTextFrame, encodeCloseFrame, performConnect,
34
- WebSocketFrameDecoder
35
- } from '../../ws/ws-helper.mjs';
36
- import { API_PATH_REGEXES } from '../../../../path-constants.mjs';
37
-
38
- const logalot = GLOBAL_LOG_A_LOT;
39
-
40
- const lc = `[WsEchoHandler]`;
41
-
42
-
43
- // ---------------------------------------------------------------------------
44
- // Public handler
45
- // ---------------------------------------------------------------------------
46
-
47
- /**
48
- * Returns true if this request is a WebSocket upgrade to the debug echo path.
49
- * Call this from the server's `upgrade` event listener.
50
- */
51
- export function canHandleWsUpgrade(req: IncomingMessage): boolean {
52
- const pathname = new URL(req.url ?? '/', 'http://localhost').pathname;
53
- return API_PATH_REGEXES.DEBUG_WS_ECHO.test(pathname);
54
- }
55
-
56
- /**
57
- * Accepts the WebSocket upgrade and sets up the echo loop.
58
- *
59
- * Client will receive a JSON `{status:"connected"}` on open, and
60
- * `{echo:<msg>}` for every message it sends.
61
- */
62
- export function handleWsEchoUpgrade(req: IncomingMessage, socket: Socket, head: Buffer): void {
63
- const lc_fn = `${lc}[handleWsEchoUpgrade]`;
64
- try {
65
- if (logalot) { console.log(`${lc_fn} starting...`); }
66
-
67
- const ok = performConnect(req, socket);
68
- if (!ok) { return; }
69
-
70
- // Send the "connected" greeting
71
- socket.write(encodeTextFrame(JSON.stringify({ status: 'connected', msg: 'ws-echo ready' })));
72
-
73
- // Echo loop
74
- const decoder = new WebSocketFrameDecoder();
75
- socket.on('data', (data: Buffer) => {
76
- try {
77
- decoder.addChunk(data);
78
- let frameText = decoder.nextFrame();
79
- while (frameText !== null) {
80
- if (logalot) { console.log(`${lc_fn} echo: ${frameText}`); }
81
- socket.write(encodeTextFrame(JSON.stringify({ echo: frameText })));
82
- frameText = decoder.nextFrame();
83
- }
84
- } catch (error) {
85
- console.error(`${lc_fn} error in data handler: ${extractErrorMsg(error)}`);
86
- socket.write(encodeCloseFrame(1000));
87
- socket.end();
88
- }
89
- });
90
-
91
- socket.on('error', (error) => {
92
- console.error(`${lc_fn} socket error: ${extractErrorMsg(error)}`);
93
- });
94
-
95
- socket.on('close', () => {
96
- if (logalot) { console.log(`${lc_fn} socket closed.`); }
97
- });
98
-
99
- } catch (error) {
100
- console.error(`${lc_fn} ${extractErrorMsg(error)}`);
101
- socket.destroy();
102
- } finally {
103
- if (logalot) { console.log(`${lc_fn} complete.`); }
104
- }
105
- }