Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
202 commits
Select commit Hold shift + click to select a range
0037586
feat(sheets-web): add standalone web build entry
uirmb Aug 10, 2026
6972875
feat(sheets-web): add standalone web shell
uirmb Aug 10, 2026
cdff96f
feat(xlsx-engine): add Rust HTTP service skeleton
uirmb Aug 10, 2026
5b8789e
feat(xlsx-engine): add session-oriented HTTP API skeleton
uirmb Aug 10, 2026
978f52d
feat(sheets-web): add XLSX engine HTTP client
uirmb Aug 10, 2026
cab17c4
feat(sheets-web): add first browser bootstrap
uirmb Aug 10, 2026
3105e4b
feat(sheets-web): add web scripts
uirmb Aug 10, 2026
8152af7
feat(sheets-web): add root web and engine scripts
uirmb Aug 10, 2026
d900700
ci(sheets-web): add web and engine foundation checks
uirmb Aug 10, 2026
4c92275
docs(xlsx-engine): document single-node deployment contract
uirmb Aug 10, 2026
d27a2d7
feat(sheets-web): add browser DesktopApi adapter
uirmb Aug 10, 2026
13d6df9
feat(sheets-web): boot existing React Univer renderer
uirmb Aug 10, 2026
6433716
fix(sheets-web): install browser DesktopApi via property definition
uirmb Aug 10, 2026
d2bc6a8
fix(sheets-web): make disabled AI settings type-safe
uirmb Aug 10, 2026
48ef0d7
feat(sheets-web): add real workbook engine transport
uirmb Aug 10, 2026
547be73
feat(sheets-web): connect open and lazy range to Rust engine
uirmb Aug 10, 2026
9c84b79
feat(xlsx-engine): reuse existing workbook engine in HTTP service
uirmb Aug 10, 2026
dba2649
feat(xlsx-engine): expose real workbook open and range endpoints
uirmb Aug 10, 2026
046d07b
feat(sheets-web): add Web product policy
uirmb Aug 10, 2026
34e560b
feat(sheets-web): apply Web UI policy
uirmb Aug 10, 2026
1e4c5f7
fix(sheets-web): allow mutable range reads in engine service
uirmb Aug 10, 2026
811f84c
feat(protocol): add XLSX export capability
uirmb Aug 10, 2026
f5051e4
test(sheets-web): verify real XLSX open and range read
uirmb Aug 10, 2026
a1b1702
refactor(sheets-web): open XLSX engine sessions from host bytes
uirmb Aug 10, 2026
6c2b038
fix(sheets-web): hide server temp paths from workbook metadata
uirmb Aug 10, 2026
61b5516
feat(sheets-web): add office host workbook controller
uirmb Aug 10, 2026
6e4d389
feat(sheets-web): attach shared office host runtime
uirmb Aug 10, 2026
424d434
fix(web-runtime): make optional host fields exact-optional safe
uirmb Aug 10, 2026
2e410fb
fix(protocol): keep optional fields exact-optional compatible
uirmb Aug 10, 2026
ed7ed47
fix(web-runtime): accept explicit optional bridge settings
uirmb Aug 10, 2026
f0a07f0
feat(sheets-web): add Excel iframe host demo
uirmb Aug 10, 2026
0bcf042
feat(sheets-web): add Excel iframe host demo UI
uirmb Aug 10, 2026
b6dd323
feat(sheets-web): style Excel iframe host demo
uirmb Aug 10, 2026
c38a322
feat(sheets-web): wire Excel iframe host demo lifecycle
uirmb Aug 10, 2026
bc323aa
feat(sheets-web): add archive transport dependency
uirmb Aug 10, 2026
5e6731a
feat(sheets-web): expose session archive transport
uirmb Aug 10, 2026
937f2b4
feat(sheets-web): support real blank xlsx workbooks
uirmb Aug 10, 2026
2973de3
feat(sheets-web): add real blank workbook sessions
uirmb Aug 10, 2026
dee38ed
feat(sheets-web): add workbook archive client
uirmb Aug 10, 2026
d735da2
feat(sheets-web): plan preservation saves in browser
uirmb Aug 10, 2026
c0fe39b
feat(sheets-web): connect workbook saves to office host
uirmb Aug 10, 2026
7cbf279
fix(sheets-web): map workbook cell edits into xlsx planner
uirmb Aug 10, 2026
0143969
fix(sheets-web): pass workbook metadata into save planner
uirmb Aug 10, 2026
82af5e1
feat(sheets-web): enable xlsx host demo persistence
uirmb Aug 10, 2026
46b4525
chore(sheets-web): add xlsx host scripts
uirmb Aug 10, 2026
0ffa77c
test(sheets-web): cover blank and archive save roundtrip
uirmb Aug 10, 2026
385d52f
fix(sheets-web): isolate Electron XLSX node imports from Vite
uirmb Aug 11, 2026
21e9b72
feat(sheets-web): make XLSX host save state testable
uirmb Aug 11, 2026
6def5c8
feat(sheets-web): add XLSX host download control
uirmb Aug 11, 2026
db463f3
test(sheets-web): proxy XLSX engine from production preview
uirmb Aug 11, 2026
63e8836
test(sheets-web): add real iframe XLSX browser roundtrip
uirmb Aug 11, 2026
3bc9e3a
test(sheets-web): run real Chromium XLSX iframe roundtrip
uirmb Aug 11, 2026
5233258
feat(sheets-web): expose formula cells through XLSX engine
uirmb Aug 11, 2026
44276c7
feat(sheets-web): add formula-cell engine client
uirmb Aug 11, 2026
baa2896
feat(sheets-web): enable formula closure reads
uirmb Aug 11, 2026
9f640d4
test(sheets-web): verify browser formula-cell reads
uirmb Aug 11, 2026
4a4de49
feat(sheets-web): expose IronCalc recalculation over HTTP
uirmb Aug 11, 2026
ee442a9
feat(sheets-web): add IronCalc recalc engine client
uirmb Aug 11, 2026
461bfcf
feat(sheets-web): enable IronCalc recalculation
uirmb Aug 11, 2026
9b9a385
test(sheets-web): verify IronCalc recalc in Chromium
uirmb Aug 11, 2026
003aed6
test(sheets-web): match normalized formula contract
uirmb Aug 11, 2026
f8fe3bf
feat(sheets-web): read workbook media through XLSX archive sessions
uirmb Aug 11, 2026
8d4fd87
feat(sheets-web): enable workbook image reads
uirmb Aug 11, 2026
bb37158
test(sheets-web): cover workbook media reads
uirmb Aug 11, 2026
abbaa7b
test(sheets-web): gate Web media client behavior
uirmb Aug 11, 2026
ed31cab
feat(sheets-web): persist recalculated formula cache values
uirmb Aug 11, 2026
6eae250
test(sheets-web): verify formula caches survive Web save
uirmb Aug 11, 2026
710da37
docs(web): update Web Office foundation status
uirmb Aug 11, 2026
01076dc
docs(sheets-web): document current XLSX engine API
uirmb Aug 11, 2026
7c7b172
docs(sheets-web): document XLSX iframe host demo
uirmb Aug 11, 2026
8649743
feat(sheets-web): enable first advanced XLSX save journals
uirmb Aug 11, 2026
c561e57
test(sheets-web): verify advanced worksheet save journals
uirmb Aug 11, 2026
b3adfdc
test(sheets-web): create CF and DV after formula recalc
uirmb Aug 11, 2026
c3a09f6
test(sheets-web): preserve Chromium failure diagnostics
uirmb Aug 11, 2026
040ff45
fix(sheets): declare relationship namespace when adding notes
uirmb Aug 11, 2026
32a6b33
test(sheets): cover note relationship namespace
uirmb Aug 11, 2026
8c98297
test(sheets-web): use recalc-compatible advanced journal fixture
uirmb Aug 11, 2026
4c10162
docs(sheets-web): mark advanced save tranche verified
uirmb Aug 11, 2026
6b3c851
feat(sheets-web): enable sheet management saves
uirmb Aug 11, 2026
fadf16b
test(sheets-web): cover sheet management round-trip
uirmb Aug 11, 2026
72d6111
feat(sheets-web): enable structural worksheet saves
uirmb Aug 11, 2026
36854a5
test(sheets-web): cover structural worksheet operations
uirmb Aug 11, 2026
1447ad1
test(sheets-web): make sheet state assertion order independent
uirmb Aug 11, 2026
31fafc3
fix(sheets-web): normalize optional structural planner type
uirmb Aug 11, 2026
251fa04
feat(sheets-web): enable defined-name saves
uirmb Aug 11, 2026
ac753b1
test(sheets-web): cover defined-name save round-trip
uirmb Aug 11, 2026
a16aace
ci(sheets-web): run defined-name browser coverage
uirmb Aug 11, 2026
4824bff
feat(sheets-web): enable chart edits
uirmb Aug 11, 2026
23d7a89
test(sheets-web): cover chart edit round-trip
uirmb Aug 11, 2026
3329dcb
ci(sheets-web): run chart browser coverage
uirmb Aug 11, 2026
5d7242c
feat(sheets-web): enable visual and image saves
uirmb Aug 11, 2026
6331b0a
test(sheets-web): cover image insertion and visual movement
uirmb Aug 11, 2026
4301e88
ci(sheets-web): run image browser coverage
uirmb Aug 11, 2026
d11222e
fix(sheets-web): decode image base64 in browser boundary
uirmb Aug 11, 2026
1f71f68
feat(sheets-web): enable table and sparkline saves
uirmb Aug 11, 2026
d79e933
test(sheets-web): cover table and sparkline saves
uirmb Aug 11, 2026
549950d
ci(sheets-web): run table and sparkline browser coverage
uirmb Aug 11, 2026
a43e087
feat(sheets-web): read pivot definitions from workbook sessions
uirmb Aug 11, 2026
71db521
feat(sheets-web): install pivot definition reader
uirmb Aug 11, 2026
f43ffe5
test(sheets-web): cover pivot definition reads
uirmb Aug 11, 2026
4fd8941
ci(sheets-web): run pivot definition browser coverage
uirmb Aug 11, 2026
b717c38
feat(sheets-web): enable pivot refresh-on-load saves
uirmb Aug 11, 2026
bd9a76e
test(sheets-web): verify pivot refresh-on-load save
uirmb Aug 11, 2026
79416e5
feat(sheets-web): enable pivot creation saves
uirmb Aug 11, 2026
7d3a111
test(sheets-web): cover native pivot creation round-trip
uirmb Aug 11, 2026
525f866
ci(sheets-web): validate native pivot creation in chromium
uirmb Aug 11, 2026
4d16749
feat(sheets-web): read inserted images through office host
uirmb Aug 11, 2026
89e5bd1
feat(sheets-web): wire host-backed image selection
uirmb Aug 11, 2026
20b582f
test(sheets-web): verify host file picker image insertion
uirmb Aug 11, 2026
ddf761a
test(sheets-web): cover token-backed host images
uirmb Aug 11, 2026
33763ac
test(web-host): exercise token-backed system file picks
uirmb Aug 11, 2026
8444657
refactor(sheets-web): centralize browser desktop adapters
uirmb Aug 11, 2026
b0a4ea5
refactor(sheets-web): install browser adapters explicitly
uirmb Aug 11, 2026
9d2f925
hardening(xlsx-engine): bound upload and mutation request sizes
uirmb Aug 11, 2026
242423b
docs(xlsx-engine): document production request limits
uirmb Aug 11, 2026
0727dc9
test(xlsx-engine): gate configured request limits
uirmb Aug 11, 2026
c3c7738
docs(xlsx-engine): note remaining session lifecycle hardening
uirmb Aug 11, 2026
bbd688b
test(sheets-web): verify token-backed workbook open
uirmb Aug 11, 2026
658ad74
hardening(xlsx-engine): expire abandoned workbook sessions
uirmb Aug 11, 2026
44f400d
test(xlsx-engine): verify abandoned session expiry
uirmb Aug 11, 2026
cc3e5ad
docs(xlsx-engine): document session expiry hardening
uirmb Aug 11, 2026
20d0f0a
hardening(xlsx-engine): isolate and clean endpoint workspaces
uirmb Aug 11, 2026
d866fb7
test(xlsx-engine): verify endpoint workspace cleanup
uirmb Aug 11, 2026
8935af0
docs(xlsx-engine): document endpoint workspace cleanup
uirmb Aug 11, 2026
3e6bb37
feat(examples): add UC Web OS Excel host
uirmb Aug 11, 2026
d7ec674
feat(examples): add UC Web OS Excel host shell
uirmb Aug 11, 2026
a05a9bd
feat(examples): bridge UC file RPC to Excel office protocol
uirmb Aug 11, 2026
113f0d0
docs(examples): document UC Web OS Excel host bridge
uirmb Aug 11, 2026
9f52ffc
build(examples): wire UC Web OS Excel host scripts
uirmb Aug 11, 2026
48f6085
ci(examples): gate UC Web OS Excel host build
uirmb Aug 11, 2026
bb52547
test(examples): typecheck UC Web OS Excel host
uirmb Aug 11, 2026
4f966ac
ci(examples): typecheck UC Web OS Excel host
uirmb Aug 11, 2026
086ac6b
test(uc-host): verify UC RPC Excel open save and save-as
uirmb Aug 11, 2026
65f6f39
test(uc-host): run nested Excel UC RPC round-trip
uirmb Aug 11, 2026
c1174ea
fix(sheets-web): allow clean workbook save-as
uirmb Aug 11, 2026
f935d76
feat(uc-host): define optimistic save version checks
uirmb Aug 11, 2026
cffb951
feat(uc-host): reject stale normal saves
uirmb Aug 11, 2026
37e4bf2
test(uc-host): cover stale normal save conflict
uirmb Aug 11, 2026
5671a0a
feat(xlsx-engine): bound heavy request admission
uirmb Aug 11, 2026
81e7841
build(xlsx-engine): enable explicit Tokio time support
uirmb Aug 11, 2026
256cc48
ci(xlsx-engine): verify heavy request admission
uirmb Aug 11, 2026
5e3255b
docs(xlsx-engine): document heavy request admission
uirmb Aug 11, 2026
ac0a550
docs(uc-host): document optimistic save conflicts
uirmb Aug 11, 2026
78aefd4
feat(xlsx-engine): add request observability
uirmb Aug 11, 2026
e159397
feat(xlsx-engine): expose request logs and metrics
uirmb Aug 11, 2026
3453aa8
ci(xlsx-engine): verify request observability
uirmb Aug 11, 2026
7d5f89e
fix(sheets): allow clean save-as and localize version conflicts
uirmb Aug 11, 2026
ce75035
fix(sheets-web): surface host save failures
uirmb Aug 11, 2026
37e7c22
test(uc-host): assert visible version conflict failure
uirmb Aug 11, 2026
edfcda8
docs(xlsx-engine): document request logs and metrics
uirmb Aug 11, 2026
ddfa2a1
fix(sheets): count sparkline and pivot refresh journals
uirmb Aug 11, 2026
233e108
feat(sheets-web): restore browser file shortcuts
uirmb Aug 11, 2026
5079766
test(uc-host): verify clean save-as browser shortcut
uirmb Aug 11, 2026
f31f21f
ci(uc-host): gate browser file shortcuts
uirmb Aug 11, 2026
2fe8350
feat(deploy): add XLSX engine production env template
uirmb Aug 11, 2026
4fecff1
feat(deploy): add hardened XLSX engine systemd unit
uirmb Aug 11, 2026
b66e2c5
feat(deploy): add Sheets Web nginx reverse proxy
uirmb Aug 11, 2026
26de41f
docs(deploy): add single-node Sheets Web runbook
uirmb Aug 11, 2026
c14c5e7
test(sheets): add Rust-backed XLSX compatibility corpus
uirmb Aug 11, 2026
f87f1e6
test(sheets): expose Web Engine compatibility runner
uirmb Aug 11, 2026
131f097
ci(sheets): gate Rust-backed compatibility corpus
uirmb Aug 11, 2026
8e387f6
fix(sheets): type Rust compatibility upload body
uirmb Aug 11, 2026
6ee7364
feat(sheets-web): enable existing pivot layout refresh save
uirmb Aug 11, 2026
c1799e8
test(sheets-web): cover existing Pivot layout refresh
uirmb Aug 11, 2026
2ff338f
ci(sheets): gate existing Pivot refresh in Chromium
uirmb Aug 11, 2026
0950160
test(sheets-web): assert Pivot conflict message
uirmb Aug 11, 2026
11c666e
test(sheets-web): prove Pivot conflict leaves Host file unchanged
uirmb Aug 11, 2026
1de4c80
docs(web-office): bring Sheets Web status current
uirmb Aug 11, 2026
d8da945
ci(sheets): add targeted production dependency audit
uirmb Aug 11, 2026
e9c636e
test(sheets-web): add production bundle size report
uirmb Aug 11, 2026
ba02225
ci(sheets-web): measure production bundle sizes
uirmb Aug 11, 2026
aecd557
feat(deploy): add XLSX engine deployment smoke script
uirmb Aug 11, 2026
28229fd
feat(sheets-web): add host capability policy
uirmb Aug 12, 2026
3348372
feat(sheets-web): add file menu strings
uirmb Aug 12, 2026
c11f861
feat(sheets-web): merge file menu strings
uirmb Aug 12, 2026
c85ab4e
feat(sheets-web): define web file actions
uirmb Aug 12, 2026
88a2c19
feat(sheets-web): add history and xlsx export save flows
uirmb Aug 12, 2026
9ce321e
feat(sheets-web): complete host file lifecycle
uirmb Aug 12, 2026
22c12d1
feat(sheets-web): install host policy and snapshot actions
uirmb Aug 12, 2026
b4e2d6a
feat(sheets-web): align file menu and capability styling
uirmb Aug 12, 2026
d53b89b
feat(sheets-web): add Word-aligned File menu
uirmb Aug 12, 2026
95075dd
feat(sheets-web): mount Web File menu
uirmb Aug 12, 2026
26e596b
fix(sheets-web): align File tab with ribbon row
uirmb Aug 12, 2026
9f9e003
feat(sheets-web): complete demo host file lifecycle
uirmb Aug 12, 2026
090aa3c
fix(sheets-web): listen on all local interfaces
uirmb Aug 12, 2026
0cfc1d5
fix(sheets-web): expose demo host on local interfaces
uirmb Aug 12, 2026
adebe8f
fix(sheets-web): keep File locale keys required
uirmb Aug 12, 2026
fda486e
test(sheets-web): cover deployable File menu lifecycle
uirmb Aug 12, 2026
f3d6893
ci(sheets-web): add deployable File UI gate
uirmb Aug 12, 2026
1be4b9f
fix(sheets-web): close only after dirty save succeeds
uirmb Aug 12, 2026
89cb7b2
test(sheets-web): verify Save and Exit handshake
uirmb Aug 12, 2026
25bfe97
fix(sheets-web): keep File tab anchored to top ribbon
uirmb Aug 12, 2026
dfc146a
test(sheets-web): assert zero visible AI chrome
uirmb Aug 12, 2026
753c262
test(sheets-web): verify File labels and shortcuts separately
uirmb Aug 12, 2026
2d01e28
feat(sheets-web): correlate host window close requests
uirmb Aug 12, 2026
508a773
feat(sheets-web): expose host close request to file exit flow
uirmb Aug 12, 2026
97f39cb
feat(sheets-web): route host window close through File exit UI
uirmb Aug 12, 2026
931dca1
feat(sheets-web): install correlated host close lifecycle
uirmb Aug 12, 2026
c181db8
test(sheets-web): cover correlated host window close lifecycle
uirmb Aug 12, 2026
6e06523
fix(sheets-web): cancel stalled close transaction after save failure
uirmb Aug 12, 2026
678d15e
test(sheets-web): stabilize worksheet edit for close lifecycle
uirmb Aug 12, 2026
b89fd93
test(sheets-web): make Host close part of File UI release gate
uirmb Aug 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/sheets-web-bundle-audit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Sheets Web Bundle Audit

