@luckystack/server 0.8.0 → 0.8.2
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/CHANGELOG.md +12 -0
- package/CLAUDE.md +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +22 -12
- package/dist/index.js.map +1 -1
- package/docs/runtime-maps.md +9 -6
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.2] - 2026-07-27
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Processes can compose non-overlapping atomic presets whose generated maps repeat the same full function registry; equivalent function entries deduplicate while conflicting function implementations and duplicate API/sync ownership still fail closed.
|
|
15
|
+
|
|
16
|
+
## [0.8.1] - 2026-07-27
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Production route maps, dev-tool startup, cookie security, bootstrap checks and port auto-increment now follow `NODE_ENV`; named topology environments remain available for health and routing identity.
|
|
21
|
+
|
|
10
22
|
## [0.8.0] - 2026-07-27
|
|
11
23
|
|
|
12
24
|
### Added
|
package/CLAUDE.md
CHANGED
|
@@ -36,7 +36,7 @@ One-call server bootstrap for a LuckyStack project. Wires together a raw Node.js
|
|
|
36
36
|
| `getParsedBundles()` | Returns the preset list parsed by `applyServerArgv()` (empty array before first call). | -> docs/argv-parsing.md |
|
|
37
37
|
| `getParsedPort()` | Returns the port parsed by `applyServerArgv()` (`null` if argv omitted it). | -> docs/argv-parsing.md |
|
|
38
38
|
| `@luckystack/server/parseArgv` (side-effect import) | First-line import that runs `applyServerArgv()` before any module reads `process.env.SERVER_PORT` (notably `config.ts`). | -> docs/argv-parsing.md |
|
|
39
|
-
| `createProdRuntimeMapsProvider(options)` | Build a `RuntimeMapsProvider` that loads generated maps in prod and delegates to devkit discovery in dev. Returns the provider without registering. | -> docs/runtime-maps.md |
|
|
39
|
+
| `createProdRuntimeMapsProvider(options)` | Build a `RuntimeMapsProvider` that loads generated maps in prod and delegates to devkit discovery in dev. Composed presets reject duplicate API/sync ownership, deduplicate equivalent full-registry function entries, and reject differing function implementations. Returns the provider without registering. | -> docs/runtime-maps.md |
|
|
40
40
|
| `registerProdRuntimeMapsProvider(options)` | Convenience wrapper: builds the provider AND calls `registerRuntimeMapsProvider`. Most consumers want this. | -> docs/runtime-maps.md |
|
|
41
41
|
| `registerCustomRoute(handler, options?)` | Append a custom HTTP route handler. `options.phase`: `'post-params'` (default, runs after body parse) or `'pre-params'` (runs before `getParams`, raw `req` stream intact — webhooks + streaming uploads). | -> /docs/ARCHITECTURE_HTTP.md |
|
|
42
42
|
| `getCustomRoutes()` | Read the `'post-params'` registry snapshot (the default phase). | -> /docs/ARCHITECTURE_HTTP.md |
|
package/dist/index.d.ts
CHANGED
|
@@ -110,7 +110,7 @@ interface CreateLuckyStackServerOptions {
|
|
|
110
110
|
customRoutes?: CustomRouteHandler;
|
|
111
111
|
/**
|
|
112
112
|
* Enable dev-mode tooling (devkit hot reload, REPL, console init).
|
|
113
|
-
* Defaults to `
|
|
113
|
+
* Defaults to `resolveRuntimeMode() !== 'production'` (NODE_ENV-based).
|
|
114
114
|
*/
|
|
115
115
|
enableDevTools?: boolean;
|
|
116
116
|
/**
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
|
|
10
10
|
// src/createServer.ts
|
|
11
11
|
import http from "http";
|
|
12
|
-
import { registerBindAddress, registerBoundAddress, writeBootUuid, startBootUuidHeartbeat, getLogger as getLogger13, getProjectConfig as getProjectConfig15, tryCatch as tryCatch10, tryCatchSync as tryCatchSync3,
|
|
12
|
+
import { registerBindAddress, registerBoundAddress, writeBootUuid, startBootUuidHeartbeat, getLogger as getLogger13, getProjectConfig as getProjectConfig15, tryCatch as tryCatch10, tryCatchSync as tryCatchSync3, resolveRuntimeMode, dispatchHook as dispatchHook8 } from "@luckystack/core";
|
|
13
13
|
|
|
14
14
|
// src/httpHandler.ts
|
|
15
15
|
import { randomUUID } from "crypto";
|
|
@@ -475,11 +475,11 @@ import {
|
|
|
475
475
|
} from "@luckystack/core";
|
|
476
476
|
|
|
477
477
|
// src/httpRoutes/sessionCookie.ts
|
|
478
|
-
import {
|
|
478
|
+
import { isProductionRuntime } from "@luckystack/core";
|
|
479
479
|
var resolveCookieSecure = (sessionCookieSecure, secureEnv) => {
|
|
480
480
|
if (sessionCookieSecure !== void 0) return sessionCookieSecure;
|
|
481
481
|
if (secureEnv === "true") return true;
|
|
482
|
-
return
|
|
482
|
+
return isProductionRuntime();
|
|
483
483
|
};
|
|
484
484
|
|
|
485
485
|
// src/httpRoutes/authApiRoute.ts
|
|
@@ -2020,7 +2020,7 @@ import {
|
|
|
2020
2020
|
isLocalizedNormalizerRegistered,
|
|
2021
2021
|
isProjectConfigRegistered,
|
|
2022
2022
|
isRuntimeMapsProviderRegistered,
|
|
2023
|
-
|
|
2023
|
+
isProductionRuntime as isProductionRuntime2
|
|
2024
2024
|
} from "@luckystack/core";
|
|
2025
2025
|
var verifyBootstrap = async (requirements = {}) => {
|
|
2026
2026
|
const missing = [];
|
|
@@ -2059,7 +2059,7 @@ var verifyBootstrap = async (requirements = {}) => {
|
|
|
2059
2059
|
}
|
|
2060
2060
|
}
|
|
2061
2061
|
if (!isRuntimeMapsProviderRegistered()) {
|
|
2062
|
-
if (
|
|
2062
|
+
if (isProductionRuntime2()) {
|
|
2063
2063
|
missing.push(
|
|
2064
2064
|
"RuntimeMapsProvider \u2014 call `registerRuntimeMapsProvider({...})` from `server/prod/runtimeMaps.ts`. Without it, every api/sync request returns notFound."
|
|
2065
2065
|
);
|
|
@@ -2070,7 +2070,7 @@ var verifyBootstrap = async (requirements = {}) => {
|
|
|
2070
2070
|
}
|
|
2071
2071
|
}
|
|
2072
2072
|
if (!isLocalizedNormalizerRegistered()) {
|
|
2073
|
-
if (
|
|
2073
|
+
if (isProductionRuntime2()) {
|
|
2074
2074
|
missing.push(
|
|
2075
2075
|
"LocalizedNormalizer \u2014 call `registerLocalizedNormalizer({...})` from your bootstrap. Without it, error response messages will be the raw errorCode (no i18n)."
|
|
2076
2076
|
);
|
|
@@ -2113,7 +2113,7 @@ var verifyBootstrap = async (requirements = {}) => {
|
|
|
2113
2113
|
import {
|
|
2114
2114
|
getLogger as getLogger10,
|
|
2115
2115
|
registerRuntimeMapsProvider,
|
|
2116
|
-
|
|
2116
|
+
isProductionRuntime as isProductionRuntime3
|
|
2117
2117
|
} from "@luckystack/core";
|
|
2118
2118
|
var emptyRuntimeMaps = {
|
|
2119
2119
|
apisObject: {},
|
|
@@ -2151,10 +2151,20 @@ var resolvePresets = (options) => {
|
|
|
2151
2151
|
}
|
|
2152
2152
|
return ["default"];
|
|
2153
2153
|
};
|
|
2154
|
+
var areEquivalentFunctionEntries = (left, right) => {
|
|
2155
|
+
if (Object.is(left, right)) return true;
|
|
2156
|
+
if (!isRuntimeMapRecord(left) || !isRuntimeMapRecord(right)) return false;
|
|
2157
|
+
const leftKeys = Object.keys(left);
|
|
2158
|
+
const rightKeys = Object.keys(right);
|
|
2159
|
+
return leftKeys.length === rightKeys.length && leftKeys.every((key) => Object.hasOwn(right, key) && Object.is(left[key], right[key]));
|
|
2160
|
+
};
|
|
2154
2161
|
var mergeInto = (target, source, kind, fromPreset, keyOrigin) => {
|
|
2155
2162
|
for (const key of Object.keys(source)) {
|
|
2156
2163
|
const previousPreset = keyOrigin.get(key);
|
|
2157
2164
|
if (previousPreset !== void 0 && previousPreset !== fromPreset) {
|
|
2165
|
+
if (kind === "function" && areEquivalentFunctionEntries(target[key], source[key])) {
|
|
2166
|
+
continue;
|
|
2167
|
+
}
|
|
2158
2168
|
throw new Error(
|
|
2159
2169
|
`[luckystack:runtimeMaps] ${kind} key collision: "${key}" present in both preset "${previousPreset}" and preset "${fromPreset}". Services must belong to exactly one preset (see docs/ARCHITECTURE_PACKAGING.md \xA710).`
|
|
2160
2170
|
);
|
|
@@ -2163,7 +2173,7 @@ var mergeInto = (target, source, kind, fromPreset, keyOrigin) => {
|
|
|
2163
2173
|
target[key] = source[key];
|
|
2164
2174
|
}
|
|
2165
2175
|
};
|
|
2166
|
-
var isProduction = () =>
|
|
2176
|
+
var isProduction = () => isProductionRuntime3();
|
|
2167
2177
|
var createProdRuntimeMapsProvider = (options) => {
|
|
2168
2178
|
let prodMapsPromise = null;
|
|
2169
2179
|
let devkitModulePromise = null;
|
|
@@ -2371,9 +2381,9 @@ var initDevTools = async () => {
|
|
|
2371
2381
|
};
|
|
2372
2382
|
var listenLuckyStackServer = (httpServer, ip, port, callback) => new Promise((resolve, reject) => {
|
|
2373
2383
|
const startPort = normalizeServerPort(port);
|
|
2374
|
-
const
|
|
2375
|
-
const production =
|
|
2376
|
-
const test =
|
|
2384
|
+
const runtimeMode = resolveRuntimeMode();
|
|
2385
|
+
const production = runtimeMode === "production";
|
|
2386
|
+
const test = runtimeMode === "test";
|
|
2377
2387
|
const autoIncrementEnv = (process.env.SERVER_PORT_AUTO_INCREMENT ?? "").toLowerCase();
|
|
2378
2388
|
let autoIncrement;
|
|
2379
2389
|
if (["0", "false"].includes(autoIncrementEnv)) autoIncrement = false;
|
|
@@ -2456,7 +2466,7 @@ var createLuckyStackServer = async (options = {}) => {
|
|
|
2456
2466
|
envPort: process.env.SERVER_PORT
|
|
2457
2467
|
});
|
|
2458
2468
|
const ip = options.ip ?? process.env.SERVER_IP ?? "127.0.0.1";
|
|
2459
|
-
const enableDevTools = options.enableDevTools ??
|
|
2469
|
+
const enableDevTools = options.enableDevTools ?? resolveRuntimeMode() !== "production";
|
|
2460
2470
|
registerBindAddress({ ip, port });
|
|
2461
2471
|
if (enableDevTools) {
|
|
2462
2472
|
await initDevTools();
|