@luckystack/server 0.7.6 → 0.8.1

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 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.1] - 2026-07-27
11
+
12
+ ### Fixed
13
+
14
+ - 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.
15
+
16
+ ## [0.8.0] - 2026-07-27
17
+
18
+ ### Added
19
+
20
+ - Routed GET API calls can carry a lossless typed payload through the reserved `__luckystack_data` query value while public key-per-query callers remain compatible.
21
+
10
22
  ## [0.7.6] - 2026-07-23
11
23
 
12
24
  ### Fixed
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 `resolveEnvKey() !== 'production'`.
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 tryCatchSync2, resolveEnvKey as resolveEnvKey5, dispatchHook as dispatchHook8 } from "@luckystack/core";
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";
@@ -24,7 +24,7 @@ import {
24
24
  normalizeOrigin,
25
25
  readSession as readSession3,
26
26
  tryCatch as tryCatch7,
27
- tryCatchSync
27
+ tryCatchSync as tryCatchSync2
28
28
  } from "@luckystack/core";
29
29
 
30
30
  // src/logSanitize.ts
@@ -475,11 +475,11 @@ import {
475
475
  } from "@luckystack/core";
476
476
 
477
477
  // src/httpRoutes/sessionCookie.ts
478
- import { resolveEnvKey as resolveEnvKey2 } from "@luckystack/core";
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 resolveEnvKey2() === "production";
482
+ return isProductionRuntime();
483
483
  };
484
484
 
485
485
  // src/httpRoutes/authApiRoute.ts
@@ -921,7 +921,8 @@ import {
921
921
  dispatchHook as dispatchHook3,
922
922
  extractTokenFromRequest,
923
923
  getLogger as getLogger4,
924
- tryCatch as tryCatch4
924
+ tryCatch as tryCatch4,
925
+ tryCatchSync
925
926
  } from "@luckystack/core";
926
927
  import { handleHttpApiRequest } from "@luckystack/api";
927
928
 
