@starkeep/query-orchestrator 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aaron Koller, Pedro Pinto, Craig Schroeder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @starkeep/query-orchestrator
2
+
3
+ Search shared data records via a thin orchestrator over the storage adapter. Today's surface covers type filtering, a `createdAt` date range, and cursor pagination; metadata joins, full-text search, and sync-eligibility filtering are not implemented.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @starkeep/query-orchestrator
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { createUnifiedIndex } from "@starkeep/query-orchestrator";
15
+
16
+ const unifiedIndex = createUnifiedIndex({
17
+ databaseAdapter: myDatabaseAdapter,
18
+ });
19
+
20
+ // Filter by type and/or date range, paginate with cursor.
21
+ const searchResult = await unifiedIndex.search({
22
+ types: ["jpg", "png"],
23
+ dateRange: { start: someHlc, end: laterHlc },
24
+ limit: 50,
25
+ });
26
+
27
+ for (const item of searchResult.items) {
28
+ console.log(item.dataRecord.id);
29
+ }
30
+
31
+ // Fetch a single record by id.
32
+ const singleItem = await unifiedIndex.getWithMetadata(recordId);
33
+ ```
34
+
35
+ ## API
36
+
37
+ ### Factory
38
+
39
+ | Function | Description |
40
+ |---|---|
41
+ | `createUnifiedIndex(options)` | Creates a `UnifiedIndex` over a `DatabaseAdapter`. |
42
+ | `planQuery(query, databaseAdapter)` | Translates an `IndexQuery` into a planned `Query` for the adapter. |
43
+
44
+ ### `UnifiedIndex`
45
+
46
+ | Method | Description |
47
+ |---|---|
48
+ | `search(query)` | Query data records with type filter, date range, and pagination. |
49
+ | `getWithMetadata(recordId)` | Retrieve a single data record by id. Returns `{ dataRecord }` — no metadata is joined in today's implementation. |
50
+
51
+ ### Key Types
52
+
53
+ | Type | Description |
54
+ |---|---|
55
+ | `IndexQuery` | `{ types?, dateRange?, limit?, cursor? }`. |
56
+ | `IndexItem` | `{ dataRecord }`. |
57
+ | `IndexResult` | Paginated search result with `items`, `nextCursor`, and `hasMore`. |
58
+
59
+ ## Testing
60
+
61
+ ```bash
62
+ pnpm --filter @starkeep/query-orchestrator test
63
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ createUnifiedIndex: () => createUnifiedIndex,
24
+ planQuery: () => planQuery
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/query-planner.ts
29
+ async function planQuery(query, _databaseAdapter) {
30
+ const filters = [];
31
+ if (query.types && query.types.length > 0) {
32
+ filters.push({ field: "type", operator: "in", value: query.types });
33
+ }
34
+ if (query.dateRange) {
35
+ filters.push({
36
+ field: "createdAt",
37
+ operator: "gte",
38
+ value: query.dateRange.start
39
+ });
40
+ filters.push({
41
+ field: "createdAt",
42
+ operator: "lte",
43
+ value: query.dateRange.end
44
+ });
45
+ }
46
+ const dataQuery = {
47
+ filters: filters.length > 0 ? filters : void 0,
48
+ limit: query.limit,
49
+ cursor: query.cursor
50
+ };
51
+ return { dataQuery };
52
+ }
53
+
54
+ // src/unified-index.ts
55
+ function createUnifiedIndex(options) {
56
+ const { databaseAdapter } = options;
57
+ return {
58
+ async search(query) {
59
+ const { dataQuery } = await planQuery(query, databaseAdapter);
60
+ const dataResult = await databaseAdapter.query(dataQuery);
61
+ const items = dataResult.records.map((dataRecord) => ({ dataRecord }));
62
+ return {
63
+ items,
64
+ nextCursor: dataResult.nextCursor,
65
+ hasMore: dataResult.hasMore
66
+ };
67
+ },
68
+ async getWithMetadata(recordId) {
69
+ const record = await databaseAdapter.get(recordId);
70
+ if (!record) return null;
71
+ return { dataRecord: record };
72
+ }
73
+ };
74
+ }
75
+ // Annotate the CommonJS export names for ESM import in node:
76
+ 0 && (module.exports = {
77
+ createUnifiedIndex,
78
+ planQuery
79
+ });
80
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/query-planner.ts","../src/unified-index.ts"],"sourcesContent":["export type {\n IndexQuery,\n IndexItem,\n IndexResult,\n UnifiedIndex,\n} from \"./types.js\";\n\nexport { createUnifiedIndex, type CreateUnifiedIndexOptions } from \"./unified-index.js\";\nexport { planQuery, type PlannedQueries } from \"./query-planner.js\";\n","import type { DatabaseAdapter, Query, Filter } from \"@starkeep/storage-adapter\";\nimport type { IndexQuery } from \"./types.js\";\n\nexport interface PlannedQueries {\n readonly dataQuery: Query;\n}\n\nexport async function planQuery(\n query: IndexQuery,\n _databaseAdapter: DatabaseAdapter,\n): Promise<PlannedQueries> {\n const filters: Filter[] = [];\n\n if (query.types && query.types.length > 0) {\n filters.push({ field: \"type\", operator: \"in\", value: query.types });\n }\n\n if (query.dateRange) {\n filters.push({\n field: \"createdAt\",\n operator: \"gte\",\n value: query.dateRange.start,\n });\n filters.push({\n field: \"createdAt\",\n operator: \"lte\",\n value: query.dateRange.end,\n });\n }\n\n const dataQuery: Query = {\n filters: filters.length > 0 ? filters : undefined,\n limit: query.limit,\n cursor: query.cursor,\n };\n\n return { dataQuery };\n}\n","import type { StarkeepId } from \"@starkeep/protocol-primitives\";\nimport type { DatabaseAdapter } from \"@starkeep/storage-adapter\";\nimport type { UnifiedIndex, IndexQuery, IndexItem, IndexResult } from \"./types.js\";\nimport { planQuery } from \"./query-planner.js\";\n\nexport interface CreateUnifiedIndexOptions {\n readonly databaseAdapter: DatabaseAdapter;\n}\n\nexport function createUnifiedIndex(options: CreateUnifiedIndexOptions): UnifiedIndex {\n const { databaseAdapter } = options;\n\n return {\n async search(query: IndexQuery): Promise<IndexResult> {\n const { dataQuery } = await planQuery(query, databaseAdapter);\n const dataResult = await databaseAdapter.query(dataQuery);\n\n const items: IndexItem[] = dataResult.records.map((dataRecord) => ({ dataRecord }));\n\n return {\n items,\n nextCursor: dataResult.nextCursor,\n hasMore: dataResult.hasMore,\n };\n },\n\n async getWithMetadata(recordId: StarkeepId): Promise<IndexItem | null> {\n const record = await databaseAdapter.get(recordId);\n if (!record) return null;\n return { dataRecord: record };\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOA,eAAsB,UACpB,OACA,kBACyB;AACzB,QAAM,UAAoB,CAAC;AAE3B,MAAI,MAAM,SAAS,MAAM,MAAM,SAAS,GAAG;AACzC,YAAQ,KAAK,EAAE,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,MAAM,CAAC;AAAA,EACpE;AAEA,MAAI,MAAM,WAAW;AACnB,YAAQ,KAAK;AAAA,MACX,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO,MAAM,UAAU;AAAA,IACzB,CAAC;AACD,YAAQ,KAAK;AAAA,MACX,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO,MAAM,UAAU;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,QAAM,YAAmB;AAAA,IACvB,SAAS,QAAQ,SAAS,IAAI,UAAU;AAAA,IACxC,OAAO,MAAM;AAAA,IACb,QAAQ,MAAM;AAAA,EAChB;AAEA,SAAO,EAAE,UAAU;AACrB;;;AC5BO,SAAS,mBAAmB,SAAkD;AACnF,QAAM,EAAE,gBAAgB,IAAI;AAE5B,SAAO;AAAA,IACL,MAAM,OAAO,OAAyC;AACpD,YAAM,EAAE,UAAU,IAAI,MAAM,UAAU,OAAO,eAAe;AAC5D,YAAM,aAAa,MAAM,gBAAgB,MAAM,SAAS;AAExD,YAAM,QAAqB,WAAW,QAAQ,IAAI,CAAC,gBAAgB,EAAE,WAAW,EAAE;AAElF,aAAO;AAAA,QACL;AAAA,QACA,YAAY,WAAW;AAAA,QACvB,SAAS,WAAW;AAAA,MACtB;AAAA,IACF;AAAA,IAEA,MAAM,gBAAgB,UAAiD;AACrE,YAAM,SAAS,MAAM,gBAAgB,IAAI,QAAQ;AACjD,UAAI,CAAC,OAAQ,QAAO;AACpB,aAAO,EAAE,YAAY,OAAO;AAAA,IAC9B;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,36 @@
1
+ import { DataRecord, HLCTimestamp, StarkeepId } from '@starkeep/protocol-primitives';
2
+ import { DatabaseAdapter, Query } from '@starkeep/storage-adapter';
3
+
4
+ interface IndexQuery {
5
+ readonly types?: string[];
6
+ readonly dateRange?: {
7
+ readonly start: HLCTimestamp;
8
+ readonly end: HLCTimestamp;
9
+ };
10
+ readonly limit?: number;
11
+ readonly cursor?: string;
12
+ }
13
+ interface IndexItem {
14
+ readonly dataRecord: DataRecord;
15
+ }
16
+ interface IndexResult {
17
+ readonly items: IndexItem[];
18
+ readonly nextCursor: string | null;
19
+ readonly hasMore: boolean;
20
+ }
21
+ interface UnifiedIndex {
22
+ search(query: IndexQuery): Promise<IndexResult>;
23
+ getWithMetadata(recordId: StarkeepId): Promise<IndexItem | null>;
24
+ }
25
+
26
+ interface CreateUnifiedIndexOptions {
27
+ readonly databaseAdapter: DatabaseAdapter;
28
+ }
29
+ declare function createUnifiedIndex(options: CreateUnifiedIndexOptions): UnifiedIndex;
30
+
31
+ interface PlannedQueries {
32
+ readonly dataQuery: Query;
33
+ }
34
+ declare function planQuery(query: IndexQuery, _databaseAdapter: DatabaseAdapter): Promise<PlannedQueries>;
35
+
36
+ export { type CreateUnifiedIndexOptions, type IndexItem, type IndexQuery, type IndexResult, type PlannedQueries, type UnifiedIndex, createUnifiedIndex, planQuery };
@@ -0,0 +1,36 @@
1
+ import { DataRecord, HLCTimestamp, StarkeepId } from '@starkeep/protocol-primitives';
2
+ import { DatabaseAdapter, Query } from '@starkeep/storage-adapter';
3
+
4
+ interface IndexQuery {
5
+ readonly types?: string[];
6
+ readonly dateRange?: {
7
+ readonly start: HLCTimestamp;
8
+ readonly end: HLCTimestamp;
9
+ };
10
+ readonly limit?: number;
11
+ readonly cursor?: string;
12
+ }
13
+ interface IndexItem {
14
+ readonly dataRecord: DataRecord;
15
+ }
16
+ interface IndexResult {
17
+ readonly items: IndexItem[];
18
+ readonly nextCursor: string | null;
19
+ readonly hasMore: boolean;
20
+ }
21
+ interface UnifiedIndex {
22
+ search(query: IndexQuery): Promise<IndexResult>;
23
+ getWithMetadata(recordId: StarkeepId): Promise<IndexItem | null>;
24
+ }
25
+
26
+ interface CreateUnifiedIndexOptions {
27
+ readonly databaseAdapter: DatabaseAdapter;
28
+ }
29
+ declare function createUnifiedIndex(options: CreateUnifiedIndexOptions): UnifiedIndex;
30
+
31
+ interface PlannedQueries {
32
+ readonly dataQuery: Query;
33
+ }
34
+ declare function planQuery(query: IndexQuery, _databaseAdapter: DatabaseAdapter): Promise<PlannedQueries>;
35
+
36
+ export { type CreateUnifiedIndexOptions, type IndexItem, type IndexQuery, type IndexResult, type PlannedQueries, type UnifiedIndex, createUnifiedIndex, planQuery };
package/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ // src/query-planner.ts
2
+ async function planQuery(query, _databaseAdapter) {
3
+ const filters = [];
4
+ if (query.types && query.types.length > 0) {
5
+ filters.push({ field: "type", operator: "in", value: query.types });
6
+ }
7
+ if (query.dateRange) {
8
+ filters.push({
9
+ field: "createdAt",
10
+ operator: "gte",
11
+ value: query.dateRange.start
12
+ });
13
+ filters.push({
14
+ field: "createdAt",
15
+ operator: "lte",
16
+ value: query.dateRange.end
17
+ });
18
+ }
19
+ const dataQuery = {
20
+ filters: filters.length > 0 ? filters : void 0,
21
+ limit: query.limit,
22
+ cursor: query.cursor
23
+ };
24
+ return { dataQuery };
25
+ }
26
+
27
+ // src/unified-index.ts
28
+ function createUnifiedIndex(options) {
29
+ const { databaseAdapter } = options;
30
+ return {
31
+ async search(query) {
32
+ const { dataQuery } = await planQuery(query, databaseAdapter);
33
+ const dataResult = await databaseAdapter.query(dataQuery);
34
+ const items = dataResult.records.map((dataRecord) => ({ dataRecord }));
35
+ return {
36
+ items,
37
+ nextCursor: dataResult.nextCursor,
38
+ hasMore: dataResult.hasMore
39
+ };
40
+ },
41
+ async getWithMetadata(recordId) {
42
+ const record = await databaseAdapter.get(recordId);
43
+ if (!record) return null;
44
+ return { dataRecord: record };
45
+ }
46
+ };
47
+ }
48
+ export {
49
+ createUnifiedIndex,
50
+ planQuery
51
+ };
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/query-planner.ts","../src/unified-index.ts"],"sourcesContent":["import type { DatabaseAdapter, Query, Filter } from \"@starkeep/storage-adapter\";\nimport type { IndexQuery } from \"./types.js\";\n\nexport interface PlannedQueries {\n readonly dataQuery: Query;\n}\n\nexport async function planQuery(\n query: IndexQuery,\n _databaseAdapter: DatabaseAdapter,\n): Promise<PlannedQueries> {\n const filters: Filter[] = [];\n\n if (query.types && query.types.length > 0) {\n filters.push({ field: \"type\", operator: \"in\", value: query.types });\n }\n\n if (query.dateRange) {\n filters.push({\n field: \"createdAt\",\n operator: \"gte\",\n value: query.dateRange.start,\n });\n filters.push({\n field: \"createdAt\",\n operator: \"lte\",\n value: query.dateRange.end,\n });\n }\n\n const dataQuery: Query = {\n filters: filters.length > 0 ? filters : undefined,\n limit: query.limit,\n cursor: query.cursor,\n };\n\n return { dataQuery };\n}\n","import type { StarkeepId } from \"@starkeep/protocol-primitives\";\nimport type { DatabaseAdapter } from \"@starkeep/storage-adapter\";\nimport type { UnifiedIndex, IndexQuery, IndexItem, IndexResult } from \"./types.js\";\nimport { planQuery } from \"./query-planner.js\";\n\nexport interface CreateUnifiedIndexOptions {\n readonly databaseAdapter: DatabaseAdapter;\n}\n\nexport function createUnifiedIndex(options: CreateUnifiedIndexOptions): UnifiedIndex {\n const { databaseAdapter } = options;\n\n return {\n async search(query: IndexQuery): Promise<IndexResult> {\n const { dataQuery } = await planQuery(query, databaseAdapter);\n const dataResult = await databaseAdapter.query(dataQuery);\n\n const items: IndexItem[] = dataResult.records.map((dataRecord) => ({ dataRecord }));\n\n return {\n items,\n nextCursor: dataResult.nextCursor,\n hasMore: dataResult.hasMore,\n };\n },\n\n async getWithMetadata(recordId: StarkeepId): Promise<IndexItem | null> {\n const record = await databaseAdapter.get(recordId);\n if (!record) return null;\n return { dataRecord: record };\n },\n };\n}\n"],"mappings":";AAOA,eAAsB,UACpB,OACA,kBACyB;AACzB,QAAM,UAAoB,CAAC;AAE3B,MAAI,MAAM,SAAS,MAAM,MAAM,SAAS,GAAG;AACzC,YAAQ,KAAK,EAAE,OAAO,QAAQ,UAAU,MAAM,OAAO,MAAM,MAAM,CAAC;AAAA,EACpE;AAEA,MAAI,MAAM,WAAW;AACnB,YAAQ,KAAK;AAAA,MACX,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO,MAAM,UAAU;AAAA,IACzB,CAAC;AACD,YAAQ,KAAK;AAAA,MACX,OAAO;AAAA,MACP,UAAU;AAAA,MACV,OAAO,MAAM,UAAU;AAAA,IACzB,CAAC;AAAA,EACH;AAEA,QAAM,YAAmB;AAAA,IACvB,SAAS,QAAQ,SAAS,IAAI,UAAU;AAAA,IACxC,OAAO,MAAM;AAAA,IACb,QAAQ,MAAM;AAAA,EAChB;AAEA,SAAO,EAAE,UAAU;AACrB;;;AC5BO,SAAS,mBAAmB,SAAkD;AACnF,QAAM,EAAE,gBAAgB,IAAI;AAE5B,SAAO;AAAA,IACL,MAAM,OAAO,OAAyC;AACpD,YAAM,EAAE,UAAU,IAAI,MAAM,UAAU,OAAO,eAAe;AAC5D,YAAM,aAAa,MAAM,gBAAgB,MAAM,SAAS;AAExD,YAAM,QAAqB,WAAW,QAAQ,IAAI,CAAC,gBAAgB,EAAE,WAAW,EAAE;AAElF,aAAO;AAAA,QACL;AAAA,QACA,YAAY,WAAW;AAAA,QACvB,SAAS,WAAW;AAAA,MACtB;AAAA,IACF;AAAA,IAEA,MAAM,gBAAgB,UAAiD;AACrE,YAAM,SAAS,MAAM,gBAAgB,IAAI,QAAQ;AACjD,UAAI,CAAC,OAAQ,QAAO;AACpB,aAAO,EAAE,YAAY,OAAO;AAAA,IAC9B;AAAA,EACF;AACF;","names":[]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@starkeep/query-orchestrator",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/starkeep-dev/starkeep-core.git",
26
+ "directory": "packages/query-orchestrator"
27
+ },
28
+ "homepage": "https://github.com/starkeep-dev/starkeep-core/tree/main/packages/query-orchestrator",
29
+ "dependencies": {
30
+ "@starkeep/storage-adapter": "0.1.0",
31
+ "@starkeep/protocol-primitives": "0.1.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^25.4.0",
35
+ "tsup": "^8.0.0",
36
+ "typescript": "^5.7.0",
37
+ "vitest": "^3.0.0"
38
+ },
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "test": "vitest run",
42
+ "typecheck": "tsc --noEmit",
43
+ "lint": "eslint src/"
44
+ }
45
+ }