@aigne/afs-index 1.12.0-beta.5
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.md +26 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
- package/dist/backend/d1-index-backend.cjs +656 -0
- package/dist/backend/d1-index-backend.d.cts +149 -0
- package/dist/backend/d1-index-backend.d.cts.map +1 -0
- package/dist/backend/d1-index-backend.d.mts +149 -0
- package/dist/backend/d1-index-backend.d.mts.map +1 -0
- package/dist/backend/d1-index-backend.mjs +657 -0
- package/dist/backend/d1-index-backend.mjs.map +1 -0
- package/dist/backend/d1-vector-backend.cjs +83 -0
- package/dist/backend/d1-vector-backend.d.cts +21 -0
- package/dist/backend/d1-vector-backend.d.cts.map +1 -0
- package/dist/backend/d1-vector-backend.d.mts +21 -0
- package/dist/backend/d1-vector-backend.d.mts.map +1 -0
- package/dist/backend/d1-vector-backend.mjs +84 -0
- package/dist/backend/d1-vector-backend.mjs.map +1 -0
- package/dist/backend/memory-backend.cjs +304 -0
- package/dist/backend/memory-backend.d.cts +66 -0
- package/dist/backend/memory-backend.d.cts.map +1 -0
- package/dist/backend/memory-backend.d.mts +66 -0
- package/dist/backend/memory-backend.d.mts.map +1 -0
- package/dist/backend/memory-backend.mjs +305 -0
- package/dist/backend/memory-backend.mjs.map +1 -0
- package/dist/backend/prefix-range.cjs +25 -0
- package/dist/backend/prefix-range.mjs +25 -0
- package/dist/backend/prefix-range.mjs.map +1 -0
- package/dist/backend/schema.cjs +187 -0
- package/dist/backend/schema.mjs +188 -0
- package/dist/backend/schema.mjs.map +1 -0
- package/dist/backend/sqlite-backend.cjs +889 -0
- package/dist/backend/sqlite-backend.d.cts +96 -0
- package/dist/backend/sqlite-backend.d.cts.map +1 -0
- package/dist/backend/sqlite-backend.d.mts +96 -0
- package/dist/backend/sqlite-backend.d.mts.map +1 -0
- package/dist/backend/sqlite-backend.mjs +890 -0
- package/dist/backend/sqlite-backend.mjs.map +1 -0
- package/dist/backend/types.d.cts +209 -0
- package/dist/backend/types.d.cts.map +1 -0
- package/dist/backend/types.d.mts +209 -0
- package/dist/backend/types.d.mts.map +1 -0
- package/dist/backend/upstash-vector-backend.cjs +98 -0
- package/dist/backend/upstash-vector-backend.d.cts +21 -0
- package/dist/backend/upstash-vector-backend.d.cts.map +1 -0
- package/dist/backend/upstash-vector-backend.d.mts +21 -0
- package/dist/backend/upstash-vector-backend.d.mts.map +1 -0
- package/dist/backend/upstash-vector-backend.mjs +98 -0
- package/dist/backend/upstash-vector-backend.mjs.map +1 -0
- package/dist/backend/vector-backend.d.cts +29 -0
- package/dist/backend/vector-backend.d.cts.map +1 -0
- package/dist/backend/vector-backend.d.mts +29 -0
- package/dist/backend/vector-backend.d.mts.map +1 -0
- package/dist/dirty-queue.d.cts +41 -0
- package/dist/dirty-queue.d.cts.map +1 -0
- package/dist/dirty-queue.d.mts +41 -0
- package/dist/dirty-queue.d.mts.map +1 -0
- package/dist/embed.cjs +45 -0
- package/dist/embed.d.cts +20 -0
- package/dist/embed.d.cts.map +1 -0
- package/dist/embed.d.mts +20 -0
- package/dist/embed.d.mts.map +1 -0
- package/dist/embed.mjs +46 -0
- package/dist/embed.mjs.map +1 -0
- package/dist/extraction/defaults.cjs +242 -0
- package/dist/extraction/defaults.d.cts +14 -0
- package/dist/extraction/defaults.d.cts.map +1 -0
- package/dist/extraction/defaults.d.mts +14 -0
- package/dist/extraction/defaults.d.mts.map +1 -0
- package/dist/extraction/defaults.mjs +242 -0
- package/dist/extraction/defaults.mjs.map +1 -0
- package/dist/extraction/field-map.cjs +162 -0
- package/dist/extraction/field-map.d.cts +70 -0
- package/dist/extraction/field-map.d.cts.map +1 -0
- package/dist/extraction/field-map.d.mts +70 -0
- package/dist/extraction/field-map.d.mts.map +1 -0
- package/dist/extraction/field-map.mjs +157 -0
- package/dist/extraction/field-map.mjs.map +1 -0
- package/dist/extraction/manager.cjs +74 -0
- package/dist/extraction/manager.d.cts +47 -0
- package/dist/extraction/manager.d.cts.map +1 -0
- package/dist/extraction/manager.d.mts +47 -0
- package/dist/extraction/manager.d.mts.map +1 -0
- package/dist/extraction/manager.mjs +74 -0
- package/dist/extraction/manager.mjs.map +1 -0
- package/dist/extraction/path-anchors.cjs +86 -0
- package/dist/extraction/path-anchors.d.cts +72 -0
- package/dist/extraction/path-anchors.d.cts.map +1 -0
- package/dist/extraction/path-anchors.d.mts +72 -0
- package/dist/extraction/path-anchors.d.mts.map +1 -0
- package/dist/extraction/path-anchors.mjs +86 -0
- package/dist/extraction/path-anchors.mjs.map +1 -0
- package/dist/follower-scheduler.cjs +92 -0
- package/dist/follower-scheduler.d.cts +58 -0
- package/dist/follower-scheduler.d.cts.map +1 -0
- package/dist/follower-scheduler.d.mts +58 -0
- package/dist/follower-scheduler.d.mts.map +1 -0
- package/dist/follower-scheduler.mjs +92 -0
- package/dist/follower-scheduler.mjs.map +1 -0
- package/dist/follower.cjs +577 -0
- package/dist/follower.d.cts +241 -0
- package/dist/follower.d.cts.map +1 -0
- package/dist/follower.d.mts +241 -0
- package/dist/follower.d.mts.map +1 -0
- package/dist/follower.mjs +571 -0
- package/dist/follower.mjs.map +1 -0
- package/dist/index-provider.cjs +1166 -0
- package/dist/index-provider.d.cts +175 -0
- package/dist/index-provider.d.cts.map +1 -0
- package/dist/index-provider.d.mts +175 -0
- package/dist/index-provider.d.mts.map +1 -0
- package/dist/index-provider.mjs +1167 -0
- package/dist/index-provider.mjs.map +1 -0
- package/dist/index.cjs +53 -0
- package/dist/index.d.cts +22 -0
- package/dist/index.d.mts +22 -0
- package/dist/index.mjs +20 -0
- package/dist/keys/exact.cjs +20 -0
- package/dist/keys/exact.mjs +20 -0
- package/dist/keys/exact.mjs.map +1 -0
- package/dist/keys/location.cjs +13 -0
- package/dist/keys/location.mjs +13 -0
- package/dist/keys/location.mjs.map +1 -0
- package/dist/keys/normalized.cjs +62 -0
- package/dist/keys/normalized.mjs +63 -0
- package/dist/keys/normalized.mjs.map +1 -0
- package/dist/keys/person.cjs +15 -0
- package/dist/keys/person.mjs +15 -0
- package/dist/keys/person.mjs.map +1 -0
- package/dist/keys/registry.cjs +45 -0
- package/dist/keys/registry.d.cts +15 -0
- package/dist/keys/registry.d.cts.map +1 -0
- package/dist/keys/registry.d.mts +15 -0
- package/dist/keys/registry.d.mts.map +1 -0
- package/dist/keys/registry.mjs +46 -0
- package/dist/keys/registry.mjs.map +1 -0
- package/dist/keys/time.cjs +128 -0
- package/dist/keys/time.mjs +128 -0
- package/dist/keys/time.mjs.map +1 -0
- package/dist/keys/topic.cjs +23 -0
- package/dist/keys/topic.mjs +23 -0
- package/dist/keys/topic.mjs.map +1 -0
- package/dist/manifest-index.cjs +29 -0
- package/dist/manifest-index.d.cts +24 -0
- package/dist/manifest-index.d.cts.map +1 -0
- package/dist/manifest-index.d.mts +24 -0
- package/dist/manifest-index.d.mts.map +1 -0
- package/dist/manifest-index.mjs +28 -0
- package/dist/manifest-index.mjs.map +1 -0
- package/dist/offline-rebuild.cjs +48 -0
- package/dist/offline-rebuild.d.cts +57 -0
- package/dist/offline-rebuild.d.cts.map +1 -0
- package/dist/offline-rebuild.d.mts +57 -0
- package/dist/offline-rebuild.d.mts.map +1 -0
- package/dist/offline-rebuild.mjs +49 -0
- package/dist/offline-rebuild.mjs.map +1 -0
- package/dist/query/engine.cjs +433 -0
- package/dist/query/engine.d.cts +34 -0
- package/dist/query/engine.d.cts.map +1 -0
- package/dist/query/engine.d.mts +34 -0
- package/dist/query/engine.d.mts.map +1 -0
- package/dist/query/engine.mjs +433 -0
- package/dist/query/engine.mjs.map +1 -0
- package/dist/query/limits.cjs +12 -0
- package/dist/query/limits.mjs +12 -0
- package/dist/query/limits.mjs.map +1 -0
- package/dist/text/cjk.cjs +30 -0
- package/dist/text/cjk.d.cts +24 -0
- package/dist/text/cjk.d.cts.map +1 -0
- package/dist/text/cjk.d.mts +24 -0
- package/dist/text/cjk.d.mts.map +1 -0
- package/dist/text/cjk.mjs +30 -0
- package/dist/text/cjk.mjs.map +1 -0
- package/dist/text/fts.cjs +244 -0
- package/dist/text/fts.mjs +245 -0
- package/dist/text/fts.mjs.map +1 -0
- package/dist/text/host.cjs +39 -0
- package/dist/text/host.mjs +38 -0
- package/dist/text/host.mjs.map +1 -0
- package/dist/types.cjs +44 -0
- package/dist/types.d.cts +393 -0
- package/dist/types.d.cts.map +1 -0
- package/dist/types.d.mts +393 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/types.mjs +42 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const require_exact = require('./exact.cjs');
|
|
2
|
+
const require_location = require('./location.cjs');
|
|
3
|
+
const require_person = require('./person.cjs');
|
|
4
|
+
const require_time = require('./time.cjs');
|
|
5
|
+
const require_topic = require('./topic.cjs');
|
|
6
|
+
|
|
7
|
+
//#region src/keys/registry.ts
|
|
8
|
+
/**
|
|
9
|
+
* The 4 anchor types with a built-in, multi-dimensional key generator
|
|
10
|
+
* (registered in the constructor below). Manifest-declared or discovered
|
|
11
|
+
* fields sharing one of these names must NOT overwrite the built-in — see
|
|
12
|
+
* `KeyGeneratorRegistry.isBuiltin` and issue #934 P0 regression (a manifest
|
|
13
|
+
* `fields.time` declaration silently replaced `generateTimeKeys`'s 8-dimension
|
|
14
|
+
* bucketing with a flat normalizedValue generator, killing month-bucket
|
|
15
|
+
* queries like `time:2026-06`).
|
|
16
|
+
*/
|
|
17
|
+
const BUILTIN_ANCHOR_TYPES = [
|
|
18
|
+
"time",
|
|
19
|
+
"location",
|
|
20
|
+
"person",
|
|
21
|
+
"topic"
|
|
22
|
+
];
|
|
23
|
+
var KeyGeneratorRegistry = class {
|
|
24
|
+
generators = /* @__PURE__ */ new Map();
|
|
25
|
+
builtins = new Set(BUILTIN_ANCHOR_TYPES);
|
|
26
|
+
constructor() {
|
|
27
|
+
this.generators.set("time", require_time.generateTimeKeys);
|
|
28
|
+
this.generators.set("location", require_location.generateLocationKeys);
|
|
29
|
+
this.generators.set("person", require_person.generatePersonKeys);
|
|
30
|
+
this.generators.set("topic", require_topic.generateTopicKeys);
|
|
31
|
+
}
|
|
32
|
+
/** True for the 4 built-in anchor types registered in the constructor. */
|
|
33
|
+
isBuiltin(type) {
|
|
34
|
+
return this.builtins.has(type);
|
|
35
|
+
}
|
|
36
|
+
register(type, generator) {
|
|
37
|
+
this.generators.set(type, generator);
|
|
38
|
+
}
|
|
39
|
+
generateKeys(anchor) {
|
|
40
|
+
return (this.generators.get(anchor.type) ?? require_exact.generateExactKeys)(anchor);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
exports.KeyGeneratorRegistry = KeyGeneratorRegistry;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Anchor, KeyGenerator } from "../types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/keys/registry.d.ts
|
|
4
|
+
declare class KeyGeneratorRegistry {
|
|
5
|
+
private readonly generators;
|
|
6
|
+
private readonly builtins;
|
|
7
|
+
constructor();
|
|
8
|
+
/** True for the 4 built-in anchor types registered in the constructor. */
|
|
9
|
+
isBuiltin(type: string): boolean;
|
|
10
|
+
register(type: string, generator: KeyGenerator): void;
|
|
11
|
+
generateKeys(anchor: Anchor): string[];
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { KeyGeneratorRegistry };
|
|
15
|
+
//# sourceMappingURL=registry.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.cts","names":[],"sources":["../../src/keys/registry.ts"],"mappings":";;;cAwBa,oBAAA;EAAA,iBACM,UAAA;EAAA,iBACA,QAAA;;;EAUjB,SAAA,CAAU,IAAA;EAIV,QAAA,CAAS,IAAA,UAAc,SAAA,EAAW,YAAA;EAIlC,YAAA,CAAa,MAAA,EAAQ,MAAA;AAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Anchor, KeyGenerator } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/keys/registry.d.ts
|
|
4
|
+
declare class KeyGeneratorRegistry {
|
|
5
|
+
private readonly generators;
|
|
6
|
+
private readonly builtins;
|
|
7
|
+
constructor();
|
|
8
|
+
/** True for the 4 built-in anchor types registered in the constructor. */
|
|
9
|
+
isBuiltin(type: string): boolean;
|
|
10
|
+
register(type: string, generator: KeyGenerator): void;
|
|
11
|
+
generateKeys(anchor: Anchor): string[];
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { KeyGeneratorRegistry };
|
|
15
|
+
//# sourceMappingURL=registry.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.mts","names":[],"sources":["../../src/keys/registry.ts"],"mappings":";;;cAwBa,oBAAA;EAAA,iBACM,UAAA;EAAA,iBACA,QAAA;;;EAUjB,SAAA,CAAU,IAAA;EAIV,QAAA,CAAS,IAAA,UAAc,SAAA,EAAW,YAAA;EAIlC,YAAA,CAAa,MAAA,EAAQ,MAAA;AAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { generateExactKeys } from "./exact.mjs";
|
|
2
|
+
import { generateLocationKeys } from "./location.mjs";
|
|
3
|
+
import { generatePersonKeys } from "./person.mjs";
|
|
4
|
+
import { generateTimeKeys } from "./time.mjs";
|
|
5
|
+
import { generateTopicKeys } from "./topic.mjs";
|
|
6
|
+
|
|
7
|
+
//#region src/keys/registry.ts
|
|
8
|
+
/**
|
|
9
|
+
* The 4 anchor types with a built-in, multi-dimensional key generator
|
|
10
|
+
* (registered in the constructor below). Manifest-declared or discovered
|
|
11
|
+
* fields sharing one of these names must NOT overwrite the built-in — see
|
|
12
|
+
* `KeyGeneratorRegistry.isBuiltin` and issue #934 P0 regression (a manifest
|
|
13
|
+
* `fields.time` declaration silently replaced `generateTimeKeys`'s 8-dimension
|
|
14
|
+
* bucketing with a flat normalizedValue generator, killing month-bucket
|
|
15
|
+
* queries like `time:2026-06`).
|
|
16
|
+
*/
|
|
17
|
+
const BUILTIN_ANCHOR_TYPES = [
|
|
18
|
+
"time",
|
|
19
|
+
"location",
|
|
20
|
+
"person",
|
|
21
|
+
"topic"
|
|
22
|
+
];
|
|
23
|
+
var KeyGeneratorRegistry = class {
|
|
24
|
+
generators = /* @__PURE__ */ new Map();
|
|
25
|
+
builtins = new Set(BUILTIN_ANCHOR_TYPES);
|
|
26
|
+
constructor() {
|
|
27
|
+
this.generators.set("time", generateTimeKeys);
|
|
28
|
+
this.generators.set("location", generateLocationKeys);
|
|
29
|
+
this.generators.set("person", generatePersonKeys);
|
|
30
|
+
this.generators.set("topic", generateTopicKeys);
|
|
31
|
+
}
|
|
32
|
+
/** True for the 4 built-in anchor types registered in the constructor. */
|
|
33
|
+
isBuiltin(type) {
|
|
34
|
+
return this.builtins.has(type);
|
|
35
|
+
}
|
|
36
|
+
register(type, generator) {
|
|
37
|
+
this.generators.set(type, generator);
|
|
38
|
+
}
|
|
39
|
+
generateKeys(anchor) {
|
|
40
|
+
return (this.generators.get(anchor.type) ?? generateExactKeys)(anchor);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
export { KeyGeneratorRegistry };
|
|
46
|
+
//# sourceMappingURL=registry.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.mjs","names":[],"sources":["../../src/keys/registry.ts"],"sourcesContent":["/**\n * Key Generator Registry — maps anchor types to their key generation functions.\n *\n * Built-in generators: time, location, person, topic.\n * Unknown types fall back to exact match.\n */\nimport type { Anchor, KeyGenerator } from \"../types.js\";\nimport { generateExactKeys } from \"./exact.js\";\nimport { generateLocationKeys } from \"./location.js\";\nimport { generatePersonKeys } from \"./person.js\";\nimport { generateTimeKeys } from \"./time.js\";\nimport { generateTopicKeys } from \"./topic.js\";\n\n/**\n * The 4 anchor types with a built-in, multi-dimensional key generator\n * (registered in the constructor below). Manifest-declared or discovered\n * fields sharing one of these names must NOT overwrite the built-in — see\n * `KeyGeneratorRegistry.isBuiltin` and issue #934 P0 regression (a manifest\n * `fields.time` declaration silently replaced `generateTimeKeys`'s 8-dimension\n * bucketing with a flat normalizedValue generator, killing month-bucket\n * queries like `time:2026-06`).\n */\nexport const BUILTIN_ANCHOR_TYPES = [\"time\", \"location\", \"person\", \"topic\"] as const;\n\nexport class KeyGeneratorRegistry {\n private readonly generators = new Map<string, KeyGenerator>();\n private readonly builtins = new Set<string>(BUILTIN_ANCHOR_TYPES);\n\n constructor() {\n this.generators.set(\"time\", generateTimeKeys);\n this.generators.set(\"location\", generateLocationKeys);\n this.generators.set(\"person\", generatePersonKeys);\n this.generators.set(\"topic\", generateTopicKeys);\n }\n\n /** True for the 4 built-in anchor types registered in the constructor. */\n isBuiltin(type: string): boolean {\n return this.builtins.has(type);\n }\n\n register(type: string, generator: KeyGenerator): void {\n this.generators.set(type, generator);\n }\n\n generateKeys(anchor: Anchor): string[] {\n const generator = this.generators.get(anchor.type) ?? generateExactKeys;\n return generator(anchor);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAsBA,MAAa,uBAAuB;CAAC;CAAQ;CAAY;CAAU;CAAQ;AAE3E,IAAa,uBAAb,MAAkC;CAChC,AAAiB,6BAAa,IAAI,KAA2B;CAC7D,AAAiB,WAAW,IAAI,IAAY,qBAAqB;CAEjE,cAAc;AACZ,OAAK,WAAW,IAAI,QAAQ,iBAAiB;AAC7C,OAAK,WAAW,IAAI,YAAY,qBAAqB;AACrD,OAAK,WAAW,IAAI,UAAU,mBAAmB;AACjD,OAAK,WAAW,IAAI,SAAS,kBAAkB;;;CAIjD,UAAU,MAAuB;AAC/B,SAAO,KAAK,SAAS,IAAI,KAAK;;CAGhC,SAAS,MAAc,WAA+B;AACpD,OAAK,WAAW,IAAI,MAAM,UAAU;;CAGtC,aAAa,QAA0B;AAErC,UADkB,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,mBACrC,OAAO"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/keys/time.ts
|
|
3
|
+
const WEEKDAYS = [
|
|
4
|
+
"sun",
|
|
5
|
+
"mon",
|
|
6
|
+
"tue",
|
|
7
|
+
"wed",
|
|
8
|
+
"thu",
|
|
9
|
+
"fri",
|
|
10
|
+
"sat"
|
|
11
|
+
];
|
|
12
|
+
const SEASONS_NORTH = {
|
|
13
|
+
1: "winter",
|
|
14
|
+
2: "winter",
|
|
15
|
+
3: "spring",
|
|
16
|
+
4: "spring",
|
|
17
|
+
5: "spring",
|
|
18
|
+
6: "summer",
|
|
19
|
+
7: "summer",
|
|
20
|
+
8: "summer",
|
|
21
|
+
9: "autumn",
|
|
22
|
+
10: "autumn",
|
|
23
|
+
11: "autumn",
|
|
24
|
+
12: "winter"
|
|
25
|
+
};
|
|
26
|
+
const SEASONS_SOUTH = {
|
|
27
|
+
1: "summer",
|
|
28
|
+
2: "summer",
|
|
29
|
+
3: "autumn",
|
|
30
|
+
4: "autumn",
|
|
31
|
+
5: "autumn",
|
|
32
|
+
6: "winter",
|
|
33
|
+
7: "winter",
|
|
34
|
+
8: "winter",
|
|
35
|
+
9: "spring",
|
|
36
|
+
10: "spring",
|
|
37
|
+
11: "spring",
|
|
38
|
+
12: "summer"
|
|
39
|
+
};
|
|
40
|
+
function getSeason(month, hemisphere) {
|
|
41
|
+
return (hemisphere === "south" ? SEASONS_SOUTH : SEASONS_NORTH)[month];
|
|
42
|
+
}
|
|
43
|
+
function getDaytime(hour) {
|
|
44
|
+
if (hour >= 5 && hour < 12) return "morning";
|
|
45
|
+
if (hour >= 12 && hour < 17) return "afternoon";
|
|
46
|
+
if (hour >= 17 && hour < 21) return "evening";
|
|
47
|
+
return "night";
|
|
48
|
+
}
|
|
49
|
+
function getISOWeek(year, month, day) {
|
|
50
|
+
const d = new Date(Date.UTC(year, month - 1, day));
|
|
51
|
+
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
|
|
52
|
+
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
|
53
|
+
return Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
|
|
54
|
+
}
|
|
55
|
+
function getQuarter(month) {
|
|
56
|
+
return Math.ceil(month / 3);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve date components in the user's local timezone (if provided) or UTC.
|
|
60
|
+
*
|
|
61
|
+
* When a timezone is given (e.g., "Asia/Shanghai"), the date, weekday, hour
|
|
62
|
+
* are computed in that timezone. This matters because "2026-03-10T01:00:00+08:00"
|
|
63
|
+
* is March 10 locally but March 9 in UTC — the date, weekday, and daytime
|
|
64
|
+
* would all be wrong without timezone awareness.
|
|
65
|
+
*/
|
|
66
|
+
function resolveComponents(date, timezone) {
|
|
67
|
+
if (timezone) {
|
|
68
|
+
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
69
|
+
timeZone: timezone,
|
|
70
|
+
year: "numeric",
|
|
71
|
+
month: "2-digit",
|
|
72
|
+
day: "2-digit",
|
|
73
|
+
weekday: "short",
|
|
74
|
+
hour: "2-digit",
|
|
75
|
+
hour12: false
|
|
76
|
+
});
|
|
77
|
+
const parts = Object.fromEntries(fmt.formatToParts(date).map((p) => [p.type, p.value]));
|
|
78
|
+
return {
|
|
79
|
+
year: Number(parts.year),
|
|
80
|
+
month: Number(parts.month),
|
|
81
|
+
day: Number(parts.day),
|
|
82
|
+
weekday: [
|
|
83
|
+
"sun",
|
|
84
|
+
"mon",
|
|
85
|
+
"tue",
|
|
86
|
+
"wed",
|
|
87
|
+
"thu",
|
|
88
|
+
"fri",
|
|
89
|
+
"sat"
|
|
90
|
+
][new Date(Date.UTC(Number(parts.year), Number(parts.month) - 1, Number(parts.day))).getUTCDay()],
|
|
91
|
+
hour: Number(parts.hour)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
year: date.getUTCFullYear(),
|
|
96
|
+
month: date.getUTCMonth() + 1,
|
|
97
|
+
day: date.getUTCDate(),
|
|
98
|
+
weekday: WEEKDAYS[date.getUTCDay()],
|
|
99
|
+
hour: date.getUTCHours()
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function generateTimeKeys(anchor, include) {
|
|
103
|
+
const timestamp = anchor.timestamp;
|
|
104
|
+
if (!timestamp) return [];
|
|
105
|
+
const date = new Date(timestamp);
|
|
106
|
+
if (Number.isNaN(date.getTime())) return [];
|
|
107
|
+
const timezone = anchor.timezone;
|
|
108
|
+
const hemisphere = anchor.hemisphere;
|
|
109
|
+
const { year, month, day, weekday, hour } = resolveComponents(date, timezone);
|
|
110
|
+
const week = getISOWeek(year, month, day);
|
|
111
|
+
const quarter = getQuarter(month);
|
|
112
|
+
const season = getSeason(month, hemisphere);
|
|
113
|
+
const candidates = [
|
|
114
|
+
["year", `time:${year}`],
|
|
115
|
+
["month", `time:${year}-${String(month).padStart(2, "0")}`],
|
|
116
|
+
["day", `time:${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`],
|
|
117
|
+
["quarter", `time:${year}-Q${quarter}`],
|
|
118
|
+
["week", `time:${year}-W${week}`],
|
|
119
|
+
["season", `time:${year}-${season}`],
|
|
120
|
+
["weekday", `time:weekday:${weekday}`]
|
|
121
|
+
];
|
|
122
|
+
if (timestamp.includes("T")) candidates.push(["daytime", `time:daytime:${getDaytime(hour)}`]);
|
|
123
|
+
if (!include) return candidates.map(([, key]) => key);
|
|
124
|
+
return candidates.filter(([g]) => include.has(g)).map(([, key]) => key);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
//#endregion
|
|
128
|
+
exports.generateTimeKeys = generateTimeKeys;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
//#region src/keys/time.ts
|
|
2
|
+
const WEEKDAYS = [
|
|
3
|
+
"sun",
|
|
4
|
+
"mon",
|
|
5
|
+
"tue",
|
|
6
|
+
"wed",
|
|
7
|
+
"thu",
|
|
8
|
+
"fri",
|
|
9
|
+
"sat"
|
|
10
|
+
];
|
|
11
|
+
const SEASONS_NORTH = {
|
|
12
|
+
1: "winter",
|
|
13
|
+
2: "winter",
|
|
14
|
+
3: "spring",
|
|
15
|
+
4: "spring",
|
|
16
|
+
5: "spring",
|
|
17
|
+
6: "summer",
|
|
18
|
+
7: "summer",
|
|
19
|
+
8: "summer",
|
|
20
|
+
9: "autumn",
|
|
21
|
+
10: "autumn",
|
|
22
|
+
11: "autumn",
|
|
23
|
+
12: "winter"
|
|
24
|
+
};
|
|
25
|
+
const SEASONS_SOUTH = {
|
|
26
|
+
1: "summer",
|
|
27
|
+
2: "summer",
|
|
28
|
+
3: "autumn",
|
|
29
|
+
4: "autumn",
|
|
30
|
+
5: "autumn",
|
|
31
|
+
6: "winter",
|
|
32
|
+
7: "winter",
|
|
33
|
+
8: "winter",
|
|
34
|
+
9: "spring",
|
|
35
|
+
10: "spring",
|
|
36
|
+
11: "spring",
|
|
37
|
+
12: "summer"
|
|
38
|
+
};
|
|
39
|
+
function getSeason(month, hemisphere) {
|
|
40
|
+
return (hemisphere === "south" ? SEASONS_SOUTH : SEASONS_NORTH)[month];
|
|
41
|
+
}
|
|
42
|
+
function getDaytime(hour) {
|
|
43
|
+
if (hour >= 5 && hour < 12) return "morning";
|
|
44
|
+
if (hour >= 12 && hour < 17) return "afternoon";
|
|
45
|
+
if (hour >= 17 && hour < 21) return "evening";
|
|
46
|
+
return "night";
|
|
47
|
+
}
|
|
48
|
+
function getISOWeek(year, month, day) {
|
|
49
|
+
const d = new Date(Date.UTC(year, month - 1, day));
|
|
50
|
+
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));
|
|
51
|
+
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
|
52
|
+
return Math.ceil(((d.getTime() - yearStart.getTime()) / 864e5 + 1) / 7);
|
|
53
|
+
}
|
|
54
|
+
function getQuarter(month) {
|
|
55
|
+
return Math.ceil(month / 3);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve date components in the user's local timezone (if provided) or UTC.
|
|
59
|
+
*
|
|
60
|
+
* When a timezone is given (e.g., "Asia/Shanghai"), the date, weekday, hour
|
|
61
|
+
* are computed in that timezone. This matters because "2026-03-10T01:00:00+08:00"
|
|
62
|
+
* is March 10 locally but March 9 in UTC — the date, weekday, and daytime
|
|
63
|
+
* would all be wrong without timezone awareness.
|
|
64
|
+
*/
|
|
65
|
+
function resolveComponents(date, timezone) {
|
|
66
|
+
if (timezone) {
|
|
67
|
+
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
68
|
+
timeZone: timezone,
|
|
69
|
+
year: "numeric",
|
|
70
|
+
month: "2-digit",
|
|
71
|
+
day: "2-digit",
|
|
72
|
+
weekday: "short",
|
|
73
|
+
hour: "2-digit",
|
|
74
|
+
hour12: false
|
|
75
|
+
});
|
|
76
|
+
const parts = Object.fromEntries(fmt.formatToParts(date).map((p) => [p.type, p.value]));
|
|
77
|
+
return {
|
|
78
|
+
year: Number(parts.year),
|
|
79
|
+
month: Number(parts.month),
|
|
80
|
+
day: Number(parts.day),
|
|
81
|
+
weekday: [
|
|
82
|
+
"sun",
|
|
83
|
+
"mon",
|
|
84
|
+
"tue",
|
|
85
|
+
"wed",
|
|
86
|
+
"thu",
|
|
87
|
+
"fri",
|
|
88
|
+
"sat"
|
|
89
|
+
][new Date(Date.UTC(Number(parts.year), Number(parts.month) - 1, Number(parts.day))).getUTCDay()],
|
|
90
|
+
hour: Number(parts.hour)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
year: date.getUTCFullYear(),
|
|
95
|
+
month: date.getUTCMonth() + 1,
|
|
96
|
+
day: date.getUTCDate(),
|
|
97
|
+
weekday: WEEKDAYS[date.getUTCDay()],
|
|
98
|
+
hour: date.getUTCHours()
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function generateTimeKeys(anchor, include) {
|
|
102
|
+
const timestamp = anchor.timestamp;
|
|
103
|
+
if (!timestamp) return [];
|
|
104
|
+
const date = new Date(timestamp);
|
|
105
|
+
if (Number.isNaN(date.getTime())) return [];
|
|
106
|
+
const timezone = anchor.timezone;
|
|
107
|
+
const hemisphere = anchor.hemisphere;
|
|
108
|
+
const { year, month, day, weekday, hour } = resolveComponents(date, timezone);
|
|
109
|
+
const week = getISOWeek(year, month, day);
|
|
110
|
+
const quarter = getQuarter(month);
|
|
111
|
+
const season = getSeason(month, hemisphere);
|
|
112
|
+
const candidates = [
|
|
113
|
+
["year", `time:${year}`],
|
|
114
|
+
["month", `time:${year}-${String(month).padStart(2, "0")}`],
|
|
115
|
+
["day", `time:${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`],
|
|
116
|
+
["quarter", `time:${year}-Q${quarter}`],
|
|
117
|
+
["week", `time:${year}-W${week}`],
|
|
118
|
+
["season", `time:${year}-${season}`],
|
|
119
|
+
["weekday", `time:weekday:${weekday}`]
|
|
120
|
+
];
|
|
121
|
+
if (timestamp.includes("T")) candidates.push(["daytime", `time:daytime:${getDaytime(hour)}`]);
|
|
122
|
+
if (!include) return candidates.map(([, key]) => key);
|
|
123
|
+
return candidates.filter(([g]) => include.has(g)).map(([, key]) => key);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
//#endregion
|
|
127
|
+
export { generateTimeKeys };
|
|
128
|
+
//# sourceMappingURL=time.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time.mjs","names":[],"sources":["../../src/keys/time.ts"],"sourcesContent":["/**\n * Time key generator — expands a timestamp into multi-dimensional index keys.\n *\n * Generates up to 8 keys covering: year, month, day, quarter, ISO week,\n * season, weekday, and daytime period.\n */\nimport type { Anchor, TimeKeyGranularity } from \"../types.js\";\n\nconst WEEKDAYS = [\"sun\", \"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\"] as const;\n\nconst SEASONS_NORTH: Record<number, string> = {\n 1: \"winter\",\n 2: \"winter\",\n 3: \"spring\",\n 4: \"spring\",\n 5: \"spring\",\n 6: \"summer\",\n 7: \"summer\",\n 8: \"summer\",\n 9: \"autumn\",\n 10: \"autumn\",\n 11: \"autumn\",\n 12: \"winter\",\n};\n\nconst SEASONS_SOUTH: Record<number, string> = {\n 1: \"summer\",\n 2: \"summer\",\n 3: \"autumn\",\n 4: \"autumn\",\n 5: \"autumn\",\n 6: \"winter\",\n 7: \"winter\",\n 8: \"winter\",\n 9: \"spring\",\n 10: \"spring\",\n 11: \"spring\",\n 12: \"summer\",\n};\n\nfunction getSeason(month: number, hemisphere?: string): string {\n const table = hemisphere === \"south\" ? SEASONS_SOUTH : SEASONS_NORTH;\n return table[month]!;\n}\n\nfunction getDaytime(hour: number): string {\n if (hour >= 5 && hour < 12) return \"morning\";\n if (hour >= 12 && hour < 17) return \"afternoon\";\n if (hour >= 17 && hour < 21) return \"evening\";\n return \"night\";\n}\n\nfunction getISOWeek(year: number, month: number, day: number): number {\n const d = new Date(Date.UTC(year, month - 1, day));\n d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7));\n const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);\n}\n\nfunction getQuarter(month: number): number {\n return Math.ceil(month / 3);\n}\n\n/**\n * Resolve date components in the user's local timezone (if provided) or UTC.\n *\n * When a timezone is given (e.g., \"Asia/Shanghai\"), the date, weekday, hour\n * are computed in that timezone. This matters because \"2026-03-10T01:00:00+08:00\"\n * is March 10 locally but March 9 in UTC — the date, weekday, and daytime\n * would all be wrong without timezone awareness.\n */\nfunction resolveComponents(date: Date, timezone?: string) {\n if (timezone) {\n // Use Intl.DateTimeFormat to extract local components\n const fmt = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n weekday: \"short\",\n hour: \"2-digit\",\n hour12: false,\n });\n const parts = Object.fromEntries(fmt.formatToParts(date).map((p) => [p.type, p.value]));\n return {\n year: Number(parts.year),\n month: Number(parts.month),\n day: Number(parts.day),\n weekday: ([\"sun\", \"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\"] as const)[\n new Date(\n Date.UTC(Number(parts.year), Number(parts.month) - 1, Number(parts.day)),\n ).getUTCDay()\n ]!,\n hour: Number(parts.hour),\n };\n }\n return {\n year: date.getUTCFullYear(),\n month: date.getUTCMonth() + 1,\n day: date.getUTCDate(),\n weekday: WEEKDAYS[date.getUTCDay()]!,\n hour: date.getUTCHours(),\n };\n}\n\nexport function generateTimeKeys(anchor: Anchor, include?: Set<TimeKeyGranularity>): string[] {\n const timestamp = anchor.timestamp as string | undefined;\n if (!timestamp) return [];\n\n const date = new Date(timestamp);\n if (Number.isNaN(date.getTime())) return [];\n\n const timezone = anchor.timezone as string | undefined;\n const hemisphere = anchor.hemisphere as string | undefined;\n const { year, month, day, weekday, hour } = resolveComponents(date, timezone);\n const week = getISOWeek(year, month, day);\n const quarter = getQuarter(month);\n const season = getSeason(month, hemisphere);\n\n const candidates: Array<[TimeKeyGranularity, string]> = [\n [\"year\", `time:${year}`],\n [\"month\", `time:${year}-${String(month).padStart(2, \"0\")}`],\n [\"day\", `time:${year}-${String(month).padStart(2, \"0\")}-${String(day).padStart(2, \"0\")}`],\n [\"quarter\", `time:${year}-Q${quarter}`],\n [\"week\", `time:${year}-W${week}`],\n [\"season\", `time:${year}-${season}`],\n [\"weekday\", `time:weekday:${weekday}`],\n ];\n\n // Only add daytime if timestamp includes time component (contains 'T')\n const hasTime = timestamp.includes(\"T\");\n if (hasTime) {\n candidates.push([\"daytime\", `time:daytime:${getDaytime(hour)}`]);\n }\n\n if (!include) return candidates.map(([, key]) => key);\n return candidates.filter(([g]) => include.has(g)).map(([, key]) => key);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/keys/topic.ts
|
|
3
|
+
function generateTopicKeys(anchor) {
|
|
4
|
+
const keys = [];
|
|
5
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6
|
+
const push = (raw) => {
|
|
7
|
+
if (typeof raw !== "string") return;
|
|
8
|
+
const topic = raw.trim().toLowerCase();
|
|
9
|
+
if (!topic || seen.has(topic)) return;
|
|
10
|
+
seen.add(topic);
|
|
11
|
+
keys.push(`topic:${topic}`);
|
|
12
|
+
};
|
|
13
|
+
const arr = anchor.values;
|
|
14
|
+
if (Array.isArray(arr)) {
|
|
15
|
+
for (const v of arr) if (typeof v === "string") for (const seg of v.split(",")) push(seg);
|
|
16
|
+
}
|
|
17
|
+
const single = anchor.value;
|
|
18
|
+
if (typeof single === "string") for (const seg of single.split(",")) push(seg);
|
|
19
|
+
return keys;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
exports.generateTopicKeys = generateTopicKeys;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/keys/topic.ts
|
|
2
|
+
function generateTopicKeys(anchor) {
|
|
3
|
+
const keys = [];
|
|
4
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5
|
+
const push = (raw) => {
|
|
6
|
+
if (typeof raw !== "string") return;
|
|
7
|
+
const topic = raw.trim().toLowerCase();
|
|
8
|
+
if (!topic || seen.has(topic)) return;
|
|
9
|
+
seen.add(topic);
|
|
10
|
+
keys.push(`topic:${topic}`);
|
|
11
|
+
};
|
|
12
|
+
const arr = anchor.values;
|
|
13
|
+
if (Array.isArray(arr)) {
|
|
14
|
+
for (const v of arr) if (typeof v === "string") for (const seg of v.split(",")) push(seg);
|
|
15
|
+
}
|
|
16
|
+
const single = anchor.value;
|
|
17
|
+
if (typeof single === "string") for (const seg of single.split(",")) push(seg);
|
|
18
|
+
return keys;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { generateTopicKeys };
|
|
23
|
+
//# sourceMappingURL=topic.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topic.mjs","names":[],"sources":["../../src/keys/topic.ts"],"sourcesContent":["/**\n * Topic key generator — generates normalized keys for topic anchors.\n *\n * Two input shapes coexist (query-side and indexer side both treat\n * topics as multi-valued):\n *\n * - `value: \"fundraising,investment\"` (legacy single-string with\n * comma-separated values).\n * - `values: [\"fundraising\", \"investment\"]` (canonical array; what\n * `queryAnchors` already expects on the matching side).\n *\n * Without supporting `values`, every topic anchor written via the\n * standard `{ type: \"topic\", values: [...] }` shape produced ZERO\n * `idx_anchor_key` rows — `idx_anchor_data` had the raw blob but the lookup\n * table was empty, so `queryAnchors` never matched anything. The\n * retrieval bench surfaced this as a silent gap.\n */\nimport type { Anchor } from \"../types.js\";\n\nexport function generateTopicKeys(anchor: Anchor): string[] {\n const keys: string[] = [];\n const seen = new Set<string>();\n\n const push = (raw: unknown): void => {\n if (typeof raw !== \"string\") return;\n const topic = raw.trim().toLowerCase();\n if (!topic || seen.has(topic)) return;\n seen.add(topic);\n keys.push(`topic:${topic}`);\n };\n\n // Canonical array shape — preferred. Each element may itself be a\n // comma list for back-compat, so split before pushing.\n const arr = anchor.values as unknown;\n if (Array.isArray(arr)) {\n for (const v of arr) {\n if (typeof v === \"string\") {\n for (const seg of v.split(\",\")) push(seg);\n }\n }\n }\n\n // Legacy single-string shape — `value: \"a,b\"`.\n const single = anchor.value;\n if (typeof single === \"string\") {\n for (const seg of single.split(\",\")) push(seg);\n }\n\n return keys;\n}\n"],"mappings":";AAmBA,SAAgB,kBAAkB,QAA0B;CAC1D,MAAM,OAAiB,EAAE;CACzB,MAAM,uBAAO,IAAI,KAAa;CAE9B,MAAM,QAAQ,QAAuB;AACnC,MAAI,OAAO,QAAQ,SAAU;EAC7B,MAAM,QAAQ,IAAI,MAAM,CAAC,aAAa;AACtC,MAAI,CAAC,SAAS,KAAK,IAAI,MAAM,CAAE;AAC/B,OAAK,IAAI,MAAM;AACf,OAAK,KAAK,SAAS,QAAQ;;CAK7B,MAAM,MAAM,OAAO;AACnB,KAAI,MAAM,QAAQ,IAAI,EACpB;OAAK,MAAM,KAAK,IACd,KAAI,OAAO,MAAM,SACf,MAAK,MAAM,OAAO,EAAE,MAAM,IAAI,CAAE,MAAK,IAAI;;CAM/C,MAAM,SAAS,OAAO;AACtB,KAAI,OAAO,WAAW,SACpB,MAAK,MAAM,OAAO,OAAO,MAAM,IAAI,CAAE,MAAK,IAAI;AAGhD,QAAO"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/manifest-index.ts
|
|
3
|
+
/**
|
|
4
|
+
* Project a single manifest domain declaration to a DomainRegistration.
|
|
5
|
+
* Does NOT write any files — returns plain data structures for the caller to use.
|
|
6
|
+
*/
|
|
7
|
+
function projectDomain(domain) {
|
|
8
|
+
const anchorTypes = [];
|
|
9
|
+
if (domain.fields) for (const fieldName of Object.keys(domain.fields)) anchorTypes.push({ name: fieldName });
|
|
10
|
+
const config = { ...domain.indexable ? { indexable: domain.indexable } : {} };
|
|
11
|
+
return {
|
|
12
|
+
name: domain.name,
|
|
13
|
+
...domain.scope ? { scope: domain.scope } : {},
|
|
14
|
+
config,
|
|
15
|
+
anchorTypes
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Project all domains in a `BlockletIndex` declaration.
|
|
20
|
+
* Returns one `DomainRegistration` per domain, ready to be passed to
|
|
21
|
+
* `register-domain` exec actions on the index provider.
|
|
22
|
+
*/
|
|
23
|
+
function projectManifestIndex(index) {
|
|
24
|
+
return index.domains.map(projectDomain);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
exports.projectDomain = projectDomain;
|
|
29
|
+
exports.projectManifestIndex = projectManifestIndex;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AnchorTypeDefinition, IndexConfig } from "./types.cjs";
|
|
2
|
+
import { BlockletIndex, BlockletIndexDomain } from "@aigne/afs";
|
|
3
|
+
|
|
4
|
+
//#region src/manifest-index.d.ts
|
|
5
|
+
interface DomainRegistration {
|
|
6
|
+
name: string;
|
|
7
|
+
scope?: string;
|
|
8
|
+
config: IndexConfig;
|
|
9
|
+
anchorTypes: AnchorTypeDefinition[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Project a single manifest domain declaration to a DomainRegistration.
|
|
13
|
+
* Does NOT write any files — returns plain data structures for the caller to use.
|
|
14
|
+
*/
|
|
15
|
+
declare function projectDomain(domain: BlockletIndexDomain): DomainRegistration;
|
|
16
|
+
/**
|
|
17
|
+
* Project all domains in a `BlockletIndex` declaration.
|
|
18
|
+
* Returns one `DomainRegistration` per domain, ready to be passed to
|
|
19
|
+
* `register-domain` exec actions on the index provider.
|
|
20
|
+
*/
|
|
21
|
+
declare function projectManifestIndex(index: BlockletIndex): DomainRegistration[];
|
|
22
|
+
//#endregion
|
|
23
|
+
export { DomainRegistration, projectDomain, projectManifestIndex };
|
|
24
|
+
//# sourceMappingURL=manifest-index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-index.d.cts","names":[],"sources":["../src/manifest-index.ts"],"mappings":";;;;UAgBiB,kBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA,EAAQ,WAAA;EACR,WAAA,EAAa,oBAAA;AAAA;;;;;iBAOC,aAAA,CAAc,MAAA,EAAQ,mBAAA,GAAsB,kBAAA;;;;;;iBA0B5C,oBAAA,CAAqB,KAAA,EAAO,aAAA,GAAgB,kBAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AnchorTypeDefinition, IndexConfig } from "./types.mjs";
|
|
2
|
+
import { BlockletIndex, BlockletIndexDomain } from "@aigne/afs";
|
|
3
|
+
|
|
4
|
+
//#region src/manifest-index.d.ts
|
|
5
|
+
interface DomainRegistration {
|
|
6
|
+
name: string;
|
|
7
|
+
scope?: string;
|
|
8
|
+
config: IndexConfig;
|
|
9
|
+
anchorTypes: AnchorTypeDefinition[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Project a single manifest domain declaration to a DomainRegistration.
|
|
13
|
+
* Does NOT write any files — returns plain data structures for the caller to use.
|
|
14
|
+
*/
|
|
15
|
+
declare function projectDomain(domain: BlockletIndexDomain): DomainRegistration;
|
|
16
|
+
/**
|
|
17
|
+
* Project all domains in a `BlockletIndex` declaration.
|
|
18
|
+
* Returns one `DomainRegistration` per domain, ready to be passed to
|
|
19
|
+
* `register-domain` exec actions on the index provider.
|
|
20
|
+
*/
|
|
21
|
+
declare function projectManifestIndex(index: BlockletIndex): DomainRegistration[];
|
|
22
|
+
//#endregion
|
|
23
|
+
export { DomainRegistration, projectDomain, projectManifestIndex };
|
|
24
|
+
//# sourceMappingURL=manifest-index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-index.d.mts","names":[],"sources":["../src/manifest-index.ts"],"mappings":";;;;UAgBiB,kBAAA;EACf,IAAA;EACA,KAAA;EACA,MAAA,EAAQ,WAAA;EACR,WAAA,EAAa,oBAAA;AAAA;;;;;iBAOC,aAAA,CAAc,MAAA,EAAQ,mBAAA,GAAsB,kBAAA;;;;;;iBA0B5C,oBAAA,CAAqB,KAAA,EAAO,aAAA,GAAgB,kBAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/manifest-index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Project a single manifest domain declaration to a DomainRegistration.
|
|
4
|
+
* Does NOT write any files — returns plain data structures for the caller to use.
|
|
5
|
+
*/
|
|
6
|
+
function projectDomain(domain) {
|
|
7
|
+
const anchorTypes = [];
|
|
8
|
+
if (domain.fields) for (const fieldName of Object.keys(domain.fields)) anchorTypes.push({ name: fieldName });
|
|
9
|
+
const config = { ...domain.indexable ? { indexable: domain.indexable } : {} };
|
|
10
|
+
return {
|
|
11
|
+
name: domain.name,
|
|
12
|
+
...domain.scope ? { scope: domain.scope } : {},
|
|
13
|
+
config,
|
|
14
|
+
anchorTypes
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Project all domains in a `BlockletIndex` declaration.
|
|
19
|
+
* Returns one `DomainRegistration` per domain, ready to be passed to
|
|
20
|
+
* `register-domain` exec actions on the index provider.
|
|
21
|
+
*/
|
|
22
|
+
function projectManifestIndex(index) {
|
|
23
|
+
return index.domains.map(projectDomain);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { projectDomain, projectManifestIndex };
|
|
28
|
+
//# sourceMappingURL=manifest-index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-index.mjs","names":[],"sources":["../src/manifest-index.ts"],"sourcesContent":["/**\n * manifest-index.ts — bridge between blocklet.yaml `index:` declarations and\n * the AFSIndex register-domain action.\n *\n * Given a parsed `BlockletIndex` (from parseBlockletManifest), this module\n * produces the `register-domain` call arguments for each declared domain so\n * that the CF/Node session-view wiring code can register them at startup.\n *\n * Each field entry in the manifest becomes an AnchorTypeDefinition with the\n * default `normalizedValue` key generator (the index provider wires this\n * automatically for types without an explicit keyGenerator — see discoverProvider\n * wiring in index-provider.ts:1117-1124).\n */\nimport type { BlockletIndex, BlockletIndexDomain } from \"@aigne/afs\";\nimport type { AnchorTypeDefinition, IndexConfig } from \"./types.js\";\n\nexport interface DomainRegistration {\n name: string;\n scope?: string;\n config: IndexConfig;\n anchorTypes: AnchorTypeDefinition[];\n}\n\n/**\n * Project a single manifest domain declaration to a DomainRegistration.\n * Does NOT write any files — returns plain data structures for the caller to use.\n */\nexport function projectDomain(domain: BlockletIndexDomain): DomainRegistration {\n const anchorTypes: AnchorTypeDefinition[] = [];\n\n if (domain.fields) {\n for (const fieldName of Object.keys(domain.fields)) {\n anchorTypes.push({ name: fieldName });\n }\n }\n\n const config: IndexConfig = {\n ...(domain.indexable ? { indexable: domain.indexable } : {}),\n };\n\n return {\n name: domain.name,\n ...(domain.scope ? { scope: domain.scope } : {}),\n config,\n anchorTypes,\n };\n}\n\n/**\n * Project all domains in a `BlockletIndex` declaration.\n * Returns one `DomainRegistration` per domain, ready to be passed to\n * `register-domain` exec actions on the index provider.\n */\nexport function projectManifestIndex(index: BlockletIndex): DomainRegistration[] {\n return index.domains.map(projectDomain);\n}\n"],"mappings":";;;;;AA2BA,SAAgB,cAAc,QAAiD;CAC7E,MAAM,cAAsC,EAAE;AAE9C,KAAI,OAAO,OACT,MAAK,MAAM,aAAa,OAAO,KAAK,OAAO,OAAO,CAChD,aAAY,KAAK,EAAE,MAAM,WAAW,CAAC;CAIzC,MAAM,SAAsB,EAC1B,GAAI,OAAO,YAAY,EAAE,WAAW,OAAO,WAAW,GAAG,EAAE,EAC5D;AAED,QAAO;EACL,MAAM,OAAO;EACb,GAAI,OAAO,QAAQ,EAAE,OAAO,OAAO,OAAO,GAAG,EAAE;EAC/C;EACA;EACD;;;;;;;AAQH,SAAgB,qBAAqB,OAA4C;AAC/E,QAAO,MAAM,QAAQ,IAAI,cAAc"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const require_time = require('./keys/time.cjs');
|
|
2
|
+
const require_registry = require('./keys/registry.cjs');
|
|
3
|
+
const require_follower = require('./follower.cjs');
|
|
4
|
+
|
|
5
|
+
//#region src/offline-rebuild.ts
|
|
6
|
+
async function offlineRebuildScope(opts) {
|
|
7
|
+
const { backend, spaceAfs, domains, livePaths, timeKeyGranularity } = opts;
|
|
8
|
+
if (timeKeyGranularity?.length && backend.setKeyRegistry) {
|
|
9
|
+
const registry = new require_registry.KeyGeneratorRegistry();
|
|
10
|
+
const include = new Set(timeKeyGranularity);
|
|
11
|
+
registry.register("time", (anchor) => require_time.generateTimeKeys(anchor, include));
|
|
12
|
+
backend.setKeyRegistry(registry);
|
|
13
|
+
}
|
|
14
|
+
let cleared = 0;
|
|
15
|
+
const boundDomains = domains.map((d) => d.name);
|
|
16
|
+
const existing = backend.listEntries ? await backend.listEntries({ boundDomains }) : [];
|
|
17
|
+
if (existing.length > 0 && backend.purgeEntries) {
|
|
18
|
+
opts.onProgress?.({
|
|
19
|
+
phase: "clear",
|
|
20
|
+
done: 0,
|
|
21
|
+
total: existing.length
|
|
22
|
+
});
|
|
23
|
+
cleared = await backend.purgeEntries(existing.map((e) => e.entryPath), { skipVector: true });
|
|
24
|
+
opts.onProgress?.({
|
|
25
|
+
phase: "clear",
|
|
26
|
+
done: cleared,
|
|
27
|
+
total: existing.length
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const { indexed, failed, skipped } = await new require_follower.IndexFollower({
|
|
31
|
+
spaceAfs,
|
|
32
|
+
backend,
|
|
33
|
+
domains
|
|
34
|
+
}).reindexPaths(livePaths, (done, total) => opts.onProgress?.({
|
|
35
|
+
phase: "rebuild",
|
|
36
|
+
done,
|
|
37
|
+
total
|
|
38
|
+
}));
|
|
39
|
+
return {
|
|
40
|
+
cleared,
|
|
41
|
+
indexed,
|
|
42
|
+
failed,
|
|
43
|
+
skipped
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
exports.offlineRebuildScope = offlineRebuildScope;
|