@remnic/core 1.1.29 → 1.1.31

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.
Files changed (100) hide show
  1. package/dist/access-cli.js +13 -13
  2. package/dist/access-http.d.ts +2 -1
  3. package/dist/access-http.js +8 -8
  4. package/dist/access-mcp.d.ts +1 -1
  5. package/dist/access-mcp.js +7 -7
  6. package/dist/access-schema.d.ts +55 -5
  7. package/dist/access-schema.js +4 -2
  8. package/dist/{access-service-CEyV8XJ5.d.ts → access-service-CkZyb35d.d.ts} +10 -2
  9. package/dist/access-service.d.ts +1 -1
  10. package/dist/access-service.js +5 -5
  11. package/dist/briefing.js +2 -2
  12. package/dist/causal-consolidation.js +3 -3
  13. package/dist/{chunk-25YQM6XW.js → chunk-2IWUMAES.js} +3 -3
  14. package/dist/{chunk-6CB4E7ZV.js → chunk-3ZLVGM76.js} +4 -4
  15. package/dist/{chunk-QYHQ2JHL.js → chunk-43PJZYGL.js} +2 -2
  16. package/dist/{chunk-YITUHONZ.js → chunk-4KGVTPGD.js} +2 -2
  17. package/dist/{chunk-TR4DK5OH.js → chunk-76FLAAUC.js} +2 -2
  18. package/dist/{chunk-6BFAEWQS.js → chunk-77H5NU3M.js} +2 -2
  19. package/dist/{chunk-IANK6Y5W.js → chunk-A6KTB5R6.js} +2 -2
  20. package/dist/{chunk-7D6O46PF.js → chunk-BVF3AGJP.js} +2 -2
  21. package/dist/{chunk-4H6DURG6.js → chunk-JA3AK3PT.js} +2 -2
  22. package/dist/{chunk-RCZRL5BE.js → chunk-MRILGULB.js} +2 -2
  23. package/dist/{chunk-CWWDIQZB.js → chunk-QLLBRHAT.js} +8 -8
  24. package/dist/{chunk-2WIPXV3Y.js → chunk-RR2PKP3I.js} +2 -2
  25. package/dist/{chunk-3F24QTRI.js → chunk-SAZS2QZB.js} +2 -2
  26. package/dist/{chunk-VYU7PXUS.js → chunk-SIC6U3GZ.js} +2 -2
  27. package/dist/{chunk-WDSIV3AK.js → chunk-TPU5L5EY.js} +12 -12
  28. package/dist/{chunk-AMVN77EU.js → chunk-U7EJOMFC.js} +371 -91
  29. package/dist/chunk-U7EJOMFC.js.map +1 -0
  30. package/dist/{chunk-F33CJ5CH.js → chunk-VBJ7V5SK.js} +40 -8
  31. package/dist/chunk-VBJ7V5SK.js.map +1 -0
  32. package/dist/{chunk-6WV2HYTZ.js → chunk-W6AQJ2PY.js} +4 -4
  33. package/dist/{chunk-PUXCIHRL.js → chunk-XSZEP4SF.js} +2 -2
  34. package/dist/{chunk-NW7JW5GA.js → chunk-YROHKYBY.js} +41 -6
  35. package/dist/chunk-YROHKYBY.js.map +1 -0
  36. package/dist/{chunk-JUYT2J3K.js → chunk-YU5KIWYQ.js} +136 -8
  37. package/dist/chunk-YU5KIWYQ.js.map +1 -0
  38. package/dist/{chunk-LCTP7YRU.js → chunk-ZAVUCJ4H.js} +38 -7
  39. package/dist/chunk-ZAVUCJ4H.js.map +1 -0
  40. package/dist/{cli-BguVmIwO.d.ts → cli-kuh9PwZ5.d.ts} +1 -1
  41. package/dist/cli.d.ts +2 -2
  42. package/dist/cli.js +17 -17
  43. package/dist/compounding/engine.js +2 -2
  44. package/dist/connectors/codex-materialize-runner.js +2 -2
  45. package/dist/connectors/index.js +2 -2
  46. package/dist/entity-retrieval.js +2 -2
  47. package/dist/index.d.ts +4 -4
  48. package/dist/index.js +34 -22
  49. package/dist/index.js.map +1 -1
  50. package/dist/maintenance/memory-governance.js +2 -2
  51. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +2 -2
  52. package/dist/maintenance/rebuild-memory-projection.js +3 -3
  53. package/dist/mcp-memory-inspector-app.d.ts +1 -1
  54. package/dist/namespaces/migrate.js +3 -3
  55. package/dist/namespaces/storage.js +2 -2
  56. package/dist/offline-sync.d.ts +56 -1
  57. package/dist/offline-sync.js +15 -1
  58. package/dist/operator-toolkit.js +5 -5
  59. package/dist/orchestrator.js +9 -9
  60. package/dist/schemas.d.ts +22 -22
  61. package/dist/semantic-consolidation.js +3 -3
  62. package/dist/semantic-rule-promotion.js +2 -2
  63. package/dist/semantic-rule-verifier.js +2 -2
  64. package/dist/storage.d.ts +5 -0
  65. package/dist/storage.js +1 -1
  66. package/dist/transfer/types.d.ts +12 -12
  67. package/dist/verified-recall.js +2 -2
  68. package/package.json +1 -1
  69. package/src/access-http.test.ts +355 -0
  70. package/src/access-http.ts +149 -1
  71. package/src/access-schema.ts +58 -3
  72. package/src/access-service-namespace.test.ts +56 -1
  73. package/src/access-service-offline-file-content.test.ts +17 -0
  74. package/src/access-service.ts +47 -1
  75. package/src/index.ts +7 -0
  76. package/src/offline-sync.test.ts +1055 -1
  77. package/src/offline-sync.ts +465 -97
  78. package/src/storage.ts +36 -2
  79. package/dist/chunk-AMVN77EU.js.map +0 -1
  80. package/dist/chunk-F33CJ5CH.js.map +0 -1
  81. package/dist/chunk-JUYT2J3K.js.map +0 -1
  82. package/dist/chunk-LCTP7YRU.js.map +0 -1
  83. package/dist/chunk-NW7JW5GA.js.map +0 -1
  84. /package/dist/{chunk-25YQM6XW.js.map → chunk-2IWUMAES.js.map} +0 -0
  85. /package/dist/{chunk-6CB4E7ZV.js.map → chunk-3ZLVGM76.js.map} +0 -0
  86. /package/dist/{chunk-QYHQ2JHL.js.map → chunk-43PJZYGL.js.map} +0 -0
  87. /package/dist/{chunk-YITUHONZ.js.map → chunk-4KGVTPGD.js.map} +0 -0
  88. /package/dist/{chunk-TR4DK5OH.js.map → chunk-76FLAAUC.js.map} +0 -0
  89. /package/dist/{chunk-6BFAEWQS.js.map → chunk-77H5NU3M.js.map} +0 -0
  90. /package/dist/{chunk-IANK6Y5W.js.map → chunk-A6KTB5R6.js.map} +0 -0
  91. /package/dist/{chunk-7D6O46PF.js.map → chunk-BVF3AGJP.js.map} +0 -0
  92. /package/dist/{chunk-4H6DURG6.js.map → chunk-JA3AK3PT.js.map} +0 -0
  93. /package/dist/{chunk-RCZRL5BE.js.map → chunk-MRILGULB.js.map} +0 -0
  94. /package/dist/{chunk-CWWDIQZB.js.map → chunk-QLLBRHAT.js.map} +0 -0
  95. /package/dist/{chunk-2WIPXV3Y.js.map → chunk-RR2PKP3I.js.map} +0 -0
  96. /package/dist/{chunk-3F24QTRI.js.map → chunk-SAZS2QZB.js.map} +0 -0
  97. /package/dist/{chunk-VYU7PXUS.js.map → chunk-SIC6U3GZ.js.map} +0 -0
  98. /package/dist/{chunk-WDSIV3AK.js.map → chunk-TPU5L5EY.js.map} +0 -0
  99. /package/dist/{chunk-6WV2HYTZ.js.map → chunk-W6AQJ2PY.js.map} +0 -0
  100. /package/dist/{chunk-PUXCIHRL.js.map → chunk-XSZEP4SF.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listNamespaces
3
- } from "./chunk-6BFAEWQS.js";
3
+ } from "./chunk-77H5NU3M.js";
4
4
  import {
5
5
  runConsolidationProvenanceCheck
6
6
  } from "./chunk-5HRY2WRF.js";
