Commit Graph
113 Commits
Author SHA1 Message Date
Zakaria El OrcheandClaude Opus 5 c5179146c0 docs(data): write the data-layer docs in English
The three data modules' docs were in Italian, so the synchronization contract
added in the previous commit went in as Italian too, to match its file. English
is the project's language for docs, comments and READMEs alike, and a file half
in each is worse than either — so all three are translated, not just the new
section.

Content is otherwise unchanged, except the "synchronizations run on
commit/rollback" line in the two backend READMEs, which was vague before and is
now accurate about which hook sees the session/connection still bound, pointing
at flash-ext-data-core's README for the full contract.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 23:36:11 +00:00
Zakaria El OrcheandClaude Opus 5 0194470c1f feat(data): actually invoke TxSynchronization.beforeCommit, and document the contract
beforeCommit(boolean) has been part of the TxSynchronization API from the
start and was invoked by nothing, in either manager — anyone implementing it
got silence, the same failure class as the dropped afterCommit callbacks in
the previous commit. Left out of that one because fixing it is a design
decision rather than a restored behaviour; this is that decision, written
down.

It now runs immediately before the real commit, with the transaction still
active and its session/connection still bound, which is the whole reason to
have a hook on this side of the commit: it can still write through the same
resource and land in the same atomic unit. Skipped when the transaction is
already rollback-only, since there is no commit to precede.

Throwing from it vetoes the commit: the transaction rolls back, the surviving
callbacks hear ROLLED_BACK, and the exception propagates. Without that, a hook
running before the commit would be strictly less useful than one running
after. A commit that fails on its own now takes the same path instead of
completing silently with no callback at all, and a rollback that also fails is
attached as a suppressed exception rather than replacing the one that explains
the failure.

Documented on the interface itself and in flash-ext-data-core/docs/README.md:
which hook sits on which side of the commit, what each may still touch, what
throwing does, and the per-transaction scoping rule from the previous commit.

Tests: 6 more (3 per manager) — runs inside the transaction with the resource
still bound, receives the read-only flag, skipped on a rollback-only
transaction, and vetoes the commit when it throws. 37 across the two managers
now, all green, reactor verify passes the 80% Jacoco gate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 23:33:05 +00:00
Zakaria El OrcheandClaude Opus 5 7299490d0d fix(data): fire transaction synchronizations, and scope them to their transaction
Two defects in the same mechanism, both silent.

1. HibernateTxManager#commit fired synchronizations *after* its finally block,
   where cleanupIfIdle() had already called ResourceRegistry.cleanup() and
   removed the ThreadLocal list holding them. fireSynchronizations() then read
   a freshly initialized empty list and did nothing. No afterCommit callback
   had ever run on the Hibernate path: no exception, no log, just silence.
   rollback() twenty lines below had the order right, which is what makes this
   an ordering slip rather than a design choice.

   Found in production, from the far end: an admin write landed in Postgres
   while the in-memory cache it was registered to refresh never heard about it,
   so the change only took effect when the process restarted and re-read the
   database at boot.

2. Synchronizations were a single flat per-thread list, fired from index 0 by
   whichever transaction completed first. A REQUIRES_NEW inner transaction
   therefore fired the *suspended* outer transaction's callbacks too — early,
   with the inner transaction's outcome, for a transaction that might still
   roll back. Each new transaction now records how many synchronizations were
   already registered when it began, and fires only its own tail.

Both managers get the fix and the same callback ordering: unbind the session or
connection first, so a callback that opens its own transaction (a cache reload,
an outbox drain) gets a fresh one instead of joining the transaction that just
committed, then fire, then clean up.

Also fixes JdbcTxStatus rejecting a null connection, which turned the two
propagations that deliberately produce a connectionless status — SUPPORTS with
no active transaction, and NOT_SUPPORTED — into an NPE inside begin(). The
Hibernate manager always allowed it, and resource() already reports the real
mistake with a message that names it.

