feat: complete production naming and reference lifecycle gates
This commit is contained in:
95
public/chrome-partdesign-reference-lifecycle-harness.html
Normal file
95
public/chrome-partdesign-reference-lifecycle-harness.html
Normal file
@@ -0,0 +1,95 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Chrome PartDesign external reference lifecycle harness</title>
|
||||
<pre id="result">running</pre>
|
||||
<script type="module">
|
||||
import { createMockFacade } from '/src/facade/mockFacade.ts'
|
||||
import { ExternalPartDesignLinkRegistry } from '/src/facade/externalPartDesignLinks.ts'
|
||||
|
||||
const output = document.querySelector('#result')
|
||||
const report = { schemaVersion: 1, browserId: 'chrome', userAgent: navigator.userAgent, crossOriginIsolated: globalThis.crossOriginIsolated === true, status: 'running' }
|
||||
const facade = createMockFacade()
|
||||
const sourcePath = '/projects/XLinkSource.FCStd'
|
||||
const objectEvidence = async (objectId, shape, dimensions) => {
|
||||
const [mass, quality] = await Promise.all([facade.geometry.massProperties(shape), facade.geometry.qualityReport(shape)])
|
||||
if (quality.solids !== 1 || quality.isNull || Math.abs(mass.volume - dimensions.length * dimensions.width * dimensions.height) > 1e-7) throw new Error(`${objectId} OCCT evidence is invalid.`)
|
||||
return { objectId, ...dimensions, volume: mass.volume, surfaceArea: mass.surfaceArea, shapeId: shape.id }
|
||||
}
|
||||
const sourceEvidence = async (revision, sourceShape, secondShape, sourceDimensions, secondDimensions) => ({
|
||||
documentId: 'XLinkSource', path: sourcePath, revision,
|
||||
objects: {
|
||||
SourceBox: await objectEvidence('SourceBox', sourceShape, sourceDimensions),
|
||||
SecondBox: await objectEvidence('SecondBox', secondShape, secondDimensions),
|
||||
},
|
||||
})
|
||||
const writeArchive = async (name, registry) => {
|
||||
const root = await navigator.storage.getDirectory()
|
||||
const directory = await root.getDirectoryHandle('partdesign-external-reference-lifecycle', { create: true })
|
||||
const file = await directory.getFileHandle(name, { create: true })
|
||||
const writer = await file.createWritable()
|
||||
await writer.write(registry.serialize())
|
||||
await writer.close()
|
||||
}
|
||||
const readArchive = async (name) => {
|
||||
const root = await navigator.storage.getDirectory()
|
||||
const directory = await root.getDirectoryHandle('partdesign-external-reference-lifecycle')
|
||||
const file = await directory.getFileHandle(name)
|
||||
return ExternalPartDesignLinkRegistry.deserialize(await (await file.getFile()).text())
|
||||
}
|
||||
|
||||
try {
|
||||
if (!report.crossOriginIsolated || !navigator.storage?.getDirectory) throw new Error('Chrome PartDesign reference lifecycle requires isolated OPFS.')
|
||||
const initialized = await facade.geometry.initialize()
|
||||
if (initialized.status !== 'ready') throw new Error(initialized.reason || 'Bitbybit geometry runtime is unavailable.')
|
||||
|
||||
const sourceShape = await facade.geometry.createBox({ documentId: 'XLinkSource', documentVersion: 1, width: 5, length: 4, height: 6 })
|
||||
const secondShape = await facade.geometry.createBox({ documentId: 'XLinkSource', documentVersion: 1, width: 7, length: 3, height: 2 })
|
||||
const initialEvidence = await sourceEvidence(1, sourceShape, secondShape, { length: 4, width: 5, height: 6 }, { length: 3, width: 7, height: 2 })
|
||||
const registry = new ExternalPartDesignLinkRegistry(initialEvidence)
|
||||
const initial = registry.snapshot()
|
||||
|
||||
registry.closeSource()
|
||||
const closed = registry.snapshot()
|
||||
registry.relinkSource(initialEvidence)
|
||||
const relinkedAfterClose = registry.snapshot()
|
||||
registry.closeSource()
|
||||
registry.markSourceMissing()
|
||||
const missing = registry.snapshot()
|
||||
await writeArchive('missing.json', registry)
|
||||
const reopenedMissingRegistry = await readArchive('missing.json')
|
||||
const reopenedMissing = reopenedMissingRegistry.snapshot()
|
||||
reopenedMissingRegistry.relinkSource(initialEvidence)
|
||||
const relinkedAfterMissing = reopenedMissingRegistry.snapshot()
|
||||
|
||||
const editedSourceShape = await facade.geometry.createBox({ documentId: 'XLinkSource', documentVersion: 2, width: 9, length: 8, height: 6 })
|
||||
const editedSecondShape = await facade.geometry.createBox({ documentId: 'XLinkSource', documentVersion: 2, width: 7, length: 3, height: 4 })
|
||||
const editedEvidence = await sourceEvidence(2, editedSourceShape, editedSecondShape, { length: 8, width: 9, height: 6 }, { length: 3, width: 7, height: 4 })
|
||||
reopenedMissingRegistry.editSource(editedEvidence)
|
||||
const edited = reopenedMissingRegistry.snapshot()
|
||||
reopenedMissingRegistry.undo()
|
||||
const undone = reopenedMissingRegistry.snapshot()
|
||||
reopenedMissingRegistry.redo()
|
||||
const redone = reopenedMissingRegistry.snapshot()
|
||||
await writeArchive('edited.json', reopenedMissingRegistry)
|
||||
const finalRegistry = await readArchive('edited.json')
|
||||
const reopened = finalRegistry.snapshot()
|
||||
finalRegistry.undo()
|
||||
const reopenedUndo = finalRegistry.snapshot()
|
||||
finalRegistry.redo()
|
||||
const reopenedRedo = finalRegistry.snapshot()
|
||||
|
||||
await Promise.all([sourceShape, secondShape, editedSourceShape, editedSecondShape].map((shape) => facade.geometry.release(shape)))
|
||||
const root = await navigator.storage.getDirectory()
|
||||
await root.removeEntry('partdesign-external-reference-lifecycle', { recursive: true })
|
||||
facade.geometry.dispose()
|
||||
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||
const released = { ...facade.geometry.capabilities(), opfsRemoved: true }
|
||||
Object.assign(report, { status: 'pass', initial, closed, relinkedAfterClose, missing, reopenedMissing, relinkedAfterMissing, edited, undone, redone, reopened, reopenedUndo, reopenedRedo, released })
|
||||
} catch (error) {
|
||||
facade.geometry.dispose()
|
||||
Object.assign(report, { status: 'failed', error: error instanceof Error ? error.stack || error.message : String(error) })
|
||||
}
|
||||
|
||||
output.textContent = JSON.stringify(report, null, 2)
|
||||
await fetch('/__partdesign-reference-lifecycle-report', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(report) })
|
||||
</script>
|
||||
Reference in New Issue
Block a user