@modusensus/dsh-mneme 0.14.0-beta.1 → 0.14.0-beta.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/LICENSE +21 -21
- package/README.md +830 -830
- package/assets/icon.svg +3 -3
- package/bin/cli.mjs +964 -964
- package/bin/dsh-mneme-choro.mjs +262 -262
- package/bin/dsh-mneme-mcp.mjs +510 -510
- package/bin/dsh-mneme-serve.mjs +151 -151
- package/cordis.patch.yml +21 -21
- package/docs/CONFIGURATION.md +407 -404
- package/docs/CONTINUITY.md +139 -139
- package/docs/DAEMON.md +57 -57
- package/docs/DIRECTORIES.md +114 -114
- package/docs/DISTILL.md +397 -371
- package/docs/DSH-GO.md +97 -97
- package/docs/ENTITIES.md +247 -247
- package/docs/FORGET.md +77 -77
- package/docs/KB.md +110 -110
- package/docs/LOCAL_MODEL.md +222 -222
- package/docs/SEMANTIC.md +256 -256
- package/docs/SHARE.md +552 -552
- package/docs/SLEEP.md +202 -202
- package/docs/STORAGE.md +122 -122
- package/docs/WORKFLOWS.md +366 -366
- package/lib/api-standalone.js +1007 -1007
- package/lib/api.js +3600 -3600
- package/lib/attachment-text.js +122 -122
- package/lib/bootstrap-http.js +105 -105
- package/lib/bootstrap.js +215 -215
- package/lib/candidates.js +454 -454
- package/lib/capabilities.js +819 -819
- package/lib/choro-command.js +111 -111
- package/lib/client.js +14420 -14322
- package/lib/commands.js +95 -95
- package/lib/config-keys.js +144 -144
- package/lib/config.js +1361 -1344
- package/lib/content-hash.js +54 -54
- package/lib/continuity.js +258 -258
- package/lib/date-hint.js +32 -0
- package/lib/diary/auto.js +190 -190
- package/lib/diary/compose.js +440 -440
- package/lib/diary/dir.js +59 -59
- package/lib/diary/export.js +97 -97
- package/lib/diary/index.js +26 -26
- package/lib/diary/library.js +189 -189
- package/lib/diary/qq-inbox.js +142 -142
- package/lib/diary/rollover.js +61 -61
- package/lib/diary/session-provider.js +122 -122
- package/lib/document-index.js +94 -94
- package/lib/document.js +322 -322
- package/lib/dream/clustering.js +123 -123
- package/lib/dream/decisions.js +945 -945
- package/lib/dream/narratives.js +44 -44
- package/lib/dream/sleep.js +2027 -2027
- package/lib/dream/triage.js +139 -139
- package/lib/dream.js +1879 -1879
- package/lib/dsh-go/host.js +162 -162
- package/lib/dsh-go/panel.js +2091 -2091
- package/lib/dsh-go/text.js +342 -342
- package/lib/dsh-go/views/common.js +68 -68
- package/lib/dsh-go/views/entity.js +48 -48
- package/lib/dsh-go/views/memory.js +198 -198
- package/lib/dsh-go/views/root.js +30 -30
- package/lib/dsh-go/views/settings.js +398 -398
- package/lib/dsh-go/views/status.js +51 -51
- package/lib/embedding.js +342 -342
- package/lib/entities/extractor.js +285 -285
- package/lib/fence.js +24 -24
- package/lib/graph/anchoring.js +184 -184
- package/lib/guide.js +74 -74
- package/lib/heat.js +144 -144
- package/lib/hot-memory.js +119 -119
- package/lib/image-describe.js +158 -0
- package/lib/index.js +852 -852
- package/lib/inject.js +656 -651
- package/lib/kb/index.js +309 -309
- package/lib/kb/routes.js +219 -219
- package/lib/kb/tools.js +148 -148
- package/lib/lang.js +607 -595
- package/lib/local-embedder.js +358 -358
- package/lib/maintenance.js +162 -162
- package/lib/memory-source.js +9 -9
- package/lib/mirror.js +330 -330
- package/lib/organize.js +456 -456
- package/lib/peak-hours.js +172 -172
- package/lib/pipeline-activities.js +178 -178
- package/lib/pipeline-attribution.js +165 -165
- package/lib/pipeline-command.js +279 -279
- package/lib/pipeline-confirm.js +142 -142
- package/lib/pipeline-exec.js +174 -174
- package/lib/pipeline-nudge-auto.js +129 -129
- package/lib/pipeline-nudge.js +1623 -1623
- package/lib/pipeline-observations.js +181 -181
- package/lib/pipeline-observe.js +133 -133
- package/lib/pipeline-runner.js +361 -361
- package/lib/pipeline-runs.js +442 -442
- package/lib/pipeline.js +716 -716
- package/lib/placement.js +13 -13
- package/lib/pre-inject-gate.js +354 -354
- package/lib/profile-extract.js +164 -164
- package/lib/profile-facts.js +356 -356
- package/lib/provenance-http.js +251 -251
- package/lib/quality-filter.js +162 -162
- package/lib/recall-stats.js +190 -190
- package/lib/reclaim-http.js +150 -150
- package/lib/reranker.js +269 -269
- package/lib/runtime/adopt.js +176 -176
- package/lib/runtime/closure.js +172 -172
- package/lib/runtime/download.js +247 -247
- package/lib/runtime/layout.js +265 -265
- package/lib/runtime/loader.js +252 -252
- package/lib/runtime/model-fetch.js +361 -361
- package/lib/runtime/provision.js +237 -237
- package/lib/runtime/tarball.js +130 -130
- package/lib/runtime/verify.js +223 -223
- package/lib/safe-slice.js +18 -18
- package/lib/scope-state.js +277 -277
- package/lib/scope.js +187 -187
- package/lib/search/adaptive.js +60 -60
- package/lib/search/bm25.js +96 -96
- package/lib/semantic.js +572 -572
- package/lib/sensitive-scan.js +209 -209
- package/lib/serve.js +228 -228
- package/lib/service.js +3268 -3268
- package/lib/session-gate.js +91 -91
- package/lib/session-usage.js +350 -350
- package/lib/settings.js +827 -817
- package/lib/share-http.js +281 -281
- package/lib/share-import.js +234 -234
- package/lib/share.js +335 -335
- package/lib/store.js +5895 -5895
- package/lib/summarize.js +1388 -1343
- package/lib/tools.js +1370 -1356
- package/lib/user-settings.js +230 -230
- package/lib/vector-index.js +180 -180
- package/lib/version-check.js +122 -122
- package/lib/wiki/claims.js +267 -267
- package/lib/wiki/cli-hint.js +90 -90
- package/lib/wiki/inject.js +164 -164
- package/lib/wiki/partition.js +200 -200
- package/lib/wiki/plan.js +214 -214
- package/lib/wiki/queries.js +640 -640
- package/lib/wiki/render.js +261 -261
- package/lib/wiki/scan.js +371 -371
- package/lib/wiki/t0.js +500 -500
- package/lib/wiki/t1-jobs.js +232 -232
- package/lib/wiki/t1.js +609 -609
- package/lib/write-admission.js +404 -404
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +1 -1
- package/runtime-manifest.json +526 -526
- package/scripts/benchmark-embed.js +201 -201
- package/scripts/benchmark-recall.js +249 -249
- package/scripts/benchmark-rerank.js +166 -166
- package/scripts/build-runtime-manifest.mjs +224 -224
- package/scripts/changelog-prep.mjs +91 -91
- package/scripts/check-sync.js +44 -44
- package/scripts/e2e-dsh.js +220 -220
- package/scripts/mneme-runtime.mjs +277 -277
- package/scripts/publish-gate.mjs +197 -197
- package/scripts/release-docs.mjs +210 -210
- package/scripts/release-notes.mjs +164 -164
- package/scripts/stress-dsh.js +255 -255
- package/scripts/sync-lib.js +47 -47
- package/scripts/sync-test-badge.mjs +69 -69
- package/scripts/test-count-sync.mjs +48 -48
- package/src/api-standalone.js +1007 -1007
- package/src/api.js +3600 -3600
- package/src/attachment-text.js +122 -122
- package/src/bootstrap-http.js +105 -105
- package/src/bootstrap.js +215 -215
- package/src/candidates.js +454 -454
- package/src/capabilities.js +819 -819
- package/src/choro-command.js +111 -111
- package/src/commands.js +95 -95
- package/src/config-keys.js +144 -144
- package/src/config.js +1361 -1344
- package/src/content-hash.js +54 -54
- package/src/continuity.js +258 -258
- package/src/date-hint.js +32 -0
- package/src/diary/auto.js +190 -190
- package/src/diary/compose.js +440 -440
- package/src/diary/dir.js +59 -59
- package/src/diary/export.js +97 -97
- package/src/diary/index.js +26 -26
- package/src/diary/library.js +189 -189
- package/src/diary/qq-inbox.js +142 -142
- package/src/diary/rollover.js +61 -61
- package/src/diary/session-provider.js +122 -122
- package/src/document-index.js +94 -94
- package/src/document.js +322 -322
- package/src/dream/clustering.js +123 -123
- package/src/dream/decisions.js +945 -945
- package/src/dream/narratives.js +44 -44
- package/src/dream/sleep.js +2027 -2027
- package/src/dream/triage.js +139 -139
- package/src/dream.js +1879 -1879
- package/src/dsh-go/host.js +162 -162
- package/src/dsh-go/panel.js +2091 -2091
- package/src/dsh-go/text.js +342 -342
- package/src/dsh-go/views/common.js +68 -68
- package/src/dsh-go/views/entity.js +48 -48
- package/src/dsh-go/views/memory.js +198 -198
- package/src/dsh-go/views/root.js +30 -30
- package/src/dsh-go/views/settings.js +398 -398
- package/src/dsh-go/views/status.js +51 -51
- package/src/embedding.js +342 -342
- package/src/entities/extractor.js +285 -285
- package/src/fence.js +24 -24
- package/src/graph/anchoring.js +184 -184
- package/src/guide.js +74 -74
- package/src/heat.js +144 -144
- package/src/hot-memory.js +119 -119
- package/src/image-describe.js +158 -0
- package/src/index.js +852 -852
- package/src/inject.js +656 -651
- package/src/kb/index.js +309 -309
- package/src/kb/routes.js +219 -219
- package/src/kb/tools.js +148 -148
- package/src/lang.js +607 -595
- package/src/local-embedder.js +358 -358
- package/src/maintenance.js +162 -162
- package/src/memory-source.js +9 -9
- package/src/mirror.js +330 -330
- package/src/organize.js +456 -456
- package/src/peak-hours.js +172 -172
- package/src/pipeline-activities.js +178 -178
- package/src/pipeline-attribution.js +165 -165
- package/src/pipeline-command.js +279 -279
- package/src/pipeline-confirm.js +142 -142
- package/src/pipeline-exec.js +174 -174
- package/src/pipeline-nudge-auto.js +129 -129
- package/src/pipeline-nudge.js +1623 -1623
- package/src/pipeline-observations.js +181 -181
- package/src/pipeline-observe.js +133 -133
- package/src/pipeline-runner.js +361 -361
- package/src/pipeline-runs.js +442 -442
- package/src/pipeline.js +716 -716
- package/src/placement.js +13 -13
- package/src/pre-inject-gate.js +354 -354
- package/src/profile-extract.js +164 -164
- package/src/profile-facts.js +356 -356
- package/src/provenance-http.js +251 -251
- package/src/quality-filter.js +162 -162
- package/src/recall-stats.js +190 -190
- package/src/reclaim-http.js +150 -150
- package/src/reranker.js +269 -269
- package/src/runtime/adopt.js +176 -176
- package/src/runtime/closure.js +172 -172
- package/src/runtime/download.js +247 -247
- package/src/runtime/layout.js +265 -265
- package/src/runtime/loader.js +252 -252
- package/src/runtime/model-fetch.js +361 -361
- package/src/runtime/provision.js +237 -237
- package/src/runtime/tarball.js +130 -130
- package/src/runtime/verify.js +223 -223
- package/src/safe-slice.js +18 -18
- package/src/scope-state.js +277 -277
- package/src/scope.js +187 -187
- package/src/search/adaptive.js +60 -60
- package/src/search/bm25.js +96 -96
- package/src/semantic.js +572 -572
- package/src/sensitive-scan.js +209 -209
- package/src/serve.js +228 -228
- package/src/service.js +3268 -3268
- package/src/session-gate.js +91 -91
- package/src/session-usage.js +350 -350
- package/src/settings.js +827 -817
- package/src/share-http.js +281 -281
- package/src/share-import.js +234 -234
- package/src/share.js +335 -335
- package/src/store.js +5895 -5895
- package/src/summarize.js +1388 -1343
- package/src/tools.js +1370 -1356
- package/src/user-settings.js +230 -230
- package/src/vector-index.js +180 -180
- package/src/version-check.js +122 -122
- package/src/wiki/claims.js +267 -267
- package/src/wiki/cli-hint.js +90 -90
- package/src/wiki/inject.js +164 -164
- package/src/wiki/partition.js +200 -200
- package/src/wiki/plan.js +214 -214
- package/src/wiki/queries.js +640 -640
- package/src/wiki/render.js +261 -261
- package/src/wiki/scan.js +371 -371
- package/src/wiki/t0.js +500 -500
- package/src/wiki/t1-jobs.js +232 -232
- package/src/wiki/t1.js +609 -609
- package/src/write-admission.js +404 -404
- package/test/adaptive-inject-budget.test.js +85 -85
- package/test/api-hardening.test.js +173 -173
- package/test/api-nudge-route.test.js +259 -259
- package/test/api-routes-gaps.test.js +1092 -1092
- package/test/api.test.js +3007 -2998
- package/test/attachment-text.test.js +139 -139
- package/test/audit.test.js +448 -448
- package/test/baseline-persist.test.js +248 -248
- package/test/benchmark.test.js +94 -94
- package/test/bm25-corpus-cache.test.js +145 -145
- package/test/bootstrap.test.js +228 -228
- package/test/candidates.test.js +345 -345
- package/test/capabilities.test.js +577 -577
- package/test/capacity-warning.test.js +262 -262
- package/test/changelog-prep.test.js +125 -125
- package/test/choro-command.test.js +218 -218
- package/test/cli-enums.test.js +37 -37
- package/test/cli-flag-value.test.js +86 -86
- package/test/cli-receive.test.js +390 -390
- package/test/cli-share.test.js +437 -437
- package/test/client-share.test.js +225 -225
- package/test/client.test.js +4595 -4425
- package/test/clustering.test.js +100 -100
- package/test/commands.test.js +106 -106
- package/test/config-keys-routes.test.js +233 -233
- package/test/config.test.js +153 -153
- package/test/conflict-freeze.test.js +344 -344
- package/test/conflict-ledger-enforce.test.js +452 -452
- package/test/conflict-ledger.test.js +242 -242
- package/test/conflict-reviewed.test.js +79 -79
- package/test/content-hash.test.js +204 -204
- package/test/continuity.test.js +452 -452
- package/test/contrast.test.js +432 -432
- package/test/date-hint.test.js +156 -0
- package/test/dedupe-candidate-window.test.js +180 -180
- package/test/dependency-overrides.test.js +78 -78
- package/test/diary-library.test.js +187 -187
- package/test/diary.test.js +576 -576
- package/test/differentiate-feedback.test.js +248 -248
- package/test/distill-tx-embed-gap.test.js +110 -110
- package/test/docs-config-keys.test.js +65 -65
- package/test/document-dir.test.js +233 -233
- package/test/document.test.js +703 -703
- package/test/dream-archive-guardrail.test.js +116 -116
- package/test/dream-baseline-clamp.test.js +174 -174
- package/test/dream-candidate-hybrid.test.js +281 -281
- package/test/dream-coverage-degrade.test.js +86 -86
- package/test/dream-decision-evidence.test.js +314 -314
- package/test/dream-failure-backoff.test.js +173 -173
- package/test/dream-fence.test.js +207 -207
- package/test/dream-maxtokens-fallback.test.js +132 -132
- package/test/dream-merge-guardrail.test.js +219 -219
- package/test/dream-peak-hours.test.js +194 -194
- package/test/dream.test.js +1528 -1528
- package/test/dsh-go-host.test.js +134 -134
- package/test/dsh-go-panel-actions.test.js +854 -854
- package/test/dsh-go-panel.test.js +251 -251
- package/test/embed-ready-poll.test.js +94 -94
- package/test/embed-text-reasons.test.js +112 -112
- package/test/embedding-cache-f32.test.js +276 -276
- package/test/embedding-ready.test.js +226 -226
- package/test/entities.test.js +711 -711
- package/test/entity-recall.test.js +179 -179
- package/test/epistemic.test.js +325 -325
- package/test/failure-query.test.js +147 -147
- package/test/failure-retention.test.js +105 -105
- package/test/fnew-0112.test.js +311 -311
- package/test/fnew-03.test.js +422 -422
- package/test/forget-corrections.test.js +70 -70
- package/test/graph-anchoring.test.js +184 -184
- package/test/graph-api.test.js +333 -333
- package/test/graph-boosted-relations.test.js +189 -189
- package/test/graph-inject-budget.test.js +103 -103
- package/test/graph-multipath.test.js +269 -269
- package/test/graph-passive-confirm.test.js +91 -91
- package/test/graph-weight-evolution.test.js +104 -104
- package/test/heat.test.js +175 -175
- package/test/helpers/dream-mock.js +86 -86
- package/test/helpers/peer-worker.mjs +25 -25
- package/test/helpers/runtime-source.js +60 -60
- package/test/helpers/tar-builder.js +80 -80
- package/test/helpers/write-admission-samples.js +312 -312
- package/test/hot-memory.test.js +259 -259
- package/test/image-description.test.js +271 -0
- package/test/image-memory.test.js +170 -170
- package/test/inject-content-cap.test.js +91 -91
- package/test/inject-first-round-bm25.test.js +89 -89
- package/test/inject-heat.test.js +77 -77
- package/test/inject-parent-gate.test.js +134 -109
- package/test/inject-pin-explicit.test.js +300 -300
- package/test/inject-pin-vector-crowd.test.js +225 -225
- package/test/inject-pools.test.js +195 -195
- package/test/inject-recall.test.js +172 -172
- package/test/inject-rotation.test.js +161 -161
- package/test/inject.test.js +553 -553
- package/test/issue-617-step1-query-and-fusion.test.js +361 -361
- package/test/kb-api-wiring.test.js +128 -128
- package/test/kb-collections.test.js +272 -272
- package/test/kb-routes.test.js +379 -379
- package/test/lang.test.js +98 -98
- package/test/lastrunat-persist.test.js +101 -101
- package/test/lib-smoke.test.js +116 -116
- package/test/llm-audit.test.js +815 -815
- package/test/llm-message-source.test.js +207 -207
- package/test/local-embedder.test.js +292 -292
- package/test/maintenance.test.js +501 -501
- package/test/mcp-stdio.test.js +385 -385
- package/test/mint-source.test.js +311 -311
- package/test/mirror-dirty.test.js +424 -424
- package/test/mirror-edit-digest.test.js +187 -187
- package/test/mirror-generation.test.js +499 -499
- package/test/mirror-types.test.js +208 -208
- package/test/mirror.test.js +249 -249
- package/test/narrative-bars.test.js +162 -162
- package/test/organize-tool.test.js +232 -232
- package/test/organize.test.js +418 -418
- package/test/panel-chart-scale.test.js +90 -90
- package/test/panel-tokens.test.js +245 -245
- package/test/peak-hours-observability.test.js +70 -70
- package/test/peer-blockers.test.js +193 -193
- package/test/persona-addressing.test.js +83 -83
- package/test/persona-api.test.js +172 -172
- package/test/persona-by-session.test.js +568 -568
- package/test/persona-flag.test.js +36 -36
- package/test/persona-inject.test.js +145 -145
- package/test/persona-settings.test.js +198 -198
- package/test/pipeline-activities.test.js +155 -155
- package/test/pipeline-attribution.test.js +175 -175
- package/test/pipeline-command.test.js +243 -243
- package/test/pipeline-confirm.test.js +148 -148
- package/test/pipeline-exec.test.js +172 -172
- package/test/pipeline-nudge-auto.test.js +248 -248
- package/test/pipeline-nudge.test.js +1278 -1278
- package/test/pipeline-observations.test.js +157 -157
- package/test/pipeline-observe.test.js +127 -127
- package/test/pipeline-r1r2.test.js +278 -278
- package/test/pipeline-runner.test.js +468 -468
- package/test/pipeline-runs.test.js +767 -767
- package/test/pipeline.test.js +636 -636
- package/test/placement.test.js +36 -36
- package/test/policy-epoch.test.js +259 -259
- package/test/pre-inject-gate.test.js +444 -444
- package/test/profile-extract.test.js +269 -269
- package/test/profile-facts.test.js +492 -492
- package/test/prompt-stance.test.js +128 -128
- package/test/provenance-http.test.js +367 -367
- package/test/publish-gate.test.js +272 -272
- package/test/quality-backfill.test.js +290 -290
- package/test/quality-filter.test.js +295 -295
- package/test/readme-claims.test.js +113 -113
- package/test/reasoning-effort.test.js +752 -752
- package/test/recall-anti-update.test.js +82 -82
- package/test/recall-evals.test.js +253 -253
- package/test/recall-layer.test.js +326 -326
- package/test/recall-retention.test.js +128 -128
- package/test/recall-stats.test.js +274 -274
- package/test/receipt-chain.test.js +451 -451
- package/test/reclaim-http.test.js +209 -209
- package/test/reflection-update-gate.test.js +129 -129
- package/test/reflection.test.js +226 -226
- package/test/reindex-backfill.test.js +475 -475
- package/test/reindex-scheduler.test.js +369 -369
- package/test/release-docs.test.js +156 -156
- package/test/release-notes.test.js +265 -265
- package/test/release-workflow.test.js +93 -93
- package/test/reranker-single-logit.test.js +73 -73
- package/test/reranker.test.js +197 -197
- package/test/resident-status.test.js +83 -83
- package/test/route-policy.test.js +113 -113
- package/test/runtime-adopt.test.js +206 -206
- package/test/runtime-cli.test.js +89 -89
- package/test/runtime-closure.test.js +193 -193
- package/test/runtime-download.test.js +302 -302
- package/test/runtime-layout.test.js +163 -163
- package/test/runtime-loader.test.js +255 -255
- package/test/runtime-manifest.test.js +159 -159
- package/test/runtime-model-fetch.test.js +348 -348
- package/test/runtime-provision.test.js +101 -101
- package/test/runtime-tarball.test.js +81 -81
- package/test/runtime-verify.test.js +319 -319
- package/test/scope-candidates.test.js +491 -491
- package/test/scope-distill-stamp.test.js +134 -134
- package/test/scope-explicit.test.js +452 -452
- package/test/scope-inject-soft.test.js +106 -106
- package/test/scope-optional-service.test.js +110 -110
- package/test/scope-retrieval.test.js +197 -197
- package/test/scope-state.test.js +610 -610
- package/test/scope-storage.test.js +255 -255
- package/test/scope-strict.test.js +367 -367
- package/test/search-fusion.test.js +90 -90
- package/test/security-doc.test.js +188 -188
- package/test/semantic.test.js +124 -124
- package/test/sensitive-scan.test.js +251 -251
- package/test/serve-bin.test.js +121 -121
- package/test/serve.test.js +258 -258
- package/test/service-search.test.js +174 -174
- package/test/service.test.js +410 -410
- package/test/session-gate.test.js +264 -264
- package/test/session-usage.test.js +317 -317
- package/test/settings.test.js +273 -273
- package/test/share-foreign-rows.test.js +144 -144
- package/test/share-http.test.js +144 -144
- package/test/share-import.test.js +577 -577
- package/test/share-imported-guard.test.js +311 -311
- package/test/share-imported-identity.test.js +111 -111
- package/test/share-pack.test.js +511 -511
- package/test/share-receive-http.test.js +756 -756
- package/test/share-routes.test.js +337 -337
- package/test/share-store.test.js +133 -133
- package/test/share-validate.test.js +101 -101
- package/test/skip-invalid-restore.test.js +262 -262
- package/test/sleep-action-set.test.js +441 -441
- package/test/sleep-catchup.test.js +315 -315
- package/test/sleep-failure-backoff.test.js +156 -156
- package/test/sleep-heat.test.js +174 -174
- package/test/sleep-scheduler-rearm.test.js +89 -89
- package/test/sleep.test.js +1455 -1455
- package/test/standalone-api.test.js +1344 -1344
- package/test/store-vector-cache.test.js +98 -98
- package/test/store-write-path-columns.test.js +191 -191
- package/test/store.test.js +744 -744
- package/test/stress.test.js +209 -209
- package/test/summarize-occurred-at.test.js +127 -127
- package/test/summarize-parse-diagnostics.test.js +75 -75
- package/test/summarize-reasoning-effort.test.js +189 -189
- package/test/summarize.test.js +2251 -2251
- package/test/supersede-state-tracking.test.js +394 -394
- package/test/test-count-sync.test.js +71 -71
- package/test/tool-state-ignore.test.js +65 -65
- package/test/tools-dto-schema-matrix.test.js +398 -398
- package/test/tools-memory-get-schema.test.js +65 -65
- package/test/tools.test.js +585 -585
- package/test/updated-at-semantics.test.js +113 -113
- package/test/user-settings-preview.test.js +127 -127
- package/test/user-settings-segments.test.js +527 -527
- package/test/vector-index.test.js +334 -334
- package/test/version-check.test.js +152 -152
- package/test/webServer-optional.test.js +82 -82
- package/test/wiki-api.test.js +734 -734
- package/test/wiki-claims.test.js +194 -194
- package/test/wiki-cli-hint.test.js +118 -118
- package/test/wiki-inject.test.js +265 -265
- package/test/wiki-partition.test.js +112 -112
- package/test/wiki-plan.test.js +80 -80
- package/test/wiki-provenance.test.js +202 -202
- package/test/wiki-queries.test.js +398 -398
- package/test/wiki-scan.test.js +208 -208
- package/test/wiki-store.test.js +190 -190
- package/test/wiki-t0.test.js +456 -456
- package/test/wiki-t1-jobs.test.js +125 -125
- package/test/wiki-t1.test.js +460 -460
- package/test/wiki-tools.test.js +176 -176
- package/test/workflow-guards.test.js +155 -155
- package/test/write-admission.test.js +668 -668
package/lib/share-http.js
CHANGED
|
@@ -1,281 +1,281 @@
|
|
|
1
|
-
// 分享包在两张皮上共用的解析与答复(形状照 src/reclaim-http.js,#411)。
|
|
2
|
-
// 只返回 {status, body},绝不自己写 res —— 两侧的 sendJson 签名不同(api.js 有
|
|
3
|
-
// headers 第四参、api-standalone.js 没有),把写 res 留在各侧 handler 里是唯一
|
|
4
|
-
// 能让一份实现喂两张脸的做法。
|
|
5
|
-
//
|
|
6
|
-
// 哪些行进包、以什么原因不进,一条判据都不在这里重复:那是 src/share.js 的事。本模块
|
|
7
|
-
// 只做协议层的事——读 body、把结果包成答复、给一个能落盘的文件名。
|
|
8
|
-
import { buildSharePack } from "./share.js";
|
|
9
|
-
|
|
10
|
-
/** 拒发时的下一步动作。它是给调用方看的,出口只许有一处措辞(同 RECLAIM_CONFIRM_HINT)。 */
|
|
11
|
-
const SHARE_ERROR_HINT = "包体超过分享水位:用 --type 或 --tag 分批,别整库外发。";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 记日志这一手,只许经这里。
|
|
15
|
-
*
|
|
16
|
-
* 「这一层从不抛」是**层的契约**,不是每个调用面的运气(C5 评审裁定):warn 裸调时,宿主
|
|
17
|
-
* logger 自己坏掉就会从 catch 块里再抛出去,而两侧 handler 那个外层 try 在 .then 的回调里
|
|
18
|
-
* 早已退栈——现场就是「一个字节都没回」(#410)。守卫住在面上一处一个,等于每接一张新脸
|
|
19
|
-
* 都要记得再兜一次;住在层里,两侧、以及后面的 CLI(C7)拿到的都是同一个脾气。
|
|
20
|
-
*
|
|
21
|
-
* 三个构造器(shareReply / receiveReply / undoReply)都走这里,**对称本身就是要点**:
|
|
22
|
-
* 只给新加的两个上守卫、出包那侧留一处裸调,下一个读者就会照那处裸的抄。
|
|
23
|
-
* 日志环坏掉时答复照旧送出——对面拿到的仍是那一个状态码,只是少了一条日志迹。
|
|
24
|
-
*/
|
|
25
|
-
function warnSafely(warn, message) {
|
|
26
|
-
try {
|
|
27
|
-
warn?.(message);
|
|
28
|
-
} catch { /* 记日志是自己的事,坏了的日志不许把已经算好的答复一起带走 */ }
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* 解析 POST body(已由调用方读成文本)→ buildSharePack 的入参集合。
|
|
33
|
-
*
|
|
34
|
-
* 空 body 等价于 `{}`:分享的主用法就是「一个字节都不发,按整库口径打」。坏 JSON 与
|
|
35
|
-
* 发成数组/null 是两个不同的错码(前者是调用方发坏了,后者是发错了顶层形状),
|
|
36
|
-
* 与 reclaim 侧同款,出口要能分支。
|
|
37
|
-
*
|
|
38
|
-
* 只认这三个键,多余的键丢掉:面板与 CLI 各写各的选项时,静默接受一个拼错的键等于
|
|
39
|
-
* 让她以为筛过了。
|
|
40
|
-
*
|
|
41
|
-
* 这里**没有** dryRun:share 是纯读、不改库,spec §4 明确它不套 reclaim 的
|
|
42
|
-
* dry-run/confirm 纪律,干跑由 CLI 侧的 `--dry-run` 决定(它压根不发这个键)。上一版
|
|
43
|
-
* 把它「登记但不参与答复构造」留着,等于凭空多出一个没人消费的公开字段:今天发
|
|
44
|
-
* `dryRun: true` 的人拿到的是真包,而哪天要给它真语义、或把它删掉,两侧都是破坏性改动。
|
|
45
|
-
* 删掉后它和别的多余键走同一条规则——丢掉,不再是一个特例。
|
|
46
|
-
*
|
|
47
|
-
* @returns {{ok: true, options: {alias?: string, type?: unknown, tag?: unknown}}
|
|
48
|
-
* | {ok: false, error: string}}
|
|
49
|
-
*/
|
|
50
|
-
export function parseShareBody(text) {
|
|
51
|
-
if (text === undefined || text === null || String(text).trim() === "") return { ok: true, options: {} };
|
|
52
|
-
let body;
|
|
53
|
-
try {
|
|
54
|
-
body = JSON.parse(String(text));
|
|
55
|
-
} catch {
|
|
56
|
-
return { ok: false, error: "invalid-json" };
|
|
57
|
-
}
|
|
58
|
-
if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
|
|
59
|
-
const options = {};
|
|
60
|
-
if (typeof body.alias === "string") options.alias = body.alias;
|
|
61
|
-
// type / tag 在这里只判「填没填」,不判形状。收窄口径是 share.js 的 shareFilterSet,
|
|
62
|
-
// 它钉死的是「读不懂的形状只许收窄到 0 条,不许当没填」(错的方向是少发,当场看得见)。
|
|
63
|
-
// 本层若再校验一次形状、把裸字符串或混进非字符串条目的数组丢成「没填」,就等于在 HTTP
|
|
64
|
-
// 面上把那条洞反着挖开——她以为只发了一类,实际整库进包,而 report 看不出异样。
|
|
65
|
-
if (body.type !== undefined && body.type !== null) options.type = body.type;
|
|
66
|
-
if (body.tag !== undefined && body.tag !== null) options.tag = body.tag;
|
|
67
|
-
return { ok: true, options };
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** 包文件名:日期 + pack_id 前 8 位。Content-Disposition 与 CLI 落盘共用这一个拼法。 */
|
|
71
|
-
export function shareFilename(packId, now = () => new Date()) {
|
|
72
|
-
const stamp = now().toISOString().slice(0, 10).replace(/-/g, "");
|
|
73
|
-
return `dsh-mneme-share-${stamp}-${String(packId).slice(0, 8)}.json`;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* 组包并给出答复。`service.all()` 是「全库含归档/已遗忘」的现成通道(store.js 的 all()
|
|
78
|
-
* 不带 WHERE),口径判据全在 share.js 里判,本模块不重复任何一条。
|
|
79
|
-
*
|
|
80
|
-
* filters 两个键只在填了时才挂上去:buildSharePack 的默认值兜的是 `filters` 整个参数为
|
|
81
|
-
* undefined,构造一个 `filters: null` 会直接在对端解引用时抛——没填的键就让它不存在。
|
|
82
|
-
*
|
|
83
|
-
* 413 那条绝不回 pack:这条答复存在的原因恰恰是包太大,把 memories 序列化回去等于把
|
|
84
|
-
* 刚拒绝掉的那几 MB 再发一遍。report + 量到的字节 + 水位 + 提示够出口说清「大了多少、
|
|
85
|
-
* 怎么分批」(share.js 超限时也把完整 pack 交回,本层只用它的 report)。
|
|
86
|
-
*
|
|
87
|
-
* 抛错在这里兜住并回 500,不留给调用方的 try:面板侧 handler 的形状是
|
|
88
|
-
* `try { return readBody(...).then(...) } catch`,外层 try 在 .then 的回调里已经退栈,
|
|
89
|
-
* 从这里抛出去就是一个没人接的 rejection,客户端拿到的不是 500 而是「一个字节都没回」
|
|
90
|
-
* (#410,reclaim-http.js 里 reclaimReply 那段注释记的就是这一次)。共用层兜一次,两张
|
|
91
|
-
* 皮才不会因为各自接线不同而有一种会漏。warn 可选:数据面的 logger 未必接得上,少一个
|
|
92
|
-
* 回调也不许把异常漏出去。
|
|
93
|
-
*
|
|
94
|
-
* @param {{service: {all: () => object[]}, packageVersion: string, homeDir: string,
|
|
95
|
-
* now?: () => Date, options?: object, warn?: ((msg: string) => void)|null}} input
|
|
96
|
-
* @returns {{status: number, body: object}}
|
|
97
|
-
*/
|
|
98
|
-
export function shareReply({ service, packageVersion, homeDir, now = () => new Date(), options = {}, warn = null }) {
|
|
99
|
-
try {
|
|
100
|
-
const rows = typeof service?.all === "function" ? service.all() : [];
|
|
101
|
-
const filters = {};
|
|
102
|
-
if (options.type !== undefined) filters.type = options.type;
|
|
103
|
-
if (options.tag !== undefined) filters.tag = options.tag;
|
|
104
|
-
const out = buildSharePack({
|
|
105
|
-
rows, alias: options.alias, homeDir, packageVersion,
|
|
106
|
-
filters,
|
|
107
|
-
generatedAt: now().toISOString()
|
|
108
|
-
});
|
|
109
|
-
if (!out.ok) {
|
|
110
|
-
return {
|
|
111
|
-
status: 413,
|
|
112
|
-
body: { error: out.error, bytes: out.bytes, limitBytes: out.limitBytes, hint: SHARE_ERROR_HINT, report: out.pack.report }
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
return { status: 200, body: out.pack };
|
|
116
|
-
} catch (error) {
|
|
117
|
-
// 日志里留住原始文本(现场最难下手的就是「只回了 internal」那一类),对外只有一个码。
|
|
118
|
-
warnSafely(warn, `[dsh-mneme] share pack failed: ${String(error)}`);
|
|
119
|
-
return { status: 500, body: { error: "internal" } };
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// --- 接收侧(车道 C,spec §5)--------------------------------------------------
|
|
124
|
-
// 入库与整包退出同属「两张皮只许差在鉴权与路径」那条纪律(#411),所以这两组解析/答复
|
|
125
|
-
// 也住在本模块,与出包侧同一个形状:只回 {status, body},绝不写 res。
|
|
126
|
-
//
|
|
127
|
-
// 这里刻意**不**重跑 validateSharePack:整包闸门住在 share.js、由 service 的
|
|
128
|
-
// importSharePack 自己调(src/share-import.js)。本层再判一次就是第二套口径——两份实现
|
|
129
|
-
// 各自演进时最坏情况是「路由放行、service 拒」或反过来,而一个包有没有合格从此没有准信。
|
|
130
|
-
// 失败靠 err.code 鸭子类型映射成状态码:ShareImportError 是刻意不从 service 再导出的
|
|
131
|
-
// (类跨模块之后,instanceof 就退化成「只在同一个实例内成立」),码才是契约。
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* 导入错误码 → HTTP 状态。一张表喂两张皮(数据面那半也从这儿取),码集由 share.js 的
|
|
135
|
-
* validateSharePack 定:闸门新增一格必须在这里登记。认不出的码走「500 + 日志」那一条,
|
|
136
|
-
* 绝不静默降级成 400 冒充「你的包不合格」——那会把存储故障报成对方的错。
|
|
137
|
-
*/
|
|
138
|
-
export const SHARE_IMPORT_ERRORS = Object.freeze({
|
|
139
|
-
"invalid-kind": 400,
|
|
140
|
-
"invalid-pack-id": 400,
|
|
141
|
-
"invalid-memories": 400,
|
|
142
|
-
"empty-pack": 400,
|
|
143
|
-
"invalid-type": 400,
|
|
144
|
-
"invalid-entry": 400,
|
|
145
|
-
"external-id-mismatch": 400,
|
|
146
|
-
"duplicate-external-id": 400
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 「收侧没接线」的码(headless 或旧装配里没有那两个方法)。与 RECLAIM_UNAVAILABLE 同一
|
|
151
|
-
* 处置:字面量只许住在本模块,两张皮都从这一个导出取,否则各写一种拼法就没法按码分支。
|
|
152
|
-
*/
|
|
153
|
-
export const SHARE_IMPORT_UNAVAILABLE = "share-import-unavailable";
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* 缺省即干跑:没有 confirm 就是预览。脾气照 readReclaimFields 的 confirm(只认真布尔),
|
|
157
|
-
* 但这一面的方向更硬——写的是**收件人的库**,所以唯一的入口就是 confirm,`dryRun` 之类
|
|
158
|
-
* 的第二个旋钮一概不认(reclaim 的 body 形状里就带 dryRun,手熟的人会顺手发来,把它读成
|
|
159
|
-
* 「要写」等于替她点头)。
|
|
160
|
-
*/
|
|
161
|
-
function readDryRun(body) {
|
|
162
|
-
return body?.confirm !== true;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* 答复壳里唯一由本层加的一格。service 那一侧收的是 opts.dryRun、不认识 dry_run,对面读的
|
|
167
|
-
* 却是这一格,所以放在本层加:两张皮拿到的键才完全相同。
|
|
168
|
-
*
|
|
169
|
-
* `dryRun !== false` 而不是 `=== true`:认不出的值(字符串、对象、undefined)一律落回**干跑**,
|
|
170
|
-
* 与解析侧同一个失败方向;而传下去的那个布尔值与写进答复的那一格永远同一个数——「其实没写、
|
|
171
|
-
* 却说写了」和「其实写了、却说没写」都是说谎,这一格不许和实参分家。
|
|
172
|
-
*/
|
|
173
|
-
function withDryRun(reply, dryRun) {
|
|
174
|
-
return { ...reply, dry_run: dryRun !== false };
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* 解析 POST /receive 的 body(已读成文本)→ { pack, dryRun }。
|
|
179
|
-
*
|
|
180
|
-
* 三个码分开是有原因的:invalid-json(发坏了)、invalid-body(顶层就不是对象)、
|
|
181
|
-
* missing-pack(对象里没有包)——对面据此知道改哪一头,而它们全是 400。空 body 是
|
|
182
|
-
* **错**的,与出包侧相反:那边「一个字节都不发」是整库口径,这边压根没东西可写。
|
|
183
|
-
*
|
|
184
|
-
* pack 那一格只判「是不是个对象」,不判包:数组或 `{kind:"nope"}` 都往下交,由闸门整包拒
|
|
185
|
-
* (invalid-kind)。判据只许有一处。
|
|
186
|
-
*
|
|
187
|
-
* @returns {{ok: true, pack: object, dryRun: boolean} | {ok: false, error: string}}
|
|
188
|
-
*/
|
|
189
|
-
export function parseReceiveBody(text) {
|
|
190
|
-
if (text === undefined || text === null || String(text).trim() === "") return { ok: false, error: "invalid-body" };
|
|
191
|
-
let body;
|
|
192
|
-
try {
|
|
193
|
-
body = JSON.parse(String(text));
|
|
194
|
-
} catch {
|
|
195
|
-
return { ok: false, error: "invalid-json" };
|
|
196
|
-
}
|
|
197
|
-
if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
|
|
198
|
-
if (!body.pack || typeof body.pack !== "object") return { ok: false, error: "missing-pack" };
|
|
199
|
-
return { ok: true, pack: body.pack, dryRun: readDryRun(body) };
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* 解析 POST /receive/undo 的 body → { packId, dryRun }。顶层形状与「有没有 id」是两个错,
|
|
204
|
-
* 与 receive 侧同一口径(发坏了 / 发错了形状 / 没填)。
|
|
205
|
-
*
|
|
206
|
-
* id 在这里 trim,与 deleteSharePack 首行同一把尺;非字符串与空白一律不进删除那条路——
|
|
207
|
-
* 让空白去 service 那儿换回一个 `pack_id: ""` 的 0 删除,读数上看不出是「没填」还是
|
|
208
|
-
* 「那个包本来就没导入过」,而这两种在出口是完全不同的事。
|
|
209
|
-
*
|
|
210
|
-
* @returns {{ok: true, packId: string, dryRun: boolean} | {ok: false, error: string}}
|
|
211
|
-
*/
|
|
212
|
-
export function parseUndoBody(text) {
|
|
213
|
-
if (text === undefined || text === null || String(text).trim() === "") return { ok: false, error: "invalid-body" };
|
|
214
|
-
let body;
|
|
215
|
-
try {
|
|
216
|
-
body = JSON.parse(String(text));
|
|
217
|
-
} catch {
|
|
218
|
-
return { ok: false, error: "invalid-json" };
|
|
219
|
-
}
|
|
220
|
-
if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
|
|
221
|
-
const packId = typeof body.packId === "string" ? body.packId.trim() : "";
|
|
222
|
-
if (!packId) return { ok: false, error: "missing-pack-id" };
|
|
223
|
-
return { ok: true, packId, dryRun: readDryRun(body) };
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* 入库的答复。`pack` 原样交给 service,校验在那儿跑(见本段开头那句「判据只许有一处」)。
|
|
228
|
-
*
|
|
229
|
-
* 抛错在这儿兜住并回 500,不留给调用方的 try:两侧 handler 的形状都是
|
|
230
|
-
* `try { return readBody(...).then(...) } catch`,外层 try 在 .then 的回调里已经退栈,
|
|
231
|
-
* 从这里抛出去就是一个没人接的 rejection(#410)。warn 可选——数据面的 logger 未必接得上,
|
|
232
|
-
* 少一个回调不许把异常漏出去。
|
|
233
|
-
*
|
|
234
|
-
* @param {{service: {importSharePack?: Function}, pack: object, dryRun?: boolean,
|
|
235
|
-
* warn?: ((msg: string) => void)|null}} input
|
|
236
|
-
* @returns {{status: number, body: object}}
|
|
237
|
-
*/
|
|
238
|
-
export function receiveReply({ service, pack, dryRun, warn = null }) {
|
|
239
|
-
if (typeof service?.importSharePack !== "function") {
|
|
240
|
-
return { status: 503, body: { error: SHARE_IMPORT_UNAVAILABLE } };
|
|
241
|
-
}
|
|
242
|
-
const dry = dryRun !== false;
|
|
243
|
-
try {
|
|
244
|
-
return { status: 200, body: withDryRun(service.importSharePack(pack, { dryRun: dry }), dry) };
|
|
245
|
-
} catch (error) {
|
|
246
|
-
const code = typeof error?.code === "string" ? error.code : null;
|
|
247
|
-
const status = code === null ? undefined : SHARE_IMPORT_ERRORS[code];
|
|
248
|
-
if (status) {
|
|
249
|
-
// detail 是闸门给的那一格(哪个字段、哪个坏类型),只转发不加工;没有就不造这一格。
|
|
250
|
-
const detail = typeof error.detail === "string" && error.detail ? { detail: error.detail } : {};
|
|
251
|
-
return { status, body: { error: code, ...detail } };
|
|
252
|
-
}
|
|
253
|
-
warnSafely(warn, `[dsh-mneme] share import failed: ${String(error)}`);
|
|
254
|
-
return { status: 500, body: { error: "internal" } };
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* 整包退出的答复。这一面**不查** SHARE_IMPORT_ERRORS:packId 的形状闸门在 parseUndoBody,
|
|
260
|
-
* service 那侧不抛带码的错(非字符串/空白它回一个 0 删除,不是异常),所以真抛出来就是
|
|
261
|
-
* 存储故障。别在这儿补第二张表——那张表只会成为 SHARE_IMPORT_ERRORS 的影子。
|
|
262
|
-
*
|
|
263
|
-
* 答复里的 pack_id 是 service 的读数而不是请求的回显(非字符串/空白那一支它回 ""),
|
|
264
|
-
* 本层不改写、不兜底;dry_run 由 withDryRun 加,与入库那侧同一格键。
|
|
265
|
-
*
|
|
266
|
-
* @param {{service: {deleteSharePack?: Function}, packId: string, dryRun?: boolean,
|
|
267
|
-
* warn?: ((msg: string) => void)|null}} input
|
|
268
|
-
* @returns {{status: number, body: object}}
|
|
269
|
-
*/
|
|
270
|
-
export function undoReply({ service, packId, dryRun, warn = null }) {
|
|
271
|
-
if (typeof service?.deleteSharePack !== "function") {
|
|
272
|
-
return { status: 503, body: { error: SHARE_IMPORT_UNAVAILABLE } };
|
|
273
|
-
}
|
|
274
|
-
const dry = dryRun !== false;
|
|
275
|
-
try {
|
|
276
|
-
return { status: 200, body: withDryRun(service.deleteSharePack(packId, { dryRun: dry }), dry) };
|
|
277
|
-
} catch (error) {
|
|
278
|
-
warnSafely(warn, `[dsh-mneme] share undo failed: ${String(error)}`);
|
|
279
|
-
return { status: 500, body: { error: "internal" } };
|
|
280
|
-
}
|
|
281
|
-
}
|
|
1
|
+
// 分享包在两张皮上共用的解析与答复(形状照 src/reclaim-http.js,#411)。
|
|
2
|
+
// 只返回 {status, body},绝不自己写 res —— 两侧的 sendJson 签名不同(api.js 有
|
|
3
|
+
// headers 第四参、api-standalone.js 没有),把写 res 留在各侧 handler 里是唯一
|
|
4
|
+
// 能让一份实现喂两张脸的做法。
|
|
5
|
+
//
|
|
6
|
+
// 哪些行进包、以什么原因不进,一条判据都不在这里重复:那是 src/share.js 的事。本模块
|
|
7
|
+
// 只做协议层的事——读 body、把结果包成答复、给一个能落盘的文件名。
|
|
8
|
+
import { buildSharePack } from "./share.js";
|
|
9
|
+
|
|
10
|
+
/** 拒发时的下一步动作。它是给调用方看的,出口只许有一处措辞(同 RECLAIM_CONFIRM_HINT)。 */
|
|
11
|
+
const SHARE_ERROR_HINT = "包体超过分享水位:用 --type 或 --tag 分批,别整库外发。";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 记日志这一手,只许经这里。
|
|
15
|
+
*
|
|
16
|
+
* 「这一层从不抛」是**层的契约**,不是每个调用面的运气(C5 评审裁定):warn 裸调时,宿主
|
|
17
|
+
* logger 自己坏掉就会从 catch 块里再抛出去,而两侧 handler 那个外层 try 在 .then 的回调里
|
|
18
|
+
* 早已退栈——现场就是「一个字节都没回」(#410)。守卫住在面上一处一个,等于每接一张新脸
|
|
19
|
+
* 都要记得再兜一次;住在层里,两侧、以及后面的 CLI(C7)拿到的都是同一个脾气。
|
|
20
|
+
*
|
|
21
|
+
* 三个构造器(shareReply / receiveReply / undoReply)都走这里,**对称本身就是要点**:
|
|
22
|
+
* 只给新加的两个上守卫、出包那侧留一处裸调,下一个读者就会照那处裸的抄。
|
|
23
|
+
* 日志环坏掉时答复照旧送出——对面拿到的仍是那一个状态码,只是少了一条日志迹。
|
|
24
|
+
*/
|
|
25
|
+
function warnSafely(warn, message) {
|
|
26
|
+
try {
|
|
27
|
+
warn?.(message);
|
|
28
|
+
} catch { /* 记日志是自己的事,坏了的日志不许把已经算好的答复一起带走 */ }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 解析 POST body(已由调用方读成文本)→ buildSharePack 的入参集合。
|
|
33
|
+
*
|
|
34
|
+
* 空 body 等价于 `{}`:分享的主用法就是「一个字节都不发,按整库口径打」。坏 JSON 与
|
|
35
|
+
* 发成数组/null 是两个不同的错码(前者是调用方发坏了,后者是发错了顶层形状),
|
|
36
|
+
* 与 reclaim 侧同款,出口要能分支。
|
|
37
|
+
*
|
|
38
|
+
* 只认这三个键,多余的键丢掉:面板与 CLI 各写各的选项时,静默接受一个拼错的键等于
|
|
39
|
+
* 让她以为筛过了。
|
|
40
|
+
*
|
|
41
|
+
* 这里**没有** dryRun:share 是纯读、不改库,spec §4 明确它不套 reclaim 的
|
|
42
|
+
* dry-run/confirm 纪律,干跑由 CLI 侧的 `--dry-run` 决定(它压根不发这个键)。上一版
|
|
43
|
+
* 把它「登记但不参与答复构造」留着,等于凭空多出一个没人消费的公开字段:今天发
|
|
44
|
+
* `dryRun: true` 的人拿到的是真包,而哪天要给它真语义、或把它删掉,两侧都是破坏性改动。
|
|
45
|
+
* 删掉后它和别的多余键走同一条规则——丢掉,不再是一个特例。
|
|
46
|
+
*
|
|
47
|
+
* @returns {{ok: true, options: {alias?: string, type?: unknown, tag?: unknown}}
|
|
48
|
+
* | {ok: false, error: string}}
|
|
49
|
+
*/
|
|
50
|
+
export function parseShareBody(text) {
|
|
51
|
+
if (text === undefined || text === null || String(text).trim() === "") return { ok: true, options: {} };
|
|
52
|
+
let body;
|
|
53
|
+
try {
|
|
54
|
+
body = JSON.parse(String(text));
|
|
55
|
+
} catch {
|
|
56
|
+
return { ok: false, error: "invalid-json" };
|
|
57
|
+
}
|
|
58
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
|
|
59
|
+
const options = {};
|
|
60
|
+
if (typeof body.alias === "string") options.alias = body.alias;
|
|
61
|
+
// type / tag 在这里只判「填没填」,不判形状。收窄口径是 share.js 的 shareFilterSet,
|
|
62
|
+
// 它钉死的是「读不懂的形状只许收窄到 0 条,不许当没填」(错的方向是少发,当场看得见)。
|
|
63
|
+
// 本层若再校验一次形状、把裸字符串或混进非字符串条目的数组丢成「没填」,就等于在 HTTP
|
|
64
|
+
// 面上把那条洞反着挖开——她以为只发了一类,实际整库进包,而 report 看不出异样。
|
|
65
|
+
if (body.type !== undefined && body.type !== null) options.type = body.type;
|
|
66
|
+
if (body.tag !== undefined && body.tag !== null) options.tag = body.tag;
|
|
67
|
+
return { ok: true, options };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** 包文件名:日期 + pack_id 前 8 位。Content-Disposition 与 CLI 落盘共用这一个拼法。 */
|
|
71
|
+
export function shareFilename(packId, now = () => new Date()) {
|
|
72
|
+
const stamp = now().toISOString().slice(0, 10).replace(/-/g, "");
|
|
73
|
+
return `dsh-mneme-share-${stamp}-${String(packId).slice(0, 8)}.json`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 组包并给出答复。`service.all()` 是「全库含归档/已遗忘」的现成通道(store.js 的 all()
|
|
78
|
+
* 不带 WHERE),口径判据全在 share.js 里判,本模块不重复任何一条。
|
|
79
|
+
*
|
|
80
|
+
* filters 两个键只在填了时才挂上去:buildSharePack 的默认值兜的是 `filters` 整个参数为
|
|
81
|
+
* undefined,构造一个 `filters: null` 会直接在对端解引用时抛——没填的键就让它不存在。
|
|
82
|
+
*
|
|
83
|
+
* 413 那条绝不回 pack:这条答复存在的原因恰恰是包太大,把 memories 序列化回去等于把
|
|
84
|
+
* 刚拒绝掉的那几 MB 再发一遍。report + 量到的字节 + 水位 + 提示够出口说清「大了多少、
|
|
85
|
+
* 怎么分批」(share.js 超限时也把完整 pack 交回,本层只用它的 report)。
|
|
86
|
+
*
|
|
87
|
+
* 抛错在这里兜住并回 500,不留给调用方的 try:面板侧 handler 的形状是
|
|
88
|
+
* `try { return readBody(...).then(...) } catch`,外层 try 在 .then 的回调里已经退栈,
|
|
89
|
+
* 从这里抛出去就是一个没人接的 rejection,客户端拿到的不是 500 而是「一个字节都没回」
|
|
90
|
+
* (#410,reclaim-http.js 里 reclaimReply 那段注释记的就是这一次)。共用层兜一次,两张
|
|
91
|
+
* 皮才不会因为各自接线不同而有一种会漏。warn 可选:数据面的 logger 未必接得上,少一个
|
|
92
|
+
* 回调也不许把异常漏出去。
|
|
93
|
+
*
|
|
94
|
+
* @param {{service: {all: () => object[]}, packageVersion: string, homeDir: string,
|
|
95
|
+
* now?: () => Date, options?: object, warn?: ((msg: string) => void)|null}} input
|
|
96
|
+
* @returns {{status: number, body: object}}
|
|
97
|
+
*/
|
|
98
|
+
export function shareReply({ service, packageVersion, homeDir, now = () => new Date(), options = {}, warn = null }) {
|
|
99
|
+
try {
|
|
100
|
+
const rows = typeof service?.all === "function" ? service.all() : [];
|
|
101
|
+
const filters = {};
|
|
102
|
+
if (options.type !== undefined) filters.type = options.type;
|
|
103
|
+
if (options.tag !== undefined) filters.tag = options.tag;
|
|
104
|
+
const out = buildSharePack({
|
|
105
|
+
rows, alias: options.alias, homeDir, packageVersion,
|
|
106
|
+
filters,
|
|
107
|
+
generatedAt: now().toISOString()
|
|
108
|
+
});
|
|
109
|
+
if (!out.ok) {
|
|
110
|
+
return {
|
|
111
|
+
status: 413,
|
|
112
|
+
body: { error: out.error, bytes: out.bytes, limitBytes: out.limitBytes, hint: SHARE_ERROR_HINT, report: out.pack.report }
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return { status: 200, body: out.pack };
|
|
116
|
+
} catch (error) {
|
|
117
|
+
// 日志里留住原始文本(现场最难下手的就是「只回了 internal」那一类),对外只有一个码。
|
|
118
|
+
warnSafely(warn, `[dsh-mneme] share pack failed: ${String(error)}`);
|
|
119
|
+
return { status: 500, body: { error: "internal" } };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// --- 接收侧(车道 C,spec §5)--------------------------------------------------
|
|
124
|
+
// 入库与整包退出同属「两张皮只许差在鉴权与路径」那条纪律(#411),所以这两组解析/答复
|
|
125
|
+
// 也住在本模块,与出包侧同一个形状:只回 {status, body},绝不写 res。
|
|
126
|
+
//
|
|
127
|
+
// 这里刻意**不**重跑 validateSharePack:整包闸门住在 share.js、由 service 的
|
|
128
|
+
// importSharePack 自己调(src/share-import.js)。本层再判一次就是第二套口径——两份实现
|
|
129
|
+
// 各自演进时最坏情况是「路由放行、service 拒」或反过来,而一个包有没有合格从此没有准信。
|
|
130
|
+
// 失败靠 err.code 鸭子类型映射成状态码:ShareImportError 是刻意不从 service 再导出的
|
|
131
|
+
// (类跨模块之后,instanceof 就退化成「只在同一个实例内成立」),码才是契约。
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* 导入错误码 → HTTP 状态。一张表喂两张皮(数据面那半也从这儿取),码集由 share.js 的
|
|
135
|
+
* validateSharePack 定:闸门新增一格必须在这里登记。认不出的码走「500 + 日志」那一条,
|
|
136
|
+
* 绝不静默降级成 400 冒充「你的包不合格」——那会把存储故障报成对方的错。
|
|
137
|
+
*/
|
|
138
|
+
export const SHARE_IMPORT_ERRORS = Object.freeze({
|
|
139
|
+
"invalid-kind": 400,
|
|
140
|
+
"invalid-pack-id": 400,
|
|
141
|
+
"invalid-memories": 400,
|
|
142
|
+
"empty-pack": 400,
|
|
143
|
+
"invalid-type": 400,
|
|
144
|
+
"invalid-entry": 400,
|
|
145
|
+
"external-id-mismatch": 400,
|
|
146
|
+
"duplicate-external-id": 400
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 「收侧没接线」的码(headless 或旧装配里没有那两个方法)。与 RECLAIM_UNAVAILABLE 同一
|
|
151
|
+
* 处置:字面量只许住在本模块,两张皮都从这一个导出取,否则各写一种拼法就没法按码分支。
|
|
152
|
+
*/
|
|
153
|
+
export const SHARE_IMPORT_UNAVAILABLE = "share-import-unavailable";
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 缺省即干跑:没有 confirm 就是预览。脾气照 readReclaimFields 的 confirm(只认真布尔),
|
|
157
|
+
* 但这一面的方向更硬——写的是**收件人的库**,所以唯一的入口就是 confirm,`dryRun` 之类
|
|
158
|
+
* 的第二个旋钮一概不认(reclaim 的 body 形状里就带 dryRun,手熟的人会顺手发来,把它读成
|
|
159
|
+
* 「要写」等于替她点头)。
|
|
160
|
+
*/
|
|
161
|
+
function readDryRun(body) {
|
|
162
|
+
return body?.confirm !== true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 答复壳里唯一由本层加的一格。service 那一侧收的是 opts.dryRun、不认识 dry_run,对面读的
|
|
167
|
+
* 却是这一格,所以放在本层加:两张皮拿到的键才完全相同。
|
|
168
|
+
*
|
|
169
|
+
* `dryRun !== false` 而不是 `=== true`:认不出的值(字符串、对象、undefined)一律落回**干跑**,
|
|
170
|
+
* 与解析侧同一个失败方向;而传下去的那个布尔值与写进答复的那一格永远同一个数——「其实没写、
|
|
171
|
+
* 却说写了」和「其实写了、却说没写」都是说谎,这一格不许和实参分家。
|
|
172
|
+
*/
|
|
173
|
+
function withDryRun(reply, dryRun) {
|
|
174
|
+
return { ...reply, dry_run: dryRun !== false };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 解析 POST /receive 的 body(已读成文本)→ { pack, dryRun }。
|
|
179
|
+
*
|
|
180
|
+
* 三个码分开是有原因的:invalid-json(发坏了)、invalid-body(顶层就不是对象)、
|
|
181
|
+
* missing-pack(对象里没有包)——对面据此知道改哪一头,而它们全是 400。空 body 是
|
|
182
|
+
* **错**的,与出包侧相反:那边「一个字节都不发」是整库口径,这边压根没东西可写。
|
|
183
|
+
*
|
|
184
|
+
* pack 那一格只判「是不是个对象」,不判包:数组或 `{kind:"nope"}` 都往下交,由闸门整包拒
|
|
185
|
+
* (invalid-kind)。判据只许有一处。
|
|
186
|
+
*
|
|
187
|
+
* @returns {{ok: true, pack: object, dryRun: boolean} | {ok: false, error: string}}
|
|
188
|
+
*/
|
|
189
|
+
export function parseReceiveBody(text) {
|
|
190
|
+
if (text === undefined || text === null || String(text).trim() === "") return { ok: false, error: "invalid-body" };
|
|
191
|
+
let body;
|
|
192
|
+
try {
|
|
193
|
+
body = JSON.parse(String(text));
|
|
194
|
+
} catch {
|
|
195
|
+
return { ok: false, error: "invalid-json" };
|
|
196
|
+
}
|
|
197
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
|
|
198
|
+
if (!body.pack || typeof body.pack !== "object") return { ok: false, error: "missing-pack" };
|
|
199
|
+
return { ok: true, pack: body.pack, dryRun: readDryRun(body) };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 解析 POST /receive/undo 的 body → { packId, dryRun }。顶层形状与「有没有 id」是两个错,
|
|
204
|
+
* 与 receive 侧同一口径(发坏了 / 发错了形状 / 没填)。
|
|
205
|
+
*
|
|
206
|
+
* id 在这里 trim,与 deleteSharePack 首行同一把尺;非字符串与空白一律不进删除那条路——
|
|
207
|
+
* 让空白去 service 那儿换回一个 `pack_id: ""` 的 0 删除,读数上看不出是「没填」还是
|
|
208
|
+
* 「那个包本来就没导入过」,而这两种在出口是完全不同的事。
|
|
209
|
+
*
|
|
210
|
+
* @returns {{ok: true, packId: string, dryRun: boolean} | {ok: false, error: string}}
|
|
211
|
+
*/
|
|
212
|
+
export function parseUndoBody(text) {
|
|
213
|
+
if (text === undefined || text === null || String(text).trim() === "") return { ok: false, error: "invalid-body" };
|
|
214
|
+
let body;
|
|
215
|
+
try {
|
|
216
|
+
body = JSON.parse(String(text));
|
|
217
|
+
} catch {
|
|
218
|
+
return { ok: false, error: "invalid-json" };
|
|
219
|
+
}
|
|
220
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return { ok: false, error: "invalid-body" };
|
|
221
|
+
const packId = typeof body.packId === "string" ? body.packId.trim() : "";
|
|
222
|
+
if (!packId) return { ok: false, error: "missing-pack-id" };
|
|
223
|
+
return { ok: true, packId, dryRun: readDryRun(body) };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* 入库的答复。`pack` 原样交给 service,校验在那儿跑(见本段开头那句「判据只许有一处」)。
|
|
228
|
+
*
|
|
229
|
+
* 抛错在这儿兜住并回 500,不留给调用方的 try:两侧 handler 的形状都是
|
|
230
|
+
* `try { return readBody(...).then(...) } catch`,外层 try 在 .then 的回调里已经退栈,
|
|
231
|
+
* 从这里抛出去就是一个没人接的 rejection(#410)。warn 可选——数据面的 logger 未必接得上,
|
|
232
|
+
* 少一个回调不许把异常漏出去。
|
|
233
|
+
*
|
|
234
|
+
* @param {{service: {importSharePack?: Function}, pack: object, dryRun?: boolean,
|
|
235
|
+
* warn?: ((msg: string) => void)|null}} input
|
|
236
|
+
* @returns {{status: number, body: object}}
|
|
237
|
+
*/
|
|
238
|
+
export function receiveReply({ service, pack, dryRun, warn = null }) {
|
|
239
|
+
if (typeof service?.importSharePack !== "function") {
|
|
240
|
+
return { status: 503, body: { error: SHARE_IMPORT_UNAVAILABLE } };
|
|
241
|
+
}
|
|
242
|
+
const dry = dryRun !== false;
|
|
243
|
+
try {
|
|
244
|
+
return { status: 200, body: withDryRun(service.importSharePack(pack, { dryRun: dry }), dry) };
|
|
245
|
+
} catch (error) {
|
|
246
|
+
const code = typeof error?.code === "string" ? error.code : null;
|
|
247
|
+
const status = code === null ? undefined : SHARE_IMPORT_ERRORS[code];
|
|
248
|
+
if (status) {
|
|
249
|
+
// detail 是闸门给的那一格(哪个字段、哪个坏类型),只转发不加工;没有就不造这一格。
|
|
250
|
+
const detail = typeof error.detail === "string" && error.detail ? { detail: error.detail } : {};
|
|
251
|
+
return { status, body: { error: code, ...detail } };
|
|
252
|
+
}
|
|
253
|
+
warnSafely(warn, `[dsh-mneme] share import failed: ${String(error)}`);
|
|
254
|
+
return { status: 500, body: { error: "internal" } };
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* 整包退出的答复。这一面**不查** SHARE_IMPORT_ERRORS:packId 的形状闸门在 parseUndoBody,
|
|
260
|
+
* service 那侧不抛带码的错(非字符串/空白它回一个 0 删除,不是异常),所以真抛出来就是
|
|
261
|
+
* 存储故障。别在这儿补第二张表——那张表只会成为 SHARE_IMPORT_ERRORS 的影子。
|
|
262
|
+
*
|
|
263
|
+
* 答复里的 pack_id 是 service 的读数而不是请求的回显(非字符串/空白那一支它回 ""),
|
|
264
|
+
* 本层不改写、不兜底;dry_run 由 withDryRun 加,与入库那侧同一格键。
|
|
265
|
+
*
|
|
266
|
+
* @param {{service: {deleteSharePack?: Function}, packId: string, dryRun?: boolean,
|
|
267
|
+
* warn?: ((msg: string) => void)|null}} input
|
|
268
|
+
* @returns {{status: number, body: object}}
|
|
269
|
+
*/
|
|
270
|
+
export function undoReply({ service, packId, dryRun, warn = null }) {
|
|
271
|
+
if (typeof service?.deleteSharePack !== "function") {
|
|
272
|
+
return { status: 503, body: { error: SHARE_IMPORT_UNAVAILABLE } };
|
|
273
|
+
}
|
|
274
|
+
const dry = dryRun !== false;
|
|
275
|
+
try {
|
|
276
|
+
return { status: 200, body: withDryRun(service.deleteSharePack(packId, { dryRun: dry }), dry) };
|
|
277
|
+
} catch (error) {
|
|
278
|
+
warnSafely(warn, `[dsh-mneme] share undo failed: ${String(error)}`);
|
|
279
|
+
return { status: 500, body: { error: "internal" } };
|
|
280
|
+
}
|
|
281
|
+
}
|