Skip to content

Commit f856d6e

Browse files
committed
Merge branch 'main' of https://github.com/cubap/TinyNode
2 parents 651f478 + 6a75a14 commit f856d6e

30 files changed

Lines changed: 3481 additions & 6059 deletions

.github/workflows/cd_dev.yaml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ jobs:
77
runs-on: ubuntu-latest
88
steps:
99
- uses: actions/checkout@master
10+
- name: Fetch all branches
11+
run: git fetch --all
1012
- name: Merge with main
1113
uses: devmasx/merge-branch@master
1214
with:
@@ -34,7 +36,7 @@ jobs:
3436
- name: Setup Node.js
3537
uses: actions/setup-node@master
3638
with:
37-
node-version: "22"
39+
node-version: "24"
3840
- name: Cache node modules
3941
uses: actions/cache@master
4042
env:
@@ -59,7 +61,7 @@ jobs:
5961
strategy:
6062
matrix:
6163
node-version:
62-
- 22
64+
- 24
6365
machines:
6466
- vlcdhp02
6567
runs-on: ${{ matrix.machines }}
@@ -74,8 +76,8 @@ jobs:
7476
cd /srv/node/tiny-node/
7577
pm2 stop tinyNode
7678
git stash
77-
git pull
78-
git checkout ${{ github.head_ref }}
79-
git pull
79+
git fetch --prune origin
80+
git checkout -B ${{ github.head_ref }} origin/${{ github.head_ref }}
81+
git reset --hard origin/${{ github.head_ref }}
8082
npm install
8183
pm2 start -i max bin/tinyNode.js

.github/workflows/cd_prod.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
strategy:
2626
matrix:
2727
node-version:
28-
- 22
28+
- 24
2929
machines:
3030
- vlcdhprdp02
3131
runs-on: ${{ matrix.machines }}

UPSTREAM_CANDIDATES.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# TinyPen to TinyNode Upstream Candidates
2+
3+
This document tracks candidate updates identified from TinyPen that may be upstreamed into TinyNode.
4+
5+
## Summary
6+
7+
- Inclusion policy: high-confidence candidates plus uncertainty items.
8+
- Evidence policy: each candidate must include TinyPen evidence references.
9+
- Delivery policy: multiple focused PRs by theme.
10+
11+
## Candidate Matrix
12+
13+
| ID | Candidate | Status | TinyPen Evidence | TinyNode Targets | Notes |
14+
| --- | --- | --- | --- | --- | --- |
15+
| C-001 | Content-Type validation middleware for JSON endpoints | upstream-now | PR #39 | `routes/query.js`, `routes/create.js`, `routes/update.js`, `routes/delete.js`, `routes/overwrite.js` | Detect malformed or unsupported media types and return 415. |
16+
| C-002 | Query body validation for empty object/array | upstream-now | PR #33 | `routes/query.js`, `routes/__tests__/query.test.js` | Reject empty query payloads with 400. |
17+
| C-003 | Query pagination validation for `limit` and `skip` | upstream-now | PR #33 | `routes/query.js`, `routes/__tests__/query.test.js` | Require non-negative integers when provided. |
18+
| C-004 | Route-level error semantic consistency | investigate-first | PR #39 and related | `routes/*.js`, `error-messenger.js` | Normalize error objects/status handling before broad refactor. |
19+
| C-005 | Dependency cleanup after Node upgrade | investigate-first | TinyPen dependency diffs | `package.json` | Verify runtime paths before removing deps (`morgan`, `dotenv-expand`, `jsonld`). |
20+
| C-006 | Optimistic locking parity improvements | investigate-first | PR #20 | `routes/overwrite.js`, `routes/__tests__/overwrite.test.js` | Keep current behavior, evaluate if more parity is needed. |
21+
| C-007 | Temporary test alignment imports from TinyPen | upstream-now | PR #35 context | `routes/__tests__/*` | Include useful generated coverage temporarily while test strategy evolves. |
22+
23+
## Excluded or Deferred
24+
25+
| ID | Item | Reason |
26+
| --- | --- | --- |
27+
| X-001 | `.claude` and Claude-specific workflow changes | TPEN-internal tooling. |
28+
| X-002 | TinyPen naming substitutions in API messages | TinyNode and TinyPen naming is intentionally distinct for disambiguation. |
29+
| X-003 | Test framework architecture migration | Out of current scope. |
30+
31+
## PR Grouping Proposal
32+
33+
1. PR-A: request/content validation guards (`C-001`, `C-002`, `C-003`)
34+
2. PR-B: error semantic consistency (`C-004`)
35+
3. PR-C: cleanup and dependency simplification (`C-005`)
36+
4. PR-D: temporary test alignment updates (`C-007`)
37+
38+
## Verification Gates
39+
40+
1. Each merged candidate row includes evidence reference and touched file list.
41+
2. Targeted route tests pass for touched modules.
42+
3. Full test suite passes before merge.
43+
4. Dependency changes include runtime verification notes.
44+
5. Uncertain candidates remain blocked until evidence is upgraded from investigate-first to upstream-now.