on:
pull_request:
branches: [main, agent/ppt-web-foundation]
workflow_dispatch:

permissions:
contents: read

jobs:
bundle-report:
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
cache: npm
cache-dependency-path: package-lock.json

- name: Install dependencies
run: npm ci

- name: Build Sheets Web
run: npm run build:web:sheets

- name: Measure production bundle
run: |
node apps/sheets/scripts/report-web-bundle.mjs \
apps/sheets/dist-web \
apps/sheets/reports/web-bundle.json
cat apps/sheets/reports/web-bundle.json

- name: Upload bundle report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sheets-web-bundle-report
path: apps/sheets/reports/web-bundle.json
retention-days: 14
254 changes: 254 additions & 0 deletions .github/workflows/sheets-web-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
name: Sheets Web E2E

on:
pull_request:
branches: [main, agent/ppt-web-foundation]
workflow_dispatch:

permissions:
contents: read

jobs:
sheets-web-foundation:
runs-on: ubuntu-22.04
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
cache: npm
cache-dependency-path: package-lock.json

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable

- name: Install dependencies
run: npm ci

- name: Install Chromium
run: npx playwright install --with-deps chromium

- name: Typecheck Sheets
run: npm run typecheck -w @genoffice/sheets

- name: Web client unit tests
run: npx vitest run tests/web-engine-client.test.ts
working-directory: apps/sheets

