@delali/narsil 0.2.3-next.34 → 0.2.3-next.36
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 +2 -2
- package/dist/adapters/filesystem.mjs +1 -1
- package/dist/adapters/indexeddb.mjs +1 -1
- package/dist/{chunk-EMI63EXP.mjs → chunk-GB2IIJJG.mjs} +2 -0
- package/dist/{chunk-RO4EFWE6.mjs → chunk-GRWFY2HI.mjs} +10 -1
- package/dist/{chunk-36ER4WCG.mjs → chunk-JQUL2T6I.mjs} +2 -1
- package/dist/{chunk-GN7KF675.mjs → chunk-MMSWEEZT.mjs} +88 -164
- package/dist/{chunk-GODECMDT.mjs → chunk-PM52SMBT.mjs} +1 -1
- package/dist/chunk-WU2UZEVD.mjs +137 -0
- package/dist/{client-DQHB_swQ.d.ts → client-BobVnoIK.d.ts} +2 -2
- package/dist/client.d.ts +8 -4
- package/dist/client.mjs +2 -0
- package/dist/{config-ChZ7lfqc.d.ts → config-Byyl1QqH.d.ts} +2 -2
- package/dist/config-fLC4lbmg.d.ts +194 -0
- package/dist/{direct-executor-YARCDMJF.mjs → direct-executor-MSJEVPZU.mjs} +2 -2
- package/dist/distribution/coordinator/etcd.d.ts +5 -7
- package/dist/distribution/coordinator/etcd.mjs +27 -8
- package/dist/distribution/coordinator/in-memory.d.ts +2 -2
- package/dist/distribution/transport/grpc.mjs +3 -3
- package/dist/distribution/transport/in-memory.mjs +1 -1
- package/dist/distribution/transport/tcp.mjs +2 -2
- package/dist/distribution.d.ts +10 -108
- package/dist/distribution.mjs +1328 -370
- package/dist/embeddings/openai.mjs +1 -1
- package/dist/{engine-DScGlT2Z.d.ts → engine-BE45D5ZG.d.ts} +3 -3
- package/dist/index.browser.mjs +90 -24
- package/dist/index.d.ts +7 -7
- package/dist/index.mjs +5 -4
- package/dist/{options-BORJg5XB.d.ts → options-EXYFcem-.d.ts} +9 -0
- package/dist/persistence/durability/checkpoint-worker.d.ts +3 -1
- package/dist/persistence/durability/checkpoint-worker.mjs +5 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.mjs +2 -0
- package/dist/{schema-emTQfEiX.d.ts → schema-ZRbk8BgH.d.ts} +1 -0
- package/dist/{search-CQ-9bKxo.d.ts → search-DHuXwJYk.d.ts} +29 -2
- package/dist/server.d.ts +9 -5
- package/dist/server.mjs +101 -7
- package/dist/{types-BhdINMtE.d.ts → types-B5Tsaalz.d.ts} +19 -2
- package/dist/workers/entry.mjs +2 -2
- package/package.json +1 -1
package/dist/server.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { validateIndexName } from './chunk-WU2UZEVD.mjs';
|
|
2
|
+
import { ServerErrorCodes, NarsilError, ErrorCodes } from './chunk-GB2IIJJG.mjs';
|
|
3
|
+
export { ServerErrorCodes } from './chunk-GB2IIJJG.mjs';
|
|
3
4
|
import { randomUUID } from 'crypto';
|
|
4
5
|
|
|
5
6
|
// src/server/capabilities.ts
|
|
@@ -117,6 +118,8 @@ var STATUS_BY_CODE = {
|
|
|
117
118
|
CONTROLLER_NOT_ACTIVE: 503,
|
|
118
119
|
NODE_ALREADY_JOINED: 409,
|
|
119
120
|
NODE_NOT_JOINED: 503,
|
|
121
|
+
NODE_NOT_READY: 503,
|
|
122
|
+
NODE_NOT_CONTROLLER: 503,
|
|
120
123
|
NODE_BOOTSTRAP_FAILED: 503,
|
|
121
124
|
COORDINATOR_DEPENDENCY_MISSING: 500,
|
|
122
125
|
SNAPSHOT_SYNC_UNAUTHORIZED: 403,
|
|
@@ -649,6 +652,79 @@ function createCapabilitiesHandler() {
|
|
|
649
652
|
return { report };
|
|
650
653
|
}
|
|
651
654
|
|
|
655
|
+
// src/server/handlers/cluster.ts
|
|
656
|
+
function requireCluster(deps) {
|
|
657
|
+
if (deps.cluster === void 0) {
|
|
658
|
+
throw new NarsilError(
|
|
659
|
+
ErrorCodes.CLUSTER_OPERATION_UNSUPPORTED,
|
|
660
|
+
"This server fronts a single engine, so it reports no cluster",
|
|
661
|
+
{}
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
return deps.cluster;
|
|
665
|
+
}
|
|
666
|
+
function describeNode(cluster) {
|
|
667
|
+
return { ...cluster.getNodeInfo(), readiness: cluster.getReadiness(), isController: cluster.isControllerActive() };
|
|
668
|
+
}
|
|
669
|
+
function malformedIndexName(indexName) {
|
|
670
|
+
try {
|
|
671
|
+
validateIndexName(indexName);
|
|
672
|
+
return null;
|
|
673
|
+
} catch (error) {
|
|
674
|
+
return error instanceof Error ? error.message : String(error);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function createClusterHandlers(deps) {
|
|
678
|
+
async function topology(ctx) {
|
|
679
|
+
try {
|
|
680
|
+
const cluster = requireCluster(deps);
|
|
681
|
+
const [nodes, controllerNodeId] = await Promise.all([cluster.listNodes(), cluster.getControllerNodeId()]);
|
|
682
|
+
respondJson(ctx, {
|
|
683
|
+
node: describeNode(cluster),
|
|
684
|
+
controllerNodeId,
|
|
685
|
+
nodes: nodes.map((node) => ({ nodeId: node.nodeId, address: node.address, roles: [...node.roles] }))
|
|
686
|
+
});
|
|
687
|
+
} catch (err) {
|
|
688
|
+
respondError(ctx, err);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
async function allocation(ctx) {
|
|
692
|
+
try {
|
|
693
|
+
const cluster = requireCluster(deps);
|
|
694
|
+
const indexName = ctx.params[0] ?? "";
|
|
695
|
+
const malformed = malformedIndexName(indexName);
|
|
696
|
+
if (malformed !== null) {
|
|
697
|
+
badRequest(ctx.res, malformed, { indexName });
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
const table = await cluster.getAllocation(indexName);
|
|
701
|
+
if (table === null) {
|
|
702
|
+
respondJson(ctx, { indexName, allocated: false, version: null, partitions: [] });
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
const partitions = [];
|
|
706
|
+
for (const [partitionId, assignment] of table.assignments) {
|
|
707
|
+
partitions.push({
|
|
708
|
+
partitionId,
|
|
709
|
+
state: assignment.state,
|
|
710
|
+
primary: assignment.primary,
|
|
711
|
+
primaryTerm: assignment.primaryTerm,
|
|
712
|
+
commitPoint: assignment.commitPoint,
|
|
713
|
+
replicas: [...assignment.replicas],
|
|
714
|
+
inSyncSet: [...assignment.inSyncSet],
|
|
715
|
+
lastHolders: [...assignment.lastHolders ?? []],
|
|
716
|
+
unassignedReason: assignment.unassignedReason ?? null
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
partitions.sort((left, right) => left.partitionId - right.partitionId);
|
|
720
|
+
respondJson(ctx, { indexName, allocated: partitions.length > 0, version: table.version, partitions });
|
|
721
|
+
} catch (err) {
|
|
722
|
+
respondError(ctx, err);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
return { topology, allocation };
|
|
726
|
+
}
|
|
727
|
+
|
|
652
728
|
// src/server/handlers/documents.ts
|
|
653
729
|
function createDocumentHandlers(deps) {
|
|
654
730
|
const { engine, limits } = deps;
|
|
@@ -804,11 +880,25 @@ function createHealthHandlers(deps) {
|
|
|
804
880
|
respondJson(ctx, { status: "ok" });
|
|
805
881
|
}
|
|
806
882
|
function readyz(ctx) {
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
883
|
+
const cluster = deps.cluster;
|
|
884
|
+
if (cluster === void 0) {
|
|
885
|
+
if (deps.isReady()) {
|
|
886
|
+
respondJson(ctx, { status: "ready" });
|
|
887
|
+
} else {
|
|
888
|
+
respondJson(ctx, { status: "unavailable" }, 503);
|
|
889
|
+
}
|
|
890
|
+
return;
|
|
811
891
|
}
|
|
892
|
+
const readiness = cluster.getReadiness();
|
|
893
|
+
const ready = deps.isReady() && readiness === "SERVING";
|
|
894
|
+
respondJson(
|
|
895
|
+
ctx,
|
|
896
|
+
{
|
|
897
|
+
status: ready ? "ready" : "unavailable",
|
|
898
|
+
cluster: describeNode(cluster)
|
|
899
|
+
},
|
|
900
|
+
ready ? 200 : 503
|
|
901
|
+
);
|
|
812
902
|
}
|
|
813
903
|
return { livez, readyz };
|
|
814
904
|
}
|
|
@@ -1576,7 +1666,8 @@ var NarsilHttpServer = class {
|
|
|
1576
1666
|
tasks: new TaskRegistry(taskStore, instanceId, limits.maxConcurrentTasks),
|
|
1577
1667
|
limits,
|
|
1578
1668
|
isReady: () => this.ready,
|
|
1579
|
-
build: resolveBuild(options.build)
|
|
1669
|
+
build: resolveBuild(options.build),
|
|
1670
|
+
cluster: options.cluster
|
|
1580
1671
|
};
|
|
1581
1672
|
}
|
|
1582
1673
|
async listen() {
|
|
@@ -1622,6 +1713,7 @@ var NarsilHttpServer = class {
|
|
|
1622
1713
|
const search = createSearchHandlers(this.deps);
|
|
1623
1714
|
const admin = createAdminHandlers(this.deps);
|
|
1624
1715
|
const health = createHealthHandlers(this.deps);
|
|
1716
|
+
const cluster = createClusterHandlers(this.deps);
|
|
1625
1717
|
const version = createVersionHandler(this.deps);
|
|
1626
1718
|
const capabilities = createCapabilitiesHandler();
|
|
1627
1719
|
const importNdjson = createImportHandler(this.deps);
|
|
@@ -1641,6 +1733,7 @@ var NarsilHttpServer = class {
|
|
|
1641
1733
|
app.get("/health", json(health.livez, { maxBytes: 0, skipHooks: true }));
|
|
1642
1734
|
app.get("/version", json(version.report, { maxBytes: 0, skipHooks: true }));
|
|
1643
1735
|
app.get("/capabilities", json(capabilities.report, { maxBytes: 0, skipHooks: true }));
|
|
1736
|
+
app.get("/cluster", json(cluster.topology, { maxBytes: 0 }));
|
|
1644
1737
|
app.get("/stats/memory", json(admin.memory, { maxBytes: 0 }));
|
|
1645
1738
|
app.get("/tasks", json(admin.listTasks, { maxBytes: 0 }));
|
|
1646
1739
|
app.get("/tasks/:id", json(admin.getTask, { paramCount: 1, maxBytes: 0 }));
|
|
@@ -1650,6 +1743,7 @@ var NarsilHttpServer = class {
|
|
|
1650
1743
|
app.del("/indexes/:name", json(idx.drop, { paramCount: 1, maxBytes: 0 }));
|
|
1651
1744
|
app.get("/indexes/:name/stats", json(idx.stats, { paramCount: 1, maxBytes: 0 }));
|
|
1652
1745
|
app.get("/indexes/:name/partitions", json(idx.partitions, { paramCount: 1, maxBytes: 0 }));
|
|
1746
|
+
app.get("/indexes/:name/cluster", json(cluster.allocation, { paramCount: 1, maxBytes: 0 }));
|
|
1653
1747
|
app.post("/indexes/:name/_clear", json(idx.clear, { paramCount: 1, maxBytes: 0 }));
|
|
1654
1748
|
app.get("/indexes/:name/count", json(doc.count, { paramCount: 1, maxBytes: 0 }));
|
|
1655
1749
|
app.post("/indexes/:name/documents", json(doc.insert, { paramCount: 1, needsBody: true, maxBytes: maxBodyBytes }));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { S as SchemaDefinition } from './schema-
|
|
1
|
+
import { S as SchemaDefinition } from './schema-ZRbk8BgH.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* What a node does in a cluster. A node may hold several roles at once.
|
|
@@ -20,6 +20,19 @@ type NodeRole = 'data' | 'coordinator' | 'controller';
|
|
|
20
20
|
* @public
|
|
21
21
|
*/
|
|
22
22
|
type PartitionState = 'UNASSIGNED' | 'INITIALISING' | 'ACTIVE' | 'MIGRATING' | 'DECOMMISSIONING';
|
|
23
|
+
/**
|
|
24
|
+
* Why a partition stays `UNASSIGNED` after the controller has asked its last holders for a copy.
|
|
25
|
+
*
|
|
26
|
+
* `HOLDER_OFFLINE` means a last holder has yet to register again, so the controller is still waiting for it.
|
|
27
|
+
* `HOLDER_UNREACHABLE` means a registered holder left the request unanswered or answered with a payload the
|
|
28
|
+
* controller could not read. `HOLDER_IDENTITY_MISMATCH` means a holder answered under a different index identity,
|
|
29
|
+
* so its copy holds the documents of an earlier index of the same name, or it keeps no copy of that name at all.
|
|
30
|
+
* `HOLDER_WITHOUT_DATA` means every holder answered under the coordinator's identity with a list that left the
|
|
31
|
+
* partition out.
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
type UnassignedReason = 'HOLDER_OFFLINE' | 'HOLDER_UNREACHABLE' | 'HOLDER_IDENTITY_MISMATCH' | 'HOLDER_WITHOUT_DATA';
|
|
23
36
|
/**
|
|
24
37
|
* What one node has to offer, which the allocator weighs when it places
|
|
25
38
|
* partitions.
|
|
@@ -67,12 +80,16 @@ interface PartitionAssignment {
|
|
|
67
80
|
replicas: string[];
|
|
68
81
|
/** These replicas are current enough to be promoted, which is the set a failover picks from. */
|
|
69
82
|
inSyncSet: string[];
|
|
83
|
+
/** These nodes still hold a copy of a partition no node serves, and the field stays until the partition is `ACTIVE`. */
|
|
84
|
+
lastHolders?: string[];
|
|
70
85
|
/** This says where the partition stands in its move between nodes. */
|
|
71
86
|
state: PartitionState;
|
|
72
87
|
/** This rises each time the primary changes, which is what makes a stale primary's writes detectable. */
|
|
73
88
|
primaryTerm: number;
|
|
74
89
|
/** The primary has acknowledged every sequence number up to here, so every in-sync replica holds them. */
|
|
75
90
|
commitPoint: number;
|
|
91
|
+
/** Why the partition stays `UNASSIGNED`, which the controller records each time it asks the last holders. */
|
|
92
|
+
unassignedReason?: UnassignedReason;
|
|
76
93
|
}
|
|
77
94
|
/**
|
|
78
95
|
* How one index's partitions are spread across the cluster.
|
|
@@ -323,4 +340,4 @@ interface ClusterCoordinator {
|
|
|
323
340
|
shutdown(): Promise<void>;
|
|
324
341
|
}
|
|
325
342
|
|
|
326
|
-
export type { AllocationTable as A, ClusterCoordinator as C, NodeRole as N, PartitionAssignment as P, SchemaEvent as S,
|
|
343
|
+
export type { AllocationTable as A, ClusterCoordinator as C, NodeRole as N, PartitionAssignment as P, SchemaEvent as S, UnassignedReason as U, NodeRegistration as a, NodeCapacity as b, AllocationConstraints as c, AllocationEvent as d, NodeEvent as e, PartitionState as f };
|
package/dist/workers/entry.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isValidWorkerAction } from '../chunk-WTONLDU3.mjs';
|
|
2
|
-
import { NarsilError, ErrorCodes } from '../chunk-
|
|
2
|
+
import { NarsilError, ErrorCodes } from '../chunk-GB2IIJJG.mjs';
|
|
3
3
|
|
|
4
4
|
// src/workers/action-handler.ts
|
|
5
5
|
function buildErrorResponse(requestId, code, message) {
|
|
@@ -55,7 +55,7 @@ async function setup() {
|
|
|
55
55
|
} catch {
|
|
56
56
|
parentPort = null;
|
|
57
57
|
}
|
|
58
|
-
const { createDirectExecutor } = await import('../direct-executor-
|
|
58
|
+
const { createDirectExecutor } = await import('../direct-executor-MSJEVPZU.mjs');
|
|
59
59
|
const handleAction = createActionHandler(createDirectExecutor());
|
|
60
60
|
if (parentPort) {
|
|
61
61
|
const port = parentPort;
|
package/package.json
CHANGED