11 Commits

Author SHA1 Message Date
dillard 3fc8601344 Keep occ output brackets escaped through the formatters
The overtyping and from_ansi formatters unescape brackets before they
parse the text, so escaping them beforehand was not enough: literal
brackets were still read as formatting. Enable
unixFormattingEscapeBrackets so both formatters escape the text again
after parsing. Verified in the browser: Symfony's "[alias]" in
`occ list` stays in place, ANSI colors still work, and formatting in
the output text (colors, links) is no longer applied.

Bump the version to 0.4.4 so browsers load the new script.
2026-09-30 02:25:13 +02:00
dillard 635cdd4b24 Escape brackets in occ output before rendering
jQuery Terminal reads "[" and "]" as its own formatting syntax. occ
output was echoed as is, so literal brackets, such as Symfony's
"[alias]" in `occ list`, closed the color formatting of the next line
early and moved text to the wrong place. Text from the output, like a
display name, could also inject terminal formatting.

Escape the brackets in the text and keep the ANSI sequences, so the
colors still work.
2026-09-30 02:07:46 +02:00
dillard 76368f154e Add check-on-branch guard: HEAD's branch, not just its cleanliness
git archive HEAD packages whatever commit the checkout currently points to,
regardless of branch - check-clean-tree only guards uncommitted changes, not
HEAD being a feature branch, old tag, PR checkout, or detached HEAD entirely.
Wired into source/appstore/version alongside the existing guards.
Override via RELEASE_BRANCH=<branch> for an intentional non-main release.
2026-09-27 00:45:18 +02:00
dillard a607426a9c Only load vendored jQuery on NC34+, verified against NC32/33/34 in testbak/
Core still provides a working jQuery on NC32/33, but via a read-only
window.$ getter - loading our own vendored copy there too made its UMD
wrapper throw trying to reassign window.$ (confirmed on real containers,
harmless in practice since this app attaches via window.jQuery, but a real
avoidable console exception). Gate the extra script() call on
ServerVersion::getMajorVersion() >= 34 instead.

Re-tested both sides of the boundary: NC32 no longer requests jquery.js and
has zero console errors; NC34 still requests it and still works.
2026-09-27 00:24:47 +02:00
dillard 35e1f5df32 Fix NC35 fatal in OccOutput, verify+narrow supported version range to 32-35
testbak/ (local, non-AIO docker compat rigs for NC32/33/34/35) found a real
fatal on NC35: OccOutput::setErrorOutput() didn't declare the ": void"
return type the Symfony Console version NC35 bundles now requires on
ConsoleOutputInterface. Fixed by declaring it - compatible with older
Symfony/NC versions too since it only narrows an untyped parent signature.

32/33 were also verified functional (the previously-suspected jQuery
getter-conflict console exception on those versions is real but harmless -
the app attaches via window.jQuery, not window.$).

min-version/max-version narrowed from 30/34 to 32/35: 30/31 were never
actually tested even before this session, so keeping them was an unverified
claim; 35 is now genuinely verified rather than guessed.
2026-09-27 00:17:28 +02:00
dillard 4b84be3cb7 Fix sixth Codex finding: check-clean-tree only guarded version, not source/appstore
Running make appstore/source/dist directly (bypassing make version)
still had the stale-archive risk check-clean-tree was added for:
app_name/paths read from a dirty working tree while git archive HEAD
packages the last commit. Added check-clean-tree as a prerequisite to
source and appstore directly, not just transitively through version.
2026-09-26 17:18:26 +02:00
dillard 93244a0d4d Fix fifth Codex finding: app_name silently empty without xpath installed
app_name now comes from xpath against appinfo/info.xml (needed so
packaging works regardless of what this checkout is named - see the
git-archive fix). If xpath isn't installed, $(shell ...) just returns
an empty string rather than failing the build: --prefix=$(app_name)/
would silently become --prefix=/, producing a broken, wrongly-rooted
archive with no indication anything went wrong. Previously app_name
came from the checkout directory name, so this failure mode didn't
exist. Added a check-app-name prerequisite to source/appstore/sign
that fails loudly if app_name is empty.
2026-09-26 17:14:19 +02:00
dillard 8fc4942517 Fix fourth Codex finding: reject a dirty tree before releasing
VERSION/app_name are read live from the working tree's info.xml, but
the packaged/signed content comes from git archive HEAD (the last
commit). Bumping <version> without committing first would tag and
sign an artifact named/keyed after the new version while its actual
contents are still the previous commit's. make version now refuses to
proceed if there are any uncommitted changes to tracked files.
2026-09-26 17:08:22 +02:00
dillard 95cdd06426 Fix third Codex finding: make version hardcoded a non-portable remote name
git push fork v\$(VERSION) only works on this maintainer's own machine,
where "fork" happens to be configured (and where "origin" still means
the stale upstream, from how this repo was originally forked). A plain
clone via the README's own instructions only ever creates "origin",
pointing at dillardblom/occweb - so make version would tag locally,
then fail at the push step before packaging/signing ever ran.

