@ibgib/space-gib 0.0.4 → 0.0.6
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/README.md +7 -0
- package/dist/client/bootstrap.mjs +1 -1
- package/dist/client/chunk-734MMI4C.mjs +42 -0
- package/dist/client/chunk-734MMI4C.mjs.map +7 -0
- package/dist/client/{chunk-ZUEU37Z5.mjs → chunk-SMOZ2D5E.mjs} +170 -41
- package/dist/client/chunk-SMOZ2D5E.mjs.map +7 -0
- package/dist/client/index.html +35 -14
- package/dist/client/index.mjs +1 -1
- package/dist/client/script.mjs +1 -1
- package/dist/client/style.css +29 -5
- package/dist/server/server.mjs +338 -31
- package/dist/server/server.mjs.map +3 -3
- package/package.json +4 -4
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/components/identity-header/identity-header.css +40 -2
- package/src/client/components/identity-header/identity-header.html +3 -2
- package/src/client/components/identity-header/identity-header.mts +87 -26
- package/src/client/components/identity-manager/IMPLEMENTATION.md +10 -10
- package/src/client/components/identity-manager/identity-manager.css +39 -0
- package/src/client/components/identity-manager/identity-manager.html +20 -0
- package/src/client/components/identity-manager/identity-manager.mts +59 -0
- package/src/client/components/keystone-creator/keystone-creator.mts +88 -12
- package/src/client/dev-tools/common.mts +505 -10
- package/src/client/dev-tools/phase-4-1.mts +19 -4
- package/src/client/dev-tools/phase-4-10.mts +77 -305
- package/src/client/dev-tools/phase-4-2.mts +46 -212
- package/src/client/dev-tools/phase-4-3.mts +57 -198
- package/src/client/dev-tools/phase-4-4.mts +57 -170
- package/src/client/dev-tools/phase-4-5.mts +48 -204
- package/src/client/dev-tools/phase-4-6.mts +37 -103
- package/src/client/dev-tools/phase-4-7.mts +44 -228
- package/src/client/dev-tools/phase-4-8.mts +33 -136
- package/src/client/dev-tools/phase-4-9.mts +33 -137
- package/src/client/dev-tools/phase-4.mts +30 -6
- package/src/client/dev-tools.mts +18 -0
- package/src/client/index.html +35 -14
- package/src/client/style.css +29 -5
- package/src/client/types.mts +4 -1
- package/dist/client/chunk-NCXKCVYS.mjs +0 -42
- package/dist/client/chunk-NCXKCVYS.mjs.map +0 -7
- package/dist/client/chunk-ZUEU37Z5.mjs.map +0 -7
- package/dist/respec-gib.node.mjs +0 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ibgib/space-gib",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "ibgib storage and provider service — SaaS at ibgib.space",
|
|
6
6
|
"scripts": {
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"build:test": "tsc -p tsconfig.test.json"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@ibgib/core-gib": "^0.1.
|
|
15
|
+
"@ibgib/core-gib": "^0.1.63",
|
|
16
16
|
"@ibgib/helper-gib": "^0.0.36",
|
|
17
17
|
"@ibgib/ts-gib": "^0.5.32",
|
|
18
|
-
"@ibgib/web-gib": "^0.0.
|
|
19
|
-
"@ibgib/node-gib": "^0.0.
|
|
18
|
+
"@ibgib/web-gib": "^0.0.49",
|
|
19
|
+
"@ibgib/node-gib": "^0.0.7"
|
|
20
20
|
},
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=20.0.0"
|
|
@@ -18,14 +18,13 @@
|
|
|
18
18
|
background: var(--tab-background-color-active, rgba(255, 255, 255, 0.1));
|
|
19
19
|
border: 1px solid var(--tab-border-color-active, rgba(80, 250, 123, 0.3));
|
|
20
20
|
border-radius: var(--radius-lg, 20px);
|
|
21
|
-
cursor:
|
|
21
|
+
cursor: default;
|
|
22
22
|
transition: all 0.2s ease-in-out;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
.identity-pill:hover {
|
|
26
26
|
background: rgba(80, 250, 123, 0.15);
|
|
27
27
|
border-color: var(--clr-accent, #50fa7b);
|
|
28
|
-
transform: translateY(-1px);
|
|
29
28
|
box-shadow: 0 2px 8px rgba(80, 250, 123, 0.1);
|
|
30
29
|
}
|
|
31
30
|
|
|
@@ -72,3 +71,42 @@
|
|
|
72
71
|
.hidden {
|
|
73
72
|
display: none !important;
|
|
74
73
|
}
|
|
74
|
+
|
|
75
|
+
/* Styled selector dropdown */
|
|
76
|
+
.identity-select {
|
|
77
|
+
font-family: var(--font-sans, sans-serif);
|
|
78
|
+
font-size: 0.85rem;
|
|
79
|
+
color: var(--clr-text-primary, #ffffff);
|
|
80
|
+
background: transparent;
|
|
81
|
+
border: none;
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
font-weight: 500;
|
|
84
|
+
outline: none;
|
|
85
|
+
padding: 0 0.2rem;
|
|
86
|
+
max-width: 150px;
|
|
87
|
+
text-overflow: ellipsis;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.identity-select option {
|
|
91
|
+
background: var(--clr-bg-surface, #1e1e2e);
|
|
92
|
+
color: var(--clr-text-primary, #ffffff);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Gear manage button */
|
|
96
|
+
.manage-btn {
|
|
97
|
+
background: transparent;
|
|
98
|
+
border: none;
|
|
99
|
+
font-size: 1rem;
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
padding: 0 0.2rem;
|
|
102
|
+
display: flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
justify-content: center;
|
|
105
|
+
color: var(--clr-text-secondary, #b3b3b3);
|
|
106
|
+
transition: color 0.2s ease, transform 0.2s ease;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.manage-btn:hover {
|
|
110
|
+
color: var(--clr-accent, #50fa7b);
|
|
111
|
+
transform: rotate(45deg);
|
|
112
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<div id="container" class="header-widget-container">
|
|
2
2
|
<!-- Active Identity Pill -->
|
|
3
|
-
<div id="active-identity-pill" class="identity-pill hidden"
|
|
3
|
+
<div id="active-identity-pill" class="identity-pill hidden">
|
|
4
4
|
<div id="identity-avatar" class="avatar-circle">-</div>
|
|
5
|
-
<
|
|
5
|
+
<select id="identity-selector" class="identity-select" title="Switch active identity"></select>
|
|
6
|
+
<button id="btn-manage-identities" class="manage-btn" title="Manage Identities">⚙️</button>
|
|
6
7
|
</div>
|
|
7
8
|
|
|
8
9
|
<!-- Fallback Action Button -->
|
|
@@ -68,7 +68,8 @@ export class IdentityHeaderComponentMeta extends IbGibDynamicComponentMetaBase {
|
|
|
68
68
|
interface IdentityHeaderElements extends ElementsBase {
|
|
69
69
|
containerEl: HTMLDivElement;
|
|
70
70
|
activeIdentityPillEl: HTMLDivElement;
|
|
71
|
-
|
|
71
|
+
identitySelectorEl: HTMLSelectElement;
|
|
72
|
+
btnManageIdentitiesEl: HTMLButtonElement;
|
|
72
73
|
btnCreateIdentityEl: HTMLButtonElement;
|
|
73
74
|
identityAvatarEl: HTMLDivElement;
|
|
74
75
|
}
|
|
@@ -132,7 +133,8 @@ export class IdentityHeaderComponentInstance
|
|
|
132
133
|
const shadow = this.shadowRoot!;
|
|
133
134
|
this.elements.containerEl = shadow.getElementById('container') as HTMLDivElement;
|
|
134
135
|
this.elements.activeIdentityPillEl = shadow.getElementById('active-identity-pill') as HTMLDivElement;
|
|
135
|
-
this.elements.
|
|
136
|
+
this.elements.identitySelectorEl = shadow.getElementById('identity-selector') as HTMLSelectElement;
|
|
137
|
+
this.elements.btnManageIdentitiesEl = shadow.getElementById('btn-manage-identities') as HTMLButtonElement;
|
|
136
138
|
this.elements.btnCreateIdentityEl = shadow.getElementById('btn-create-identity') as HTMLButtonElement;
|
|
137
139
|
this.elements.identityAvatarEl = shadow.getElementById('identity-avatar') as HTMLDivElement;
|
|
138
140
|
|
|
@@ -182,9 +184,24 @@ export class IdentityHeaderComponentInstance
|
|
|
182
184
|
}
|
|
183
185
|
|
|
184
186
|
private initHandlers() {
|
|
185
|
-
// Handle clicks: route to the full identity manager
|
|
186
|
-
this.elements!.activeIdentityPillEl.addEventListener('click', () => this.navigateToManager());
|
|
187
187
|
this.elements!.btnCreateIdentityEl.addEventListener('click', () => this.navigateToManager());
|
|
188
|
+
this.elements!.btnManageIdentitiesEl.addEventListener('click', (e) => {
|
|
189
|
+
e.stopPropagation();
|
|
190
|
+
this.navigateToManager();
|
|
191
|
+
});
|
|
192
|
+
this.elements!.identitySelectorEl.addEventListener('click', (e) => {
|
|
193
|
+
e.stopPropagation();
|
|
194
|
+
});
|
|
195
|
+
this.elements!.identitySelectorEl.addEventListener('change', () => {
|
|
196
|
+
const selectedAddr = this.elements!.identitySelectorEl.value;
|
|
197
|
+
if (selectedAddr) {
|
|
198
|
+
window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, {
|
|
199
|
+
detail: { activeIdentityAddr: selectedAddr },
|
|
200
|
+
bubbles: true,
|
|
201
|
+
composed: true
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
});
|
|
188
205
|
}
|
|
189
206
|
|
|
190
207
|
private navigateToManager() {
|
|
@@ -222,7 +239,7 @@ export class IdentityHeaderComponentInstance
|
|
|
222
239
|
}
|
|
223
240
|
|
|
224
241
|
// Sync with globalState.identity
|
|
225
|
-
const globalState = getIbGibGlobalThis_SpaceGib(APP_CONFIG)
|
|
242
|
+
const globalState = getIbGibGlobalThis_SpaceGib(APP_CONFIG);
|
|
226
243
|
if (this.activeAddr) {
|
|
227
244
|
const metaspace = globalState.metaspace;
|
|
228
245
|
if (metaspace) {
|
|
@@ -230,12 +247,44 @@ export class IdentityHeaderComponentInstance
|
|
|
230
247
|
if (space) {
|
|
231
248
|
const res = await metaspace.get({ addr: this.activeAddr, space });
|
|
232
249
|
if (res.success && res.ibGibs && res.ibGibs.length > 0) {
|
|
233
|
-
|
|
250
|
+
const domainIdentity = res.ibGibs[0] as KeystoneIbGib_V1;
|
|
251
|
+
|
|
252
|
+
// Find delegate with the sync allowed verb
|
|
253
|
+
let syncDelegateIdentity: KeystoneIbGib_V1 | undefined;
|
|
254
|
+
const delegates = domainIdentity.data?.delegates;
|
|
255
|
+
if (delegates) {
|
|
256
|
+
for (const delegateInfo of Object.values(delegates)) {
|
|
257
|
+
if (delegateInfo.allowedVerbs?.includes('sync^gib') || (!delegateInfo.allowedVerbs && delegateInfo.delegateTjpAddr)) {
|
|
258
|
+
// Fetch the delegate's latest tip from space
|
|
259
|
+
const delegateLatestAddr = await metaspace.getLatestAddr({
|
|
260
|
+
addr: delegateInfo.delegateTjpAddr,
|
|
261
|
+
space
|
|
262
|
+
});
|
|
263
|
+
if (delegateLatestAddr) {
|
|
264
|
+
const resDelegate = await metaspace.get({ addr: delegateLatestAddr, space });
|
|
265
|
+
if (resDelegate.success && resDelegate.ibGibs && resDelegate.ibGibs.length > 0) {
|
|
266
|
+
syncDelegateIdentity = resDelegate.ibGibs[0] as KeystoneIbGib_V1;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
globalState.identity = {
|
|
275
|
+
resolved: true,
|
|
276
|
+
authenticated: true,
|
|
277
|
+
domainIdentity,
|
|
278
|
+
syncDelegateIdentity
|
|
279
|
+
};
|
|
234
280
|
}
|
|
235
281
|
}
|
|
236
282
|
}
|
|
237
283
|
} else {
|
|
238
|
-
globalState.identity =
|
|
284
|
+
globalState.identity = {
|
|
285
|
+
resolved: false,
|
|
286
|
+
authenticated: false
|
|
287
|
+
};
|
|
239
288
|
}
|
|
240
289
|
} catch (error) {
|
|
241
290
|
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
@@ -251,24 +300,47 @@ export class IdentityHeaderComponentInstance
|
|
|
251
300
|
// Double check state on render
|
|
252
301
|
await this.resolveActiveIdentity();
|
|
253
302
|
|
|
254
|
-
|
|
303
|
+
const keystones = this.ibGib?.rel8ns?.keystone ?? [];
|
|
304
|
+
|
|
305
|
+
if (this.activeAddr && keystones.length > 0) {
|
|
255
306
|
this.elements.activeIdentityPillEl.classList.remove('hidden');
|
|
256
307
|
this.elements.btnCreateIdentityEl.classList.add('hidden');
|
|
257
308
|
|
|
258
309
|
const addr = this.activeAddr;
|
|
259
310
|
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
311
|
+
// Populate the dropdown selector
|
|
312
|
+
this.elements.identitySelectorEl.innerHTML = '';
|
|
313
|
+
for (const kAddr of keystones) {
|
|
314
|
+
const option = document.createElement('option');
|
|
315
|
+
option.value = kAddr;
|
|
316
|
+
|
|
317
|
+
let displayAddr = kAddr;
|
|
318
|
+
if (displayAddr.length > 14) {
|
|
319
|
+
displayAddr = displayAddr.substring(0, 7) + '...' + displayAddr.substring(displayAddr.length - 5);
|
|
320
|
+
}
|
|
321
|
+
option.textContent = displayAddr;
|
|
322
|
+
|
|
323
|
+
// Load details asynchronously so we don't block
|
|
324
|
+
this.getKeystoneDetails(kAddr).then(details => {
|
|
325
|
+
if (details.username) {
|
|
326
|
+
let name = details.username;
|
|
327
|
+
if (name.length > 14) {
|
|
328
|
+
name = name.substring(0, 11) + '...';
|
|
329
|
+
}
|
|
330
|
+
option.textContent = name;
|
|
331
|
+
}
|
|
332
|
+
}).catch(err => {});
|
|
333
|
+
|
|
334
|
+
this.elements.identitySelectorEl.appendChild(option);
|
|
264
335
|
}
|
|
265
|
-
this.elements.
|
|
336
|
+
this.elements.identitySelectorEl.value = addr;
|
|
337
|
+
|
|
338
|
+
// Render active avatar
|
|
266
339
|
this.elements.identityAvatarEl.textContent = '-';
|
|
267
340
|
this.elements.identityAvatarEl.style.backgroundColor = 'var(--clr-accent)';
|
|
268
341
|
this.elements.identityAvatarEl.style.color = '#11111b';
|
|
269
|
-
this.elements.activeIdentityPillEl.title = `Active Identity: ${addr}\nClick to manage.`;
|
|
270
342
|
|
|
271
|
-
// Load details dynamically
|
|
343
|
+
// Load details dynamically for the active identity
|
|
272
344
|
const details = await this.getKeystoneDetails(addr);
|
|
273
345
|
|
|
274
346
|
// First letter of username, or fallback to first char of address (or 'A')
|
|
@@ -290,16 +362,6 @@ export class IdentityHeaderComponentInstance
|
|
|
290
362
|
this.elements.identityAvatarEl.style.backgroundColor = bg;
|
|
291
363
|
this.elements.identityAvatarEl.style.color = fg;
|
|
292
364
|
|
|
293
|
-
// Set user display name or address in pill
|
|
294
|
-
let displayName = details.username;
|
|
295
|
-
const maxLen = 14;
|
|
296
|
-
if (displayName) {
|
|
297
|
-
if (displayName.length > maxLen) {
|
|
298
|
-
displayName = displayName.substring(0, maxLen - 3) + '...';
|
|
299
|
-
}
|
|
300
|
-
this.elements.identityAddressTruncatedEl.textContent = displayName;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
365
|
// Title with full details
|
|
304
366
|
const titleParts: string[] = [];
|
|
305
367
|
if (details.username) {
|
|
@@ -312,7 +374,6 @@ export class IdentityHeaderComponentInstance
|
|
|
312
374
|
titleParts.push(`Desc: ${desc}`);
|
|
313
375
|
}
|
|
314
376
|
titleParts.push(`Addr: ${addr}`);
|
|
315
|
-
titleParts.push(`Click to manage.`);
|
|
316
377
|
this.elements.activeIdentityPillEl.title = titleParts.join('\n');
|
|
317
378
|
} else {
|
|
318
379
|
this.elements.activeIdentityPillEl.classList.add('hidden');
|
|
@@ -68,9 +68,9 @@ Following the custom `web-gib` Web Component microframework, the component consi
|
|
|
68
68
|
- [x] Document the custom `web-gib` Web Component microframework (covering element lifecycles, routing, parent-child delegation, and settings/tabs state persistence).
|
|
69
69
|
|
|
70
70
|
### Phase 5: UI/UX Enhancements & Bugs
|
|
71
|
-
- [
|
|
71
|
+
- [x] Center/align the `<ibgib-identity-manager>` component instead of having it shoved to the left (maxing out at ~66% width of the center-panel).
|
|
72
72
|
- [x] Adjust scrolling behavior so the entire manager or manager-content div scrolls, instead of limiting the scroll region to the accordion detail pre-tag.
|
|
73
|
-
- [
|
|
73
|
+
- [x] Automatically select/activate the newly created identity keystone in the tab list upon creation.
|
|
74
74
|
|
|
75
75
|
### Phase 6: Detail Views (Pools & Keystone Metadata)
|
|
76
76
|
- [x] Add a details view for challenge pools on the keystone (`KeystoneData_V1.challengePools`).
|
|
@@ -86,14 +86,14 @@ Following the custom `web-gib` Web Component microframework, the component consi
|
|
|
86
86
|
- [x] Implement history scrubber navigation (First, Back 10, Back 1, Next 1, Next 10, Latest) to traverse the keystone timeline.
|
|
87
87
|
|
|
88
88
|
### Phase 8: Active Identity Management
|
|
89
|
-
- [
|
|
90
|
-
- [
|
|
91
|
-
- [
|
|
92
|
-
- [
|
|
93
|
-
- [
|
|
94
|
-
- [
|
|
95
|
-
- [
|
|
96
|
-
- [
|
|
89
|
+
- [x] Define reusable event constants (`EVENT_IBGIB_IDENTITY_REQUEST_CHANGE` and `EVENT_IBGIB_IDENTITY_CHANGED`) in `libs/web-gib/src/ui/ui-constants.mts`.
|
|
90
|
+
- [x] Add checkbox in `<ibgib-keystone-creator>` to make the newly created identity the active one. Enforce/lock to checked if no identities exist yet.
|
|
91
|
+
- [x] If checked on creation, `<ibgib-keystone-creator>` dispatches `EVENT_IBGIB_IDENTITY_REQUEST_CHANGE` containing the new keystone address.
|
|
92
|
+
- [x] Add "Set as Active Identity" button to `<ibgib-identity-manager>` details view. When clicked, it dispatches `EVENT_IBGIB_IDENTITY_REQUEST_CHANGE` with the selected keystone address.
|
|
93
|
+
- [x] Decouple tab clicks in `<ibgib-identity-manager>` so they only browse details via `viewIdentityDetails(addr)` without setting active identity.
|
|
94
|
+
- [x] Update `<ibgib-identity-header>` to listen for `EVENT_IBGIB_IDENTITY_REQUEST_CHANGE`. On receipt, write the address to its settings timeline, update `ibGibGlobalThis.identity`, re-render, and dispatch `EVENT_IBGIB_IDENTITY_CHANGED`.
|
|
95
|
+
- [x] Set `ibGibGlobalThis.identity` on `<ibgib-identity-header>` initialization using settings.
|
|
96
|
+
- [x] Update `<ibgib-identity-manager>` to subscribe to `EVENT_IBGIB_IDENTITY_CHANGED` and re-render/update its "Set as Active" button state accordingly.
|
|
97
97
|
- [ ] TODO: Enhance the `<ibgib-identity-header>` component to support selecting/switching between loaded identities directly from a dropdown/dropdown-like UI inside the header.
|
|
98
98
|
|
|
99
99
|
### Testing Protocol
|
|
@@ -464,4 +464,43 @@ h2 {
|
|
|
464
464
|
white-space: nowrap;
|
|
465
465
|
overflow: hidden;
|
|
466
466
|
text-overflow: ellipsis;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/* Delegates Card styling */
|
|
470
|
+
.delegates-table {
|
|
471
|
+
width: 100%;
|
|
472
|
+
border-collapse: collapse;
|
|
473
|
+
margin-top: 1rem;
|
|
474
|
+
font-size: 0.9rem;
|
|
475
|
+
background: rgba(0, 0, 0, 0.2);
|
|
476
|
+
border-radius: var(--radius-sm, 6px);
|
|
477
|
+
overflow: hidden;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.delegates-table th,
|
|
481
|
+
.delegates-table td {
|
|
482
|
+
padding: 0.75rem 1rem;
|
|
483
|
+
text-align: left;
|
|
484
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.delegates-table th {
|
|
488
|
+
font-family: var(--font-sans);
|
|
489
|
+
font-size: 0.75rem;
|
|
490
|
+
font-weight: 600;
|
|
491
|
+
text-transform: uppercase;
|
|
492
|
+
letter-spacing: 0.05em;
|
|
493
|
+
color: var(--clr-text-secondary, #8fa08f);
|
|
494
|
+
background: rgba(255, 255, 255, 0.02);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.delegates-table td {
|
|
498
|
+
font-family: var(--font-mono, monospace);
|
|
499
|
+
font-size: 0.8rem;
|
|
500
|
+
color: var(--clr-text-primary, #ffffff);
|
|
501
|
+
word-break: break-all;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.delegates-table tbody tr:hover {
|
|
505
|
+
background: rgba(255, 255, 255, 0.02);
|
|
467
506
|
}
|
|
@@ -85,6 +85,26 @@
|
|
|
85
85
|
</div>
|
|
86
86
|
</div>
|
|
87
87
|
|
|
88
|
+
<!-- Delegates Card -->
|
|
89
|
+
<div class="card">
|
|
90
|
+
<h3>Registered Delegates</h3>
|
|
91
|
+
<div id="delegates-container" class="delegates-container">
|
|
92
|
+
<p class="description">Active sub-keystones authorized to perform sync and operations on behalf of this Domain Identity.</p>
|
|
93
|
+
<table class="delegates-table">
|
|
94
|
+
<thead>
|
|
95
|
+
<tr>
|
|
96
|
+
<th>Name / Description</th>
|
|
97
|
+
<th>TJP Address</th>
|
|
98
|
+
<th>Allowed Verbs</th>
|
|
99
|
+
</tr>
|
|
100
|
+
</thead>
|
|
101
|
+
<tbody id="delegates-list">
|
|
102
|
+
<!-- Dynamic list of delegates gets injected here -->
|
|
103
|
+
</tbody>
|
|
104
|
+
</table>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
88
108
|
<!-- Replicas / Sync Peers Repository Manager -->
|
|
89
109
|
<!-- <div class="card">
|
|
90
110
|
<h3>Replication & Spaces</h3>
|
|
@@ -102,6 +102,7 @@ interface IdentityManagerElements extends ElementsBase {
|
|
|
102
102
|
rawAccordionHeaderEl: HTMLDivElement;
|
|
103
103
|
rawAccordionContentEl: HTMLDivElement;
|
|
104
104
|
rawKeystoneJsonEl: HTMLPreElement;
|
|
105
|
+
delegatesListEl: HTMLTableSectionElement;
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
/**
|
|
@@ -201,6 +202,7 @@ export class IdentityManagerComponentInstance
|
|
|
201
202
|
this.elements.rawAccordionHeaderEl = shadow.getElementById('raw-accordion-header') as HTMLDivElement;
|
|
202
203
|
this.elements.rawAccordionContentEl = shadow.getElementById('raw-accordion-content') as HTMLDivElement;
|
|
203
204
|
this.elements.rawKeystoneJsonEl = shadow.getElementById('raw-keystone-json') as HTMLPreElement;
|
|
205
|
+
this.elements.delegatesListEl = shadow.getElementById('delegates-list') as HTMLTableSectionElement;
|
|
204
206
|
|
|
205
207
|
// ElementBase requires contentEl (points to the main container/body area)
|
|
206
208
|
this.elements.contentEl = shadow.getElementById('identity-manager-content') as HTMLDivElement;
|
|
@@ -524,6 +526,9 @@ export class IdentityManagerComponentInstance
|
|
|
524
526
|
this.elements.identityAggrDetailsEl.textContent = '{}';
|
|
525
527
|
this.elements.scrubberStatusEl.textContent = 'Frame - / -';
|
|
526
528
|
this.elements.poolsContainerEl.innerHTML = '';
|
|
529
|
+
if (this.elements.delegatesListEl) {
|
|
530
|
+
this.elements.delegatesListEl.innerHTML = '';
|
|
531
|
+
}
|
|
527
532
|
this.history = [];
|
|
528
533
|
this.currentFrameIndex = -1;
|
|
529
534
|
}
|
|
@@ -681,6 +686,9 @@ export class IdentityManagerComponentInstance
|
|
|
681
686
|
|
|
682
687
|
// Render Challenge Pools
|
|
683
688
|
this.renderChallengePools(keystone.data?.challengePools || []);
|
|
689
|
+
|
|
690
|
+
// Render Delegates
|
|
691
|
+
await this.renderDelegates(keystone.data?.delegates);
|
|
684
692
|
}
|
|
685
693
|
|
|
686
694
|
private renderChallengePools(pools: any[]) {
|
|
@@ -761,6 +769,57 @@ export class IdentityManagerComponentInstance
|
|
|
761
769
|
}
|
|
762
770
|
}
|
|
763
771
|
|
|
772
|
+
private async renderDelegates(delegates: Record<string, any> | undefined) {
|
|
773
|
+
if (!this.elements) return;
|
|
774
|
+
const listEl = this.elements.delegatesListEl;
|
|
775
|
+
listEl.innerHTML = '';
|
|
776
|
+
|
|
777
|
+
if (!delegates || Object.keys(delegates).length === 0) {
|
|
778
|
+
listEl.innerHTML = `
|
|
779
|
+
<tr>
|
|
780
|
+
<td colspan="3" style="text-align: center; color: var(--clr-text-secondary, #b3b3b3);">
|
|
781
|
+
No registered delegates.
|
|
782
|
+
</td>
|
|
783
|
+
</tr>
|
|
784
|
+
`;
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
for (const [delegateTjpAddr, info] of Object.entries(delegates)) {
|
|
789
|
+
const tr = document.createElement('tr');
|
|
790
|
+
|
|
791
|
+
const tdName = document.createElement('td');
|
|
792
|
+
tdName.textContent = 'Loading...';
|
|
793
|
+
|
|
794
|
+
const tdTjp = document.createElement('td');
|
|
795
|
+
tdTjp.textContent = delegateTjpAddr;
|
|
796
|
+
tdTjp.title = delegateTjpAddr;
|
|
797
|
+
|
|
798
|
+
const tdVerbs = document.createElement('td');
|
|
799
|
+
tdVerbs.textContent = info.allowedVerbs ? info.allowedVerbs.join(', ') : '-';
|
|
800
|
+
tdVerbs.title = tdVerbs.textContent;
|
|
801
|
+
|
|
802
|
+
tr.appendChild(tdName);
|
|
803
|
+
tr.appendChild(tdTjp);
|
|
804
|
+
tr.appendChild(tdVerbs);
|
|
805
|
+
listEl.appendChild(tr);
|
|
806
|
+
|
|
807
|
+
if (info.delegateAddr) {
|
|
808
|
+
this.getKeystoneDetails(info.delegateAddr).then(details => {
|
|
809
|
+
const textParts: string[] = [];
|
|
810
|
+
if (details.username) textParts.push(details.username);
|
|
811
|
+
if (details.description) textParts.push(details.description);
|
|
812
|
+
tdName.textContent = textParts.join(' / ') || 'Unnamed Delegate';
|
|
813
|
+
tdName.title = `Addr: ${info.delegateAddr}\n` + textParts.join('\n');
|
|
814
|
+
}).catch(err => {
|
|
815
|
+
tdName.textContent = 'Unknown Delegate';
|
|
816
|
+
});
|
|
817
|
+
} else {
|
|
818
|
+
tdName.textContent = 'No Address';
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
764
823
|
override async handleContextUpdated(): Promise<void> {
|
|
765
824
|
await this.renderUI();
|
|
766
825
|
}
|
|
@@ -2,7 +2,7 @@ import thisCss from "./keystone-creator.css";
|
|
|
2
2
|
import thisHtml from "./keystone-creator.html";
|
|
3
3
|
import styleCss from "../../style.css";
|
|
4
4
|
|
|
5
|
-
import { delay, extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
5
|
+
import { delay, extractErrorMsg, hash } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
6
6
|
import { HashAlgorithm } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
7
7
|
import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
|
|
8
8
|
import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
|
|
@@ -32,7 +32,8 @@ import { SettingsType } from "@ibgib/web-gib/dist/common/settings/settings-const
|
|
|
32
32
|
import { SettingsIbGib_V1 } from "@ibgib/web-gib/dist/common/settings/settings-types.mjs";
|
|
33
33
|
import { updateSpecialIndex, mut8Timeline } from "@ibgib/core-gib/dist/timeline/timeline-api.mjs";
|
|
34
34
|
import { toDto } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
|
|
35
|
-
import { KEYSTONE_USERNAME_REGEXP, KEYSTONE_DESCRIPTION_REGEXP } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
|
|
35
|
+
import { KEYSTONE_USERNAME_REGEXP, KEYSTONE_DESCRIPTION_REGEXP, KEYSTONE_VERB_SYNC } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
|
|
36
|
+
import { deriveDelegateSecret } from "@ibgib/core-gib/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs";
|
|
36
37
|
import { EVENT_IBGIB_IDENTITY_REQUEST_CHANGE } from "@ibgib/web-gib/dist/ui/ui-constants.mjs";
|
|
37
38
|
|
|
38
39
|
export const KEYSTONE_CREATOR_COMPONENT_NAME = 'ibgib-keystone-creator';
|
|
@@ -247,12 +248,13 @@ export class KeystoneCreatorComponentInstance
|
|
|
247
248
|
loadingText: 'Generating...'
|
|
248
249
|
});
|
|
249
250
|
|
|
250
|
-
// 1. Prepare Keystone Configs
|
|
251
|
-
const builder = KeystoneProfileBuilder.buildKeystone('
|
|
251
|
+
// 1. Prepare Primary/Domain Keystone Configs
|
|
252
|
+
const builder = KeystoneProfileBuilder.buildKeystone('domain')
|
|
252
253
|
.withUsername(username)
|
|
253
254
|
.withDescription(description)
|
|
254
255
|
.withDetails({
|
|
255
256
|
client: 'space-gib-web',
|
|
257
|
+
role: 'domain-identity'
|
|
256
258
|
});
|
|
257
259
|
const configs = await builder.compileConfigs();
|
|
258
260
|
|
|
@@ -280,20 +282,66 @@ export class KeystoneCreatorComponentInstance
|
|
|
280
282
|
const addr = getIbGibAddr({ ibGib: keystoneIbGib });
|
|
281
283
|
console.log(`${lc} [NAG][ibgib-paradigm] local genesis complete: ${addr}`);
|
|
282
284
|
await delay(humanEyeDelay); // for human eyes, not needed for functionality
|
|
283
|
-
this.setStatus("Local genesis complete.
|
|
285
|
+
this.setStatus("Local genesis complete. Creating sync delegate...", "info");
|
|
284
286
|
devLog(`✓ Local genesis complete: ${addr}`);
|
|
285
287
|
|
|
286
|
-
//
|
|
287
|
-
(
|
|
288
|
-
|
|
288
|
+
// Automatically generate Sync Delegate Keystone
|
|
289
|
+
this.showBusy({
|
|
290
|
+
isBusy: true,
|
|
291
|
+
title: 'Creating Sync Delegate...',
|
|
292
|
+
msg: 'Generating cryptographic sync delegate keys...',
|
|
293
|
+
animationEmoji: '🔑'
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
const delegateSecret = await deriveDelegateSecret({ masterSecret });
|
|
297
|
+
const delegateBuilder = KeystoneProfileBuilder.buildKeystone('sync')
|
|
298
|
+
.withUsername(`${username}-sync`)
|
|
299
|
+
.withDescription(`Sync Delegate for ${username}`)
|
|
300
|
+
.withDetails({
|
|
301
|
+
client: 'space-gib-web',
|
|
302
|
+
role: 'sync-delegate'
|
|
303
|
+
});
|
|
304
|
+
const delegateConfigs = await delegateBuilder.compileConfigs();
|
|
305
|
+
|
|
306
|
+
const delegateKeystoneIbGib = await keystoneService.genesis({
|
|
307
|
+
masterSecret: delegateSecret,
|
|
308
|
+
configs: delegateConfigs,
|
|
309
|
+
metaspace,
|
|
310
|
+
space,
|
|
311
|
+
frameDetails: delegateBuilder.getFrameDetails()
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
const delegateAddr = getIbGibAddr({ ibGib: delegateKeystoneIbGib });
|
|
315
|
+
console.log(`${lc} sync delegate genesis complete: ${delegateAddr}`);
|
|
316
|
+
await delay(humanEyeDelay);
|
|
317
|
+
|
|
318
|
+
// Register delegate on parent
|
|
319
|
+
this.setStatus("Registering delegate on parent...", "info");
|
|
320
|
+
this.showBusy({
|
|
321
|
+
isBusy: true,
|
|
322
|
+
title: 'Registering Delegate...',
|
|
323
|
+
msg: 'Evolving domain identity to register delegate...',
|
|
324
|
+
animationEmoji: '📝'
|
|
325
|
+
});
|
|
326
|
+
const evolvedParentKeystoneIbGib = await keystoneService.registerDelegate({
|
|
327
|
+
parentKeystone: keystoneIbGib,
|
|
328
|
+
delegateKeystone: delegateKeystoneIbGib,
|
|
329
|
+
masterSecret,
|
|
330
|
+
metaspace,
|
|
331
|
+
space,
|
|
332
|
+
allowedVerbs: [KEYSTONE_VERB_SYNC]
|
|
333
|
+
});
|
|
334
|
+
const evolvedParentAddr = getIbGibAddr({ ibGib: evolvedParentKeystoneIbGib });
|
|
335
|
+
console.log(`${lc} delegate registered. evolved parent address: ${evolvedParentAddr}`);
|
|
336
|
+
await delay(humanEyeDelay);
|
|
289
337
|
|
|
290
338
|
// 4. Post to Server
|
|
291
339
|
devLog(`Posting genesis keystone to server...`);
|
|
340
|
+
this.setStatus("Syncing genesis to server...", "info");
|
|
292
341
|
this.showBusy({
|
|
293
342
|
isBusy: true,
|
|
294
343
|
title: 'Syncing to Server...',
|
|
295
344
|
msg: [
|
|
296
|
-
'Local genesis complete!',
|
|
297
345
|
'Posting genesis keystone to server sync node...',
|
|
298
346
|
'(may take awhile, depending on strength of keystone...)',
|
|
299
347
|
].join('\n'),
|
|
@@ -306,6 +354,25 @@ export class KeystoneCreatorComponentInstance
|
|
|
306
354
|
return; /* <<<< returns early */
|
|
307
355
|
}
|
|
308
356
|
|
|
357
|
+
// Post evolved keystone + delegate keystone
|
|
358
|
+
this.setStatus("Syncing delegate registration to server...", "info");
|
|
359
|
+
this.showBusy({
|
|
360
|
+
isBusy: true,
|
|
361
|
+
title: 'Syncing Delegate...',
|
|
362
|
+
msg: 'Posting evolved domain identity and sync delegate to server...',
|
|
363
|
+
animationEmoji: '🔄'
|
|
364
|
+
});
|
|
365
|
+
const resEvolve = await spaceGibApiBridge.putEvolveKeystone(
|
|
366
|
+
addr,
|
|
367
|
+
evolvedParentKeystoneIbGib,
|
|
368
|
+
[delegateKeystoneIbGib]
|
|
369
|
+
);
|
|
370
|
+
if (!resEvolve.success) {
|
|
371
|
+
this.setStatus(`Delegate registration sync failed: ${resEvolve.message}`, "error");
|
|
372
|
+
devLog(`✗ Server rejected delegate registration: ${resEvolve.message}`);
|
|
373
|
+
return; /* <<<< returns early */
|
|
374
|
+
}
|
|
375
|
+
|
|
309
376
|
// 5. Register with the keystones special index
|
|
310
377
|
this.showBusy({
|
|
311
378
|
isBusy: true,
|
|
@@ -319,25 +386,34 @@ export class KeystoneCreatorComponentInstance
|
|
|
319
386
|
rel8nInfos: [
|
|
320
387
|
{
|
|
321
388
|
rel8nName: "keystone",
|
|
322
|
-
ibGibs: [
|
|
389
|
+
ibGibs: [
|
|
390
|
+
toDto({ ibGib: evolvedParentKeystoneIbGib }),
|
|
391
|
+
toDto({ ibGib: delegateKeystoneIbGib })
|
|
392
|
+
],
|
|
323
393
|
},
|
|
324
394
|
],
|
|
325
395
|
metaspace,
|
|
326
396
|
space,
|
|
327
397
|
});
|
|
328
398
|
|
|
399
|
+
// Expose for dev tools
|
|
400
|
+
(window as any).dev_domainI = evolvedParentKeystoneIbGib;
|
|
401
|
+
(window as any).dev_domainIMasterSecret = masterSecret;
|
|
402
|
+
(window as any).dev_syncDelegate = delegateKeystoneIbGib;
|
|
403
|
+
(window as any).dev_syncDelegateSecret = delegateSecret;
|
|
404
|
+
|
|
329
405
|
// 6. Request to make the new identity active if the checkbox is checked
|
|
330
406
|
const makeActive = this.elements!.checkboxMakeActive?.checked;
|
|
331
407
|
if (makeActive) {
|
|
332
408
|
window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, {
|
|
333
|
-
detail: { activeIdentityAddr:
|
|
409
|
+
detail: { activeIdentityAddr: evolvedParentAddr },
|
|
334
410
|
bubbles: true,
|
|
335
411
|
composed: true
|
|
336
412
|
}));
|
|
337
413
|
}
|
|
338
414
|
|
|
339
415
|
// 7. Success
|
|
340
|
-
this.elements!.keystoneAddrEl.textContent =
|
|
416
|
+
this.elements!.keystoneAddrEl.textContent = evolvedParentAddr;
|
|
341
417
|
this.elements!.statusArea.classList.remove('hidden');
|
|
342
418
|
this.setStatus("Keystone successfully created and synced!", "success");
|
|
343
419
|
await delay(humanEyeDelay); // for human eyes, not needed for functionality
|