@skein-js/server-kit 0.13.1 → 0.14.0

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.
@@ -16,7 +16,8 @@ import {
16
16
  filterSkeinRoutes,
17
17
  skeinRoutes
18
18
  } from "@skein-js/agent-protocol";
19
- var ALWAYS_EXPOSED_HEADERS = ["content-location", "x-pagination-total"];
19
+ var ALWAYS_EXPOSED_HEADERS = ["content-location", "x-pagination-total", "idempotent-replay"];
20
+ var ALWAYS_ALLOWED_HEADERS = ["idempotency-key"];
20
21
  function toCorsOptions(config) {
21
22
  const options = {};
22
23
  const allowAll = config.allow_origins?.includes("*") ?? false;
@@ -31,7 +32,13 @@ function toCorsOptions(config) {
31
32
  options.origin = allowAll ? "*" : config.allow_origins;
32
33
  }
33
34
  if (config.allow_methods !== void 0) options.methods = config.allow_methods;
34
- if (config.allow_headers !== void 0) options.allowedHeaders = config.allow_headers;
35
+ if (config.allow_headers !== void 0) {
36
+ const configured = new Set(config.allow_headers.map((header) => header.toLowerCase()));
37
+ options.allowedHeaders = config.allow_headers.length === 0 ? [] : [
38
+ ...config.allow_headers,
39
+ ...ALWAYS_ALLOWED_HEADERS.filter((header) => !configured.has(header))
40
+ ];
41
+ }
35
42
  if (config.allow_credentials !== void 0) options.credentials = config.allow_credentials;
36
43
  if (config.max_age !== void 0) options.maxAge = config.max_age;
37
44
  const exposed = /* @__PURE__ */ new Set([...ALWAYS_EXPOSED_HEADERS, ...config.expose_headers ?? []]);
@@ -64,6 +71,31 @@ function disabledRoutesFromHttpConfig(http) {
64
71
  function routesFromHttpConfig(http) {
65
72
  return filterSkeinRoutes(skeinRoutes, disabledRoutesFromHttpConfig(http));
66
73
  }
74
+ function consoleMountFromHttpConfig(http) {
75
+ if (typeof http !== "object" || http === null) return void 0;
76
+ const value = http["console"];
77
+ if (value === true) return DEFAULT_CONSOLE_MOUNT;
78
+ if (typeof value !== "string") return void 0;
79
+ const trimmed = value.trim();
80
+ if (/^(false|0|off|no)$/i.test(trimmed)) return void 0;
81
+ if (/^(true|1|on|yes)$/i.test(trimmed)) return DEFAULT_CONSOLE_MOUNT;
82
+ if (trimmed === "" || trimmed === "/") return void 0;
83
+ const withLeadingSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
84
+ return withLeadingSlash.replace(/\/+$/, "");
85
+ }
86
+ var DEFAULT_CONSOLE_MOUNT = "/console";
87
+
88
+ // src/idempotency-config.ts
89
+ function resolveIdempotency(raw) {
90
+ if (!raw) return void 0;
91
+ const config = {};
92
+ if (typeof raw.retention_hours === "number") config.retentionHours = raw.retention_hours;
93
+ if (typeof raw.in_flight_minutes === "number") config.inFlightMinutes = raw.in_flight_minutes;
94
+ if (typeof raw.sweep_interval_minutes === "number") {
95
+ config.sweepIntervalMinutes = raw.sweep_interval_minutes;
96
+ }
97
+ return Object.keys(config).length > 0 ? config : void 0;
98
+ }
67
99
 
68
100
  // src/in-memory-deps.ts
69
101
  import { MemorySaver } from "@langchain/langgraph";
@@ -208,6 +240,7 @@ async function loadReloadableInMemoryRuntime(configPath, importModule, staticSch
208
240
  };
209
241
  const threadTtl = resolveThreadTtl(first.config.checkpointer?.ttl);
210
242
  const storeTtl = resolveStoreTtl(first.config.store?.ttl);
243
+ const idempotency = resolveIdempotency(first.config.skein?.idempotency);
211
244
  const store = new MemorySkeinStore2({
212
245
  maxPageSize: resolveMaxPageSize(),
213
246
  ...threadTtl ? { threadTtl } : {},
@@ -225,6 +258,8 @@ async function loadReloadableInMemoryRuntime(configPath, importModule, staticSch
225
258
  auth: await loadAuthEngine(first.config.auth, { configDir: first.configDir, importModule }),
226
259
  // Present only when configured — its presence is what starts the thread TTL sweeper.
227
260
  ...threadTtl ? { threadTtl } : {},
261
+ // Unlike `threadTtl`, absence here means *defaults*, not *off*: the header is honoured either way.
262
+ ...idempotency ? { idempotency } : {},
228
263
  ...extraDeps
229
264
  };
230
265
  return {
@@ -255,6 +290,8 @@ export {
255
290
  corsFromHttpConfig,
256
291
  disabledRoutesFromHttpConfig,
257
292
  routesFromHttpConfig,
293
+ consoleMountFromHttpConfig,
294
+ resolveIdempotency,
258
295
  resolveMaxPageSize,
259
296
  resolveMemoryBusLimits,
260
297
  normalizeEmbeddableGraphs,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  loadInMemoryRuntime,
3
3
  loadReloadableInMemoryRuntime
4
- } from "./chunk-LJGZJ5L7.js";
4
+ } from "./chunk-XDS3YWFL.js";
5
5
  import "./chunk-JUBBCC7R.js";
6
6
  export {
7
7
  loadInMemoryRuntime,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ProtocolRuntime, RouteBinding, Logger, ProtocolDeps, RunWorkerOptions, CronSchedulerOptions, RunFailureReport, GraphResolver, RouteMatcher, DisabledRouteGroups, ProtocolResponse } from '@skein-js/agent-protocol';
1
+ import { ProtocolRuntime, RouteBinding, Logger, ProtocolDeps, RunWorkerOptions, CronSchedulerOptions, RunFailureReport, IdempotencyConfig, GraphResolver, RouteMatcher, DisabledRouteGroups, ProtocolResponse } from '@skein-js/agent-protocol';
2
2
  export { CompiledGraphFactory, DEFAULT_RUN_CONCURRENCY, DEFAULT_SHUTDOWN_GRACE_MS, GraphResolver, Logger, ProtocolDeps, ResolvedGraph, RunWorkerOptions } from '@skein-js/agent-protocol';
3
3
  import { ModuleImporter, LanggraphJson, GraphSchemas } from '@skein-js/config';
4
4
  import { CorsOptions } from 'cors';
@@ -480,6 +480,23 @@ interface RawStoreTtl {
480
480
  */
481
481
  declare function resolveStoreTtl(raw: RawStoreTtl | undefined): StoreTtlConfig | undefined;
482
482
 
483
+ /** The raw `skein.idempotency` block as `langgraph.json` spells it. */
484
+ interface RawIdempotency {
485
+ retention_hours?: number;
486
+ in_flight_minutes?: number;
487
+ sweep_interval_minutes?: number;
488
+ }
489
+ /**
490
+ * Map the raw block to {@link IdempotencyConfig}, or `undefined` when nothing is set.
491
+ *
492
+ * Note what `undefined` means here, because it differs from its neighbours: **defaults, not
493
+ * disabled.** `resolveStoreTtl` returning `undefined` genuinely means items never expire, but a
494
+ * caller who sends `Idempotency-Key` has been promised their retry will not start a second run —
495
+ * there is no configuration under which the header stops being honoured, only one that tunes how
496
+ * long the promise lasts.
497
+ */
498
+ declare function resolveIdempotency(raw: RawIdempotency | undefined): IdempotencyConfig | undefined;
499
+
483
500
  type AnyCompiledGraph = CompiledGraph<any>;
484
501
  /**
485
502
  * A graph you can embed in code: any compiled LangGraph.js graph, or a factory that builds one per run
@@ -557,6 +574,17 @@ declare function disabledRoutesFromHttpConfig(http: unknown): DisabledRouteGroup
557
574
  * nothing is disabled (the same array, not a copy).
558
575
  */
559
576
  declare function routesFromHttpConfig(http: unknown): readonly RouteBinding[];
577
+ /**
578
+ * Where the console should be mounted per a langgraph.json `http.console` block, or `undefined` for
579
+ * "do not serve it".
580
+ *
581
+ * Deliberately opt-in, and deliberately strict about what counts as opting in. The console can read
582
+ * and delete every thread, every stored memory, and every schedule on the server; a config that meant
583
+ * to disable it — a `"false"` left by env substitution, a `0`, a typo — must never be read as
584
+ * enabling it. `skein dev` does not go through here at all: it serves the console by default, because
585
+ * a local dev server is exactly where you want one.
586
+ */
587
+ declare function consoleMountFromHttpConfig(http: unknown): string | undefined;
560
588
 
561
589
  type CorsSetting = true | CorsOptions;
562
590
  /**
@@ -675,4 +703,4 @@ type RuntimeGlobal = typeof globalThis & {
675
703
  /** Detect Node, Bun, or Deno without importing a runtime-specific module. */
676
704
  declare function detectRuntimeCapabilities(scope?: RuntimeGlobal): RuntimeCapabilities;
677
705
 
678
- export { type ConsoleLogLevel, type ConsoleLoggerOptions, type CorsSetting, DEFAULT_HEAP_SAMPLE_MS, DEFAULT_HEAP_WARN_PERCENT, DevStateSnapshot, type EmbeddableGraph, type FileReader, HEAP_REARM_MARGIN_PERCENT, HEAP_REARM_PERCENT, type HeapHeadroom, type HeapPressureContext, type HeapPressureMonitor, type HeapPressureMonitorOptions, type InMemoryRuntimeConfig, type IntervalHandle, type LanggraphCorsConfig, type RawStoreTtl, type RawThreadTtl, type ReloadableInMemoryRuntime, type ResolvedMemoryBusLimits, type ResolvedProtocolRuntime, type ResolvedRuntimeDeps, type RuntimeCapabilities, type RuntimeMemorySnapshot, type RuntimeSignalSubscription, type SkeinRuntimeCommonOptions, type SkeinRuntimeOptions, allowedOrigin, applyNodeCors, checkHeapHeadroom, corsFromHttpConfig, corsPreflightHeaders, corsResponseHeaders, createConsoleLogger, createInMemoryDeps, describeError, describeHeapHeadroom, describePoolPressure, detectRuntimeCapabilities, disabledRoutesFromHttpConfig, embedInMemoryGraphs, formatLogMeta, graphMapToResolver, joinList, loadInMemoryRuntime, loadReloadableInMemoryRuntime, normalizeEmbeddableGraphs, readContainerMemoryLimit, resolveCronTickMs, resolveHeapPressureOptions, resolveMaxPageSize, resolveMemoryBusLimits, resolveProtocolRuntime, resolveRunConcurrency, resolveRunTimeoutMs, resolveRuntimeDeps, resolveShutdownGraceMs, resolveStoreTtl, resolveThreadTtl, routeMatcherFor, routesFromHttpConfig, runFailureIdentity, sendNodeError, sendNodePreflight, sendNodeResponse, startHeapPressureMonitor, stripBasePath, toCorsOptions };
706
+ export { type ConsoleLogLevel, type ConsoleLoggerOptions, type CorsSetting, DEFAULT_HEAP_SAMPLE_MS, DEFAULT_HEAP_WARN_PERCENT, DevStateSnapshot, type EmbeddableGraph, type FileReader, HEAP_REARM_MARGIN_PERCENT, HEAP_REARM_PERCENT, type HeapHeadroom, type HeapPressureContext, type HeapPressureMonitor, type HeapPressureMonitorOptions, type InMemoryRuntimeConfig, type IntervalHandle, type LanggraphCorsConfig, type RawIdempotency, type RawStoreTtl, type RawThreadTtl, type ReloadableInMemoryRuntime, type ResolvedMemoryBusLimits, type ResolvedProtocolRuntime, type ResolvedRuntimeDeps, type RuntimeCapabilities, type RuntimeMemorySnapshot, type RuntimeSignalSubscription, type SkeinRuntimeCommonOptions, type SkeinRuntimeOptions, allowedOrigin, applyNodeCors, checkHeapHeadroom, consoleMountFromHttpConfig, corsFromHttpConfig, corsPreflightHeaders, corsResponseHeaders, createConsoleLogger, createInMemoryDeps, describeError, describeHeapHeadroom, describePoolPressure, detectRuntimeCapabilities, disabledRoutesFromHttpConfig, embedInMemoryGraphs, formatLogMeta, graphMapToResolver, joinList, loadInMemoryRuntime, loadReloadableInMemoryRuntime, normalizeEmbeddableGraphs, readContainerMemoryLimit, resolveCronTickMs, resolveHeapPressureOptions, resolveIdempotency, resolveMaxPageSize, resolveMemoryBusLimits, resolveProtocolRuntime, resolveRunConcurrency, resolveRunTimeoutMs, resolveRuntimeDeps, resolveShutdownGraceMs, resolveStoreTtl, resolveThreadTtl, routeMatcherFor, routesFromHttpConfig, runFailureIdentity, sendNodeError, sendNodePreflight, sendNodeResponse, startHeapPressureMonitor, stripBasePath, toCorsOptions };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ consoleMountFromHttpConfig,
2
3
  corsFromHttpConfig,
3
4
  createInMemoryDeps,
4
5
  disabledRoutesFromHttpConfig,
@@ -9,13 +10,14 @@ import {
9
10
  normalizeEmbeddableGraphs,
10
11
  positiveIntegerFromEnv,
11
12
  requirePositiveInteger,
13
+ resolveIdempotency,
12
14
  resolveMaxPageSize,
13
15
  resolveMemoryBusLimits,
14
16
  resolveStoreTtl,
15
17
  resolveThreadTtl,
16
18
  routesFromHttpConfig,
17
19
  toCorsOptions
18
- } from "./chunk-LJGZJ5L7.js";
20
+ } from "./chunk-XDS3YWFL.js";
19
21
  import "./chunk-JUBBCC7R.js";
20
22
 
21
23
  // src/resolve-runtime.ts
@@ -164,7 +166,7 @@ function resolveLogger(option, injected, frameworkLogger) {
164
166
  return option ?? frameworkLogger;
165
167
  }
166
168
  async function resolveRuntimeDeps(options, frameworkLogger) {
167
- const loaded = options.deps ? { deps: options.deps, cors: void 0, routes: skeinRoutes } : await (await import("./in-memory-runtime-KII6KQ4U.js")).loadInMemoryRuntime(options.config, options.importModule);
169
+ const loaded = options.deps ? { deps: options.deps, cors: void 0, routes: skeinRoutes } : await (await import("./in-memory-runtime-BUUSE63C.js")).loadInMemoryRuntime(options.config, options.importModule);
168
170
  const logger = resolveLogger(options.logger, loaded.deps.logger, frameworkLogger);
169
171
  if (logger && !loaded.deps.logger) loaded.deps.logger = logger;
170
172
  return { deps: loaded.deps, cors: loaded.cors, routes: loaded.routes, logger };
@@ -655,6 +657,7 @@ export {
655
657
  allowedOrigin,
656
658
  applyNodeCors,
657
659
  checkHeapHeadroom,
660
+ consoleMountFromHttpConfig,
658
661
  corsFromHttpConfig,
659
662
  corsPreflightHeaders,
660
663
  corsResponseHeaders,
@@ -675,6 +678,7 @@ export {
675
678
  readContainerMemoryLimit,
676
679
  resolveCronTickMs,
677
680
  resolveHeapPressureOptions,
681
+ resolveIdempotency,
678
682
  resolveMaxPageSize,
679
683
  resolveMemoryBusLimits,
680
684
  resolveProtocolRuntime,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skein-js/server-kit",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
4
4
  "description": "Shared, framework-agnostic building blocks for skein-js HTTP adapters — in-memory dev runtime, LangGraph dev-state import, and langgraph.json CORS mapping.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Maina Wycliffe <wmmaina7@gmail.com>",
@@ -49,10 +49,10 @@
49
49
  "cors": "^2.8.5",
50
50
  "superjson": "^2.2.6",
51
51
  "zod": "^3.25.76",
52
- "@skein-js/core": "0.13.1",
53
- "@skein-js/storage-memory": "0.13.1",
54
- "@skein-js/config": "0.13.1",
55
- "@skein-js/agent-protocol": "0.13.1"
52
+ "@skein-js/agent-protocol": "0.14.0",
53
+ "@skein-js/config": "0.14.0",
54
+ "@skein-js/core": "0.14.0",
55
+ "@skein-js/storage-memory": "0.14.0"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "@langchain/langgraph": "^1.4.0"