Made the target remote configurable via RELEASE_REMOTE, defaulting to
"origin" (correct for a normal clone), overridable for this specific
checkout's non-standard remote layout.
2026-09-26 17:01:19 +02:00
dillard 6016d0916c Fix second Codex finding: packaging symlink produced a dangling-symlink-only archive
The ensure-app-name-symlink fix from the previous commit created
../extended_occweb as a symlink so the inherited "../$(app_name)" tar
references would resolve regardless of the checkout's real directory
name - but the tar invocations ran without --dereference, so GNU tar
stored the symlink itself rather than following it into the real
files. make source/appstore therefore produced a 1-entry archive
containing nothing but a dangling absolute symlink, unusable on any
other machine. Caught by a second independent Codex pass; my own
"make appstore" test after the first fix only checked the archive's
top-level entry name, not its actual file count, so this went
unnoticed.

Rather than patch this with --dereference, replaced the whole
symlink+raw-tar approach with `git archive --prefix=$(app_name)/
HEAD`: it sets the correct top-level folder name directly (no symlink
needed at all), and - caught during this fix's own verification,
not by either Codex pass - it also closes a separate real leak the
symlink approach had: tarring the checkout directory directly
included every untracked/gitignored file too (e.g.
notes/deploy-nc01.md, which exists specifically because it must
never leave this machine). `git archive` only ever includes tracked
files. Dev/CI-only files (tests/, Makefile, composer.*, phpunit*.xml,
.travis.yml) are now stripped via `export-ignore` entries in a new
.gitattributes instead of a long list of tar --exclude flags repeated
per target - also means source and appstore now produce identical
output, which is fine given neither is part of our actual release
flow yet.

Verified end to end this time: extracted the resulting archive and
confirmed file count, absence of symlinks, absence of tests/notes/
dev files, and correct info.xml content - not just the archive's
top-level listing.
2026-09-26 16:55:55 +02:00
dillard 422748cace Fix Codex-review findings: Makefile packaging, git archive main hardcode
Independent Codex review of the app-id rename found real gaps our own
review missed:

- Makefile: app_name was derived from the checkout directory's own
  basename, not the app id in appinfo/info.xml. Our actual working
  checkout is still named "occweb" (matches the repo name), so
  building from it would have produced an "occweb"-named/rooted
  archive under the new "extended_occweb" id. Fixed by deriving
  app_name from info.xml via xpath (same technique already used for
  VERSION), and added an ensure-app-name-symlink step so the
  Makefile's inherited "../$(app_name)" references (used throughout
  the source/appstore tar exclude patterns) keep resolving correctly
  regardless of what the checkout directory is actually named.
  Verified end to end: `make appstore` now produces
  extended_occweb.tar.gz with extended_occweb/ as its single top-level
  folder, matching the App Store's stated requirement.
- Makefile: sign target had "occweb" hardcoded into both the
  certificate path and the archive filename - broken independent of
  the app_name fix above. Now derived from the same variables.
- Makefile: version target pushed the release tag to the "origin"
  remote, which in this repo is the stale upstream
  (fanategorius/occweb), not somewhere we want to push. Changed to
  "fork" (dillardblom/occweb), matching how every tag has actually
  been pushed this whole session.
- INSTALL-AIO.md / notes/deploy-nc01.md: the deploy snippet did
  `git archive main` unconditionally, silently deploying the main
  branch even if an operator had checked out a specific tag or
  maintenance branch as instructed elsewhere. Changed to `git archive
  HEAD`.