- name: Build XLSX Engine Service
run: npm run build:xlsx-engine

- name: Start XLSX Engine Service
run: |
./services/xlsx-engine-service/target/release/xlsx-engine-service > /tmp/xlsx-engine.log 2>&1 &
echo $! > /tmp/xlsx-engine.pid
for i in $(seq 1 30); do
if curl --fail --silent http://127.0.0.1:7301/health >/dev/null; then
exit 0
fi
sleep 1
done
cat /tmp/xlsx-engine.log
exit 1

- name: Verify session lifecycle
run: |
SESSION_JSON=$(curl --fail --silent \
-H 'content-type: application/json' \
-d '{"source":"blank"}' \
http://127.0.0.1:7301/v1/sessions)
echo "$SESSION_JSON"
SESSION_ID=$(node -e "const v=JSON.parse(process.argv[1]); if(!v.sessionId) process.exit(1); process.stdout.write(v.sessionId)" "$SESSION_JSON")
curl --fail --silent -X DELETE "http://127.0.0.1:7301/v1/sessions/$SESSION_ID" >/dev/null

- name: Verify real blank XLSX workbook
run: |
BLANK=$(curl --fail --silent -X POST \
'http://127.0.0.1:7301/v1/workbooks/blank?name=Untitled.xlsx')
echo "$BLANK" >/tmp/blank-meta.json
SESSION_ID=$(node -e "const v=require('/tmp/blank-meta.json'); if(!v.sessionId||!v.sheets?.length) process.exit(1); process.stdout.write(v.sessionId)")
curl --fail --silent -X DELETE "http://127.0.0.1:7301/v1/sessions/$SESSION_ID" >/dev/null

- name: Verify real XLSX open and lazy range
run: |
python3 - <<'PY'
from zipfile import ZipFile, ZIP_DEFLATED

parts = {
'[Content_Types].xml': '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
<Default Extension="xml" ContentType="application/xml"/>
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
</Types>''',
'_rels/.rels': '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
</Relationships>''',
'xl/workbook.xml': '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
<sheets><sheet name="Sheet1" sheetId="1" r:id="rId1"/></sheets>
</workbook>''',
'xl/_rels/workbook.xml.rels': '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
</Relationships>''',
'xl/styles.xml': '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<fonts count="1"><font><sz val="11"/><name val="Calibri"/></font></fonts>
<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>
<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>
<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>
<cellXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/></cellXfs>
</styleSheet>''',
'xl/worksheets/sheet1.xml': '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<dimension ref="A1:B1"/>
<sheetData><row r="1"><c r="A1" t="inlineStr"><is><t>Web Excel E2E</t></is></c><c r="B1"><v>42</v></c></row></sheetData>
</worksheet>''',
}

with ZipFile('/tmp/web-excel-e2e.xlsx', 'w', ZIP_DEFLATED) as archive:
for name, content in parts.items():
archive.writestr(name, content)
PY

META=$(curl --fail --silent \
--data-binary @/tmp/web-excel-e2e.xlsx \
'http://127.0.0.1:7301/v1/workbooks?name=web-excel-e2e.xlsx')
echo "$META" > /tmp/workbook-meta.json

SESSION_ID=$(node -e "const v=require('/tmp/workbook-meta.json'); if(!v.sessionId||!v.sheets?.[0]?.id) process.exit(1); process.stdout.write(v.sessionId)")
SHEET_ID=$(node -e "const v=require('/tmp/workbook-meta.json'); process.stdout.write(v.sheets[0].id)")

RANGE=$(curl --fail --silent \
-H 'content-type: application/json' \
-H "X-Xlsx-Session: $SESSION_ID" \
-d "{\"sheetId\":\"$SHEET_ID\",\"range\":{\"startRow\":0,\"endRow\":0,\"startColumn\":0,\"endColumn\":1}}" \
"http://127.0.0.1:7301/v1/sessions/$SESSION_ID/ranges")

node -e "const v=JSON.parse(process.argv[1]); const a=v.cells?.find(c=>c.row===0&&c.column===0); const b=v.cells?.find(c=>c.row===0&&c.column===1); if(a?.value!=='Web Excel E2E'||b?.value!==42) { console.error(v); process.exit(1) }" "$RANGE"
echo "$SESSION_ID" >/tmp/source-session-id
echo "$SHEET_ID" >/tmp/source-sheet-id

- name: Verify XLSX archive save round-trip
run: |
SESSION_ID=$(cat /tmp/source-session-id)
READ=$(curl --fail --silent \
-H 'content-type: application/json' \
-H "X-Xlsx-Session: $SESSION_ID" \
-d '{"entries":["xl/worksheets/sheet1.xml"]}' \
"http://127.0.0.1:7301/v1/sessions/$SESSION_ID/archive/read")
node - <<'NODE' "$READ"
const input = JSON.parse(process.argv[2])
const entry = input.entries.find((item) => item.name === 'xl/worksheets/sheet1.xml')
if (!entry) process.exit(1)
const xml = Buffer.from(entry.contentBase64, 'base64').toString('utf8')
const saved = xml.replace('Web Excel E2E', 'Web Excel Saved')
const payload = {
name: 'saved.xlsx',
replacements: [{
name: 'xl/worksheets/sheet1.xml',
contentBase64: Buffer.from(saved).toString('base64'),
}],
removals: [],
additions: [],
}
require('fs').writeFileSync('/tmp/save-payload.json', JSON.stringify(payload))
NODE

curl --fail --silent \
-D /tmp/save-headers.txt \
-o /tmp/saved.xlsx \
-H 'content-type: application/json' \
-H "X-Xlsx-Session: $SESSION_ID" \
--data-binary @/tmp/save-payload.json \
"http://127.0.0.1:7301/v1/sessions/$SESSION_ID/archive/save"

SAVED_SESSION=$(awk 'BEGIN{IGNORECASE=1} /^x-xlsx-session:/ {gsub("\r", "", $2); print $2}' /tmp/save-headers.txt)
test -n "$SAVED_SESSION"
SAVED_META=$(curl --fail --silent \
-H "X-Xlsx-Session: $SAVED_SESSION" \
"http://127.0.0.1:7301/v1/sessions/$SAVED_SESSION")
SAVED_SHEET=$(node -e "const v=JSON.parse(process.argv[1]); if(!v.sheets?.[0]?.id) process.exit(1); process.stdout.write(v.sheets[0].id)" "$SAVED_META")
SAVED_RANGE=$(curl --fail --silent \
-H 'content-type: application/json' \
-H "X-Xlsx-Session: $SAVED_SESSION" \
-d "{\"sheetId\":\"$SAVED_SHEET\",\"range\":{\"startRow\":0,\"endRow\":0,\"startColumn\":0,\"endColumn\":1}}" \
"http://127.0.0.1:7301/v1/sessions/$SAVED_SESSION/ranges")
node -e "const v=JSON.parse(process.argv[1]); const a=v.cells?.find(c=>c.row===0&&c.column===0); if(a?.value!=='Web Excel Saved') { console.error(v); process.exit(1) }" "$SAVED_RANGE"
curl --fail --silent -X DELETE "http://127.0.0.1:7301/v1/sessions/$SAVED_SESSION" >/dev/null
curl --fail --silent -X DELETE "http://127.0.0.1:7301/v1/sessions/$SESSION_ID" >/dev/null

- name: Generate compatibility fixtures
run: npm run fixtures -w @genoffice/sheets

- name: Verify Rust-backed compatibility corpus
env:
XLSX_ENGINE_URL: http://127.0.0.1:7301
run: npm run compat:web-engine -w @genoffice/sheets

- name: Build Sheets Web
run: npm run build:web:sheets

- name: Build XLSX Host Demo
run: npm run build:web-xlsx-host

- name: Start Sheets Web preview
run: |
npx vite preview --config vite.web.config.ts --host 127.0.0.1 --port 5275 > /tmp/sheets-web.log 2>&1 &
echo $! > /tmp/sheets-web.pid
for i in $(seq 1 30); do
if curl --fail --silent http://127.0.0.1:5275/ >/dev/null; then
exit 0
fi
sleep 1
done
cat /tmp/sheets-web.log
exit 1
working-directory: apps/sheets

- name: Start XLSX Host Demo preview
run: |
npx vite preview --config examples/web-xlsx-host/vite.config.ts --host 127.0.0.1 --port 8082 > /tmp/web-xlsx-host.log 2>&1 &
echo $! > /tmp/web-xlsx-host.pid
for i in $(seq 1 30); do
if curl --fail --silent http://127.0.0.1:8082/ >/dev/null; then
exit 0
fi
sleep 1
done
cat /tmp/web-xlsx-host.log
exit 1

- name: Browser E2E (Sheets Web)
env:
SHEETS_WEB_E2E_URL: http://127.0.0.1:5275/
SHEETS_WEB_HOST_E2E_URL: http://127.0.0.1:8082/
run: |
set -o pipefail
npx playwright test e2e/sheets-web.spec.ts e2e/sheets-web-defined-names.spec.ts e2e/sheets-web-chart.spec.ts e2e/sheets-web-image.spec.ts e2e/sheets-web-table-sparkline.spec.ts e2e/sheets-web-pivot-read.spec.ts e2e/sheets-web-pivot-refresh.spec.ts --config e2e/playwright.config.ts 2>&1 | tee /tmp/sheets-web-e2e.log

- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sheets-web-foundation-artifacts
path: |
apps/sheets/reports/web-engine-compatibility.json
e2e/test-results
e2e/playwright-report
test-results
playwright-report
/tmp/xlsx-engine.log
/tmp/sheets-web.log
/tmp/web-xlsx-host.log
/tmp/sheets-web-e2e.log
retention-days: 7
Loading