@semiont/make-meaning 0.5.29 → 0.5.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.
- package/README.md +23 -10
- package/dist/archivist-main.js +241 -150
- package/dist/archivist-main.js.map +1 -1
- package/dist/index.d.ts +26 -38
- package/dist/index.js +124 -76
- package/dist/index.js.map +1 -1
- package/dist/librarian-main.js +118 -50
- package/dist/librarian-main.js.map +1 -1
- package/dist/smelter-main.js +151 -42
- package/dist/smelter-main.js.map +1 -1
- package/dist/weaver-main.js +162 -51
- package/dist/weaver-main.js.map +1 -1
- package/package.json +13 -13
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JobQueue } from '@semiont/jobs';
|
|
2
2
|
import { SemiontProject, SemiontState } from '@semiont/core/node';
|
|
3
|
-
import { GraphServiceConfig, VectorsServiceConfig, EmbeddingServiceConfig, ArchivistServiceConfig, EnvironmentConfig, StateUnit, EventBus, Logger, ResourceId, ResourceDescriptor, components, AnnotationId, GatheredContext, ResourceAnnotations, Annotation, AnnotationCategory, ITransport, BaseUrl, ConnectionState, SemiontError, UserDID, EventMap, IContentTransport, PutBinaryRequest, PutBinaryOptions,
|
|
3
|
+
import { GraphServiceConfig, VectorsServiceConfig, EmbeddingServiceConfig, ArchivistServiceConfig, EnvironmentConfig, StateUnit, EventBus, Logger, ResourceId, ResourceDescriptor, components, AnnotationId, GatheredContext, ResourceAnnotations, Annotation, AnnotationCategory, ITransport, BaseUrl, ConnectionState, SemiontError, UserDID, EventMap, IContentTransport, PutBinaryRequest, PutBinaryOptions, AccessToken, BusRequestPrimitive, ChunkingConfig, UserId } from '@semiont/core';
|
|
4
4
|
import { EventReadStorage, ViewMaterializer, EventStore, ViewStorage, EventLog } from '@semiont/event-sourcing';
|
|
5
5
|
import { WorkingTreeStore, AnchoredTextStore, ContentReads } from '@semiont/content';
|
|
6
6
|
import { GraphDatabase } from '@semiont/graph';
|
|
@@ -337,6 +337,25 @@ declare class Stower {
|
|
|
337
337
|
private handleYieldUpdate;
|
|
338
338
|
private handleYieldMv;
|
|
339
339
|
private handleMarkCreate;
|
|
340
|
+
/**
|
|
341
|
+
* Persist a detection unit's annotations as ONE acknowledged batch, then
|
|
342
|
+
* answer (JOB-RESTART-SAFETY P6).
|
|
343
|
+
*
|
|
344
|
+
* The difference from `mark:create` is the reply, and it is the whole point.
|
|
345
|
+
* `mark:create` is fire-and-forget: the worker's emit resolves when the bus
|
|
346
|
+
* accepts it, which says nothing about the event log, so a down Stower loses
|
|
347
|
+
* a unit silently and a flapping one hangs the worker forever. This answers
|
|
348
|
+
* only after every append has returned, so the worker can gate unit
|
|
349
|
+
* completion — and its checkpoint — on durability.
|
|
350
|
+
*
|
|
351
|
+
* Appends are sequential, not concurrent: the event log is the system of
|
|
352
|
+
* record and a batch that half-lands under concurrency is harder to reason
|
|
353
|
+
* about than one that stops at the first failure. A partial batch is
|
|
354
|
+
* reported as a failure and the worker retries the WHOLE unit, which is safe
|
|
355
|
+
* because ids are deterministic (P3) and the annotation fold is idempotent
|
|
356
|
+
* by id — re-appending what already landed changes nothing.
|
|
357
|
+
*/
|
|
358
|
+
private handleMarkCommit;
|
|
340
359
|
private handleMarkDelete;
|
|
341
360
|
private handleMarkUpdateBody;
|
|
342
361
|
private handleMarkArchive;
|
|
@@ -722,8 +741,6 @@ interface LimitsDiscovery {
|
|
|
722
741
|
*
|
|
723
742
|
* Handles:
|
|
724
743
|
* - browse:resource-requested — single resource metadata (materialized from events)
|
|
725
|
-
* - browse:anchored-text-by-checksum-requested — the detection workers' read-through
|
|
726
|
-
* cache consult: a stored extraction outcome by content identity (ANCHORED-TEXT-TO-SMELTER P2)
|
|
727
744
|
* - browse:resources-requested — list resources
|
|
728
745
|
* - browse:annotations-requested — all annotations for a resource
|
|
729
746
|
* - browse:annotation-requested — single annotation with resolved resource
|
|
@@ -794,7 +811,6 @@ declare class Browser {
|
|
|
794
811
|
* parser nor engine. Read-only over the wire: the Smelter is the sole
|
|
795
812
|
* writer and never answers here.
|
|
796
813
|
*/
|
|
797
|
-
private handleAnchoredTextByChecksum;
|
|
798
814
|
private handleBrowseResource;
|
|
799
815
|
private handleBrowseResources;
|
|
800
816
|
private handleBrowseAnnotations;
|
|
@@ -1133,36 +1149,6 @@ declare class LocalContentTransport implements IContentTransport {
|
|
|
1133
1149
|
putBinary(_request: PutBinaryRequest, _options?: PutBinaryOptions): Promise<{
|
|
1134
1150
|
resourceId: ResourceId;
|
|
1135
1151
|
}>;
|
|
1136
|
-
/**
|
|
1137
|
-
* Store a derived coordinate map under the content checksum the producer
|
|
1138
|
-
* read (PERSIST-ANCHORS decision A — see the interface doc for why the
|
|
1139
|
-
* producer supplies the key). In local mode this is the same store the
|
|
1140
|
-
* HTTP route writes to — one storage authority, reached the same way from
|
|
1141
|
-
* every process (ANCHORED-TEXT-CACHE Lane 5).
|
|
1142
|
-
*/
|
|
1143
|
-
putAnchoredText(checksum: string, outcome: ExtractionOutcome, _options?: {
|
|
1144
|
-
auth?: AccessToken;
|
|
1145
|
-
}): Promise<void>;
|
|
1146
|
-
/** The stored outcome, or null when nothing has derived one — the common case. */
|
|
1147
|
-
getAnchoredText(resourceId: ResourceId, _options?: {
|
|
1148
|
-
auth?: AccessToken;
|
|
1149
|
-
}): Promise<ExtractionOutcome | null>;
|
|
1150
|
-
/**
|
|
1151
|
-
* The cache-consult read (PERSIST-ANCHORS P2c), straight from the store —
|
|
1152
|
-
* checksum-addressed, so no view resolution and no settle barrier: the
|
|
1153
|
-
* caller holds the content identity already.
|
|
1154
|
-
*/
|
|
1155
|
-
getAnchoredTextByChecksum(checksum: string, _options?: {
|
|
1156
|
-
auth?: AccessToken;
|
|
1157
|
-
}): Promise<ExtractionOutcome | null>;
|
|
1158
|
-
/**
|
|
1159
|
-
* The store's would-hit keys, straight from the store — planning data for
|
|
1160
|
-
* the reconcile diff (PERSIST-ANCHORS P0), so no settle barrier applies:
|
|
1161
|
-
* presence is being asked, not content at a moment.
|
|
1162
|
-
*/
|
|
1163
|
-
listAnchoredTextKeys(_options?: {
|
|
1164
|
-
auth?: AccessToken;
|
|
1165
|
-
}): Promise<string[]>;
|
|
1166
1152
|
getBinary(resourceId: ResourceId, _options?: {
|
|
1167
1153
|
auth?: AccessToken;
|
|
1168
1154
|
}): Promise<{
|
|
@@ -1654,10 +1640,12 @@ declare class Smelter {
|
|
|
1654
1640
|
* representation's checksum (the bytes the smelter would read), the
|
|
1655
1641
|
* current entity-type set (the discriminator the stamps must carry), and
|
|
1656
1642
|
* whether the media type's extractor derives geometry (whether an
|
|
1657
|
-
* anchored-text artifact should exist).
|
|
1658
|
-
*
|
|
1659
|
-
*
|
|
1660
|
-
*
|
|
1643
|
+
* anchored-text artifact should exist). Both answers are core's, keyed by the
|
|
1644
|
+
* media type's strategy: embeddable ⇔ the type has any text-reading strategy
|
|
1645
|
+
* at all, and geometry ⇔ that strategy derives it. Until READ-VS-EXTRACT P2
|
|
1646
|
+
* embeddability was asked as `EXTRACTORS[strategy] !== null` — true, but a
|
|
1647
|
+
* second statement of `strategy !== 'none'`, answered by resolving an
|
|
1648
|
+
* implementation to learn a fact about a media type.
|
|
1661
1649
|
* Shared by `reconcile()` and the `smelt:rebuild-anchors` planner.
|
|
1662
1650
|
*/
|
|
1663
1651
|
private classifyEmbeddable;
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { STALL_THRESHOLD_MS, FsJobQueue } from '@semiont/jobs';
|
|
2
2
|
import { FilesystemViewStorage, resolveStorageUri, EventQuery, createEventStore } from '@semiont/event-sourcing';
|
|
3
|
-
import { getResourceEntityTypes, getResourceId, getTargetSource, resourceId, decodeRepresentation, getBodySource, getStorageUri, getPrimaryRepresentation, getTargetSelector, deriveViews, getTextPositionSelector, annotationId, errField, userId, generateUuid, getExactText, busRequest, cloneToken, assembleAnnotation, applyBodyOperations, didToAgent, isGenerationJobParams, jobId, entityType, baseUrl, busLog, BRIDGED_CHANNELS, burstBuffer,
|
|
3
|
+
import { getResourceEntityTypes, getResourceId, getTargetSource, resourceId, decodeRepresentation, getBodySource, getStorageUri, getPrimaryRepresentation, getTargetSelector, deriveViews, getTextPositionSelector, annotationId, errField, userId, generateUuid, getExactText, busRequest, cloneToken, assembleAnnotation, applyBodyOperations, didToAgent, isGenerationJobParams, jobId, entityType, baseUrl, busLog, BRIDGED_CHANNELS, burstBuffer, textSourceOf, chunkText, getPrimaryMediaType, yieldsGeometryOf, isAnnotatable, softwareToAgent } from '@semiont/core';
|
|
4
4
|
import { recordGatherDegrade, withActorSpan, recordBusEmit, withSpan, SpanKind, registerJobQueueProvider, registerVectorIndexSizeProvider } from '@semiont/observability';
|
|
5
5
|
import { createInferenceClient } from '@semiont/inference';
|
|
6
6
|
import { compareByRecencyThenId, getGraphDatabase } from '@semiont/graph';
|
|
7
|
-
import { WorkingTreeStore, createAnchoredTextStore, RepresentationMissing, ChecksumMismatchError,
|
|
7
|
+
import { WorkingTreeStore, createAnchoredTextStore, RepresentationMissing, ChecksumMismatchError, derivingExtractorFor, calculateChecksum } from '@semiont/content';
|
|
8
8
|
import { getEntityTypes, DEFAULT_ENTITY_TYPES } from '@semiont/ontology';
|
|
9
9
|
import { mergeByResource } from '@semiont/vectors';
|
|
10
10
|
import { promises } from 'fs';
|
|
@@ -11335,6 +11335,7 @@ var Stower = class {
|
|
|
11335
11335
|
pipe("yield:update", (e) => this.handleYieldUpdate(e)),
|
|
11336
11336
|
pipe("yield:mv", (e) => this.handleYieldMv(e)),
|
|
11337
11337
|
pipe("mark:create", (e) => this.handleMarkCreate(e)),
|
|
11338
|
+
pipe("mark:commit", (e) => this.handleMarkCommit(e)),
|
|
11338
11339
|
pipe("mark:delete", (e) => this.handleMarkDelete(e)),
|
|
11339
11340
|
pipe("mark:update-body", (e) => this.handleMarkUpdateBody(e)),
|
|
11340
11341
|
pipe("frame:add-entity-type", (e) => this.handleAddEntityType(e)),
|
|
@@ -11560,6 +11561,61 @@ var Stower = class {
|
|
|
11560
11561
|
});
|
|
11561
11562
|
}
|
|
11562
11563
|
}
|
|
11564
|
+
/**
|
|
11565
|
+
* Persist a detection unit's annotations as ONE acknowledged batch, then
|
|
11566
|
+
* answer (JOB-RESTART-SAFETY P6).
|
|
11567
|
+
*
|
|
11568
|
+
* The difference from `mark:create` is the reply, and it is the whole point.
|
|
11569
|
+
* `mark:create` is fire-and-forget: the worker's emit resolves when the bus
|
|
11570
|
+
* accepts it, which says nothing about the event log, so a down Stower loses
|
|
11571
|
+
* a unit silently and a flapping one hangs the worker forever. This answers
|
|
11572
|
+
* only after every append has returned, so the worker can gate unit
|
|
11573
|
+
* completion — and its checkpoint — on durability.
|
|
11574
|
+
*
|
|
11575
|
+
* Appends are sequential, not concurrent: the event log is the system of
|
|
11576
|
+
* record and a batch that half-lands under concurrency is harder to reason
|
|
11577
|
+
* about than one that stops at the first failure. A partial batch is
|
|
11578
|
+
* reported as a failure and the worker retries the WHOLE unit, which is safe
|
|
11579
|
+
* because ids are deterministic (P3) and the annotation fold is idempotent
|
|
11580
|
+
* by id — re-appending what already landed changes nothing.
|
|
11581
|
+
*/
|
|
11582
|
+
async handleMarkCommit(event) {
|
|
11583
|
+
if (!event._userId) {
|
|
11584
|
+
throw new Error("mark:commit missing _userId (gateway injection)");
|
|
11585
|
+
}
|
|
11586
|
+
const annotations = event.annotations ?? [];
|
|
11587
|
+
try {
|
|
11588
|
+
let persisted = 0;
|
|
11589
|
+
for (const annotation of annotations) {
|
|
11590
|
+
await this.stores.eventStore.appendEvent({
|
|
11591
|
+
type: "mark:added",
|
|
11592
|
+
resourceId: resourceId(event.resourceId),
|
|
11593
|
+
userId: userId(event._userId),
|
|
11594
|
+
version: 1,
|
|
11595
|
+
payload: { annotation }
|
|
11596
|
+
});
|
|
11597
|
+
persisted++;
|
|
11598
|
+
}
|
|
11599
|
+
this.logger.debug("Committed annotation batch", {
|
|
11600
|
+
correlationId: event.correlationId,
|
|
11601
|
+
resourceId: event.resourceId,
|
|
11602
|
+
persisted
|
|
11603
|
+
});
|
|
11604
|
+
this.eventBus.get("mark:commit-ok").next({
|
|
11605
|
+
correlationId: event.correlationId,
|
|
11606
|
+
response: { persisted, annotationIds: annotations.map((a) => String(a.id)) }
|
|
11607
|
+
});
|
|
11608
|
+
} catch (error) {
|
|
11609
|
+
this.logger.error("Failed to commit annotation batch", {
|
|
11610
|
+
correlationId: event.correlationId,
|
|
11611
|
+
error: errField(error)
|
|
11612
|
+
});
|
|
11613
|
+
this.eventBus.get("mark:commit-failed").next({
|
|
11614
|
+
correlationId: event.correlationId,
|
|
11615
|
+
message: error instanceof Error ? error.message : String(error)
|
|
11616
|
+
});
|
|
11617
|
+
}
|
|
11618
|
+
}
|
|
11563
11619
|
async handleMarkDelete(event) {
|
|
11564
11620
|
if (!event._userId) {
|
|
11565
11621
|
throw new Error("mark:delete missing _userId (gateway injection)");
|
|
@@ -11805,17 +11861,19 @@ var Stower = class {
|
|
|
11805
11861
|
var import_rxjs4 = __toESM(require_cjs());
|
|
11806
11862
|
var import_operators4 = __toESM(require_operators());
|
|
11807
11863
|
var ANCHORED_TEXT_SETTLE_TIMEOUT_MS = 15e3;
|
|
11808
|
-
async function readAnchoredText(kb, resourceId10) {
|
|
11864
|
+
async function readAnchoredText(kb, resourceId10, settleTimeoutMs = ANCHORED_TEXT_SETTLE_TIMEOUT_MS) {
|
|
11809
11865
|
const view = await kb.views.get(resourceId(resourceId10));
|
|
11810
11866
|
const checksum = getPrimaryRepresentation(view?.resource)?.checksum;
|
|
11811
|
-
if (!checksum) return
|
|
11867
|
+
if (!checksum) return { kind: "unknown" };
|
|
11812
11868
|
const hit = await kb.anchoredText.read(checksum);
|
|
11813
11869
|
if (hit) return hit;
|
|
11814
11870
|
try {
|
|
11815
|
-
const outcome = await kb.smeltProgress.whenSettled(resourceId10, checksum,
|
|
11816
|
-
|
|
11871
|
+
const outcome = await kb.smeltProgress.whenSettled(resourceId10, checksum, settleTimeoutMs);
|
|
11872
|
+
if (outcome === "skipped") return { kind: "no-map" };
|
|
11873
|
+
if (outcome === "inert") return { kind: "not-yet" };
|
|
11874
|
+
return await kb.anchoredText.read(checksum) ?? { kind: "not-yet" };
|
|
11817
11875
|
} catch (error) {
|
|
11818
|
-
if (error instanceof SmeltProgressTimeout) return
|
|
11876
|
+
if (error instanceof SmeltProgressTimeout) return { kind: "not-yet" };
|
|
11819
11877
|
throw error;
|
|
11820
11878
|
}
|
|
11821
11879
|
}
|
|
@@ -11947,7 +12005,6 @@ var Browser = class {
|
|
|
11947
12005
|
this.subscriptions.push(
|
|
11948
12006
|
pipe("browse:resource-requested", (e) => this.handleBrowseResource(e)).subscribe({ error: errorHandler }),
|
|
11949
12007
|
pipe("browse:anchored-text-requested", (e) => this.handleAnchoredText(e)).subscribe({ error: errorHandler }),
|
|
11950
|
-
pipe("browse:anchored-text-by-checksum-requested", (e) => this.handleAnchoredTextByChecksum(e)).subscribe({ error: errorHandler }),
|
|
11951
12008
|
pipe("browse:resources-requested", (e) => this.handleBrowseResources(e)).subscribe({ error: errorHandler }),
|
|
11952
12009
|
pipe("browse:annotations-requested", (e) => this.handleBrowseAnnotations(e)).subscribe({ error: errorHandler }),
|
|
11953
12010
|
pipe("browse:annotation-requested", (e) => this.handleBrowseAnnotation(e)).subscribe({ error: errorHandler }),
|
|
@@ -12001,20 +12058,6 @@ var Browser = class {
|
|
|
12001
12058
|
* parser nor engine. Read-only over the wire: the Smelter is the sole
|
|
12002
12059
|
* writer and never answers here.
|
|
12003
12060
|
*/
|
|
12004
|
-
async handleAnchoredTextByChecksum(event) {
|
|
12005
|
-
try {
|
|
12006
|
-
this.eventBus.get("browse:anchored-text-by-checksum-result").next({
|
|
12007
|
-
correlationId: event.correlationId,
|
|
12008
|
-
response: await this.kb.anchoredText.read(event.checksum)
|
|
12009
|
-
});
|
|
12010
|
-
} catch (error) {
|
|
12011
|
-
this.logger.error("Browse anchored text by checksum failed", { checksum: event.checksum, error: errField(error) });
|
|
12012
|
-
this.eventBus.get("browse:anchored-text-by-checksum-failed").next({
|
|
12013
|
-
correlationId: event.correlationId,
|
|
12014
|
-
message: error instanceof Error ? error.message : String(error)
|
|
12015
|
-
});
|
|
12016
|
-
}
|
|
12017
|
-
}
|
|
12018
12061
|
async handleBrowseResource(event) {
|
|
12019
12062
|
try {
|
|
12020
12063
|
const response = await assembleResourceGraph(this.kb, resourceId(event.resourceId));
|
|
@@ -13194,7 +13237,7 @@ function registerJobCommandHandlers(eventBus, jobQueue, state, parentLogger) {
|
|
|
13194
13237
|
});
|
|
13195
13238
|
eventBus.get("job:fail").subscribe(async (event) => {
|
|
13196
13239
|
try {
|
|
13197
|
-
const outcome = await jobQueue.failJob(jobId(event.jobId), event.error);
|
|
13240
|
+
const outcome = await jobQueue.failJob(jobId(event.jobId), event.error, event.completedUnits, event.failureClass);
|
|
13198
13241
|
if (outcome === "retried") {
|
|
13199
13242
|
logger.info("Job re-queued for retry", { jobId: event.jobId });
|
|
13200
13243
|
} else if (outcome === null) {
|
|
@@ -13220,16 +13263,45 @@ function registerJobCommandHandlers(eventBus, jobQueue, state, parentLogger) {
|
|
|
13220
13263
|
});
|
|
13221
13264
|
}
|
|
13222
13265
|
});
|
|
13266
|
+
eventBus.get("job:checkpoint").subscribe(async (event) => {
|
|
13267
|
+
try {
|
|
13268
|
+
await jobQueue.checkpointUnits(jobId(event.jobId), event.completedUnits);
|
|
13269
|
+
} catch (error) {
|
|
13270
|
+
logger.error("Failed to checkpoint job units", {
|
|
13271
|
+
jobId: event.jobId,
|
|
13272
|
+
error: error.message
|
|
13273
|
+
});
|
|
13274
|
+
}
|
|
13275
|
+
});
|
|
13223
13276
|
eventBus.get("job:cancel-requested").subscribe(async (event) => {
|
|
13224
13277
|
try {
|
|
13225
|
-
|
|
13226
|
-
|
|
13278
|
+
let cancelled;
|
|
13279
|
+
if (event.jobId) {
|
|
13280
|
+
const target = await jobQueue.getJob(jobId(event.jobId));
|
|
13281
|
+
if (!target) {
|
|
13282
|
+
cancelled = 0;
|
|
13283
|
+
} else if (target.status === "pending") {
|
|
13284
|
+
cancelled = await jobQueue.cancelJob(jobId(event.jobId)) ? 1 : 0;
|
|
13285
|
+
} else if (target.status === "running") {
|
|
13286
|
+
logger.info("Cancel of running job delegated to its worker", { jobId: event.jobId });
|
|
13287
|
+
cancelled = 1;
|
|
13288
|
+
} else {
|
|
13289
|
+
cancelled = 0;
|
|
13290
|
+
}
|
|
13291
|
+
logger.info("Cancel requested", { jobId: event.jobId, cancelled });
|
|
13292
|
+
} else if (event.jobType) {
|
|
13293
|
+
cancelled = await jobQueue.cancelPendingJobs(event.jobType);
|
|
13294
|
+
logger.info("Cancel requested", { jobType: event.jobType, cancelled });
|
|
13295
|
+
} else {
|
|
13296
|
+
cancelled = 0;
|
|
13297
|
+
}
|
|
13227
13298
|
eventBus.get("job:cancel-ok").next({
|
|
13228
13299
|
correlationId: event.correlationId,
|
|
13229
13300
|
response: { cancelled }
|
|
13230
13301
|
});
|
|
13231
13302
|
} catch (error) {
|
|
13232
|
-
logger.error("Failed to cancel
|
|
13303
|
+
logger.error("Failed to cancel jobs", {
|
|
13304
|
+
jobId: event.jobId,
|
|
13233
13305
|
jobType: event.jobType,
|
|
13234
13306
|
error: error.message
|
|
13235
13307
|
});
|
|
@@ -13239,6 +13311,17 @@ function registerJobCommandHandlers(eventBus, jobQueue, state, parentLogger) {
|
|
|
13239
13311
|
});
|
|
13240
13312
|
}
|
|
13241
13313
|
});
|
|
13314
|
+
eventBus.get("job:cancel").subscribe(async (event) => {
|
|
13315
|
+
try {
|
|
13316
|
+
await jobQueue.cancelJob(jobId(event.jobId));
|
|
13317
|
+
logger.info("Job cancelled by its worker", { jobId: event.jobId });
|
|
13318
|
+
} catch (error) {
|
|
13319
|
+
logger.error("Failed to cancel job", {
|
|
13320
|
+
jobId: event.jobId,
|
|
13321
|
+
error: error.message
|
|
13322
|
+
});
|
|
13323
|
+
}
|
|
13324
|
+
});
|
|
13242
13325
|
}
|
|
13243
13326
|
|
|
13244
13327
|
// src/handlers/index.ts
|
|
@@ -13636,40 +13719,6 @@ var LocalContentTransport = class {
|
|
|
13636
13719
|
"LocalContentTransport does not support putBinary() \u2014 create resources via bus emits (mark/yield namespaces) in local mode"
|
|
13637
13720
|
);
|
|
13638
13721
|
}
|
|
13639
|
-
/**
|
|
13640
|
-
* Store a derived coordinate map under the content checksum the producer
|
|
13641
|
-
* read (PERSIST-ANCHORS decision A — see the interface doc for why the
|
|
13642
|
-
* producer supplies the key). In local mode this is the same store the
|
|
13643
|
-
* HTTP route writes to — one storage authority, reached the same way from
|
|
13644
|
-
* every process (ANCHORED-TEXT-CACHE Lane 5).
|
|
13645
|
-
*/
|
|
13646
|
-
async putAnchoredText(checksum, outcome, _options) {
|
|
13647
|
-
busLog("PUT", "anchored-text", { checksum });
|
|
13648
|
-
await this.kb.anchoredText.write(checksum, outcome);
|
|
13649
|
-
}
|
|
13650
|
-
/** The stored outcome, or null when nothing has derived one — the common case. */
|
|
13651
|
-
async getAnchoredText(resourceId10, _options) {
|
|
13652
|
-
busLog("GET", "anchored-text", { resourceId: resourceId10 });
|
|
13653
|
-
return readAnchoredText(this.kb, resourceId10);
|
|
13654
|
-
}
|
|
13655
|
-
/**
|
|
13656
|
-
* The cache-consult read (PERSIST-ANCHORS P2c), straight from the store —
|
|
13657
|
-
* checksum-addressed, so no view resolution and no settle barrier: the
|
|
13658
|
-
* caller holds the content identity already.
|
|
13659
|
-
*/
|
|
13660
|
-
async getAnchoredTextByChecksum(checksum, _options) {
|
|
13661
|
-
busLog("GET", "anchored-text-by-checksum", { checksum });
|
|
13662
|
-
return this.kb.anchoredText.read(checksum);
|
|
13663
|
-
}
|
|
13664
|
-
/**
|
|
13665
|
-
* The store's would-hit keys, straight from the store — planning data for
|
|
13666
|
-
* the reconcile diff (PERSIST-ANCHORS P0), so no settle barrier applies:
|
|
13667
|
-
* presence is being asked, not content at a moment.
|
|
13668
|
-
*/
|
|
13669
|
-
async listAnchoredTextKeys(_options) {
|
|
13670
|
-
busLog("GET", "anchored-text-keys", {});
|
|
13671
|
-
return this.kb.anchoredText.list();
|
|
13672
|
-
}
|
|
13673
13722
|
async getBinary(resourceId10, _options) {
|
|
13674
13723
|
busLog("GET", "content", { resourceId: resourceId10 });
|
|
13675
13724
|
return withSpan(
|
|
@@ -14011,8 +14060,8 @@ var Smelter = class _Smelter {
|
|
|
14011
14060
|
if (!rid) return;
|
|
14012
14061
|
const { data, contentType } = await this.content.getBinary(resourceId(rid));
|
|
14013
14062
|
const bytes = Buffer.from(data);
|
|
14014
|
-
const extractor =
|
|
14015
|
-
if (!extractor
|
|
14063
|
+
const extractor = derivingExtractorFor(contentType);
|
|
14064
|
+
if (!extractor) {
|
|
14016
14065
|
this.logger.info("Re-anchor found no geometry-capable extractor", { resourceId: rid, contentType });
|
|
14017
14066
|
return;
|
|
14018
14067
|
}
|
|
@@ -14051,15 +14100,12 @@ var Smelter = class _Smelter {
|
|
|
14051
14100
|
const { data, contentType } = await this.content.getBinary(resourceId(resourceId10));
|
|
14052
14101
|
const bytes = Buffer.from(data);
|
|
14053
14102
|
const checksum = calculateChecksum(bytes);
|
|
14054
|
-
const extractor =
|
|
14055
|
-
if (!extractor) {
|
|
14056
|
-
this.logger.debug("Skipping resource with no
|
|
14103
|
+
const extractor = derivingExtractorFor(contentType);
|
|
14104
|
+
if (!extractor && textSourceOf(contentType) === "none") {
|
|
14105
|
+
this.logger.debug("Skipping resource with no way to read its media type", { resourceId: resourceId10, contentType });
|
|
14057
14106
|
return { kind: "skipped", checksum, reason: "no-extractor" };
|
|
14058
14107
|
}
|
|
14059
|
-
const extracted = await extractor.extract(bytes, contentType, {
|
|
14060
|
-
key: checksum,
|
|
14061
|
-
store: this.anchoredStore
|
|
14062
|
-
});
|
|
14108
|
+
const extracted = extractor ? await extractor.extract(bytes, contentType, { key: checksum, store: this.anchoredStore }) : { kind: "extracted", text: decodeRepresentation(bytes, contentType), method: "text-passthrough" };
|
|
14063
14109
|
if (extracted.kind === "declined") {
|
|
14064
14110
|
this.logger.debug("Extractor declined", { resourceId: resourceId10, contentType, reason: extracted.declined });
|
|
14065
14111
|
return { kind: "skipped", checksum, reason: extracted.declined };
|
|
@@ -14474,22 +14520,24 @@ var Smelter = class _Smelter {
|
|
|
14474
14520
|
* representation's checksum (the bytes the smelter would read), the
|
|
14475
14521
|
* current entity-type set (the discriminator the stamps must carry), and
|
|
14476
14522
|
* whether the media type's extractor derives geometry (whether an
|
|
14477
|
-
* anchored-text artifact should exist).
|
|
14478
|
-
*
|
|
14479
|
-
*
|
|
14480
|
-
*
|
|
14523
|
+
* anchored-text artifact should exist). Both answers are core's, keyed by the
|
|
14524
|
+
* media type's strategy: embeddable ⇔ the type has any text-reading strategy
|
|
14525
|
+
* at all, and geometry ⇔ that strategy derives it. Until READ-VS-EXTRACT P2
|
|
14526
|
+
* embeddability was asked as `EXTRACTORS[strategy] !== null` — true, but a
|
|
14527
|
+
* second statement of `strategy !== 'none'`, answered by resolving an
|
|
14528
|
+
* implementation to learn a fact about a media type.
|
|
14481
14529
|
* Shared by `reconcile()` and the `smelt:rebuild-anchors` planner.
|
|
14482
14530
|
*/
|
|
14483
14531
|
classifyEmbeddable(resources) {
|
|
14484
14532
|
const embeddable = /* @__PURE__ */ new Map();
|
|
14485
14533
|
for (const resource of resources) {
|
|
14486
14534
|
const mediaType = getPrimaryMediaType(resource);
|
|
14487
|
-
const
|
|
14488
|
-
if (resource["@id"] &&
|
|
14535
|
+
const readable = mediaType !== void 0 && textSourceOf(mediaType) !== "none";
|
|
14536
|
+
if (resource["@id"] && mediaType && readable) {
|
|
14489
14537
|
embeddable.set(resource["@id"], {
|
|
14490
14538
|
checksum: getPrimaryRepresentation(resource)?.checksum,
|
|
14491
14539
|
entityTypes: getResourceEntityTypes(resource),
|
|
14492
|
-
yieldsGeometry:
|
|
14540
|
+
yieldsGeometry: yieldsGeometryOf(mediaType)
|
|
14493
14541
|
});
|
|
14494
14542
|
}
|
|
14495
14543
|
}
|