- README.md: the compatibility matrix's rollback advice
  ("git checkout v0.3.4") doesn't actually work as a rollback anymore
  post-rename - that tag still declares the old occweb id, so checking
  it out under an extended_occweb-named install just breaks. Added a
  caveat explaining what a real rollback requires; full migration docs
  are still deferred to when a test instance exists (tracked
  separately, not written up here).
2026-09-26 16:48:58 +02:00
9 changed files with 134 additions and 53 deletions
+11
View File
@@ -0,0 +1,11 @@
# Files excluded from `git archive` output - used by `make appstore` (and by
# our own nc01 deploy tarballs) to strip dev/CI-only files that don't belong
# in a running install, without needing them repeated as tar --exclude flags.
tests export-ignore
.travis.yml export-ignore
phpunit.xml export-ignore
phpunit.integration.xml export-ignore
composer.json export-ignore
composer.lock export-ignore
Makefile export-ignore
.gitattributes export-ignore
+3
View File
@@ -33,5 +33,8 @@ js/*.log
# Internal deploy notes (hostnames, paths) - never publish these
notes/
# Local compat-test docker rigs (throwaway, not part of the app release)
testbak/
# Misc logs
*.log
+1 -1
View File
@@ -20,7 +20,7 @@ The AIO container has no working git access to GitHub, so deploy a tarball inste
```bash
# 1. On your machine: clean checkout of the branch/tag you want, dev files stripped
STAGE=$(mktemp -d)
git archive main | tar -x -C "$STAGE"
git archive HEAD | tar -x -C "$STAGE"
rm -rf "$STAGE"/{tests,.travis.yml,phpunit.xml,phpunit.integration.xml,composer.json,composer.lock,Makefile}
tar -C "$STAGE" -cf /tmp/occweb-deploy.tar .
+62 -39
View File
@@ -39,7 +39,7 @@
# "build": "node node_modules/gulp-cli/bin/gulp.js"
# },
app_name=$(notdir $(CURDIR))
app_name=$(shell xpath -q -e "//info/id/text()" appinfo/info.xml)
build_tools_directory=$(CURDIR)/build/tools
source_build_directory=$(CURDIR)/build/artifacts/source
source_package_name=$(source_build_directory)/$(app_name)
@@ -110,48 +110,41 @@ dist:
make source
make appstore
# Builds the source package
# Both targets package via `git archive` rather than tarring the checkout
# directory directly: it only ever includes tracked files (so untracked/
# gitignored content - build/, notes/, any stray .env - can never leak into
# a release archive), it sets the correct top-level folder name via
# --prefix regardless of what this checkout is actually called (this repo
# is "occweb", the app id is "extended_occweb" - no symlink trick needed),
# and dev/CI-only files (tests/, Makefile, composer.*, phpunit*.xml,
# .travis.yml) are stripped via the `export-ignore` entries in
# .gitattributes instead of a long, easy-to-miss list of tar --exclude
# flags repeated per target. That also means source and appstore now
# produce the same archive; both targets are kept for compatibility with
# anything that invokes one of them by name.
#
# app_name comes from `xpath` (see its definition above) - if that binary
# is missing, $(shell ...) silently returns an empty string rather than
# failing the build, which would turn --prefix=$(app_name)/ below into
# --prefix=/ and produce a broken, unusably-rooted archive with no
# indication anything went wrong. Fail loudly instead.
.PHONY: check-app-name
check-app-name:
@test -n "$(app_name)" || \
(echo "app_name is empty - is 'xpath' (libxml2-utils/perl-XML-XPath) installed?" >&2; exit 1)
.PHONY: source
source:
source: check-app-name check-clean-tree check-on-branch
rm -rf $(source_build_directory)
mkdir -p $(source_build_directory)
tar \
--exclude-vcs \
--exclude="../$(app_name)/build" \
--exclude="../$(app_name)/js/node_modules" \
--exclude="../$(app_name)/node_modules" \
--exclude="../$(app_name)/*.log" \
--exclude="../$(app_name)/js/*.log" \
-cvzf $(source_package_name).tar.gz ../$(app_name)
git archive --format=tar --prefix=$(app_name)/ HEAD | gzip > $(source_package_name).tar.gz
# Builds the source package for the app store, ignores php and js tests
.PHONY: appstore
appstore:
appstore: check-app-name check-clean-tree check-on-branch
rm -rf $(appstore_build_directory)
mkdir -p $(appstore_build_directory)
tar \
--exclude-vcs \
--exclude="../$(app_name)/build" \
--exclude="../$(app_name)/tests" \
--exclude="../$(app_name)/Makefile" \
--exclude="../$(app_name)/*.log" \
--exclude="../$(app_name)/phpunit*xml" \
--exclude="../$(app_name)/composer.*" \
--exclude="../$(app_name)/js/node_modules" \
--exclude="../$(app_name)/js/tests" \
--exclude="../$(app_name)/js/test" \
--exclude="../$(app_name)/js/*.log" \
--exclude="../$(app_name)/js/package.json" \
--exclude="../$(app_name)/js/bower.json" \
--exclude="../$(app_name)/js/karma.*" \
--exclude="../$(app_name)/js/protractor.*" \
--exclude="../$(app_name)/package.json" \
--exclude="../$(app_name)/bower.json" \
--exclude="../$(app_name)/karma.*" \
--exclude="../$(app_name)/protractor\.*" \
--exclude="../$(app_name)/.*" \
--exclude="../$(app_name)/js/.*" \
-cvzf $(appstore_package_name).tar.gz ../$(app_name)
git archive --format=tar --prefix=$(app_name)/ HEAD | gzip > $(appstore_package_name).tar.gz
.PHONY: test
test: composer
@@ -159,8 +152,8 @@ test: composer
$(CURDIR)/vendor/phpunit/phpunit/phpunit -c phpunit.integration.xml
.PHONY: sign
sign:
@openssl dgst -sha512 -sign ~/.nextcloud/certificates/occweb.key build/artifacts/appstore/occweb.tar.gz |openssl base64
sign: check-app-name
@openssl dgst -sha512 -sign ~/.nextcloud/certificates/$(app_name).key $(appstore_package_name).tar.gz |openssl base64
VERSION := $(shell xpath -q -e "//info/version/text()" appinfo/info.xml)
@@ -168,11 +161,41 @@ VERSION := $(shell xpath -q -e "//info/version/text()" appinfo/info.xml)
show-version:
@echo $(VERSION)
# Defaults to "origin" - correct for a plain clone of this repo, where
# "origin" is dillardblom/occweb. Override for a checkout where "origin"
# means something else (e.g. this maintainer's own machine, where the repo
# was originally forked from upstream and "origin" still points there):
# make version RELEASE_REMOTE=fork
RELEASE_REMOTE ?= origin
# VERSION/app_name are read live from the working tree's appinfo/info.xml,
# but the archive this tags/packages/signs is git archive HEAD - i.e. the
# last COMMITTED state. Without this check, bumping <version> without
# committing first would tag and sign a package named/keyed after the new
# version while its actual contents are still the previous commit's.
.PHONY: check-clean-tree
check-clean-tree:
@git diff --quiet HEAD -- || \
(echo "Uncommitted changes to tracked files - commit before releasing (see 'git status')." >&2; exit 1)
# `git archive HEAD` packages whatever commit the checkout currently points
# to, regardless of branch - check-clean-tree only guards against *uncommitted*
# changes, not against HEAD being the wrong branch entirely (a feature branch,
# an old tag, a PR checkout, a detached HEAD). Override for the rare
# intentional case (e.g. releasing from a branch on purpose):
# make appstore RELEASE_BRANCH=some-branch
RELEASE_BRANCH ?= main
.PHONY: check-on-branch
check-on-branch:
@test "$$(git rev-parse --abbrev-ref HEAD)" = "$(RELEASE_BRANCH)" || \
(echo "HEAD is on '$$(git rev-parse --abbrev-ref HEAD)', not '$(RELEASE_BRANCH)' - pass RELEASE_BRANCH=<branch> to override if this is intentional." >&2; exit 1)
.PHONY: version
version:
version: check-clean-tree check-on-branch
@echo "Creating version v$(VERSION)"
@git tag v$(VERSION)
@git push origin v$(VERSION)
@git push $(RELEASE_REMOTE) v$(VERSION)
@make dist
@echo "\nRelease Signature: \n"
@make sign
+14 -2
View File
@@ -149,9 +149,21 @@ was verified, so a rollback target is obvious if a newer major causes problems.
| 0.4.0 | (untagged) | 34.0.4 | ✅ Verified (nc01, 2026-09-26) - app id renamed `occweb` → `extended_occweb` (App Store prep), no functional changes to the 0.3.5 fixes otherwise |
| 0.4.1 | `v0.4.1-nc34` | 34.0.4 | ✅ Verified (nc01, 2026-09-26) - code review fixes: correct jQuery `.fail()` signature, added a missing `.fail()` handler on the initial terminal-load request |
| 0.4.1 | `v0.4.1-nc34` | 33.0.8 | ⚠️ Same caveat as 0.3.5/0.4.0 - not re-verified, no NC33 test environment available. Also unresolved: `js/jquery.js` now loads unconditionally on every supported version, even NC30-33 where core still provides jQuery - flagged in code review, needs an NC33 environment to confirm it's harmless there. |
| 0.4.2 | (untagged) | 32.0.15 | ✅ Verified (`testbak/`, 2026-09-27) - terminal loads and runs commands correctly. Confirms the suspected jQuery issue above: core still exposes a read-only `window.$` getter here, so our vendored `js/jquery.js` throws `TypeError: Cannot set property $ of #<Window> which has only a getter` on load - a real, uncaught console exception, but harmless in practice since the app attaches via `window.jQuery` (still writable), not `window.$`. Fixed in 0.4.3. |
| 0.4.2 | (untagged) | 33.0.9 | ✅ Verified (`testbak/`, 2026-09-27) - same result as 32.0.15: functional, same harmless-but-real `window.$` console exception. Fixed in 0.4.3. |
| 0.4.2 | (untagged) | 35.0.1 | ✅ Verified (`testbak/`, 2026-09-27) after a real fix: the bootstrap request 500'd with a PHP fatal, `Declaration of OccOutput::setErrorOutput() must be compatible with ConsoleOutputInterface::setErrorOutput(): void` - NC35 bundles a Symfony Console version whose interface now declares that return type. Fixed by adding `: void` to `OccOutput::setErrorOutput()` (`lib/Controller/OccOutput.php`), which is compatible with every earlier Symfony/NC version too. Confirmed clean afterwards: no console errors, no CSRF issues, terminal fully functional. |
| 0.4.3 | (untagged) | 32.0.15, 34.0.4 | ✅ Verified (`testbak/`, 2026-09-27) - `templates/index.php` now only loads `js/jquery.js` when `\OCP\ServerVersion::getMajorVersion() >= 34`, since core still provides a working jQuery on 32/33. Re-tested both sides of the boundary: NC32 loads no `jquery.js` request at all and has zero console errors; NC34 still loads it and still works, confirming no regression. |
If a future major breaks something, `git checkout v0.3.4` is the last version confirmed
working on NC33 and older.
`min-version`/`max-version` in `appinfo/info.xml` were updated from `30`/`34` to `32`/`35` on 2026-09-27 based on the above: 30/31 have never actually been tested (not even before the app-id rename) so claiming them was never justified once the `testbak/`-based verification policy existed, and 35 is now a genuinely verified (and fixed) target rather than a guess. 30/31 are also past Nextcloud's own currently-supported boundary as of 2026-09-18 (32-35 supported), which independently confirms 32 as the right floor.
If a future major breaks something, `v0.3.4` is the last version confirmed working on NC33
and older - but a plain `git checkout v0.3.4` is **not** a working rollback by itself. That
tag predates the app id rename (it still declares `<id>occweb</id>`), so checking it out
into an `extended_occweb`-named install just produces a broken id/directory mismatch. A
real rollback means disabling/removing `extended_occweb` and deploying `v0.3.4` fresh under
an `occweb`-named directory instead, same as the original install steps above. This is one
of the items still deferred to when a proper test instance exists (see the code review
notes in git history around 0.4.1) - not yet written up in full.
## TODOs:
See [open issues](https://github.com/dillardblom/occweb/issues)
+11 -7
View File
@@ -5,7 +5,7 @@
<name>Extended OCC Web</name>
<summary>OCC Commands in a web terminal</summary>
<description><![CDATA[Run OCC Commands in a web terminal]]></description>
<version>0.4.1</version>
<version>0.4.4</version>
<licence>agpl</licence>
<author mail="dillard.blom@ensembia.com" >Dillard Blom</author>
<namespace>OCCWeb</namespace>
@@ -15,12 +15,16 @@
<repository>https://github.com/dillardblom/occweb</repository>
<screenshot>https://github.com/dillardblom/occweb/raw/main/appinfo/screenshot.png</screenshot>
<dependencies>
<!-- max-version must equal the highest NC core version this fork has
actually been verified on - never a value inherited from upstream
or guessed ahead. Test against the next major's beta and bump
this BEFORE it goes final, so occ:upgrade never has to fall back
to auto-disabling the app. -->
<nextcloud min-version="30" max-version="34"/>
<!-- min-version and max-version must equal the lowest/highest NC core
versions this fork has actually been verified on (via testbak/,
see its README) - never inherited from upstream or guessed at
either end. min-version was 30 pre-testbak, unverified since the
app-id rename/jQuery fixes - narrowed to 32 (2026-09-27) once 30/31
turned out to never have been re-tested and 32 was confirmed
working. Test against the next major's beta and bump max-version
BEFORE it goes final, so occ:upgrade never has to fall back to
auto-disabling the app. -->
<nextcloud min-version="32" max-version="35"/>
</dependencies>
<navigations>
<navigation role="admin">
+15 -1
View File
@@ -14,6 +14,17 @@
}
var baseUrl = OC.generateUrl('/apps/extended_occweb');
// occ output is plain text with ANSI colors, but jQuery Terminal reads
// "[" and "]" as its own formatting syntax. Escape the brackets in the
// text (e.g. Symfony's "[alias]" in `occ list`) and leave the ANSI
// sequences alone, so from_ansi can still turn them into colors. This
// only works together with unixFormattingEscapeBrackets (see below).
function escapeOutputBrackets(output) {
return String(output).replace(/(\x1B\[[0-9;]*[A-Za-z])|[\[\]]/g, function (match, ansi) {
return ansi ? ansi : (match === '[' ? '&#91;' : '&#93;');
});
}
// Current terminal mode: 'occ' (regular occ commands) or 'sql'
// (running arbitrary SQL queries via /db/query).
var mode = 'occ';
@@ -386,7 +397,7 @@
headers: { requesttoken: OC.requestToken },
data: JSON.stringify(occCommand)
}).done(function (response) {
term.echo('\n' + response).resume();
term.echo('\n' + escapeOutputBrackets(response)).resume();
}).fail(function (xhr, status) {
term.echo('\n[[;#ff5555;]Request failed: ]' + $.terminal.escape_formatting(xhr.status + ' ' + xhr.statusText)).resume();
});
@@ -398,6 +409,9 @@
name: 'occ',
prompt: OCC_PROMPT,
completion: response,
// The overtyping and from_ansi formatters unescape brackets before
// parsing; this makes them escape the text again afterwards.
unixFormattingEscapeBrackets: true,
keydown: function (e) {
// Shift+Enter inserts a newline instead of running the command,
// letting you type multi-line SQL scripts in sql mode.
+6 -1
View File
@@ -17,7 +17,12 @@ class OccOutput extends BufferedOutput implements ConsoleOutputInterface
return $this;
}
public function setErrorOutput(OutputInterface $error)
// NC35 bundles a Symfony Console version whose ConsoleOutputInterface
// declares this method `: void` - PHP 8 fatals ("Declaration must be
// compatible") without a matching return type here. Declaring `: void`
// is a valid narrowing of the untyped signature older Symfony/NC
// versions have, so this stays compatible with NC30-34 too.
public function setErrorOutput(OutputInterface $error): void
{
}
+10 -1
View File
@@ -2,8 +2,17 @@
// Nextcloud's global jQuery has been deprecated since NC19 and is no longer
// reliably present on NC34+ (see e.g. serverinfo needing to bundle its own) -
// term.js (jquery.terminal) and index.js both require jQuery to be loaded
// first, so ship and load our own copy rather than relying on core.
// first, so ship and load our own copy where core no longer provides one.
//
// Only do this on NC34+: on NC32/33 core still exposes a working jQuery, but
// via a read-only `window.$` getter - loading our vendored copy there too
// makes its UMD wrapper throw trying to reassign `window.$` (confirmed via
// testbak/, see the README compat matrix). Harmless in practice (this app
// attaches via window.jQuery, not window.$) but a real, avoidable console
// exception, so skip the extra load where core's own jQuery already works.
if (\OCP\Server::get(\OCP\ServerVersion::class)->getMajorVersion() >= 34) {
script('extended_occweb', 'jquery');
}
script('extended_occweb', 'index');
script('extended_occweb', 'term');
script('extended_occweb', 'unix_formatting');