app.js

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#!/usr/bin/env node
2-
import createError from "http-errors"
32
import express from "express"
43
import path from "path"
54
import { fileURLToPath } from "url"
@@ -12,12 +11,14 @@ import createRouter from "./routes/create.js"
1211
import updateRouter from "./routes/update.js"
1312
import deleteRouter from "./routes/delete.js"
1413
import overwriteRouter from "./routes/overwrite.js"
14+
import { messenger } from './error-messenger.js'
1515
import cors from "cors"
1616

1717
let app = express()
1818

1919
app.use(logger('dev'))
2020
app.use(express.json())
21+
app.use(express.text())
2122
if(process.env.OPEN_API_CORS !== "false") {
2223
// This enables CORS for all requests. We may want to update this in the future and only apply to some routes.
2324
app.use(
@@ -39,7 +40,8 @@ if(process.env.OPEN_API_CORS !== "false") {
3940
'X-HTTP-Method-Override',
4041
'Origin',
4142
'Referrer',
42-
'User-Agent'
43+
'User-Agent',
44+
'If-Overwritten-Version'
4345
],
4446
"exposedHeaders" : "*",
4547
"origin" : "*",
@@ -67,20 +69,7 @@ app.use('/app/update', updateRouter)
6769
app.use('/app/delete', deleteRouter)
6870
app.use('/app/overwrite', overwriteRouter)
6971

70-
// catch 404 and forward to error handler
71-
app.use(function(req, res, next) {
72-
next(createError(404))
73-
})
74-
75-
// error handler
76-
app.use(function(err, req, res, next) {
77-
// set locals, only providing error in development
78-
res.locals.message = err.message
79-
res.locals.error = req.app.get('env') === 'development' ? err : {}
80-
81-
// render the error page
82-
res.status(err.status || 500)
83-
res.send(err.message)
84-
})
72+
// RERUM error response handler, as well as unhandled generic app error handler
73+
app.use(messenger)
8574

8675
export default app

bin/tinyNode.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
*/
66

77
import dotenv from "dotenv"
8-
import dotenvExpand from "dotenv-expand"
9-
const storedEnv = dotenv.config()
10-
dotenvExpand.expand(storedEnv)
8+
dotenv.config()
119
import app from "../app.js"
1210
import debug from 'debug'
1311
debug('tinynode:server')

error-messenger.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Errors from RERUM are a response code with a text body (except those handled specifically upstream)
3+
* We want to send the same error code and message through. It is assumed to be RESTful and useful.
4+
* This will also handle generic (500) app level errors, as well as app level 404 errors.
5+
*
6+
* @param rerum_error_res A Fetch API Response object from a fetch() to RERUM that encountered an error. Explanatory text is in .text(). In some cases it is a unhandled generic (500) app level Error.
7+
* @param req The Express Request object from the request into TinyNode
8+
* @param res The Express Response object to send out of TinyNode
9+
* @param next The Express next() operator, unused here but required to support the middleware chain.
10+
*/
11+
export async function messenger(rerum_error_res, req, res, next) {
12+
if (res.headersSent) {
13+
return
14+
}
15+
let error = {}
16+
let rerum_err_text
17+
try {
18+
// Unless already handled upstream the rerum_error_res is an error Response with details as a textual body.
19+
rerum_err_text = await rerum_error_res.text()
20+
}
21+
catch (err) {
22+
// It is some 500
23+
rerum_err_text = undefined
24+
}
25+
if (rerum_err_text) error.message = rerum_err_text
26+
else {
27+
// Perhaps this is a more generic 500 from the app, perhaps involving RERUM, and there is no good rerum_error_res
28+
error.message = rerum_error_res.statusMessage ?? rerum_error_res.message ?? `A server error has occurred`
29+
}
30+
error.status = rerum_error_res.statusCode ?? rerum_error_res.status ?? 500
31+
console.error(error)
32+
res.set("Content-Type", "text/plain; charset=utf-8")
33+
res.status(error.status).send(error.message)
34+
}

jest.config.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ const config = {
2424
name: 'TinyNode',
2525
color: 'cyan'
2626
},
27+
// extensionsToTreatAsEsm: [".js"],
28+
testEnvironment: "node",
2729

2830
// Indicates whether the coverage information should be collected while executing the test
2931
collectCoverage: true,
@@ -206,4 +208,4 @@ const config = {
206208
// watchman: true,
207209
}
208210

209-
export default config
211+
export default config

0 commit comments

Comments
 (0)