spexcode 0.5.5 → 0.5.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/package.json +1 -1
- package/spec-cli/src/git.ts +80 -40
- package/spec-cli/src/index.ts +7 -2
- package/spec-cli/src/reviewSnapshot.ts +4 -0
- package/spec-cli/src/reviews.ts +10 -5
- package/spec-dashboard/dist/assets/{App-C5vbTw8Q.js → App-B72LuS5I.js} +2 -2
- package/spec-dashboard/dist/assets/Dashboard-C5X4Va3V.js +27 -0
- package/spec-dashboard/dist/assets/{EvalsPage-BS7ITcNo.js → EvalsPage-BTvJIW8Q.js} +2 -2
- package/spec-dashboard/dist/assets/IssuesPage-Bn94h_HQ.js +1 -0
- package/spec-dashboard/dist/assets/{MobileApp-DVLnk9hz.js → MobileApp-ClbtwZ1e.js} +2 -2
- package/spec-dashboard/dist/assets/{Modal-6mHq6fbZ.js → Modal-6l_QtCKF.js} +1 -1
- package/spec-dashboard/dist/assets/{PageScroll-CAY4S4g4.js → PageScroll-B2kxcqJJ.js} +1 -1
- package/spec-dashboard/dist/assets/{ProjectsPage-UQyzsTWN.js → ProjectsPage-C8IPsMKV.js} +1 -1
- package/spec-dashboard/dist/assets/{SessionInterface-DKU4c1Z-.js → SessionInterface-B5jf7dW7.js} +11 -11
- package/spec-dashboard/dist/assets/SessionWindow-Dag_GiJB.js +1 -0
- package/spec-dashboard/dist/assets/{Settings-igR17pns.js → Settings-J3aibcXo.js} +1 -1
- package/spec-dashboard/dist/assets/{Thread-B-ZUarN1.js → Thread-Dg35J-Pu.js} +3 -3
- package/spec-dashboard/dist/assets/{TimelineChat-sc49Qj5d.js → TimelineChat-f0UF9fXq.js} +1 -1
- package/spec-dashboard/dist/assets/{data-B1ot4PF0.js → data-SNi0AmVT.js} +1 -1
- package/spec-dashboard/dist/assets/{index-BqBNCa1V.js → index-BUKLPN_4.js} +10 -10
- package/spec-dashboard/dist/index.html +1 -1
- package/spec-dashboard/dist/assets/Dashboard-u8RIS3NY.js +0 -27
- package/spec-dashboard/dist/assets/IssuesPage-DXbqQFW_.js +0 -1
- package/spec-dashboard/dist/assets/SessionWindow-zGwJaGbR.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spexcode",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "SpexCode — a spec-driven, self-developing dev tool. The `spex` CLI + spec server reads the .spec tree and its git history, and serves the dashboard.",
|
|
6
6
|
"license": "MIT",
|
package/spec-cli/src/git.ts
CHANGED
|
@@ -360,9 +360,36 @@ type EventStreamRequest = {
|
|
|
360
360
|
}
|
|
361
361
|
|
|
362
362
|
type EventPathMemo = EventCacheLocation & {
|
|
363
|
-
common: string; shallowPath: string; grafts: string; shallow: string
|
|
363
|
+
common: string; shallowPath: string; grafts: string; shallow: string
|
|
364
|
+
replacementStorage: string; replacements: string
|
|
364
365
|
}
|
|
365
366
|
const eventPathMemo = new Map<string, EventPathMemo>()
|
|
367
|
+
function replacementStorageIdentity(common: string): string {
|
|
368
|
+
const hash = createHash('sha256')
|
|
369
|
+
const addTree = (root: string, rel: string) => {
|
|
370
|
+
if (!existsSync(root)) return
|
|
371
|
+
const stack = [{ dir: root, rel }]
|
|
372
|
+
while (stack.length) {
|
|
373
|
+
const current = stack.pop()!
|
|
374
|
+
const entries = readdirSync(current.dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))
|
|
375
|
+
for (const entry of entries) {
|
|
376
|
+
const path = join(current.dir, entry.name)
|
|
377
|
+
const name = `${current.rel}/${entry.name}`
|
|
378
|
+
if (entry.isDirectory()) stack.push({ dir: path, rel: name })
|
|
379
|
+
else hash.update(`\0${name}\0`).update(readFileSync(path))
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
addTree(join(common, 'refs', 'replace'), 'refs/replace')
|
|
384
|
+
for (const name of ['packed-refs']) {
|
|
385
|
+
const path = join(common, name)
|
|
386
|
+
if (existsSync(path)) hash.update(`\0${name}\0`).update(readFileSync(path))
|
|
387
|
+
}
|
|
388
|
+
// Reftable is opaque here by design: its bytes are only an invalidation signal. Git remains the one
|
|
389
|
+
// parser and supplies the canonical refs/replace targets when those bytes change.
|
|
390
|
+
addTree(join(common, 'reftable'), 'reftable')
|
|
391
|
+
return hash.digest('hex')
|
|
392
|
+
}
|
|
366
393
|
function eventCacheLocation(root: string): EventCacheLocation {
|
|
367
394
|
const rootId = rootKey(root), old = eventPathMemo.get(rootId)
|
|
368
395
|
const common = old?.common ?? git(['-C', root, 'rev-parse', '--path-format=absolute', '--git-common-dir']).trim()
|
|
@@ -370,7 +397,10 @@ function eventCacheLocation(root: string): EventCacheLocation {
|
|
|
370
397
|
const shallow = existsSync(shallowPath) ? readFileSync(shallowPath, 'utf8') : 'unshallow'
|
|
371
398
|
const graftsPath = join(common, 'info', 'grafts')
|
|
372
399
|
const grafts = existsSync(graftsPath) ? readFileSync(graftsPath, 'utf8') : ''
|
|
373
|
-
const
|
|
400
|
+
const replacementStorage = replacementStorageIdentity(common)
|
|
401
|
+
const replacements = old?.replacementStorage === replacementStorage
|
|
402
|
+
? old.replacements
|
|
403
|
+
: git(['-C', root, 'for-each-ref', 'refs/replace', '--format=%(refname) %(objectname)'])
|
|
374
404
|
const objectFormat = gitObjectFormat(root)
|
|
375
405
|
if (old && old.shallow === shallow && old.grafts === grafts && old.replacements === replacements && old.objectFormat === objectFormat)
|
|
376
406
|
return { path: old.path, identity: old.identity, objectFormat }
|
|
@@ -382,7 +412,7 @@ function eventCacheLocation(root: string): EventCacheLocation {
|
|
|
382
412
|
const gitDir = gitDirOf(root)
|
|
383
413
|
const storeIdentity = gitDir === root && common === root ? join(common, '.git') : common
|
|
384
414
|
const path = join(projectRuntimeRoot(storeIdentity), `${EVENT_CACHE_SCHEMA}-${identity}.ndjson`)
|
|
385
|
-
eventPathMemo.set(rootId, { common, shallowPath, grafts, shallow, replacements, path, identity, objectFormat })
|
|
415
|
+
eventPathMemo.set(rootId, { common, shallowPath, grafts, shallow, replacementStorage, replacements, path, identity, objectFormat })
|
|
386
416
|
return { path, identity, objectFormat }
|
|
387
417
|
}
|
|
388
418
|
function emptyEventCache(): EventCache {
|
|
@@ -1002,38 +1032,45 @@ function canonicalPathProjector(
|
|
|
1002
1032
|
}
|
|
1003
1033
|
|
|
1004
1034
|
type SharedIndexInputs = {
|
|
1005
|
-
|
|
1006
|
-
|
|
1035
|
+
allPaths: Set<string>
|
|
1036
|
+
specPaths: Set<string>
|
|
1037
|
+
topology: TopologyProjection
|
|
1007
1038
|
historyOut: string
|
|
1008
1039
|
driftOut: string
|
|
1009
1040
|
mergeIndex: MergeHistoryEvents
|
|
1010
1041
|
}
|
|
1011
1042
|
|
|
1043
|
+
type TopologyProjection = {
|
|
1044
|
+
order: Map<string, number>
|
|
1045
|
+
parents: Map<string, string[]>
|
|
1046
|
+
reachable: Set<string>
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1012
1049
|
async function buildIndex(root: string, tip: string, transient: boolean, useCache = true, shared?: SharedIndexInputs): Promise<HistoryIndex> {
|
|
1013
1050
|
const versions = new Map<string, Version[]>()
|
|
1014
1051
|
const stats = new Map<string, Map<string, DiffStat>>()
|
|
1015
1052
|
const mergeVersions = new Set<string>()
|
|
1016
1053
|
const commitVersions = new Map<string, Version>()
|
|
1017
1054
|
const commitOrder = new Map<string, number>()
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1055
|
+
const rawVersions = new Map<string, Version[]>()
|
|
1056
|
+
const rawStats = new Map<string, Map<string, DiffStat>>()
|
|
1057
|
+
let currentPaths: Set<string>
|
|
1058
|
+
let topology: TopologyProjection
|
|
1059
|
+
if (shared) {
|
|
1060
|
+
currentPaths = shared.specPaths
|
|
1061
|
+
topology = shared.topology
|
|
1062
|
+
} else {
|
|
1063
|
+
const [tipPathsOut, topologyOut] = await Promise.all([
|
|
1021
1064
|
strictEventGit(['-C', root, '-c', 'core.quotePath=false', 'ls-tree', '-r', '-z', '--name-only', tip, '--', '.spec']),
|
|
1022
1065
|
strictEventGit(['-C', root, 'rev-list', '--parents', tip]),
|
|
1023
1066
|
])
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
const currentPaths = new Set(tipPathsOut.split('\0').filter((path) => path.startsWith('.spec/')))
|
|
1027
|
-
const renamesByFrom = new Map<string, { hash: string; to: string }[]>()
|
|
1028
|
-
const topologyOrd = new Map<string, number>(), topologyParents = new Map<string, string[]>()
|
|
1029
|
-
let topologyPosition = 0
|
|
1030
|
-
for (const line of topologyOut.trim().split('\n')) {
|
|
1031
|
-
if (!line) continue
|
|
1032
|
-
const [hash, ...parents] = line.split(' ')
|
|
1033
|
-
topologyOrd.set(hash, topologyPosition++)
|
|
1034
|
-
topologyParents.set(hash, parents)
|
|
1067
|
+
currentPaths = new Set(tipPathsOut.split('\0').filter((path) => path.startsWith('.spec/')))
|
|
1068
|
+
topology = topologyProjection(topologyOut)
|
|
1035
1069
|
}
|
|
1036
|
-
const
|
|
1070
|
+
const renamesByFrom = new Map<string, { hash: string; to: string }[]>()
|
|
1071
|
+
const topologyOrd = topology.order
|
|
1072
|
+
const topologyParents = topology.parents
|
|
1073
|
+
const topologyReachable = topology.reachable
|
|
1037
1074
|
const out = shared?.historyOut ?? await eventStream(root, tip,
|
|
1038
1075
|
indexEventRequests(root, tip, topologyOrd, topologyReachable).numstat, !transient, useCache)
|
|
1039
1076
|
if (!out) return { versions, stats, mergeVersions }
|
|
@@ -1363,23 +1400,22 @@ async function buildDriftIndex(root: string, tip: string, transient: boolean, us
|
|
|
1363
1400
|
const acks = new Map<string, Set<string>>(), selfAcks = new Map<string, Set<string>>(), specNodes = new Map<string, Set<string>>()
|
|
1364
1401
|
const ackCandidates = new Map<string, Set<string>>(), trees = new Map<string, string>()
|
|
1365
1402
|
const idx: DriftIndex = { tip, ord, parents, fileEvents, lineageEvents, lineageKeys: (path) => [path], resolutionEvents: new Map(), acks, selfAcks, specNodes, anc: new Map() }
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1403
|
+
let currentPaths: Set<string>
|
|
1404
|
+
let topology: TopologyProjection
|
|
1405
|
+
if (shared) {
|
|
1406
|
+
currentPaths = shared.allPaths
|
|
1407
|
+
topology = shared.topology
|
|
1408
|
+
} else {
|
|
1409
|
+
const [tipPathsOut, topologyOut] = await Promise.all([
|
|
1410
|
+
strictEventGit(['-C', root, 'ls-tree', '-r', '-z', '--name-only', tip]),
|
|
1370
1411
|
strictEventGit(['-C', root, 'rev-list', '--parents', tip]),
|
|
1371
1412
|
])
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
let topologyPosition = 0
|
|
1375
|
-
for (const line of topology.trim().split('\n')) {
|
|
1376
|
-
const [hash, ...parentList] = line.split(' ')
|
|
1377
|
-
if (hash) {
|
|
1378
|
-
topologyOrder.set(hash, topologyPosition++)
|
|
1379
|
-
topologyParents.set(hash, parentList)
|
|
1380
|
-
topologyReachable.add(hash)
|
|
1381
|
-
}
|
|
1413
|
+
currentPaths = new Set(tipPathsOut.split('\0').filter(Boolean))
|
|
1414
|
+
topology = topologyProjection(topologyOut)
|
|
1382
1415
|
}
|
|
1416
|
+
const topologyOrder = topology.order
|
|
1417
|
+
const topologyParents = topology.parents
|
|
1418
|
+
const topologyReachable = topology.reachable
|
|
1383
1419
|
// Numstat is the immutable identity event: unlike a name-only stream it records both sides of a rename,
|
|
1384
1420
|
// allowing the same event-scoped projection used by spec history to follow forks and reject path reuse.
|
|
1385
1421
|
const out = shared?.driftOut ?? await eventStream(root, tip,
|
|
@@ -1507,16 +1543,17 @@ export function driftIndex(root: string, tip = 'HEAD'): Promise<DriftIndex> {
|
|
|
1507
1543
|
return p
|
|
1508
1544
|
}
|
|
1509
1545
|
|
|
1510
|
-
function topologyProjection(out: string):
|
|
1511
|
-
const order = new Map<string, number>(), reachable = new Set<string>()
|
|
1546
|
+
function topologyProjection(out: string): TopologyProjection {
|
|
1547
|
+
const order = new Map<string, number>(), parents = new Map<string, string[]>(), reachable = new Set<string>()
|
|
1512
1548
|
let position = 0
|
|
1513
1549
|
for (const line of out.trim().split('\n')) {
|
|
1514
|
-
const hash = line.split(' '
|
|
1550
|
+
const [hash, ...parentList] = line.split(' ')
|
|
1515
1551
|
if (!hash) continue
|
|
1516
1552
|
order.set(hash, position++)
|
|
1553
|
+
parents.set(hash, parentList)
|
|
1517
1554
|
reachable.add(hash)
|
|
1518
1555
|
}
|
|
1519
|
-
return { order, reachable }
|
|
1556
|
+
return { order, parents, reachable }
|
|
1520
1557
|
}
|
|
1521
1558
|
|
|
1522
1559
|
async function buildIndexPair(root: string, tip: string, transient: boolean, useCache = true): Promise<[HistoryIndex, DriftIndex]> {
|
|
@@ -1525,11 +1562,14 @@ async function buildIndexPair(root: string, tip: string, transient: boolean, use
|
|
|
1525
1562
|
strictEventGit(['-C', root, 'rev-list', '--parents', tip]),
|
|
1526
1563
|
])
|
|
1527
1564
|
const topology = topologyProjection(topologyOut)
|
|
1565
|
+
const allPaths = new Set(allPathsOut.split('\0').filter(Boolean))
|
|
1566
|
+
const specPaths = new Set([...allPaths].filter((path) => path.startsWith('.spec/')))
|
|
1528
1567
|
const requests = indexEventRequests(root, tip, topology.order, topology.reachable)
|
|
1529
1568
|
const streams = await deriveEventStreams(root, tip, EVENT_STREAM_KINDS.map((kind) => requests[kind]), !transient, useCache)
|
|
1530
1569
|
const shared: SharedIndexInputs = {
|
|
1531
|
-
|
|
1532
|
-
|
|
1570
|
+
allPaths,
|
|
1571
|
+
specPaths,
|
|
1572
|
+
topology,
|
|
1533
1573
|
historyOut: streams.get('numstat') ?? '',
|
|
1534
1574
|
driftOut: streams.get('drift-numstat') ?? '',
|
|
1535
1575
|
mergeIndex: parseMergeHistoryEvents(streams.get('merge') ?? ''),
|
package/spec-cli/src/index.ts
CHANGED
|
@@ -632,13 +632,18 @@ app.post('/api/sessions/:id/input', async (c) => {
|
|
|
632
632
|
app.post('/api/sessions/:id/stop', async (c) => {
|
|
633
633
|
const sessionId = c.req.param('id')
|
|
634
634
|
const authorization = await operationAuthorization(c.req.header.bind(c.req), { op: 'stop', sessionId })
|
|
635
|
-
|
|
635
|
+
const ok = await stopSession(sessionId, { authorization })
|
|
636
|
+
return c.json(ok ? { ok: true } : { ok: false, error: `no stop transition was committed for session ${sessionId}` }, ok ? 200 : 404)
|
|
636
637
|
})
|
|
637
638
|
app.post('/api/sessions/:id/interrupt', async (c) => {
|
|
638
639
|
const result = await interruptSession(c.req.param('id'))
|
|
639
640
|
return c.json(result, result.ok ? 200 : 502)
|
|
640
641
|
})
|
|
641
|
-
app.post('/api/sessions/:id/close', async (c) =>
|
|
642
|
+
app.post('/api/sessions/:id/close', async (c) => {
|
|
643
|
+
const sessionId = c.req.param('id')
|
|
644
|
+
const ok = await closeSession(sessionId)
|
|
645
|
+
return c.json(ok ? { ok: true } : { ok: false, error: `no close transition was committed for session ${sessionId}` }, ok ? 200 : 404)
|
|
646
|
+
})
|
|
642
647
|
// archive / legacy unarchive signpost ([[archive]]) — archive proves exact cold/offline ownership before filing;
|
|
643
648
|
// `{on:false}` enters the same resume transition and recreates the preserved conversation. {ok:false}=no such session.
|
|
644
649
|
app.post('/api/sessions/:id/archive', async (c) => {
|
|
@@ -21,3 +21,7 @@ export function readReviewSnapshot(): ReviewSnapshot {
|
|
|
21
21
|
if (!current) throw new Error('review snapshot is unavailable before the first successful graph build')
|
|
22
22
|
return current
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
export function hasReviewSnapshot(): boolean {
|
|
26
|
+
return current !== null
|
|
27
|
+
}
|
package/spec-cli/src/reviews.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { buildSessionEvals, type SessionEvals } from '../../spec-eval/src/sessio
|
|
|
5
5
|
import { evalTimeline } from '../../spec-eval/src/evaltab.js'
|
|
6
6
|
import { issuesEnabled as issuesEnabledForReview } from './localIssues.js'
|
|
7
7
|
import { issueStores as issueStoresForReview } from './issues.js'
|
|
8
|
-
import { readReviewSnapshot } from './reviewSnapshot.js'
|
|
8
|
+
import { hasReviewSnapshot, readReviewSnapshot } from './reviewSnapshot.js'
|
|
9
9
|
// @ts-expect-error The dashboard module is deliberately plain JS so the browser and server execute the
|
|
10
10
|
// exact same tokenizer/matcher. It is shipped beside the built dashboard by the root package manifest.
|
|
11
11
|
import { EVAL_FILTER_KIND, evalFilterModel, evalReviewState, issueFilterModel, tokenFilterState } from '../../spec-dashboard/src/reviewFilters.js'
|
|
@@ -121,7 +121,11 @@ const issueOrder = (a: any, b: any): number => String(b.created ?? '').localeCom
|
|
|
121
121
|
|| String(a.id ?? '').localeCompare(String(b.id ?? ''))
|
|
122
122
|
|
|
123
123
|
export async function issuesReview(query: string | undefined, requestedPage: unknown) {
|
|
124
|
-
|
|
124
|
+
// The first request must wait for the first atomic publication. Once one exists, a graph refresh may be
|
|
125
|
+
// rebuilding unrelated board/session state; the published review source remains a valid answer and its
|
|
126
|
+
// revision/poll path will deliver the next generation without making this page join that flight.
|
|
127
|
+
if (!hasReviewSnapshot()) await getBoard()
|
|
128
|
+
const sessions = await listSessions()
|
|
125
129
|
const issues = readReviewSnapshot().issues.slice().sort(issueOrder)
|
|
126
130
|
const text = String(query ?? '').trim() || ISSUE_QUERY_DEFAULT
|
|
127
131
|
const model = issueFilterModel(issues, tokenFilterState(text, 'issue'), { sessions, defaultSection: '' })
|
|
@@ -337,15 +341,16 @@ export async function evalsReview(query: string | undefined, requestedPage: unkn
|
|
|
337
341
|
}),
|
|
338
342
|
}
|
|
339
343
|
}
|
|
340
|
-
|
|
344
|
+
if (!hasReviewSnapshot()) await getBoard()
|
|
345
|
+
const sessions = await listSessions()
|
|
341
346
|
const items = trunkEvalReviewItems(readReviewSnapshot().evalNodes)
|
|
342
|
-
const filtered = evalFilterModel(items, tokenFilterState(text, 'eval'), { sessions
|
|
347
|
+
const filtered = evalFilterModel(items, tokenFilterState(text, 'eval'), { sessions, defaultKind: 'all', defaultSection: '' })
|
|
343
348
|
return {
|
|
344
349
|
scope: null,
|
|
345
350
|
gates: [],
|
|
346
351
|
unknown: 0,
|
|
347
352
|
...paginateReview(items, filtered.shown, filtered, requestedPage, {
|
|
348
|
-
domain: 'evals', items, sessions:
|
|
353
|
+
domain: 'evals', items, sessions: sessions.map((session) => session.id),
|
|
349
354
|
}),
|
|
350
355
|
}
|
|
351
356
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-
|
|
2
|
-
import{u as N,r as a,j as n,I as D,a as B,P as k,i as z,_ as T,D as M,b as G}from"./index-BqBNCa1V.js";import{a as J,l as q,s as F,p as V}from"./data-B1ot4PF0.js";const h=async e=>(e.headers.get("content-type")||"").includes("json")?e.json().catch(()=>null):null,H=5e3,O=(e,r,t)=>({title:typeof(e==null?void 0:e.title)=="string"&&e.title?e.title:r,icon:typeof(e==null?void 0:e.icon)=="string"&&e.icon?e.icon:t});function x(e){if(!e||typeof e!="object")return null;const r=e.id??e.projectId;return r?{id:String(r),identity:O(e.identity||{title:e.name,icon:e.icon},e.name||String(r),"spexcode"),root:typeof e.root=="string"?e.root:"",online:typeof e.online=="boolean"?e.online:null,url:e.url||"",port:e.port??null,gated:!!(e.gated??e.locked??e.hasPassword),configRevision:typeof e.configRevision=="string"?e.configRevision:""}:null}const W=e=>{const r=Array.isArray(e)?e:Array.isArray(e==null?void 0:e.projects)?e.projects:null;return r?r.map(x).filter(Boolean):null},Y=10;function ce(e,r,t=Y){const s=Array.isArray(e)?e:[],o=Math.max(1,Math.ceil(s.length/t)),l=Math.min(Math.max(1,Number.isInteger(r)?r:1),o);return{items:s.slice((l-1)*t,l*t),page:l,pageCount:o}}function Z(e,r,t){var s;if(!e)return t;if(!r)return null;if(r.state==="ok"){const o=(s=r.projects)==null?void 0:s.find(l=>l.id===e);return(o==null?void 0:o.identity)||{title:e,icon:"spexcode"}}return{title:(t==null?void 0:t.title)||e,icon:(t==null?void 0:t.icon)||"spexcode"}}const K=e=>(e==null?void 0:e.state)==="ok"?e.gateway.identity:{title:"Projects",icon:"gateway"},Q=e=>(e==null?void 0:e.title)||"SpexCode",R=(e,r)=>(r==null?void 0:r.state)==="absent"&&e&&e.state!=="absent"?e:r;async function X(){let e;try{e=await fetch("/projects",{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{state:"absent"}}if(e.status===401)return{state:"denied",reason:"admin-login"};if(e.status===403)return{state:"denied",reason:"locked"};if(!e.ok)return{state:"absent"};const r=await h(e),t=W(r);if(!t)return{state:"absent"};const s=r!=null&&r.gateway&&typeof r.gateway=="object"?{identity:O(r.gateway,"Projects","gateway"),revision:typeof r.gateway.revision=="string"?r.gateway.revision:""}:{identity:{title:"Projects",icon:"gateway"},revision:""};return{state:"ok",adminGated:!!(r!=null&&r.adminGated),gateway:s,projects:t}}async function ie(e,{timeoutMs:r=2500}={}){try{const t=await fetch(`/p/${encodeURIComponent(e)}/health`,{cache:"no-store",signal:AbortSignal.timeout(r)});return!t.ok||t.redirected?"unreachable":(await t.text()).trim()==="ok"?"running":"unreachable"}catch{return"unreachable"}}async function C(e,r,t){let s;try{s=await fetch(e,{method:r,headers:{"Content-Type":"application/json",Accept:"application/json"},...r==="PUT"?{body:JSON.stringify({password:t})}:{}})}catch{return{ok:!1,error:"network"}}const o=await h(s)||{};return{ok:s.ok&&o.ok!==!1,status:s.status,...o.error?{error:o.error}:{}}}const le=(e,r)=>C(`/projects/${encodeURIComponent(e)}/password`,"PUT",r),ue=e=>C(`/projects/${encodeURIComponent(e)}/password`,"DELETE"),pe=e=>C("/projects/admin-password","PUT",e),de=()=>C("/projects/admin-password","DELETE");async function ee(e,r){const t=e==="admin"?"/login":`/p/${encodeURIComponent(e.projectId)}/login`;let s;try{s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:r})})}catch{return{ok:!1,error:"network"}}return s.status===401?{ok:!1,error:"wrong-password"}:s.status===403?{ok:!1,error:"locked"}:s.ok||s.redirected?{ok:!0}:{ok:!1,error:`http-${s.status}`}}async function fe(e=""){let r;try{const s=e?`?path=${encodeURIComponent(e)}`:"";r=await fetch(`/projects/browse${s}`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.path)!="string"||!Array.isArray(t==null?void 0:t.entries)?{ok:!1,error:"unexpected answer"}:{ok:!0,path:t.path,parent:typeof t.parent=="string"?t.parent:null,home:typeof t.home=="string"?t.home:t.path,gitRoot:typeof t.gitRoot=="string"?t.gitRoot:null,initialized:!!t.initialized,cataloged:!!t.cataloged,entries:t.entries.filter(s=>s&&typeof s.name=="string"&&typeof s.path=="string").map(s=>({name:s.name,path:s.path,git:!!s.git,initialized:!!s.initialized}))}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function he(e,r={}){let t;try{t=await fetch("/projects",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({root:e,...r})})}catch{return{ok:!1,error:"network"}}const s=await h(t);if(!t.ok)return{ok:!1,status:t.status,error:(s==null?void 0:s.error)||`http-${t.status}`,...s!=null&&s.init&&typeof s.init=="object"?{code:s.init.code??null,output:String(s.init.output??"")}:{}};const o=x(s);return o?{ok:!0,project:o,setup:s.setup??null}:{ok:!1,error:"unexpected answer"}}async function je(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/config`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.content)!="string"||typeof(t==null?void 0:t.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:t.content,revision:t.revision}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function me(e,r,t){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/config`,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({content:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?typeof(o==null?void 0:o.content)!="string"||typeof(o==null?void 0:o.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:o.content,revision:o.revision}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}async function $(e,r,t){let s;try{s=await fetch(e,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({icon:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?{ok:!0,...o}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const ke=(e,r)=>$("/projects/icon",e,r),ge=(e,r,t)=>$(`/projects/${encodeURIComponent(e)}/icon`,r,t);async function U(e,r,t={}){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/${r}`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?!o||typeof o!="object"?{ok:!1,error:"unexpected answer"}:{ok:o.ok===!0,code:o.code??null,output:String(o.output??"")}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const we=(e,r)=>U(e,"init",{harness:r}),ye=e=>U(e,"doctor");async function Pe(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/serve`,{method:"POST",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.status===409?{ok:!0,already:!0,project:x(t==null?void 0:t.project)}:r.ok?{ok:!0,project:x(t==null?void 0:t.project)}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}function I({scope:e,projectLabel:r,locked:t,onUnlocked:s}){const o=N(),[l,S]=a.useState(""),[j,A]=a.useState(!1),[g,P]=a.useState(null),m=e==="admin",p=async b=>{if(b.preventDefault(),!l||j)return;A(!0),P(null);const w=await ee(m?"admin":{projectId:e.projectId},l);A(!1),w.ok?(S(""),s()):P(w.error==="wrong-password"?o("credential.wrong"):o("credential.failed"))};return n.jsx("div",{className:"cred-wrap",children:n.jsxs("form",{className:"cred-card",onSubmit:p,children:[n.jsx("div",{className:"cred-brand",children:"$ spexcode"}),n.jsxs("div",{className:"cred-title",children:[n.jsx(D,{name:"lock",size:14,className:"cred-lock"}),t?o("credential.lockedTitle"):m?o("credential.adminTitle"):o("credential.projectTitle",{name:r||e&&e.projectId||""})]}),t?n.jsx("p",{className:"cred-sub",children:o("credential.lockedBody")}):n.jsxs(n.Fragment,{children:[n.jsx("p",{className:"cred-sub",children:o(m?"credential.adminBody":"credential.projectBody")}),g&&n.jsx("div",{className:"cred-err",children:g}),n.jsx("input",{className:"cred-input",type:"password",autoFocus:!0,required:!0,placeholder:"••••••••••","aria-label":o("credential.passwordLabel"),value:l,onChange:b=>S(b.target.value)}),n.jsx("button",{className:"cred-submit",type:"submit",disabled:j||!l,children:o(j?"credential.checking":"credential.unlock")})]})]})})}const te=a.lazy(()=>T(()=>import("./Dashboard-u8RIS3NY.js").then(e=>e.D),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]))),re=a.lazy(()=>T(()=>import("./MobileApp-DVLnk9hz.js"),__vite__mapDeps([10,1,2,3,4,5,6,11,12]))),se=a.lazy(()=>T(()=>import("./ProjectsPage-UQyzsTWN.js"),__vite__mapDeps([13,1,2,7,5,6])));window.addEventListener("vite:preloadError",e=>{const r=String(e.payload);sessionStorage.getItem("spexcode.chunkReload")!==r&&(sessionStorage.setItem("spexcode.chunkReload",r),e.preventDefault(),location.reload())});function oe(){const e=N(),r=B(),[t,s]=a.useState(null),[o,l]=a.useState(!1),S=a.useRef(new Map),j=a.useCallback((u,c)=>{s(J(u,S.current,c))},[]),[A,g]=a.useState(!1),[P,m]=a.useState(null),[p,b]=a.useState(null);a.useEffect(()=>{let u=!0;const c=()=>X().then(y=>{u&&b(L=>R(L,y))}).catch(()=>{u&&b(y=>R(y,{state:"absent"}))});c();const d=setInterval(c,H);return()=>{u=!1,clearInterval(d)}},[]);const w=a.useRef(0),f=a.useCallback(()=>{const u=++w.current;return q().then(c=>{if(!(u!==w.current||!c)){if(c.authRequired){m(c.authRequired);return}m(null),g(!1),j(c.board,!0),c.seal()}}).catch(()=>{u===w.current&&g(!0)})},[j]),v=!k&&!t&&!!p&&p.state!=="absent",E=!k&&!t&&p===null;a.useEffect(()=>{if(v||E)return;f();const u=F({onBoard:(d,y)=>{w.current++,g(!1),j(d,!!(y!=null&&y.authoritative))},onLegacyChange:()=>{f()},onStatus:l}),c=setInterval(()=>{f()},15e3);return()=>{u(),clearInterval(c)}},[f,j,v,E]);const _=t?V(t):null,i=k?Z(k,p,_):v?K(p):_;return a.useEffect(()=>{i&&(document.title=Q(i))},[i==null?void 0:i.title]),a.useEffect(()=>{if(!i)return;const u=v?M:G,c=z(i.icon,u);let d=document.querySelector("link[rel~='icon']");d||(d=document.createElement("link"),d.rel="icon",document.head.appendChild(d)),d.getAttribute("href")!==c&&d.setAttribute("href",c)},[i==null?void 0:i.icon,v]),P&&k?n.jsx(I,{scope:{projectId:k},projectLabel:(i==null?void 0:i.title)||k,onUnlocked:()=>{m(null),f()}}):t?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:r?n.jsx(re,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reloadBoard:f}):n.jsx(te,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reload:f,identity:i,catalog:p,boardLive:o})}):v?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:n.jsx(se,{})}):P?n.jsx(I,{scope:"admin",locked:P==="locked",onUnlocked:()=>{m(null),f()}}):A&&(k||p&&p.state==="absent")?n.jsxs("div",{className:"loading load-error",children:[n.jsx("span",{children:e("hud.loadError")}),n.jsx("button",{className:"load-retry",onClick:()=>{g(!1),f()},children:e("hud.retry")})]}):n.jsx("div",{className:"loading",children:e("hud.loading")})}const be=Object.freeze(Object.defineProperty({__proto__:null,default:oe},Symbol.toStringTag,{value:"Module"}));export{be as A,H as C,ce as a,I as b,de as c,fe as d,je as e,ye as f,ke as g,he as h,we as i,me as j,ge as k,X as l,Pe as m,ue as n,le as o,ie as p,pe as s};
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-C5X4Va3V.js","assets/index-BUKLPN_4.js","assets/index-CzutlTDf.css","assets/SessionWindow-Dag_GiJB.js","assets/Thread-Dg35J-Pu.js","assets/PageScroll-B2kxcqJJ.js","assets/data-SNi0AmVT.js","assets/Modal-6l_QtCKF.js","assets/bindings-BC9vqpYU.js","assets/Dashboard-C5ap-Sga.css","assets/MobileApp-ClbtwZ1e.js","assets/TimelineChat-f0UF9fXq.js","assets/TimelineChat-Cp579UoJ.css","assets/ProjectsPage-C8IPsMKV.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{u as N,r as a,j as n,I as D,a as B,P as k,i as z,_ as T,D as M,b as G}from"./index-BUKLPN_4.js";import{a as J,l as q,s as F,p as V}from"./data-SNi0AmVT.js";const h=async e=>(e.headers.get("content-type")||"").includes("json")?e.json().catch(()=>null):null,H=5e3,O=(e,r,t)=>({title:typeof(e==null?void 0:e.title)=="string"&&e.title?e.title:r,icon:typeof(e==null?void 0:e.icon)=="string"&&e.icon?e.icon:t});function x(e){if(!e||typeof e!="object")return null;const r=e.id??e.projectId;return r?{id:String(r),identity:O(e.identity||{title:e.name,icon:e.icon},e.name||String(r),"spexcode"),root:typeof e.root=="string"?e.root:"",online:typeof e.online=="boolean"?e.online:null,url:e.url||"",port:e.port??null,gated:!!(e.gated??e.locked??e.hasPassword),configRevision:typeof e.configRevision=="string"?e.configRevision:""}:null}const W=e=>{const r=Array.isArray(e)?e:Array.isArray(e==null?void 0:e.projects)?e.projects:null;return r?r.map(x).filter(Boolean):null},Y=10;function ce(e,r,t=Y){const s=Array.isArray(e)?e:[],o=Math.max(1,Math.ceil(s.length/t)),l=Math.min(Math.max(1,Number.isInteger(r)?r:1),o);return{items:s.slice((l-1)*t,l*t),page:l,pageCount:o}}function Z(e,r,t){var s;if(!e)return t;if(!r)return null;if(r.state==="ok"){const o=(s=r.projects)==null?void 0:s.find(l=>l.id===e);return(o==null?void 0:o.identity)||{title:e,icon:"spexcode"}}return{title:(t==null?void 0:t.title)||e,icon:(t==null?void 0:t.icon)||"spexcode"}}const K=e=>(e==null?void 0:e.state)==="ok"?e.gateway.identity:{title:"Projects",icon:"gateway"},Q=e=>(e==null?void 0:e.title)||"SpexCode",R=(e,r)=>(r==null?void 0:r.state)==="absent"&&e&&e.state!=="absent"?e:r;async function X(){let e;try{e=await fetch("/projects",{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{state:"absent"}}if(e.status===401)return{state:"denied",reason:"admin-login"};if(e.status===403)return{state:"denied",reason:"locked"};if(!e.ok)return{state:"absent"};const r=await h(e),t=W(r);if(!t)return{state:"absent"};const s=r!=null&&r.gateway&&typeof r.gateway=="object"?{identity:O(r.gateway,"Projects","gateway"),revision:typeof r.gateway.revision=="string"?r.gateway.revision:""}:{identity:{title:"Projects",icon:"gateway"},revision:""};return{state:"ok",adminGated:!!(r!=null&&r.adminGated),gateway:s,projects:t}}async function ie(e,{timeoutMs:r=2500}={}){try{const t=await fetch(`/p/${encodeURIComponent(e)}/health`,{cache:"no-store",signal:AbortSignal.timeout(r)});return!t.ok||t.redirected?"unreachable":(await t.text()).trim()==="ok"?"running":"unreachable"}catch{return"unreachable"}}async function C(e,r,t){let s;try{s=await fetch(e,{method:r,headers:{"Content-Type":"application/json",Accept:"application/json"},...r==="PUT"?{body:JSON.stringify({password:t})}:{}})}catch{return{ok:!1,error:"network"}}const o=await h(s)||{};return{ok:s.ok&&o.ok!==!1,status:s.status,...o.error?{error:o.error}:{}}}const le=(e,r)=>C(`/projects/${encodeURIComponent(e)}/password`,"PUT",r),ue=e=>C(`/projects/${encodeURIComponent(e)}/password`,"DELETE"),pe=e=>C("/projects/admin-password","PUT",e),de=()=>C("/projects/admin-password","DELETE");async function ee(e,r){const t=e==="admin"?"/login":`/p/${encodeURIComponent(e.projectId)}/login`;let s;try{s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:r})})}catch{return{ok:!1,error:"network"}}return s.status===401?{ok:!1,error:"wrong-password"}:s.status===403?{ok:!1,error:"locked"}:s.ok||s.redirected?{ok:!0}:{ok:!1,error:`http-${s.status}`}}async function fe(e=""){let r;try{const s=e?`?path=${encodeURIComponent(e)}`:"";r=await fetch(`/projects/browse${s}`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.path)!="string"||!Array.isArray(t==null?void 0:t.entries)?{ok:!1,error:"unexpected answer"}:{ok:!0,path:t.path,parent:typeof t.parent=="string"?t.parent:null,home:typeof t.home=="string"?t.home:t.path,gitRoot:typeof t.gitRoot=="string"?t.gitRoot:null,initialized:!!t.initialized,cataloged:!!t.cataloged,entries:t.entries.filter(s=>s&&typeof s.name=="string"&&typeof s.path=="string").map(s=>({name:s.name,path:s.path,git:!!s.git,initialized:!!s.initialized}))}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function he(e,r={}){let t;try{t=await fetch("/projects",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({root:e,...r})})}catch{return{ok:!1,error:"network"}}const s=await h(t);if(!t.ok)return{ok:!1,status:t.status,error:(s==null?void 0:s.error)||`http-${t.status}`,...s!=null&&s.init&&typeof s.init=="object"?{code:s.init.code??null,output:String(s.init.output??"")}:{}};const o=x(s);return o?{ok:!0,project:o,setup:s.setup??null}:{ok:!1,error:"unexpected answer"}}async function je(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/config`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.content)!="string"||typeof(t==null?void 0:t.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:t.content,revision:t.revision}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function me(e,r,t){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/config`,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({content:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?typeof(o==null?void 0:o.content)!="string"||typeof(o==null?void 0:o.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:o.content,revision:o.revision}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}async function $(e,r,t){let s;try{s=await fetch(e,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({icon:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?{ok:!0,...o}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const ke=(e,r)=>$("/projects/icon",e,r),ge=(e,r,t)=>$(`/projects/${encodeURIComponent(e)}/icon`,r,t);async function U(e,r,t={}){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/${r}`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?!o||typeof o!="object"?{ok:!1,error:"unexpected answer"}:{ok:o.ok===!0,code:o.code??null,output:String(o.output??"")}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const we=(e,r)=>U(e,"init",{harness:r}),ye=e=>U(e,"doctor");async function Pe(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/serve`,{method:"POST",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.status===409?{ok:!0,already:!0,project:x(t==null?void 0:t.project)}:r.ok?{ok:!0,project:x(t==null?void 0:t.project)}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}function I({scope:e,projectLabel:r,locked:t,onUnlocked:s}){const o=N(),[l,S]=a.useState(""),[j,A]=a.useState(!1),[g,P]=a.useState(null),m=e==="admin",p=async b=>{if(b.preventDefault(),!l||j)return;A(!0),P(null);const w=await ee(m?"admin":{projectId:e.projectId},l);A(!1),w.ok?(S(""),s()):P(w.error==="wrong-password"?o("credential.wrong"):o("credential.failed"))};return n.jsx("div",{className:"cred-wrap",children:n.jsxs("form",{className:"cred-card",onSubmit:p,children:[n.jsx("div",{className:"cred-brand",children:"$ spexcode"}),n.jsxs("div",{className:"cred-title",children:[n.jsx(D,{name:"lock",size:14,className:"cred-lock"}),t?o("credential.lockedTitle"):m?o("credential.adminTitle"):o("credential.projectTitle",{name:r||e&&e.projectId||""})]}),t?n.jsx("p",{className:"cred-sub",children:o("credential.lockedBody")}):n.jsxs(n.Fragment,{children:[n.jsx("p",{className:"cred-sub",children:o(m?"credential.adminBody":"credential.projectBody")}),g&&n.jsx("div",{className:"cred-err",children:g}),n.jsx("input",{className:"cred-input",type:"password",autoFocus:!0,required:!0,placeholder:"••••••••••","aria-label":o("credential.passwordLabel"),value:l,onChange:b=>S(b.target.value)}),n.jsx("button",{className:"cred-submit",type:"submit",disabled:j||!l,children:o(j?"credential.checking":"credential.unlock")})]})]})})}const te=a.lazy(()=>T(()=>import("./Dashboard-C5X4Va3V.js").then(e=>e.D),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]))),re=a.lazy(()=>T(()=>import("./MobileApp-ClbtwZ1e.js"),__vite__mapDeps([10,1,2,3,4,5,6,11,12]))),se=a.lazy(()=>T(()=>import("./ProjectsPage-C8IPsMKV.js"),__vite__mapDeps([13,1,2,7,5,6])));window.addEventListener("vite:preloadError",e=>{const r=String(e.payload);sessionStorage.getItem("spexcode.chunkReload")!==r&&(sessionStorage.setItem("spexcode.chunkReload",r),e.preventDefault(),location.reload())});function oe(){const e=N(),r=B(),[t,s]=a.useState(null),[o,l]=a.useState(!1),S=a.useRef(new Map),j=a.useCallback((u,c)=>{s(J(u,S.current,c))},[]),[A,g]=a.useState(!1),[P,m]=a.useState(null),[p,b]=a.useState(null);a.useEffect(()=>{let u=!0;const c=()=>X().then(y=>{u&&b(L=>R(L,y))}).catch(()=>{u&&b(y=>R(y,{state:"absent"}))});c();const d=setInterval(c,H);return()=>{u=!1,clearInterval(d)}},[]);const w=a.useRef(0),f=a.useCallback(()=>{const u=++w.current;return q().then(c=>{if(!(u!==w.current||!c)){if(c.authRequired){m(c.authRequired);return}m(null),g(!1),j(c.board,!0),c.seal()}}).catch(()=>{u===w.current&&g(!0)})},[j]),v=!k&&!t&&!!p&&p.state!=="absent",E=!k&&!t&&p===null;a.useEffect(()=>{if(v||E)return;f();const u=F({onBoard:(d,y)=>{w.current++,g(!1),j(d,!!(y!=null&&y.authoritative))},onLegacyChange:()=>{f()},onStatus:l}),c=setInterval(()=>{f()},15e3);return()=>{u(),clearInterval(c)}},[f,j,v,E]);const _=t?V(t):null,i=k?Z(k,p,_):v?K(p):_;return a.useEffect(()=>{i&&(document.title=Q(i))},[i==null?void 0:i.title]),a.useEffect(()=>{if(!i)return;const u=v?M:G,c=z(i.icon,u);let d=document.querySelector("link[rel~='icon']");d||(d=document.createElement("link"),d.rel="icon",document.head.appendChild(d)),d.getAttribute("href")!==c&&d.setAttribute("href",c)},[i==null?void 0:i.icon,v]),P&&k?n.jsx(I,{scope:{projectId:k},projectLabel:(i==null?void 0:i.title)||k,onUnlocked:()=>{m(null),f()}}):t?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:r?n.jsx(re,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reloadBoard:f}):n.jsx(te,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reload:f,identity:i,catalog:p,boardLive:o})}):v?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:n.jsx(se,{})}):P?n.jsx(I,{scope:"admin",locked:P==="locked",onUnlocked:()=>{m(null),f()}}):A&&(k||p&&p.state==="absent")?n.jsxs("div",{className:"loading load-error",children:[n.jsx("span",{children:e("hud.loadError")}),n.jsx("button",{className:"load-retry",onClick:()=>{g(!1),f()},children:e("hud.retry")})]}):n.jsx("div",{className:"loading",children:e("hud.loading")})}const be=Object.freeze(Object.defineProperty({__proto__:null,default:oe},Symbol.toStringTag,{value:"Module"}));export{be as A,H as C,ce as a,I as b,de as c,fe as d,je as e,ye as f,ke as g,he as h,we as i,me as j,ge as k,X as l,Pe as m,ue as n,le as o,ie as p,pe as s};
|