'use strict'; const assert = require('assert/strict'); const fs = require('fs'); const os = require('os'); const path = require('path'); const { compileInput } = require('../src/compile/compiler'); const { ensureRevisionStore } = require('../src/compile/road-revisions'); const { editPreview, editState, rebaseEdits, saveEdits } = require('../workbench/server'); const workspace = fs.mkdtempSync(path.join(os.tmpdir(), 'workbench-edit-api-')); const input = { areaId: 'edit-api-test', osmFile: path.join(workspace, 'source.osm'), outDir: path.join(workspace, 'outputs', 'native-road'), stagingDir: path.join(workspace, 'outputs', '_pipeline'), overridesFile: path.join(workspace, 'native-road-overrides.json'), trafficSignalsFile: path.join(workspace, 'native-traffic-signals.json'), options: { edgeLines: false, junctionTemplates: { enabled: false, references: [] } }, }; fs.copyFileSync(path.join(__dirname, 'fixtures', 'fengshu-er-road.osm'), input.osmFile); fs.writeFileSync(input.overridesFile, `${JSON.stringify({ schema: 'native-road-overrides/v1', overrides: [] })}\n`); fs.writeFileSync( input.trafficSignalsFile, `${JSON.stringify({ schema: 'native-traffic-signals/v1', provenance: 'empty', assemblies: { type: 'FeatureCollection', features: [] } })}\n`, ); const initialized = ensureRevisionStore(workspace, input.options); const area = compileInput({ ...input, areaConfigSnapshotFile: initialized.paths.activeAreaConfig, editsFile: initialized.paths.activeEdits, }).area; const state = editState(area); assert.equal(state.active, true); assert.equal(state.documentVersion, 0); assert.equal(state.handles.schema, 'road-edit-handles/v1'); assert.equal(state.activeRevisionId, 'rev-0001'); const trackedFiles = [ initialized.paths.activeEdits, initialized.paths.activeState, initialized.paths.activeAreaConfig, ].map((file) => ({ file, bytes: fs.readFileSync(file), mtimeMs: fs.statSync(file).mtimeMs, })); const preview = editPreview(area, { previewSeq: 17, document: state.document }); assert.equal(preview.ok, true); assert.equal(preview.previewSeq, 17); assert.equal(preview.degraded, false); assert.equal(preview.handles.schema, 'road-edit-handles/v1'); assert.ok(preview.layers.roadSurface); for (const tracked of trackedFiles) { assert.deepEqual(fs.readFileSync(tracked.file), tracked.bytes, `${tracked.file} bytes unchanged by preview`); assert.equal(fs.statSync(tracked.file).mtimeMs, tracked.mtimeMs, `${tracked.file} mtime unchanged by preview`); } const saved = saveEdits(area, { expectedDocumentVersion: 0, document: state.document }); assert.equal(saved.documentVersion, 1); const beforeConflict = fs.readFileSync(initialized.paths.activeEdits); assert.throws( () => saveEdits(area, { expectedDocumentVersion: 0, document: state.document }), (error) => error.statusCode === 409 && error.current.documentVersion === 1, ); assert.deepEqual(fs.readFileSync(initialized.paths.activeEdits), beforeConflict, '409 does not write the document'); const checkpoint = require('../src/compile/road-revisions').createCheckpoint(workspace, 'Preview checkpoint'); assert.equal(checkpoint.manifest.id, 'rev-0002'); const rebased = rebaseEdits(area, checkpoint.manifest.id); assert.equal(rebased.counts.exact, 0); assert.deepEqual(rebased.constraints, []); // The map saves `constraints` + `operations`, not a whole document. That merge path // is what the client actually exercises, and leaving the operations out is exactly // how the first wiring produced a 400. const edgeHandle = state.handles.handles.find((handle) => handle.kind === 'road-edge-offset'); assert.ok(edgeHandle, 'the fixture must publish a road edge handle'); const clientConstraint = { id: `constraint:${edgeHandle.handleId}`, kind: 'road-edge-offset', anchor: edgeHandle.anchor, anchorSnapshot: { coordinate: edgeHandle.position, tangentAzimuth: 0, roadLengthMeters: 120, osmNodeIds: ['1'], }, value: { offsetMeters: 0.5, transition: 'smoothstep' }, enabled: true, status: 'exact', provenance: { operationId: 'operation:client:1', createdAt: '2026-08-27T00:00:00.000Z' }, }; const clientOperation = { id: clientConstraint.provenance.operationId, createdAt: clientConstraint.provenance.createdAt, constraintIds: [clientConstraint.id], }; assert.throws( () => saveEdits(area, { expectedDocumentVersion: 1, constraints: [clientConstraint], operations: [] }), /provenance\.operationId/, 'a constraint saved without its operation must be rejected, not written', ); const clientSaved = saveEdits(area, { expectedDocumentVersion: 1, constraints: [clientConstraint], operations: [clientOperation], }); assert.equal(clientSaved.documentVersion, 2); // A save that does not survive a reload as `exact` was cosmetic. const reloaded = editState(area); assert.equal(reloaded.documentVersion, 2); assert.deepEqual( reloaded.document.constraints.map((item) => item.id), [clientConstraint.id], ); assert.equal(reloaded.constraintStates[0].status, 'exact'); assert.equal(reloaded.constraintStates[0].applied, true); fs.rmSync(workspace, { recursive: true, force: true }); console.log('workbench edit API tests passed');