Tests: 16 new across the two managers, kept deliberately parallel since the two
are interchangeable behind TxManager — synchronization firing, ordering,
per-transaction scoping, callbacks opening their own transaction, and the
previously untested SUPPORTS/NOT_SUPPORTED/MANDATORY propagations. Nothing
covered afterCommit before, which is how both defects shipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 23:23:47 +00:00
Zakaria El OrcheandClaude Sonnet 5 88ac3c3d1f fix(build): don't skip deploying flash-extensions' own POM
Publish Maven packages / publish (push) Successful in 2m2s
Its maven-deploy-plugin was configured with <skip>true</skip>, so the
first successful publish-maven.yml run deployed flash-parent, flash,
and every flash-ext-* jar to Gitea's Maven registry, but not
flash-extensions itself — the pom-packaging aggregator every
flash-ext-* submodule's effective POM inherits from via <parent>.
Remote consumers (Pathway's Docker build, resolving flash-ext-* from
the registry instead of a local ~/.m2 install) couldn't resolve that
parent POM and failed with "artifacts could not be resolved:
flash-extensions:pom (absent)".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 20:30:12 +00:00
Zakaria El OrcheandClaude Sonnet 5 3f0b49fa36 ci: use a real PAT (PACKAGES_TOKEN) instead of GITEA_TOKEN for deploy
Publish Maven packages / publish (push) Successful in 1m55s
Root cause of the persistent 401s found: Gitea's own per-job GITEA_TOKEN
cannot publish to any package registry at all — a known, still-
unimplemented limitation (go-gitea/gitea#23642), not a settings.xml
auth-format issue as first assumed. Confirmed by testing: GITEA_TOKEN
authenticated fine against the plain API but every registry write
endpoint rejected it regardless of scope or header style.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 20:23:18 +00:00
Zakaria El OrcheandClaude Sonnet 5 a19c59770d ci: add a debug step for the persistent 401 on deploy
Publish Maven packages / publish (push) Failing after 28s
Basic auth didn't fix it either — same 401 as the httpHeaders form.
Before guessing again: confirm GITEA_TOKEN actually reaches this step
non-empty, and check whether it authenticates against the plain API at
all (both header styles), independent of Maven/wagon-http.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 19:54:47 +00:00
Zakaria El OrcheandClaude Sonnet 5 3bc5952dc7 ci: switch Maven auth to basic (username/password), not httpHeaders
Publish Maven packages / publish (push) Failing after 27s
Still 401 after granting packages:write — the httpHeaders form from
Gitea's docs is honored by Maven's resolver (dependency reads) but
apparently not reliably by the wagon-http provider maven-deploy-plugin
uploads through, which deployed unauthenticated. Basic auth is
wagon-http's oldest, always-supported path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 19:53:12 +00:00
Zakaria El OrcheandClaude Sonnet 5 9d19de50cb ci: request packages:write — repo's default Actions token is read-only
Publish Maven packages / publish (push) Failing after 26s
Deploy failed with 401 Unauthorized: this repo's default Actions token
permission mode is Restricted (read-only on packages, not Permissive),
so the auto-provided GITEA_TOKEN couldn't push to the Maven registry
without explicitly requesting write access.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 19:50:58 +00:00
Zakaria El OrcheandClaude Sonnet 5 4710cf8633 ci: replace actions/checkout with a plain git clone
Publish Maven packages / publish (push) Failing after 27s
actions/checkout@v4 is a Node-based action; the maven:3.9-eclipse-temurin-21
container it was running in has no Node, so it failed with "node: executable
file not found in \$PATH". A shell git clone needs neither Node nor any
action runtime, just git (installed here via apt).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 19:47:40 +00:00
Zakaria El OrcheandClaude Sonnet 5 6a0242d654 ci: use the global ubuntu-latest runner, not the org-scoped one
Publish Maven packages / publish (push) Failing after 59s
The "org" runner label is scoped to the Pixel-Services organization —
Flash5 lives under the separate Relism account, which can only reach
the global runner (labels ubuntu-latest/ubuntu-24.04/ubuntu-22.04).
This job just runs Maven inside a container, no Docker access needed,
so ubuntu-latest is a fine fit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 19:44:24 +00:00
Zakaria El OrcheandClaude Sonnet 5 0365c1f222 ci: fix runner label (org, not docker)
Publish Maven packages / publish (push) Canceled after 0s
The org's Gitea Actions runner is registered under the label "org" —
"docker" doesn't match anything online, so the publish job never got
picked up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 19:41:26 +00:00
Relism c235e67158 Merge pull request 'ci: publish Maven packages to Gitea registry on push to master' (#8) from ci/publish-maven into master
Publish Maven packages / publish (push) Canceled after 0s
2026-08-12 19:39:12 +00:00
Zakaria El OrcheandClaude Sonnet 5 5a16bc690c ci: publish Maven packages to Gitea registry on push to master
Lets Pathway (and other consumers) resolve dev.relism:flash from Gitea's
Maven registry instead of requiring a local `mvn install`. Every push
stamps all modules with a commit-scoped version (2.1.0-<short-sha>) before
deploying, since Gitea's registry won't let a build overwrite an existing
name+version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 19:38:18 +00:00
Relism e217f9370d Merge pull request 'feat(ext-data): add unified Data gateway; mcp: derive roles claim from OIDC' (#7) from feature/data-unified-composition into master
Publish Snapshot / Deploy Snapshot (push) Canceled after 5s
CI / Build & Test (push) Canceled after 3s
Reviewed-on: #7
2026-08-12 18:39:28 +00:00
Relism be7df3987c Merge pull request 'Feature/core/deterministic boot graph' (#6) from feature/core/deterministic-boot-graph into master
CI / Build & Test (push) Canceled after 5s
Publish Snapshot / Deploy Snapshot (push) Canceled after 3s
Reviewed-on: #6
2026-08-12 18:39:01 +00:00
Zakaria El OrcheandClaude Sonnet 5 9e045287c1 feat(ext-data): add unified Data gateway; mcp: derive roles claim from OIDC
CI / Build & Test (push) Canceled after 1m28s
CI / Build & Test (pull_request) Canceled after 16s
Data/RepositoryFactory/HibernateData give applications one cached,
stateless entry point for repositories per entity type instead of
per-request instantiation, with write()/afterCommit() replacing manual
transaction+reload choreography.

McpConfig.rolesClaimPath is removed - MCP now derives the claim path
from OidcMiddleware.rolesClaimPath() so applications never duplicate
the roles-claim config between OIDC and MCP. McpPackageScanner is
rebuilt on the shared PackageScanner.discover(packageName) primitive,
doing only McpTool/McpResource/McpPrompt classification itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-12 18:37:30 +00:00
Zakaria El Orche 891ef99b8e refactor(core): make boot and middleware ordering deterministic
CI / Build & Test (pull_request) Canceled after 23s
CI / Build & Test (push) Failing after 4m51s
2026-08-12 16:42:49 +00:00
Zakaria El OrcheandClaude Sonnet 5 d7f36a7aea feat(ext-mcp): add MCP (Model Context Protocol) server extension
CI / Build & Test (push) Failing after 4m57s
Streamable HTTP transport (JSON-RPC 2.0 over POST), one-class-per-tool/resource/prompt
API mirroring RequestHandler, boot-time-precompiled schema/list payloads for a zero-alloc
hot path, and optional OAuth2 protection built on flash-ext-oidc (lazy-loaded, RFC 8707
audience binding, RFC 9728 Protected Resource Metadata). Registers the module in the
root and flash-extensions POMs and adds the ext-mcp commit scope to AGENTS.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 00:22:40 +00:00
Zakaria El OrcheandClaude Sonnet 5 8ece9975de feat(ext-web-bundler): add build-time asset scanning and static-frontend strategy
Introduces AssetDirectoryScanner, StaticFrontendStrategy, and WebBundlerBuild for
build-time asset discovery, plus config/docs updates for frontend-type resolution.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-11 00:22:26 +00:00
Relism 4032567d75 Merge pull request 'feat(core): add HTTP QUERY method support' (#5) from feature/core/http-query-method into master
CI / Build & Test (push) Canceled after 5s
Publish Snapshot / Deploy Snapshot (push) Canceled after 7s
Reviewed-on: #5
2026-08-10 13:29:24 +00:00
Zakaria El OrcheandClaude Sonnet 5 fa0a2d79b4 feat(core): add HTTP QUERY method support
CI / Build & Test (push) Failing after 4m55s
CI / Build & Test (pull_request) Canceled after 50s
Adds the QUERY method (RFC 10008) — safe and idempotent like GET,
but carries a request body like POST, useful for complex filters
that don't fit in a URL query string.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 13:09:26 +00:00
Relism 391ae6778e Merge pull request 'feat(core): ALPN configuration and TLS visibility on Request/WebSocketSession' (#4) from feature/core/tls-alpn into master
Publish Snapshot / Deploy Snapshot (push) Failing after 4m48s
CI / Build & Test (push) Failing after 5m4s
Reviewed-on: #4
2026-08-09 23:38:27 +00:00
Zakaria El OrcheandClaude Sonnet 5 1b48d14b4f feat(core): ALPN configuration and TLS visibility on Request/WebSocketSession
CI / Build & Test (push) Failing after 5m3s
CI / Build & Test (pull_request) Failing after 4m53s
- TlsConfig.applicationProtocols(String...) sets the listener's negotiable
  ALPN protocol list via SSLParameters, inherited by every accepted socket
  like clientAuth — works on both keystore() and ofContext(), untouched
  unless called. Enables TLS-ALPN-01 (RFC 8737) style on-demand cert
  issuance: a custom KeyManager can read the already-resolved protocol via
  engine/socket getHandshakeApplicationProtocol() inside
  chooseEngineServerAlias/chooseServerAlias, since ALPN is resolved during
  ClientHello/ServerHello, always before Certificate production.
- Request gains isSecure()/sslSession(), threaded through RequestParser from
  the accepted SSLSocket exactly like remoteAddress() — reference-only,
  zero per-request allocation. sslSession() defers to SSLSocket#getSession()
  lazily, so it's a cached-field read (handshake already completed by the
  time a handler can call it), never a forced handshake.
- WebSocketSession.isSecure()/sslSession() delegate to the upgrading
  Request rather than tracking the socket a second time.
- Documents TLS end-to-end in README.md (listeners, TlsConfig, SNI, ALPN,
  mTLS, Request/WebSocketSession accessors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 23:34:22 +00:00
Relism 7cd8b3869c Merge pull request 'feat(core): add TLS/mTLS support with multi-listener and SNI' (#3) from feature/core/tls-support into master
Publish Snapshot / Deploy Snapshot (push) Failing after 4m58s
CI / Build & Test (push) Failing after 4m59s
Reviewed-on: #3
2026-08-09 22:23:53 +00:00
Zakaria El OrcheandClaude Sonnet 5 9f6808e90c feat(core): add TLS/mTLS support with multi-listener and SNI
CI / Build & Test (pull_request) Failing after 4m54s
CI / Build & Test (push) Failing after 4m54s
Flash can now serve HTTPS and WSS, on one or many listeners per app:

- FlashConfiguration gains an optional `tls` field for the single default
  listener, and a `listeners` list for apps that bind multiple ports (each
  independently plain or TLS).
- New dev.relism.flash.tls package: TlsConfig.keystore(path, password) builds
  an SSLContext from a PKCS12/JKS keystore, with SNI-based certificate
  selection for free when the keystore holds more than one alias (matched by
  SAN/CN, pure JDK APIs). TlsConfig.ofContext(sslContext) is a full escape
  hatch — Flash never calls setSSLParameters on that path, so caller-set
  protocols/cipher suites/ALPN survive untouched. TlsConfig.clientAuth(...)
  adds optional/required mTLS on either path.
- HttpServer moves from a single ServerSocket to a list of bound listeners;
  the per-request hot path (RequestParser, routing, response writing) is
  untouched — TLS only changes which bytes come out of accept(), so WSS needs
  no separate code path from WS.
- process()'s catch is widened to log non-IOException failures (e.g. a
  misbehaving custom KeyManager/TrustManager on the ofContext path) instead
  of swallowing them silently; the failure was already isolated to the one
  connection via the existing try-with-resources/executor-submission
  boundary — this only fixes the missing log line.
- Fixes a pre-existing gap where FlashConfiguration#host was accepted but
  never used to bind (listeners always bound to the wildcard address).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 21:41:57 +00:00
Relism bf2d54ca1a Merge pull request 'feat(core): WS client-mode masking, zero-copy header iteration, shared I/O relay buffer' (#1) from feature/core/ws-client-mode-io-reuse into master
Publish Snapshot / Deploy Snapshot (push) Failing after 5m32s
CI / Build & Test (push) Failing after 5m38s
Reviewed-on: #1
2026-08-09 20:38:20 +00:00
Zakaria El OrcheandClaude Sonnet 5 a037456634 feat(core): WS client-mode masking, zero-copy header iteration, shared I/O relay buffer
CI / Build & Test (push) Failing after 6m7s
CI / Build & Test (pull_request) Failing after 4m56s
- WebSocketSession supports client-mode outgoing frame masking (RFC 6455) via
  in-place XOR, reusing the unmask routine already used for inbound frames.
- HeaderMap gains an allocation-free forEach(HeaderConsumer) for callers that
  must handle an open-ended set of header names (e.g. proxying).
- HttpServer relays streaming/chunked response bodies through a shared
  per-connection ThreadLocal buffer instead of relying on InputStream#transferTo
  (which allocates internally) or a fresh byte[8192] per chunked write.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-09 20:24:56 +00:00
Relism 524bdeb28b Fix badge HTML syntax in docs workflow 2026-05-12 16:34:59 +02:00
Relism c619c17949 Refactor JavaDoc generation and verification steps 2026-05-12 16:28:20 +02:00
Relism c368843ad4 ci: fix javadoc path, encoding and delegate docs to docs.yml 2026-05-12 16:15:33 +02:00
Relism 35293a0a57 feat(ci): add workflow for publishing JavaDoc to GitHub Pages 2026-05-12 15:42:39 +02:00
Relism c514897ffc fix(ci): publish versioned javadocs only on gh-pages 2026-05-11 16:53:17 +02:00
Relism 6314bcff5f fix(ci): correct javadoc publish path and maven settings schema 2026-05-11 16:18:49 +02:00
Relism ccc5550598 feat: introduce WebSocket support with new endpoints and transaction propagation enhancements 2026-05-11 16:14:26 +02:00
github-actions[bot] a4a16bdb00 chore(release): prepare 2.1.0-SNAPSHOT 2026-05-11 13:54:19 +00:00
github-actions[bot] f941eb63f4 chore(release): 2.0.0 v2.0.0 2026-05-11 13:54:16 +00:00
Relism 8af81ac28c Merge pull request #1 from Relism/feature/ci-cd/setup
ci: setup CI/CD pipelines, versioning and agent guidelines
2026-05-11 14:24:13 +02:00
Relism 945633e5bd ci: setup CI/CD pipelines, versioning and agent guidelines 2026-05-11 14:19:54 +02:00
Relism f310646868 fix: enhance global key validation and update template parameters 2026-04-29 10:31:14 +02:00
Relism 0e2dad23e5 chore: add .idea/inspectionProfiles to gitignore 2026-04-26 13:01:55 +02:00
Relism a1cf4ada49 fix: merge jte extension refactor with static serving features
- Move JteStaticServing to dev.relism.flash package
- Fix imports in HttpStatus and test files
- Add fluent config methods to JteExtension (templateRoot, serveStatics, staticPrefix, etc.)
- Implement routes() for static asset serving with HEAD support
- Include Main.java entry point
2026-04-26 13:00:08 +02:00
Relism 5b3b887acd Merge remote-tracking branch 'origin/master'
# Conflicts:
#	.idea/workspace.xml
#	flash-extensions/flash-ext-view-jte/jte-classes/gg/jte/generated/ondemand/pages/JtehomeGenerated.class
#	flash-extensions/flash-ext-view-jte/src/main/java/dev/relism/flash/ext/view/jte/JteExtension.java
2026-04-26 12:36:26 +02:00
Relism 8a52c4f143 refactor: rename packages and files to use 'flash' prefix for consistency 2026-04-26 12:34:49 +02:00
Relism c2e3f98ea2 add static asset serving support with configurable options 2026-04-26 12:27:59 +02:00
Relism 6ef11ca595 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	.idea/workspace.xml
2026-04-21 09:34:54 +02:00
Relism 87d02aceb7 add workspace.xml to .gitignore 2026-04-21 09:34:35 +02:00
Relism 9e19f439be add core view extension with JTE and Thymeleaf support 2026-04-21 00:32:09 +02:00
Relism 34fd74068a implement OpenAPI contributor integration for rate limiting and response headers 2026-04-19 23:42:50 +02:00
Relism e161497f2c i spent the last year just spinning 2026-04-17 18:56:06 +02:00
Relism 9efbe38c0c weeks of bullshit 2026-04-17 08:18:11 +02:00