@o-a/cms-agent 0.1.0 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -58,7 +58,7 @@ Either way, the result is the same:
58
58
  ```
59
59
  cd my-site/vhost
60
60
  npm install
61
- node server.js
61
+ npm start
62
62
  ```
63
63
 
64
64
  Visit `http://localhost:3000`. `create-site` prints a real API token to
@@ -17,10 +17,10 @@ try {
17
17
  console.log('Next steps:');
18
18
  console.log(` cd ${targetArg}/vhost`);
19
19
  console.log(' npm install');
20
- console.log(' node server.js');
20
+ console.log(' npm start');
21
21
  console.log('');
22
22
  console.log('Want to edit this site from a hosted admin while developing locally?');
23
- console.log(' node server.js --tunnel');
23
+ console.log(' npm run tunnel');
24
24
  }
25
25
  catch (error) {
26
26
  if (error instanceof ScaffoldError) {
@@ -94,6 +94,16 @@ export function scaffoldSite(targetDir) {
94
94
  version: '0.0.0',
95
95
  private: true,
96
96
  type: 'module',
97
+ // "start" matters beyond convenience: several PaaS platforms
98
+ // auto-detect and run `npm start` by default for a Node app
99
+ // with no other deploy config - without this, a site pushed
100
+ // straight to one of those (no Dockerfile in the loop) simply
101
+ // wouldn't boot. "tunnel" mirrors the --tunnel flag create-site
102
+ // already tells the operator about in its own next-steps output.
103
+ scripts: {
104
+ start: 'node server.js',
105
+ tunnel: 'node server.js --tunnel',
106
+ },
97
107
  dependencies: {
98
108
  // Pinned exact, never a ^range - at v0.x even a minor bump
99
109
  // can be breaking (build plan's own word is "pinned").
@@ -153,6 +153,20 @@ function parseCheckpointIntervalMs(value) {
153
153
  // restart, since this loads once at boot - matches the existing
154
154
  // "agent upgrade = restart" story already established for schema
155
155
  // migrations, a deliberate decision, not an accident.
156
+ // PORT overrides site.config.json's own "port" (or its default) without
157
+ // editing a file - the universal Node/12-factor convention, and how
158
+ // several hosting platforms (Railway, Render, etc.) already inject the
159
+ // port a process must bind. An invalid value is ignored, not a hard
160
+ // failure - a stray non-numeric PORT shouldn't stop the whole site from
161
+ // booting when the configured/default port would have worked fine.
162
+ function resolvePort(configuredPort) {
163
+ const envPort = process.env.PORT;
164
+ if (envPort === undefined) {
165
+ return configuredPort;
166
+ }
167
+ const parsed = Number(envPort);
168
+ return Number.isInteger(parsed) && parsed >= 0 ? parsed : configuredPort;
169
+ }
156
170
  export function loadServerConfig(siteRoot) {
157
171
  const configPath = join(siteRoot, VHOST_DIR_NAME, 'site.config.json');
158
172
  let raw;
@@ -161,7 +175,7 @@ export function loadServerConfig(siteRoot) {
161
175
  }
162
176
  catch {
163
177
  return {
164
- port: DEFAULT_PORT,
178
+ port: resolvePort(DEFAULT_PORT),
165
179
  tokens: [],
166
180
  rateLimit: DEFAULT_RATE_LIMIT,
167
181
  trustProxy: false,
@@ -192,5 +206,5 @@ export function loadServerConfig(siteRoot) {
192
206
  const ipAllowlist = parseIpAllowlist(record.ipAllowlist);
193
207
  const checkpointIntervalMs = parseCheckpointIntervalMs(record.checkpointIntervalMs);
194
208
  const media = parseMedia(record.media);
195
- return { port, tokens, rateLimit, trustProxy, ipAllowlist, checkpointIntervalMs, media };
209
+ return { port: resolvePort(port), tokens, rateLimit, trustProxy, ipAllowlist, checkpointIntervalMs, media };
196
210
  }
package/dist/server.js CHANGED
@@ -142,7 +142,23 @@ export async function startServer(siteRoot, options = {}) {
142
142
  });
143
143
  // host: '0.0.0.0' - Fastify's own default binds 127.0.0.1 only,
144
144
  // which is unreachable from outside any container or remote host.
145
- await app.listen({ port: serverConfig.port, host: '0.0.0.0' });
145
+ try {
146
+ await app.listen({ port: serverConfig.port, host: '0.0.0.0' });
147
+ }
148
+ catch (error) {
149
+ // A raw EADDRINUSE crash is a wall of Node internals with no
150
+ // indication of what to actually do about it. This is the single
151
+ // most likely startup failure a developer hits on their own
152
+ // machine (something else already using the default port) - tell
153
+ // them the two real ways to pick a different one instead of
154
+ // rethrowing Node's own stack trace.
155
+ if (error instanceof Error && 'code' in error && error.code === 'EADDRINUSE') {
156
+ console.error(`Port ${serverConfig.port} is already in use.`);
157
+ console.error(`Set a different port with the PORT environment variable (e.g. PORT=3001 node server.js), or "port" in vhost/site.config.json.`);
158
+ process.exit(1);
159
+ }
160
+ throw error;
161
+ }
146
162
  if (options.tunnel) {
147
163
  try {
148
164
  tunnel = await (options.startTunnel ?? startDevTunnel)(serverConfig.port);
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "@o-a/cms-agent",
3
- "version": "0.1.0",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "description": "Self-hosted, git-backed CMS agent, distributed as a compiled npm package.",
9
9
  "license": "SEE LICENSE IN LICENSE",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/o-a-com-au/granitecms.git"
13
+ },
14
+ "homepage": "https://github.com/o-a-com-au/granitecms",
10
15
  "main": "dist/index.js",
11
16
  "types": "dist/index.d.ts",
12
17
  "exports": {