feat(backend-js): add a Node.js implementation of the Quickstart backend#1
Open
fernandomg wants to merge 8 commits intomainfrom
Open
feat(backend-js): add a Node.js implementation of the Quickstart backend#1fernandomg wants to merge 8 commits intomainfrom
fernandomg wants to merge 8 commits intomainfrom
Conversation
…mbing Adds BACKEND=java|js as a make-level selector, persisted in .env.local via make setup, with a compose override, Dockerfile, and start.sh for the JS service. The :daml gradle build emits both Java and TS codegen and skips the irrelevant one per active BACKEND. Root .gitignore gains an npm-prevention block to keep package.json/lock from leaking up to the repo root. Co-Authored-By: Gabito Esmiapodo <4015436+gabitoesmiapodo@users.noreply.github.com>
Project skeleton: package + lockfile, NodeNext tsconfig, runtime config loader, server entrypoint, app builder with ErrorResponse-shaped error handler and an empty-body JSON parser to accept the frontend's logout post. Co-Authored-By: Gabito Esmiapodo <4015436+gabitoesmiapodo@users.noreply.github.com>
Wires session, CSRF, and cookie middleware; OAuth2 (with plain-HTTP issuer opt-in for local Keycloak, JWKS cache per issuer, partyId resolved from the tenant repository); shared-secret form login that resolves the username against the tenant repository and seeds the AppProvider tenant with admin users; CSRF bypass for Bearer- authenticated service traffic; TEST_MODE party_id override applied at session population; admin-gate distinguishing 401/403 by Bearer or session presence; and the /admin, /user, and /login-links routes that sit on top of all of it. Co-Authored-By: Gabito Esmiapodo <4015436+gabitoesmiapodo@users.noreply.github.com>
Adds the read-side data access used by the licensing routes: a pg connection pool, a typed contract row helper that decodes the JSONB payload, and a licensing repository that finds active contracts by id and lists them by predicate. Co-Authored-By: Gabito Esmiapodo <4015436+gabitoesmiapodo@users.noreply.github.com>
…nd bindings Adds the write-side ledger access: a client-credentials token provider with a 30s expiry buffer, a JSON Ledger API client wrapping submit-and- wait-for-transaction, and command builders typed via the dpm codegen-js output (damlTypes.Template/Choice). Template ids carry the '#<package-name>:' prefix the JSON Ledger API requires, every submit is wrapped in the JsCommands envelope, and userId is matched to the JWT subject claim. A token-standard client adds the registry admin id and allocation transfer context lookup. Co-Authored-By: Gabito Esmiapodo <4015436+gabitoesmiapodo@users.noreply.github.com>
Adds the business surface exposed over the OpenAPI contract: a licensing service that orchestrates PQS reads and ledger writes, mappers that mirror the Java backend's DTO shapes, and the routes for feature-flags, app-install-requests, app-installs, licenses, and license-renewal-requests. Daml-choice routes register one wildcard per resource to dodge find-my-way's colon-route limitation while preserving the URL contract. Microsecond-precision timestamps are emitted on License_Renew, the new License contract id is read from the CreatedEvent walk (since submit-and-wait returns ACS_DELTA events without exerciseResult), and admin-only choice endpoints are gated by checkAdmin. Co-Authored-By: Gabito Esmiapodo <4015436+gabitoesmiapodo@users.noreply.github.com>
Adds a Backend implementations section that contrasts the Java and JS backends, documents the BACKEND selector and switching workflow, and notes the Java-only debug port and the per-backend codegen behaviour. Co-Authored-By: Gabito Esmiapodo <4015436+gabitoesmiapodo@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Close digital-asset#156
Summary
BACKEND=js(persisted in.env.localbymake setup).3975instead of gRPC, reads PQS Postgres directly, and uses the dpmcodegen-jsDaml bindings for typed command construction. The Compose stack swaps in the JS service via an override file whenBACKEND=js.Test plan
make clean-all && make setupand answeredjsto the new interactive Backend prompt — alongside the existing prompts forAUTH_MODE,OBSERVABILITY_ENABLED,TEST_MODE, andPARTY_HINT. The selection is written to.env.localasBACKEND=js, so every subsequentmake start/make restart-backend/make stopautomatically targets the JS service without needing to repeat the flag. Re-ranmake setupand chosejavato confirm the prompt round-trips and that the stack swaps back to the Java backend cleanly. Verified under bothAUTH_MODE=oauth2andAUTH_MODE=shared-secret.register-app-user-tenant,AppInstallRequestaccept/reject,Licenseissuance, the renewal flow with wallet allocation, and license expiry. Each step produced behaviour identical to the Java backend.Deferred to follow-up
The items below were surfaced during review and consciously left out of this PR. Each one is either parity-equal with the Java backend (so a JS-only fix would create drift) or a production-hardening concern that needs a cross-cutting design touching both backends. They should be tracked in a follow-up issue against both implementations.
SESSION_SECRETfalls back to random bytes per restart inbackend-js/src/auth/session.ts, invalidating signed session cookies.HttpSessionproduces the same observable behaviour: every restart logs all users out (signature mismatch in JS, lost server-side state in Java). Fix needs a stable signing secret and a persistent session store applied to both backends.application.ymlexplicitly enablesinclude-message: always,include-stacktrace: always,include-exception: truefor dev — leaks at least as much, with stacktraces. A sanitising error mapper needs to land on both backends together.Duration.parsethrowsDateTimeParseExceptionand there is no@ControllerAdvicemapping it to 400. Fix on both sides in one PR.DELETE /admin/tenant-registrations/:tenantIdremoves the OAuth2 registry entry before the tenant repo entry; if step 2 fails the registry is gone but the tenant remains.deleteTenantRegistrationuses the same ordering and has the same risk window. Proper transactional/rollback handling needs to land on both backends.AppInstallRequest_Acceptdoes not include the new AppInstall'scontractId.AppInstallRequestsApiImpl#acceptAppInstallRequest. The OpenAPI response shape and the choice-result extraction need to be updated together on both sides.