@lde/search-typesense 0.9.1 → 0.10.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/README.md CHANGED
@@ -120,7 +120,8 @@ direct use and testing.
120
120
  Indexing runs through two transactional writers, one per update mode – the
121
121
  [NDE Stack](https://docs.nde.nl/stack/patterns) patterns of the same names:
122
122
 
123
- - [**Blue/green Rebuild**](#bluegreen-rebuild: build a fresh index, then swap to it atomically;
123
+ - [**Blue/green Rebuild**](#bluegreen-rebuild): build a fresh index, then swap to
124
+ it atomically;
124
125
  - [**In-place Rebuild**](#in-place-rebuild): update the live index directly by
125
126
  upserting changed sources and sweeping the rest.
126
127
 
@@ -1 +1 @@
1
- {"version":3,"file":"blue-green-rebuild.d.ts","sourceRoot":"","sources":["../src/blue-green-rebuild.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAEV,UAAU,EACV,SAAS,EACT,MAAM,EACP,MAAM,eAAe,CAAC;AAMvB,OAAO,EAKL,KAAK,cAAc,EAEpB,MAAM,sBAAsB,CAAC;AAE9B;;yDAEyD;AACzD,MAAM,MAAM,uBAAuB,GAAG,cAAc,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,gBAAgB,CAC3B,SAAS,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAChC,YAAW,MAAM,CAAC,SAAS,CAAC;IAa1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAb7B;;;;;;;OAOG;IACH,SAAgB,cAAc,EAAE,MAAM,CAAC;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;gBAG/B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACvC,OAAO,GAAE,uBAA4B;IAQjC,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IA4FjE,4EAA4E;YAC9D,WAAW;CAW1B"}
1
+ {"version":3,"file":"blue-green-rebuild.d.ts","sourceRoot":"","sources":["../src/blue-green-rebuild.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAEV,UAAU,EACV,SAAS,EACT,MAAM,EACP,MAAM,eAAe,CAAC;AAMvB,OAAO,EAKL,KAAK,cAAc,EAEpB,MAAM,sBAAsB,CAAC;AAE9B;;yDAEyD;AACzD,MAAM,MAAM,uBAAuB,GAAG,cAAc,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,gBAAgB,CAC3B,SAAS,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAChC,YAAW,MAAM,CAAC,SAAS,CAAC;IAa1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAb7B;;;;;;;OAOG;IACH,SAAgB,cAAc,EAAE,MAAM,CAAC;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;gBAG/B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACvC,OAAO,GAAE,uBAA4B;IAQjC,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IA6FjE,4EAA4E;YAC9D,WAAW;CAW1B"}
@@ -51,10 +51,11 @@ export class BlueGreenRebuild {
51
51
  // `source` is stamped on every document for per-dataset rollback.
52
52
  assertNoReservedFields(searchType, [SOURCE_FIELD]);
53
53
  this.resolved = resolveRebuildOptions(searchType, options);
54
- this.collectionName = this.resolved.name;
54
+ this.collectionName = this.resolved.definitionOptions.name;
55
55
  }
56
56
  async openRun(context) {
57
- const { name, batchSize, lockTtlMs, definitionOptions } = this.resolved;
57
+ const { batchSize, lockTtlMs, definitionOptions } = this.resolved;
58
+ const name = this.collectionName;
58
59
  return openLockedRun(this.client, name, lockTtlMs, async () => {
59
60
  // Create the fresh (blue) collection up front, so a failure surfaces
60
61
  // before any dataset is processed. startedAt orders the versioned names;
@@ -1 +1 @@
1
- {"version":3,"file":"collection-name.d.ts","sourceRoot":"","sources":["../src/collection-name.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAanE"}
1
+ {"version":3,"file":"collection-name.d.ts","sourceRoot":"","sources":["../src/collection-name.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAWnE"}
@@ -21,35 +21,23 @@ import { physicalNameTokens } from '@lde/search/adapter';
21
21
  * deployment’s business.
22
22
  */
23
23
  export function deriveCollectionName(searchType) {
24
- if (!NAMEABLE_TYPE_NAME.test(searchType.name)) {
25
- throw new Error(`Cannot derive a Typesense collection name from search type “${searchType.name}”: it carries characters the convention would silently drop rather than name. Rename the type, or pass an explicit name.`);
26
- }
24
+ // A name the split cannot spell at all throws in physicalNameTokens, which
25
+ // owns that engine-neutral rule; what is left to check here is whether the
26
+ // formatted result is legal for THIS engine.
27
27
  const name = physicalNameTokens(searchType).join('_');
28
28
  if (!DERIVED_COLLECTION_NAME.test(name)) {
29
29
  throw new Error(`Cannot derive a Typesense collection name from search type “${searchType.name}”: it yields “${name}”, which is not a legal collection name. Rename the type, or pass an explicit name.`);
30
30
  }
31
31
  return name;
32
32
  }
33
- /**
34
- * A type name this convention can name a collection after without silently
35
- * losing part of it. {@link physicalNameTokens} matches ASCII words and drops
36
- * everything else, which is what lets a name already written `creative_work` or
37
- * `creative-work` tokenize like `CreativeWork` – but it would just as quietly
38
- * turn `Café` into `cafs` and `Musée` into `mus_es`: legal names for the wrong
39
- * collection, which is worse than no name at all. So a name is nameable only
40
- * when it is ASCII words and word separators; anything else is rejected rather
41
- * than mangled. An explicit name still overrides, since a deployment may
42
- * legitimately index a type whose name this cannot spell.
43
- */
44
- const NAMEABLE_TYPE_NAME = /^[A-Za-z0-9 _-]+$/;
45
33
  /**
46
34
  * What a *derived* name must look like. Typesense documents no collection-name
47
35
  * rules, but a name travels in the URL path of every collection call
48
36
  * (`/collections/:name`), so a character with URL meaning breaks that call
49
37
  * rather than being rejected at creation – `#` and `+` silently strand a
50
- * collection ({@link https://github.com/typesense/typesense/issues/548}). This
51
- * charset is the safe subset {@link physicalNameTokens} can produce anyway, so
52
- * the check is really a guard on the type name behind it: a `name` with no
53
- * alphanumerics at all (tokens `[]`, name `''`) is the case that reaches it.
38
+ * collection ({@link https://github.com/typesense/typesense/issues/548}).
39
+ * {@link physicalNameTokens} already guarantees lowercase ASCII words, so what
40
+ * this still rules on is the leading character: a type named `123` derives
41
+ * `123s`, and a name should open with a letter rather than read as a number.
54
42
  */
55
43
  const DERIVED_COLLECTION_NAME = /^[a-z][a-z0-9_]*$/;
@@ -1 +1 @@
1
- {"version":3,"file":"in-place-rebuild.d.ts","sourceRoot":"","sources":["../src/in-place-rebuild.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAEV,UAAU,EACV,SAAS,EACT,MAAM,EACP,MAAM,eAAe,CAAC;AAYvB,OAAO,EAKL,KAAK,cAAc,EAEpB,MAAM,sBAAsB,CAAC;AAa9B;gCACgC;AAChC,MAAM,WAAW,qBAAsB,SAAQ,cAAc;IAC3D;sEACkE;IAClE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,cAAc,CACzB,SAAS,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAChC,YAAW,MAAM,CAAC,SAAS,CAAC;IAY1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAZ7B;;;;;OAKG;IACH,SAAgB,cAAc,EAAE,MAAM,CAAC;IACvC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;gBAG/B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACvC,OAAO,GAAE,qBAA0B;IAY/B,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAqFjE;;;;;;OAMG;YACW,cAAc;CAsB7B"}
1
+ {"version":3,"file":"in-place-rebuild.d.ts","sourceRoot":"","sources":["../src/in-place-rebuild.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAEV,UAAU,EACV,SAAS,EACT,MAAM,EACP,MAAM,eAAe,CAAC;AAYvB,OAAO,EAKL,KAAK,cAAc,EAEpB,MAAM,sBAAsB,CAAC;AAa9B;gCACgC;AAChC,MAAM,WAAW,qBAAsB,SAAQ,cAAc;IAC3D;sEACkE;IAClE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,cAAc,CACzB,SAAS,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAChC,YAAW,MAAM,CAAC,SAAS,CAAC;IAY1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAZ7B;;;;;OAKG;IACH,SAAgB,cAAc,EAAE,MAAM,CAAC;IACvC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;gBAG/B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACvC,OAAO,GAAE,qBAA0B;IAY/B,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAsFjE;;;;;;OAMG;YACW,cAAc;CAsB7B"}
@@ -65,10 +65,11 @@ export class InPlaceRebuild {
65
65
  const { maxSweepableSources = DEFAULT_MAX_SWEEPABLE_SOURCES, ...rebuildOptions } = options;
66
66
  this.maxSweepableSources = maxSweepableSources;
67
67
  this.resolved = resolveRebuildOptions(searchType, rebuildOptions);
68
- this.collectionName = this.resolved.name;
68
+ this.collectionName = this.resolved.definitionOptions.name;
69
69
  }
70
70
  async openRun(context) {
71
- const { name, batchSize, lockTtlMs, definitionOptions } = this.resolved;
71
+ const { batchSize, lockTtlMs, definitionOptions } = this.resolved;
72
+ const name = this.collectionName;
72
73
  return openLockedRun(this.client, name, lockTtlMs, async () => {
73
74
  // Create the collection on demand: SearchType schema + the bookkeeping
74
75
  // fields, `source` faceted so the membership sweep can enumerate the
@@ -14,17 +14,19 @@ export interface RebuildOptions extends CollectionDefinitionOptions {
14
14
  /** The shared options resolved to concrete values plus the residual
15
15
  * collection-definition options a writer passes to {@link buildCollectionDefinition}. */
16
16
  export interface ResolvedRebuildOptions {
17
- readonly name: string;
18
17
  readonly batchSize: number;
19
18
  readonly lockTtlMs: number;
20
- readonly definitionOptions: CollectionDefinitionOptions;
19
+ /** The collection-definition options with the `name` resolved – the one place
20
+ * the resolved name lives, so the collection a writer talks to and the
21
+ * definition it creates cannot say different things. */
22
+ readonly definitionOptions: CollectionDefinitionOptions & {
23
+ readonly name: string;
24
+ };
21
25
  }
22
26
  /**
23
27
  * Apply the shared defaults, once, so neither writer restates them – including
24
28
  * the collection name, derived from the type ({@link deriveCollectionName})
25
- * when the deployment supplies none. The resolved name is put back into
26
- * `definitionOptions`, so the collection a writer talks to and the definition
27
- * it creates are the same one name, resolved once.
29
+ * when the deployment supplies none.
28
30
  *
29
31
  * Writers resolve at construction rather than per run, so an underivable name
30
32
  * throws when the writer is built, not on the first rebuild.
@@ -1 +1 @@
1
- {"version":3,"file":"rebuild-support.d.ts","sourceRoot":"","sources":["../src/rebuild-support.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAK9E;;;GAGG;AACH,MAAM,WAAW,cAAe,SAAQ,2BAA2B;IACjE,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;0FAC0F;AAC1F,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,iBAAiB,EAAE,2BAA2B,CAAC;CACzD;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,cAAc,GACtB,sBAAsB,CAaxB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,IAAI,CAWN;AAED,4EAA4E;AAC5E,wBAAuB,cAAc,CAAC,SAAS,EAC7C,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC,EACnC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACtC,aAAa,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAInD;AAED,mEAAmE;AACnE,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAKf"}
1
+ {"version":3,"file":"rebuild-support.d.ts","sourceRoot":"","sources":["../src/rebuild-support.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAK9E;;;GAGG;AACH,MAAM,WAAW,cAAe,SAAQ,2BAA2B;IACjE,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;0FAC0F;AAC1F,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;6DAEyD;IACzD,QAAQ,CAAC,iBAAiB,EAAE,2BAA2B,GAAG;QACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,cAAc,GACtB,sBAAsB,CAcxB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,IAAI,CAWN;AAED,4EAA4E;AAC5E,wBAAuB,cAAc,CAAC,SAAS,EAC7C,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC,EACnC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACtC,aAAa,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAInD;AAED,mEAAmE;AACnE,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAKf"}
@@ -4,21 +4,20 @@ import { DEFAULT_BATCH_SIZE } from './import.js';
4
4
  /**
5
5
  * Apply the shared defaults, once, so neither writer restates them – including
6
6
  * the collection name, derived from the type ({@link deriveCollectionName})
7
- * when the deployment supplies none. The resolved name is put back into
8
- * `definitionOptions`, so the collection a writer talks to and the definition
9
- * it creates are the same one name, resolved once.
7
+ * when the deployment supplies none.
10
8
  *
11
9
  * Writers resolve at construction rather than per run, so an underivable name
12
10
  * throws when the writer is built, not on the first rebuild.
13
11
  */
14
12
  export function resolveRebuildOptions(searchType, options) {
15
13
  const { batchSize = DEFAULT_BATCH_SIZE, lockTtlMs = DEFAULT_LOCK_TTL_MS, ...definitionOptions } = options;
16
- const name = definitionOptions.name ?? deriveCollectionName(searchType);
17
14
  return {
18
- name,
19
15
  batchSize,
20
16
  lockTtlMs,
21
- definitionOptions: { ...definitionOptions, name },
17
+ definitionOptions: {
18
+ ...definitionOptions,
19
+ name: definitionOptions.name ?? deriveCollectionName(searchType),
20
+ },
22
21
  };
23
22
  }
24
23
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lde/search-typesense",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "Typesense implementation of the @lde/search SearchEngine port: collection-schema builder, query compiler, label-resolving result reconstruction, and blue/green index lifecycle. Engine-specific (Typesense) but domain-agnostic.",
5
5
  "repository": {
6
6
  "url": "git+https://github.com/ldelements/lde.git",
@@ -25,7 +25,7 @@
25
25
  "!**/*.tsbuildinfo"
26
26
  ],
27
27
  "dependencies": {
28
- "@lde/search": "^0.7.1",
28
+ "@lde/search": "^0.8.0",
29
29
  "@lde/text-normalization": "^0.1.1",
30
30
  "tslib": "^2.3.0",
31
31
  "typesense": "^3.0.6"