@@ -36,13 +36,13 @@ import {
36
36
  import {
37
37
  listMemoryGovernanceRuns,
38
38
  readMemoryGovernanceRunArtifact
39
- } from "./chunk-TR4DK5OH.js";
39
+ } from "./chunk-76FLAAUC.js";
40
40
  import {
41
41
  analyzeGraphHealth
42
42
  } from "./chunk-RK2Y4XOM.js";
43
43
  import {
44
44
  StorageManager
45
- } from "./chunk-F33CJ5CH.js";
45
+ } from "./chunk-VBJ7V5SK.js";
46
46
  import {
47
47
  lintWorkspaceFiles
48
48
  } from "./chunk-DM2T26WE.js";
@@ -1314,4 +1314,4 @@ export {
1314
1314
  runBenchmarkRecall,
1315
1315
  runOperatorRepair
1316
1316
  };
1317
- //# sourceMappingURL=chunk-6WV2HYTZ.js.map
1317
+ //# sourceMappingURL=chunk-W6AQJ2PY.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runPostConsolidationMaterialize
3
- } from "./chunk-YITUHONZ.js";
3
+ } from "./chunk-4KGVTPGD.js";
4
4
  import {
5
5
  discoverMemoryExtensions,
6
6
  renderExtensionsBlock,
@@ -216,4 +216,4 @@ export {
216
216
  buildExtensionsBlockForConsolidation,
217
217
  materializeAfterSemanticConsolidation
218
218
  };
219
- //# sourceMappingURL=chunk-PUXCIHRL.js.map
219
+ //# sourceMappingURL=chunk-XSZEP4SF.js.map
@@ -5,8 +5,12 @@ import {
5
5
  CAPSULE_ID_PATTERN
6
6
  } from "./chunk-WEHSQBFR.js";
7
7
  import {
8
- OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES
9
- } from "./chunk-AMVN77EU.js";
8
+ OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
9
+ OFFLINE_SYNC_MAX_MTIME_MS
10
+ } from "./chunk-U7EJOMFC.js";
11
+ import {
12
+ validateArchiveRelativePath
13
+ } from "./chunk-AGZQD76C.js";
10
14
  import {
11
15
  ACTION_CONFIDENCE_CONTEXT_READINESS,
12
16
  ACTION_CONFIDENCE_RISK_CATEGORIES,
@@ -249,9 +253,38 @@ var capsuleImportRequestSchema = z.object({
249
253
  var capsuleListRequestSchema = z.object({
250
254
  namespace: namespaceSchema
251
255
  });
256
+ function isValidOfflineSyncPath(value) {
257
+ try {
258
+ validateArchiveRelativePath(value, "path");
259
+ return true;
260
+ } catch {
261
+ return false;
262
+ }
263
+ }
264
+ var offlineSyncPathSchema = z.string().trim().min(1, "path must be non-empty").max(4096).refine(
265
+ isValidOfflineSyncPath,
266
+ "path must be a POSIX relative path without unsafe segments"
267
+ );
268
+ var offlineSyncFileStateSchema = z.object({
269
+ path: offlineSyncPathSchema,
270
+ sha256: z.string().regex(/^[a-f0-9]{64}$/i, "sha256 must be a 64-character hex digest"),
271
+ bytes: z.number().int().min(0),
272
+ mtimeMs: z.number().finite().min(0).max(OFFLINE_SYNC_MAX_MTIME_MS)
273
+ });
274
+ var offlineSyncBaseCapturedAtSchema = z.string().trim().min(1, "baseCapturedAt must be non-empty when provided").max(64).refine((value) => Number.isFinite(Date.parse(value)), {
275
+ message: "baseCapturedAt must be a valid ISO 8601 timestamp"
276
+ });
277
+ var offlineSyncSnapshotRequestSchema = z.object({
278
+ namespace: namespaceSchema,
279
+ includeTranscripts: z.boolean().optional(),
280
+ includeContent: z.boolean().optional(),
281
+ baseCapturedAt: offlineSyncBaseCapturedAtSchema.optional(),
282
+ baseFiles: z.array(offlineSyncFileStateSchema).max(3e5, "baseFiles must contain 300000 or fewer entries").optional()
283
+ });
252
284
  var offlineSyncApplyRequestSchema = z.object({
253
285
  namespace: namespaceSchema,
254
- changeset: z.unknown()
286
+ changeset: z.unknown(),
287
+ returnCurrentFiles: z.boolean().optional()
255
288
  }).refine((value) => value.changeset !== void 0 && value.changeset !== null, {
256
289
  message: "changeset is required",
257
290
  path: ["changeset"]
@@ -259,12 +292,12 @@ var offlineSyncApplyRequestSchema = z.object({
259
292
  var offlineSyncFilesRequestSchema = z.object({
260
293
  namespace: namespaceSchema,
261
294
  includeTranscripts: z.boolean().optional(),
262
- paths: z.array(z.string().trim().min(1, "path must be non-empty").max(4096)).max(5e3, "paths must contain 5000 or fewer entries")
295
+ paths: z.array(offlineSyncPathSchema).max(5e3, "paths must contain 5000 or fewer entries")
263
296
  });
264
297
  var offlineSyncFileContentRequestSchema = z.object({
265
298
  namespace: namespaceSchema,
266
299
  includeTranscripts: z.boolean().optional(),
267
- path: z.string().trim().min(1, "path must be non-empty").max(4096),
300
+ path: offlineSyncPathSchema,
268
301
  offset: z.number().int().min(0).optional(),
269
302
  length: z.number().int().min(1).max(OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES).optional()
270
303
  });
@@ -315,6 +348,7 @@ var schemas = {
315
348
  capsuleExport: capsuleExportRequestSchema,
316
349
  capsuleImport: capsuleImportRequestSchema,
317
350
  capsuleList: capsuleListRequestSchema,
351
+ offlineSyncSnapshot: offlineSyncSnapshotRequestSchema,
318
352
  offlineSyncFiles: offlineSyncFilesRequestSchema,
319
353
  offlineSyncFileContent: offlineSyncFileContentRequestSchema,
320
354
  offlineSyncApply: offlineSyncApplyRequestSchema,
@@ -360,10 +394,11 @@ export {
360
394
  capsuleExportRequestSchema,
361
395
  capsuleImportRequestSchema,
362
396
  capsuleListRequestSchema,
397
+ offlineSyncSnapshotRequestSchema,
363
398
  offlineSyncApplyRequestSchema,
364
399
  offlineSyncFilesRequestSchema,
365
400
  offlineSyncFileContentRequestSchema,
366
401
  actionConfidenceRequestSchema,
367
402
  validateRequest
368
403
  };
369
- //# sourceMappingURL=chunk-NW7JW5GA.js.map
404
+ //# sourceMappingURL=chunk-YROHKYBY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/access-schema.ts"],"sourcesContent":["// Request/response schema validation for the Remnic HTTP API.\n// Uses zod for runtime validation — returns structured 400 errors with\n// field-level detail so consumers get clear feedback on malformed requests.\n\nimport { z } from \"zod\";\nimport {\n ACTION_CONFIDENCE_CONTEXT_READINESS,\n ACTION_CONFIDENCE_RISK_CATEGORIES,\n ACTION_CONFIDENCE_RULE_KINDS,\n} from \"./action-confidence.js\";\nimport { isValidCapsuleSince } from \"./transfer/capsule-export.js\";\nimport { validateArchiveRelativePath } from \"./transfer/fs-utils.js\";\nimport { CAPSULE_ID_PATTERN } from \"./transfer/types.js\";\nimport {\n OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,\n OFFLINE_SYNC_MAX_MTIME_MS,\n} from \"./offline-sync.js\";\n\n// ---------------------------------------------------------------------------\n// Error formatting\n// ---------------------------------------------------------------------------\n\nexport interface SchemaValidationError {\n error: string;\n code: \"validation_error\";\n details: Array<{ field: string; message: string }>;\n}\n\nexport function formatZodError(error: z.ZodError): SchemaValidationError {\n return {\n error: \"request validation failed\",\n code: \"validation_error\",\n details: error.issues.map((issue) => ({\n field: issue.path.join(\".\") || \"(root)\",\n message: issue.message,\n })),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Shared fields\n// ---------------------------------------------------------------------------\n\nconst namespaceSchema = z.string().trim().max(256).optional();\nconst sessionKeySchema = z.string().trim().min(1).max(512).optional();\nconst idempotencyKeySchema = z.string().trim().min(1).max(256).optional();\nconst dryRunSchema = z.boolean().optional();\nconst schemaVersionSchema = z.number().int().optional();\n\n// ---------------------------------------------------------------------------\n// Recall\n// ---------------------------------------------------------------------------\n\n/**\n * Coding-agent context (issue #569). Optional payload that connectors may\n * ship with a recall request so the project/branch namespace overlay\n * applies to that recall. All fields are validated per CLAUDE.md #51 —\n * empty-string projectId / rootPath is rejected, not silently accepted.\n */\nexport const codingContextSchema = z\n .object({\n projectId: z.string().trim().min(1, \"codingContext.projectId is required\").max(128),\n branch: z.string().trim().max(256).nullable(),\n rootPath: z.string().trim().min(1, \"codingContext.rootPath is required\").max(1024),\n defaultBranch: z.string().trim().max(256).nullable(),\n })\n .nullable();\n\n/**\n * Recall disclosure depth (issue #677). Mirrors the `RecallDisclosure`\n * type in `types.ts` — keep these in sync. Default-application happens\n * inside `EngramAccessService.recall()`; the schema only accepts/rejects.\n * Invalid values throw a structured 400 instead of silently defaulting,\n * per CLAUDE.md rule 51.\n */\nexport const recallDisclosureSchema = z.enum([\"chunk\", \"section\", \"raw\"]);\n\n/**\n * Tag-match semantics (issue #689). `any` (default when `tags` is provided\n * and `tagMatch` is omitted) admits a result when it carries at least one\n * of the filter tags. `all` requires every filter tag to be present.\n * Schema rejects unknown values up front — never silently defaults\n * (CLAUDE.md rule 51).\n */\nexport const tagMatchSchema = z.enum([\"any\", \"all\"]);\n\nexport const recallRequestSchema = z.object({\n query: z.string().min(1, \"query is required\"),\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n topK: z.number().int().min(0).max(200).optional(),\n mode: z.enum([\"auto\", \"no_recall\", \"minimal\", \"full\", \"graph_mode\"]).optional(),\n includeDebug: z.boolean().optional(),\n idempotencyKey: idempotencyKeySchema,\n disclosure: recallDisclosureSchema.optional(),\n codingContext: codingContextSchema.optional(),\n /** Working directory for auto git-context resolution (issue #569). */\n cwd: z.string().trim().min(1, \"cwd must be non-empty when provided\").max(2048).optional(),\n /**\n * Arbitrary project tag for non-git-based project scoping (issue #569).\n * Creates a coding context with `projectId: \"tag:<projectTag>\"`.\n */\n projectTag: z.string().trim().min(1, \"projectTag must be non-empty when provided\").max(256).optional(),\n /**\n * Historical recall pin (issue #680). ISO 8601 timestamp. The\n * schema only enforces the basic shape; the access service runs\n * `Date.parse` and emits a structured 400 on malformed input\n * (CLAUDE.md rule 51).\n */\n asOf: z.string().trim().min(1, \"asOf must be a non-empty ISO 8601 timestamp\").max(64).optional(),\n /**\n * Free-form recall tag filter (issue #689). When provided, recall results\n * whose frontmatter `tags` do not match the filter are removed before the\n * response is returned. Comparison is case-sensitive exact match.\n */\n tags: z.array(z.string().trim().min(1).max(256)).max(50).optional(),\n /**\n * Match mode for `tags` (issue #689). Defaults to `\"any\"` when `tags` is\n * provided and `tagMatch` is omitted. Ignored when `tags` is absent.\n */\n tagMatch: tagMatchSchema.optional(),\n /**\n * Include graph edges below `graphTraversalConfidenceFloor` for diagnostic\n * recall traversal (issue #681). Defaults to false.\n */\n includeLowConfidence: z.boolean().optional(),\n});\n\nexport const recallExplainRequestSchema = z.object({\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n});\n\n/**\n * Standalone \"set coding context\" request. Used by the HTTP endpoint\n * `POST /engram/v1/coding-context` and the MCP `remnic.set_coding_context`\n * tool (PR 7). `codingContext: null` clears the attached context.\n */\nexport const setCodingContextRequestSchema = z.object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n codingContext: codingContextSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Observe\n// ---------------------------------------------------------------------------\n\nconst messageSchema = z.object({\n role: z.enum([\"user\", \"assistant\"]),\n content: z.string().min(1, \"message content must be non-empty\"),\n sourceFormat: z\n .enum([\"openai\", \"anthropic\", \"openclaw\", \"pi\", \"lossless-claw\", \"remnic\"])\n .nullable()\n .optional(),\n rawContent: z.unknown().nullable().optional(),\n parts: z\n .array(\n z.object({\n ordinal: z.number().int().min(0).nullable().optional(),\n kind: z.enum([\n \"text\",\n \"tool_call\",\n \"tool_result\",\n \"patch\",\n \"file_read\",\n \"file_write\",\n \"step_start\",\n \"step_finish\",\n \"snapshot\",\n \"retry\",\n ]),\n payload: z.record(z.string(), z.unknown()),\n toolName: z.string().nullable().optional(),\n tool_name: z.string().nullable().optional(),\n filePath: z.string().nullable().optional(),\n file_path: z.string().nullable().optional(),\n createdAt: z.string().nullable().optional(),\n created_at: z.string().nullable().optional(),\n }),\n )\n .nullable()\n .optional(),\n});\n\nexport const observeRequestSchema = z.object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n messages: z.array(messageSchema).min(1, \"messages must be a non-empty array\"),\n namespace: namespaceSchema,\n skipExtraction: z.boolean().optional(),\n /** Working directory for auto git-context resolution (issue #569). */\n cwd: z.string().trim().min(1, \"cwd must be non-empty when provided\").max(2048).optional(),\n /**\n * Arbitrary project tag for non-git-based project scoping (issue #569).\n * Creates a coding context with `projectId: \"tag:<projectTag>\"`.\n */\n projectTag: z.string().trim().min(1, \"projectTag must be non-empty when provided\").max(256).optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Memory store / suggestion submit\n// ---------------------------------------------------------------------------\n\nconst writeContentSchema = z.string().min(1, \"content is required\").max(50000);\nconst categorySchema = z\n .enum([\n \"fact\", \"preference\", \"correction\", \"entity\", \"decision\",\n \"relationship\", \"principle\", \"commitment\", \"moment\", \"skill\", \"rule\", \"procedure\",\n \"reasoning_trace\",\n ])\n .optional();\nconst confidenceSchema = z.number().min(0).max(1).optional();\nconst tagsSchema = z.array(z.string().max(256)).max(50).optional();\nconst entityRefSchema = z.string().trim().max(512).optional();\nconst ttlSchema = z.string().trim().max(128).optional();\nconst sourceReasonSchema = z.string().trim().max(2000).optional();\n\nexport const memoryStoreRequestSchema = z.object({\n schemaVersion: schemaVersionSchema,\n idempotencyKey: idempotencyKeySchema,\n dryRun: dryRunSchema,\n sessionKey: sessionKeySchema,\n content: writeContentSchema,\n category: categorySchema,\n confidence: confidenceSchema,\n namespace: namespaceSchema,\n tags: tagsSchema,\n entityRef: entityRefSchema,\n ttl: ttlSchema,\n sourceReason: sourceReasonSchema,\n});\n\nexport const suggestionSubmitRequestSchema = memoryStoreRequestSchema;\n\n// ---------------------------------------------------------------------------\n// Review disposition\n// ---------------------------------------------------------------------------\n\nexport const reviewDispositionRequestSchema = z.object({\n memoryId: z.string().trim().min(1, \"memoryId is required\"),\n status: z.enum([\n \"active\", \"pending_review\", \"quarantined\", \"rejected\", \"superseded\", \"archived\",\n ]),\n reasonCode: z.string().trim().min(1, \"reasonCode is required\"),\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Trust-zone promote\n// ---------------------------------------------------------------------------\n\nexport const trustZonePromoteRequestSchema = z.object({\n recordId: z.string().trim().min(1, \"recordId is required\"),\n targetZone: z.enum([\"working\", \"trusted\"], {\n errorMap: () => ({ message: \"targetZone must be 'working' or 'trusted'\" }),\n }),\n promotionReason: z.string().trim().min(1, \"promotionReason is required\"),\n recordedAt: z.string().trim().optional(),\n summary: z.string().trim().max(5000).optional(),\n dryRun: dryRunSchema,\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Trust-zone demo-seed\n// ---------------------------------------------------------------------------\n\nexport const trustZoneDemoSeedRequestSchema = z.object({\n scenario: z.string().trim().max(256).optional(),\n recordedAt: z.string().trim().optional(),\n dryRun: dryRunSchema,\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// LCM search\n// ---------------------------------------------------------------------------\n\nexport const lcmSearchRequestSchema = z.object({\n query: z.string().min(1, \"query is required\"),\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n limit: z.number().int().min(1).max(100).optional(),\n});\n\nexport const lcmCompactionFlushRequestSchema = z.object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n namespace: namespaceSchema,\n});\n\nexport const lcmCompactionRecordRequestSchema = z.object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n namespace: namespaceSchema,\n tokensBefore: z.number().int().min(0, \"tokensBefore must be a non-negative integer\"),\n tokensAfter: z.number().int().min(0, \"tokensAfter must be a non-negative integer\"),\n});\n\n// ---------------------------------------------------------------------------\n// Day summary\n// ---------------------------------------------------------------------------\n\nexport const daySummaryRequestSchema = z.object({\n memories: z.string().max(100000).optional(),\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Capsule export\n// ---------------------------------------------------------------------------\n\nconst capsuleTopLevelSegmentSchema = z\n .string()\n .trim()\n .min(1)\n .max(128)\n .refine(\n (value) => !value.includes(\"/\") && !value.includes(\"\\\\\"),\n \"must be a top-level directory name without path separators\",\n );\n\nconst capsulePeerIdSchema = z\n .string()\n .trim()\n .min(1)\n .max(256)\n .refine(\n (value) => value !== \".\" && value !== \"..\" && !value.includes(\"/\") && !value.includes(\"\\\\\"),\n \"must be a plain peer id without path separators\",\n );\n\nconst capsuleIsoSinceSchema = z\n .string()\n .trim()\n .min(1, \"since must be a non-empty ISO 8601 timestamp\")\n .max(128)\n .refine(\n isValidCapsuleSince,\n \"since must be a valid ISO 8601 timestamp with no calendar overflow\",\n );\n\nexport const capsuleExportRequestSchema = z\n .object({\n name: z\n .string()\n .trim()\n .min(1, \"name is required\")\n .max(64, \"name must be 64 characters or fewer\")\n .regex(\n CAPSULE_ID_PATTERN,\n \"name must be alphanumeric with single dashes (no spaces, no leading/trailing dashes)\",\n ),\n namespace: namespaceSchema,\n since: capsuleIsoSinceSchema.optional(),\n includeKinds: z.array(capsuleTopLevelSegmentSchema).max(50).optional(),\n peerIds: z.array(capsulePeerIdSchema).max(100).optional(),\n includeTranscripts: z.boolean().optional(),\n encrypt: z.boolean().optional(),\n });\n\nexport const capsuleImportRequestSchema = z\n .object({\n archivePath: z.string().trim().min(1, \"archivePath is required\").max(4096),\n namespace: namespaceSchema,\n mode: z.enum([\"skip\", \"overwrite\", \"fork\"]).optional(),\n });\n\nexport const capsuleListRequestSchema = z\n .object({\n namespace: namespaceSchema,\n });\n\n// ---------------------------------------------------------------------------\n// Offline sync\n// ---------------------------------------------------------------------------\n\nfunction isValidOfflineSyncPath(value: string): boolean {\n try {\n validateArchiveRelativePath(value, \"path\");\n return true;\n } catch {\n return false;\n }\n}\n\nconst offlineSyncPathSchema = z\n .string()\n .trim()\n .min(1, \"path must be non-empty\")\n .max(4096)\n .refine(\n isValidOfflineSyncPath,\n \"path must be a POSIX relative path without unsafe segments\",\n );\n\nconst offlineSyncFileStateSchema = z.object({\n path: offlineSyncPathSchema,\n sha256: z.string().regex(/^[a-f0-9]{64}$/i, \"sha256 must be a 64-character hex digest\"),\n bytes: z.number().int().min(0),\n mtimeMs: z.number().finite().min(0).max(OFFLINE_SYNC_MAX_MTIME_MS),\n});\n\nconst offlineSyncBaseCapturedAtSchema = z\n .string()\n .trim()\n .min(1, \"baseCapturedAt must be non-empty when provided\")\n .max(64)\n .refine((value) => Number.isFinite(Date.parse(value)), {\n message: \"baseCapturedAt must be a valid ISO 8601 timestamp\",\n });\n\nexport const offlineSyncSnapshotRequestSchema = z.object({\n namespace: namespaceSchema,\n includeTranscripts: z.boolean().optional(),\n includeContent: z.boolean().optional(),\n baseCapturedAt: offlineSyncBaseCapturedAtSchema.optional(),\n baseFiles: z\n .array(offlineSyncFileStateSchema)\n .max(300_000, \"baseFiles must contain 300000 or fewer entries\")\n .optional(),\n});\n\nexport const offlineSyncApplyRequestSchema = z\n .object({\n namespace: namespaceSchema,\n changeset: z.unknown(),\n returnCurrentFiles: z.boolean().optional(),\n })\n .refine((value) => value.changeset !== undefined && value.changeset !== null, {\n message: \"changeset is required\",\n path: [\"changeset\"],\n });\n\nexport const offlineSyncFilesRequestSchema = z.object({\n namespace: namespaceSchema,\n includeTranscripts: z.boolean().optional(),\n paths: z\n .array(offlineSyncPathSchema)\n .max(5000, \"paths must contain 5000 or fewer entries\"),\n});\n\nexport const offlineSyncFileContentRequestSchema = z.object({\n namespace: namespaceSchema,\n includeTranscripts: z.boolean().optional(),\n path: offlineSyncPathSchema,\n offset: z.number().int().min(0).optional(),\n length: z.number().int().min(1).max(OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES).optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Action confidence\n// ---------------------------------------------------------------------------\n\nconst nullableOptional = <T extends z.ZodTypeAny>(schema: T) =>\n schema.optional().nullable().transform((value) => value ?? undefined);\n\nconst actionConfidenceRuleSchema = z\n .object({\n kind: z.enum(ACTION_CONFIDENCE_RULE_KINDS),\n description: nullableOptional(z.string().trim().min(1).max(2000)),\n matched: nullableOptional(z.boolean()),\n })\n .strict();\n\nconst actionConfidenceMemorySchema = z\n .object({\n source: nullableOptional(z.string().trim().min(1).max(256)),\n created: nullableOptional(z.string().trim().min(1).max(128)),\n updated: nullableOptional(z.string().trim().min(1).max(128)),\n scope: nullableOptional(z.string().trim().min(1).max(512)),\n userContextScopes: nullableOptional(z.array(z.string().trim().min(1).max(128)).max(50)),\n retrievalReason: nullableOptional(z.string().trim().min(1).max(2000)),\n confidence: nullableOptional(z.number().min(0).max(1)),\n stale: nullableOptional(z.boolean()),\n corrected: nullableOptional(z.boolean()),\n correctionState: nullableOptional(z.enum([\"none\", \"correction\", \"superseded\", \"disputed\", \"forgotten\"])),\n safeToUse: nullableOptional(z.boolean()),\n safety: nullableOptional(z.enum([\"safe\", \"requires-review\", \"blocked\"])),\n safetyReasons: nullableOptional(z.array(z.string().trim().min(1).max(1000)).max(50)),\n })\n .strict();\n\nexport const actionConfidenceRequestSchema = z\n .object({\n intendedAction: nullableOptional(z.string().trim().min(1).max(1000)),\n confidence: nullableOptional(z.number().min(0).max(1)),\n risk: nullableOptional(z.enum(ACTION_CONFIDENCE_RISK_CATEGORIES)),\n contextReadiness: nullableOptional(z.enum(ACTION_CONFIDENCE_CONTEXT_READINESS)),\n currentContextScopes: nullableOptional(z.array(z.string().trim().min(1).max(128)).max(50)),\n userRules: nullableOptional(z.array(actionConfidenceRuleSchema).max(100)),\n retrievedMemories: nullableOptional(z.array(actionConfidenceMemorySchema).max(200)),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Inferred types\n// ---------------------------------------------------------------------------\n\nexport type RecallRequest = z.infer<typeof recallRequestSchema>;\nexport type RecallExplainRequest = z.infer<typeof recallExplainRequestSchema>;\nexport type SetCodingContextRequest = z.infer<typeof setCodingContextRequestSchema>;\nexport type ObserveRequest = z.infer<typeof observeRequestSchema>;\nexport type MemoryStoreRequest = z.infer<typeof memoryStoreRequestSchema>;\nexport type SuggestionSubmitRequest = z.infer<typeof suggestionSubmitRequestSchema>;\nexport type ReviewDispositionRequest = z.infer<typeof reviewDispositionRequestSchema>;\nexport type TrustZonePromoteRequest = z.infer<typeof trustZonePromoteRequestSchema>;\nexport type TrustZoneDemoSeedRequest = z.infer<typeof trustZoneDemoSeedRequestSchema>;\nexport type LcmSearchRequest = z.infer<typeof lcmSearchRequestSchema>;\nexport type LcmCompactionFlushRequest = z.infer<typeof lcmCompactionFlushRequestSchema>;\nexport type LcmCompactionRecordRequest = z.infer<typeof lcmCompactionRecordRequestSchema>;\nexport type DaySummaryRequest = z.infer<typeof daySummaryRequestSchema>;\nexport type CapsuleExportRequest = z.infer<typeof capsuleExportRequestSchema>;\nexport type CapsuleImportRequest = z.infer<typeof capsuleImportRequestSchema>;\nexport type CapsuleListRequest = z.infer<typeof capsuleListRequestSchema>;\nexport type OfflineSyncApplyRequest = z.infer<typeof offlineSyncApplyRequestSchema>;\nexport type OfflineSyncSnapshotRequest = z.infer<typeof offlineSyncSnapshotRequestSchema>;\nexport type OfflineSyncFilesRequest = z.infer<typeof offlineSyncFilesRequestSchema>;\nexport type OfflineSyncFileContentRequest = z.infer<typeof offlineSyncFileContentRequestSchema>;\nexport type ActionConfidenceRequest = z.infer<typeof actionConfidenceRequestSchema>;\n\n// ---------------------------------------------------------------------------\n// Validation helper\n// ---------------------------------------------------------------------------\n\nexport type SchemaName =\n | \"recall\"\n | \"recallExplain\"\n | \"setCodingContext\"\n | \"observe\"\n | \"memoryStore\"\n | \"suggestionSubmit\"\n | \"reviewDisposition\"\n | \"trustZonePromote\"\n | \"trustZoneDemoSeed\"\n | \"lcmSearch\"\n | \"lcmCompactionFlush\"\n | \"lcmCompactionRecord\"\n | \"daySummary\"\n | \"capsuleExport\"\n | \"capsuleImport\"\n | \"capsuleList\"\n | \"offlineSyncSnapshot\"\n | \"offlineSyncFiles\"\n | \"offlineSyncFileContent\"\n | \"offlineSyncApply\"\n | \"actionConfidence\";\n\nexport type SchemaTypeFor<N extends SchemaName> =\n N extends \"recall\" ? RecallRequest\n : N extends \"recallExplain\" ? RecallExplainRequest\n : N extends \"setCodingContext\" ? SetCodingContextRequest\n : N extends \"observe\" ? ObserveRequest\n : N extends \"memoryStore\" ? MemoryStoreRequest\n : N extends \"suggestionSubmit\" ? SuggestionSubmitRequest\n : N extends \"reviewDisposition\" ? ReviewDispositionRequest\n : N extends \"trustZonePromote\" ? TrustZonePromoteRequest\n : N extends \"trustZoneDemoSeed\" ? TrustZoneDemoSeedRequest\n : N extends \"lcmSearch\" ? LcmSearchRequest\n : N extends \"lcmCompactionFlush\" ? LcmCompactionFlushRequest\n : N extends \"lcmCompactionRecord\" ? LcmCompactionRecordRequest\n : N extends \"daySummary\" ? DaySummaryRequest\n : N extends \"capsuleExport\" ? CapsuleExportRequest\n : N extends \"capsuleImport\" ? CapsuleImportRequest\n : N extends \"capsuleList\" ? CapsuleListRequest\n : N extends \"offlineSyncSnapshot\" ? OfflineSyncSnapshotRequest\n : N extends \"offlineSyncFiles\" ? OfflineSyncFilesRequest\n : N extends \"offlineSyncFileContent\" ? OfflineSyncFileContentRequest\n : N extends \"offlineSyncApply\" ? OfflineSyncApplyRequest\n : N extends \"actionConfidence\" ? ActionConfidenceRequest\n : never;\n\nconst schemas: Record<SchemaName, z.ZodTypeAny> = {\n recall: recallRequestSchema,\n recallExplain: recallExplainRequestSchema,\n setCodingContext: setCodingContextRequestSchema,\n observe: observeRequestSchema,\n memoryStore: memoryStoreRequestSchema,\n suggestionSubmit: suggestionSubmitRequestSchema,\n reviewDisposition: reviewDispositionRequestSchema,\n trustZonePromote: trustZonePromoteRequestSchema,\n trustZoneDemoSeed: trustZoneDemoSeedRequestSchema,\n lcmSearch: lcmSearchRequestSchema,\n lcmCompactionFlush: lcmCompactionFlushRequestSchema,\n lcmCompactionRecord: lcmCompactionRecordRequestSchema,\n daySummary: daySummaryRequestSchema,\n capsuleExport: capsuleExportRequestSchema,\n capsuleImport: capsuleImportRequestSchema,\n capsuleList: capsuleListRequestSchema,\n offlineSyncSnapshot: offlineSyncSnapshotRequestSchema,\n offlineSyncFiles: offlineSyncFilesRequestSchema,\n offlineSyncFileContent: offlineSyncFileContentRequestSchema,\n offlineSyncApply: offlineSyncApplyRequestSchema,\n actionConfidence: actionConfidenceRequestSchema,\n};\n\n/**\n * Validate a request body against the named schema.\n * Returns `{ success: true, data }` on pass or\n * `{ success: false, error }` on failure with field-level detail.\n */\nexport function validateRequest<T = unknown>(\n schemaName: SchemaName,\n body: unknown,\n): { success: true; data: T } | { success: false; error: SchemaValidationError } {\n const schema = schemas[schemaName];\n if (!schema) {\n return {\n success: false,\n error: {\n error: `unknown schema: ${schemaName}`,\n code: \"validation_error\",\n details: [],\n },\n };\n }\n const result = schema.safeParse(body);\n if (result.success) {\n return { success: true, data: result.data as T };\n }\n return { success: false, error: formatZodError(result.error) };\n}\n"],"mappings":"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","names":[]}
@@ -3,10 +3,10 @@ import {
3
3
  } from "./chunk-6FC5EGNV.js";
4
4
  import {
5
5
  EngramMcpServer
6
- } from "./chunk-6CB4E7ZV.js";
6
+ } from "./chunk-3ZLVGM76.js";
7
7
  import {
8
8
  EngramAccessInputError
9
- } from "./chunk-LCTP7YRU.js";
9
+ } from "./chunk-ZAVUCJ4H.js";
10
10
  import {
11
11
  isTrustZoneName
12
12
  } from "./chunk-QDZ2RLEC.js";
@@ -24,11 +24,12 @@ import {
24
24
  } from "./chunk-2ODBA7MQ.js";
25
25
  import {
26
26
  validateRequest
27
- } from "./chunk-NW7JW5GA.js";
27
+ } from "./chunk-YROHKYBY.js";
28
28
  import {
29
29
  OFFLINE_SYNC_APPLY_MAX_BODY_BYTES,
30
- OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES
31
- } from "./chunk-AMVN77EU.js";
30
+ OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
31
+ OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES
32
+ } from "./chunk-U7EJOMFC.js";
32
33
 
33
34
  // src/access-http.ts
34
35
  import { createServer } from "http";
@@ -38,6 +39,7 @@ import { existsSync } from "fs";
38
39
  import { readFile } from "fs/promises";
39
40
  import path from "path";
40
41
  import { fileURLToPath, URL } from "url";
42
+ import { gunzipSync } from "zlib";
41
43
  function resolveDefaultAdminConsolePublicDir() {
42
44
  const thisDir = path.dirname(fileURLToPath(import.meta.url));
43
45
  const candidates = [
@@ -101,6 +103,15 @@ function parseTrustZoneFilter(raw) {
101
103
  }
102
104
  throw new HttpError(400, "zone must be one of quarantine|working|trusted", "invalid_zone_filter");
103
105
  }
106
+ function summarizeHttpRequest(req) {
107
+ const method = req.method ?? "UNKNOWN";
108
+ try {
109
+ const parsed = new URL(req.url ?? "/", "http://localhost");
110
+ return `${method} ${parsed.pathname}`;
111
+ } catch {
112
+ return `${method} ${(req.url ?? "/").split("?")[0]}`;
113
+ }
114
+ }
104
115
  function decodePeerIdSegment(raw) {
105
116
  try {
106
117
  return decodeURIComponent(raw);
@@ -180,6 +191,10 @@ var EngramAccessHttpServer = class {
180
191
  res.destroy(err);
181
192
  return;
182
193
  }
194
+ log.error(
195
+ `engram access HTTP internal error [${correlationId}] ${summarizeHttpRequest(req)}`,
196
+ err
197
+ );
183
198
  this.respondJson(res, 500, { error: "internal_error", code: "internal_error" });
184
199
  });
185
200
  });
@@ -489,6 +504,47 @@ var EngramAccessHttpServer = class {
489
504
  this.respondJson(res, 200, result);
490
505
  return;
491
506
  }
507
+ if (req.method === "GET" && (pathname === "/engram/v1/offline-sync/snapshot-stream" || pathname === "/remnic/v1/offline-sync/snapshot-stream")) {
508
+ const includeTranscriptsRaw = parsed.searchParams.get("include_transcripts");
509
+ const includeContentRaw = parsed.searchParams.get("content");
510
+ if (includeTranscriptsRaw !== null && includeTranscriptsRaw !== "true" && includeTranscriptsRaw !== "false") {
511
+ throw new EngramAccessInputError(
512
+ `include_transcripts must be one of: true, false (got: ${includeTranscriptsRaw})`
513
+ );
514
+ }
515
+ if (includeContentRaw !== null && includeContentRaw !== "false") {
516
+ throw new EngramAccessInputError("snapshot-stream content must be false");
517
+ }
518
+ const namespaceParam = parsed.searchParams.get("namespace");
519
+ const result = await this.service.offlineSyncSnapshotStream({
520
+ namespace: this.resolveNamespace(
521
+ req,
522
+ namespaceParam && namespaceParam.length > 0 ? namespaceParam : void 0
523
+ ),
524
+ principal: this.resolveRequestPrincipal(req),
525
+ includeTranscripts: includeTranscriptsRaw !== "false",
526
+ includeContent: false
527
+ });
528
+ await this.respondOfflineSnapshotStream(res, result);
529
+ return;
530
+ }
531
+ if (req.method === "POST" && (pathname === "/engram/v1/offline-sync/snapshot" || pathname === "/remnic/v1/offline-sync/snapshot")) {
532
+ const body = await this.readValidatedBody(
533
+ req,
534
+ "offlineSyncSnapshot",
535
+ OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES
536
+ );
537
+ const result = await this.service.offlineSyncSnapshot({
538
+ namespace: this.resolveNamespace(req, body.namespace),
539
+ principal: this.resolveRequestPrincipal(req),
540
+ includeTranscripts: body.includeTranscripts,
541
+ includeContent: body.includeContent,
542
+ baseFiles: body.baseFiles,
543
+ ...body.baseCapturedAt ? { baseCapturedAt: new Date(body.baseCapturedAt) } : {}
544
+ });
545
+ this.respondJson(res, 200, result);
546
+ return;
547
+ }
492
548
  if (req.method === "POST" && (pathname === "/engram/v1/offline-sync/files" || pathname === "/remnic/v1/offline-sync/files")) {
493
549
  const body = await this.readValidatedBody(req, "offlineSyncFiles");
494
550
  const result = await this.service.offlineSyncFiles({
@@ -554,7 +610,8 @@ var EngramAccessHttpServer = class {
554
610
  const result = await this.service.offlineSyncApply({
555
611
  namespace: this.resolveNamespace(req, body.namespace),
556
612
  principal: this.resolveRequestPrincipal(req),
557
- changeset: body.changeset
613
+ changeset: body.changeset,
614
+ returnCurrentFiles: body.returnCurrentFiles
558
615
  });
559
616
  this.respondJson(res, 200, result);
560
617
  return;
@@ -1451,6 +1508,59 @@ var EngramAccessHttpServer = class {
1451
1508
  }
1452
1509
  res.end(body);
1453
1510
  }
1511
+ async respondOfflineSnapshotStream(res, snapshot) {
1512
+ res.statusCode = 200;
1513
+ res.setHeader("content-type", "application/x-ndjson; charset=utf-8");
1514
+ res.setHeader("cache-control", "no-store");
1515
+ const cid = correlationIdStore.getStore();
1516
+ if (cid) {
1517
+ res.setHeader("x-request-id", cid);
1518
+ }
1519
+ const waitForDrainOrClose = async () => new Promise((resolve, reject) => {
1520
+ const cleanup = () => {
1521
+ res.off("drain", onDrain);
1522
+ res.off("close", onClose);
1523
+ res.off("error", onError);
1524
+ };
1525
+ const onDrain = () => {
1526
+ cleanup();
1527
+ resolve(true);
1528
+ };
1529
+ const onClose = () => {
1530
+ cleanup();
1531
+ resolve(false);
1532
+ };
1533
+ const onError = (error) => {
1534
+ cleanup();
1535
+ reject(error);
1536
+ };
1537
+ res.once("drain", onDrain);
1538
+ res.once("close", onClose);
1539
+ res.once("error", onError);
1540
+ });
1541
+ const writeLine = async (payload) => {
1542
+ if (res.destroyed || res.writableEnded) return false;
1543
+ if (res.write(`${JSON.stringify(payload)}
1544
+ `)) return true;
1545
+ if (res.destroyed || res.writableEnded) return false;
1546
+ return waitForDrainOrClose();
1547
+ };
1548
+ if (!await writeLine({
1549
+ type: "snapshot",
1550
+ namespace: snapshot.namespace,
1551
+ format: snapshot.format,
1552
+ schemaVersion: snapshot.schemaVersion,
1553
+ createdAt: snapshot.createdAt,
1554
+ sourceId: snapshot.sourceId,
1555
+ includeTranscripts: snapshot.includeTranscripts
1556
+ })) return;
1557
+ for await (const file of snapshot.files) {
1558
+ if (!await writeLine({ type: "file", file })) return;
1559
+ }
1560
+ if (!res.destroyed && !res.writableEnded) {
1561
+ res.end();
1562
+ }
1563
+ }
1454
1564
  respondBinary(res, status, body, headers = {}) {
1455
1565
  res.statusCode = status;
1456
1566
  res.setHeader("content-type", "application/octet-stream");
@@ -1494,6 +1604,10 @@ var EngramAccessHttpServer = class {
1494
1604
  }
1495
1605
  }
1496
1606
  async readJsonBody(req, maxBodyBytes = this.maxBodyBytes) {
1607
+ const encoding = (this.readOptionalHeader(req, "content-encoding") ?? "identity").toLowerCase();
1608
+ if (encoding !== "identity" && encoding !== "gzip") {
1609
+ throw new HttpError(415, "unsupported_content_encoding", "unsupported_content_encoding");
1610
+ }
1497
1611
  const chunks = [];
1498
1612
  let total = 0;
1499
1613
  for await (const chunk of req) {
@@ -1505,7 +1619,21 @@ var EngramAccessHttpServer = class {
1505
1619
  chunks.push(buffer);
1506
1620
  }
1507
1621
  if (chunks.length === 0) return {};
1508
- const raw = Buffer.concat(chunks).toString("utf-8").trim();
1622
+ let body = Buffer.concat(chunks, total);
1623
+ if (encoding === "gzip") {
1624
+ try {
1625
+ body = gunzipSync(body, { maxOutputLength: maxBodyBytes });
1626
+ } catch (error) {
1627
+ if (error.code === "ERR_BUFFER_TOO_LARGE") {
1628
+ throw new HttpError(413, "request_body_too_large", "request_body_too_large");
1629
+ }
1630
+ throw new HttpError(400, "invalid_gzip_body", "invalid_gzip_body");
1631
+ }
1632
+ if (body.byteLength > maxBodyBytes) {
1633
+ throw new HttpError(413, "request_body_too_large", "request_body_too_large");
1634
+ }
1635
+ }
1636
+ const raw = body.toString("utf-8").trim();
1509
1637
  if (raw.length === 0) return {};
1510
1638
  let parsed;
1511
1639
  try {
@@ -1666,4 +1794,4 @@ var EngramAccessHttpServer = class {
1666
1794
  export {
1667
1795
  EngramAccessHttpServer
1668
1796
  };
1669
- //# sourceMappingURL=chunk-JUYT2J3K.js.map
1797
+ //# sourceMappingURL=chunk-YU5KIWYQ.js.map