@@ -1038,8 +1039,25 @@ var handleApiRoute = async ({
1038
1039
  res.end(JSON.stringify(response));
1039
1040
  return true;
1040
1041
  }
1041
- const apiData = typeof params === "object" ? { ...params } : {};
1042
+ let apiData = typeof params === "object" ? { ...params } : {};
1042
1043
  delete apiData.stream;
1044
+ const routedData = apiData.__luckystack_data;
1045
+ if (typeof routedData === "string") {
1046
+ const [parseError, parsed] = tryCatchSync(() => JSON.parse(routedData));
1047
+ if (parseError || parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
1048
+ const response = {
1049
+ status: "error",
1050
+ httpStatus: 400,
1051
+ message: "api.invalidRequestFormat",
1052
+ errorCode: "api.invalidRequestFormat"
1053
+ };
1054
+ res.setHeader("Content-Type", "application/json");
1055
+ res.writeHead(400);
1056
+ res.end(JSON.stringify(response));
1057
+ return true;
1058
+ }
1059
+ apiData = { ...parsed };
1060
+ }
1043
1061
  const requesterIp = resolveRequesterIp(req);
1044
1062
  const result = await handleHttpApiRequest({
1045
1063
  name: apiName,
@@ -1390,7 +1408,7 @@ var setSecurityHeaders = (req, res, origin) => {
1390
1408
  res.setHeader("X-Content-Type-Options", securityHeaders.contentTypeOptions);
1391
1409
  const builder = getSecurityHeadersBuilder();
1392
1410
  if (builder) {
1393
- const [error] = tryCatchSync(() => {
1411
+ const [error] = tryCatchSync2(() => {
1394
1412
  const custom = builder(req);
1395
1413
  if (custom) {
1396
1414
  for (const [name, value] of Object.entries(custom)) {
@@ -1509,7 +1527,7 @@ var handleHttpRequestInner = async (req, res, options) => {
1509
1527
  );
1510
1528
  const url = req.url ?? "/";
1511
1529
  const [routePathRaw, queryStringRaw] = url.split("?");
1512
- const [decodeError, decodedPath] = tryCatchSync(() => decodeURIComponent(routePathRaw ?? "/"));
1530
+ const [decodeError, decodedPath] = tryCatchSync2(() => decodeURIComponent(routePathRaw ?? "/"));
1513
1531
  if (decodeError || decodedPath === null) {
1514
1532
  res.statusCode = 400;
1515
1533
  res.setHeader("Content-Type", "text/plain");
@@ -2002,7 +2020,7 @@ import {
2002
2020
  isLocalizedNormalizerRegistered,
2003
2021
  isProjectConfigRegistered,
2004
2022
  isRuntimeMapsProviderRegistered,
2005
- resolveEnvKey as resolveEnvKey3
2023
+ isProductionRuntime as isProductionRuntime2
2006
2024
  } from "@luckystack/core";
2007
2025
  var verifyBootstrap = async (requirements = {}) => {
2008
2026
  const missing = [];
@@ -2041,7 +2059,7 @@ var verifyBootstrap = async (requirements = {}) => {
2041
2059
  }
2042
2060
  }
2043
2061
  if (!isRuntimeMapsProviderRegistered()) {
2044
- if (resolveEnvKey3() === "production") {
2062
+ if (isProductionRuntime2()) {
2045
2063
  missing.push(
2046
2064
  "RuntimeMapsProvider \u2014 call `registerRuntimeMapsProvider({...})` from `server/prod/runtimeMaps.ts`. Without it, every api/sync request returns notFound."
2047
2065
  );
@@ -2052,7 +2070,7 @@ var verifyBootstrap = async (requirements = {}) => {
2052
2070
  }
2053
2071
  }
2054
2072
  if (!isLocalizedNormalizerRegistered()) {
2055
- if (resolveEnvKey3() === "production") {
2073
+ if (isProductionRuntime2()) {
2056
2074
  missing.push(
2057
2075
  "LocalizedNormalizer \u2014 call `registerLocalizedNormalizer({...})` from your bootstrap. Without it, error response messages will be the raw errorCode (no i18n)."
2058
2076
  );
@@ -2095,7 +2113,7 @@ var verifyBootstrap = async (requirements = {}) => {
2095
2113
  import {
2096
2114
  getLogger as getLogger10,
2097
2115
  registerRuntimeMapsProvider,
2098
- resolveEnvKey as resolveEnvKey4
2116
+ isProductionRuntime as isProductionRuntime3
2099
2117
  } from "@luckystack/core";
2100
2118
  var emptyRuntimeMaps = {
2101
2119
  apisObject: {},
@@ -2145,7 +2163,7 @@ var mergeInto = (target, source, kind, fromPreset, keyOrigin) => {
2145
2163
  target[key] = source[key];
2146
2164
  }
2147
2165
  };
2148
- var isProduction = () => resolveEnvKey4() === "production";
2166
+ var isProduction = () => isProductionRuntime3();
2149
2167
  var createProdRuntimeMapsProvider = (options) => {
2150
2168
  let prodMapsPromise = null;
2151
2169
  let devkitModulePromise = null;
@@ -2353,9 +2371,9 @@ var initDevTools = async () => {
2353
2371
  };
2354
2372
  var listenLuckyStackServer = (httpServer, ip, port, callback) => new Promise((resolve, reject) => {
2355
2373
  const startPort = normalizeServerPort(port);
2356
- const environmentKey = resolveEnvKey5();
2357
- const production = environmentKey === "production";
2358
- const test = environmentKey === "test";
2374
+ const runtimeMode = resolveRuntimeMode();
2375
+ const production = runtimeMode === "production";
2376
+ const test = runtimeMode === "test";
2359
2377
  const autoIncrementEnv = (process.env.SERVER_PORT_AUTO_INCREMENT ?? "").toLowerCase();
2360
2378
  let autoIncrement;
2361
2379
  if (["0", "false"].includes(autoIncrementEnv)) autoIncrement = false;
@@ -2398,8 +2416,8 @@ var listenLuckyStackServer = (httpServer, ip, port, callback) => new Promise((re
2398
2416
  process.once("exit", clearDevServerInfo);
2399
2417
  }
2400
2418
  if (attemptPort !== startPort && !production) {
2401
- const configuredCallbackBase = tryCatchSync2(() => getProjectConfig15().oauthCallbackBase)[1] ?? "";
2402
- const callbackPort = tryCatchSync2(() => {
2419
+ const configuredCallbackBase = tryCatchSync3(() => getProjectConfig15().oauthCallbackBase)[1] ?? "";
2420
+ const callbackPort = tryCatchSync3(() => {
2403
2421
  const callbackUrl = new URL(configuredCallbackBase);
2404
2422
  return callbackUrl.port || (callbackUrl.protocol === "https:" ? "443" : "80");
2405
2423
  })[1] ?? "";
@@ -2438,7 +2456,7 @@ var createLuckyStackServer = async (options = {}) => {
2438
2456
  envPort: process.env.SERVER_PORT
2439
2457
  });
2440
2458
  const ip = options.ip ?? process.env.SERVER_IP ?? "127.0.0.1";
2441
- const enableDevTools = options.enableDevTools ?? resolveEnvKey5() !== "production";
2459
+ const enableDevTools = options.enableDevTools ?? resolveRuntimeMode() !== "production";
2442
2460
  registerBindAddress({ ip, port });
2443
2461
  if (enableDevTools) {
2444
2462
  await initDevTools();