wontopos 2.2.28 → 2.2.30

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
@@ -162,20 +162,28 @@ const mem = new Client({ apiKey: "...", baseUrl: "https://wos.your-host.com" });
162
162
 
163
163
  ## Changelog
164
164
 
165
- - **2.2.10** — `Memory` fix: the relevance field is `similarity` (not `score`,
166
- which was never in the response); added typed `importance`, `category`,
167
- `is_superseded`, `superseded_by`, `created_at`, `event_date`.
168
- - **2.2.9** — typed responses for every method (index-signature friendly) +
169
- typed `SearchOptions`; security round 2: 64MB response cap, key/model-name
170
- hygiene, `Client.fromEnv()`.
171
- - **2.2.8** — reliability + hardening: automatic retries (429/502/503 + connection
172
- errors, backoff + jitter, honors `Retry-After`), redirects refused, key masked in
173
- `toJSON`/inspect, `WosError.requestId`, guard against `delete()` without
174
- `memoryId`, plain-HTTP warning, `User-Agent`.
175
- - **2.2.7** — speakers: `addSpeaker` / `listSpeakers` / `removeSpeaker`.
176
- - **2.2.6** — docs: `userId` = store, clarified everywhere.
177
- - **2.2.5** — docs: speakers + recall caching sections.
178
- - **2.2.4** — Python/TypeScript/Rust converge on one version; all three now
179
- release in lockstep (same version, same surface). Patch releases are additive.
165
+ The three clients release in lockstep — same version, same surface, same day.
166
+ Patch releases are additive: nothing is removed or reordered within a minor line.
167
+
168
+ - **2.2.30** — documentation only: this changelog, which had not been updated
169
+ in the shipped package since 2.2.10.
170
+ - **2.2.29** — a store id that was PASSED but unusable no longer becomes the
171
+ default store. 2.2.28 caught a blank string; the value a failed tenant lookup
172
+ actually produces in JavaScript is `null` — and `String(null)` is the truthy
173
+ `"null"`, so it walked past the check and `null || default` sent the write to
174
+ the client's default store. `0` did the same. Anything but a non-blank string
175
+ now throws, on `deleteStore` / `deleteAll` too. Omitting the argument still
176
+ means "use the default". Also: `deleteStore` validates before it warns, so a
177
+ non-string no longer surfaces as a `TypeError` from inside the SDK.
178
+ - **2.2.28** — audit: the API key no longer survives an object spread (`private`
179
+ is erased at runtime, so `{...client}` copied it), a whitespace `memoryId` can
180
+ no longer read as a whole-store delete, and a blank store id throws instead of
181
+ silently using the default.
182
+ - **2.2.11–2.2.27** — additive fixes and hardening across all three clients.
183
+ - **2.2.10** — `Memory` fix: the relevance field is `similarity` (not `score`);
184
+ added typed `importance`, `category`, `is_superseded`, `superseded_by`,
185
+ `created_at`, `event_date`.
186
+ - **2.2.4–2.2.9** — one version across Python, TypeScript and Rust, released in
187
+ lockstep; retries, redirect refusal, response cap, key masking, speakers.
180
188
 
181
189
  License: MIT.
package/dist/wontopos.js CHANGED
@@ -37,7 +37,7 @@
37
37
  * runtime's (never disabled by this SDK; Node 18+ floors TLS at 1.2). Prefer
38
38
  * `Client.fromEnv()` over keys in source code.
39
39
  */
40
- const VERSION = "2.2.28";
40
+ const VERSION = "2.2.30";
41
41
  /** Runtime info helps support debug a report ("node 18 on Windows...") —
42
42
  * platform only, never anything identifying. Browsers have no `process` (and
43
43
  * silently drop the UA header anyway). */
@@ -448,9 +448,18 @@ export class Client {
448
448
  // tenant id and got nothing. Falling back there writes one customer's memories into
449
449
  // whatever store this client defaults to, silently. Omission is a choice; a blank
450
450
  // string is a bug, and it should say so where it happened.
451
- if (userId !== undefined && !String(userId).trim()) {
452
- throw new Error("userId was passed but is blank. Omit it to use the client's default store, or pass a real store id — " +
453
- "a blank id would silently write into the default store.");
451
+ //
452
+ // The check is `typeof !== "string"`, not `!String(userId).trim()`. The old form
453
+ // only caught a blank STRING, and the value a failed lookup actually produces in
454
+ // JavaScript is `null` — `String(null)` is the truthy "null", so it sailed through
455
+ // the guard and then `null || default` sent the write to the client's default
456
+ // store. `0` (an integer primary key) did the same. Both are the exact outcome the
457
+ // guard was written to stop, and both were still silent.
458
+ //
459
+ // `undefined` alone means "omitted", because that is what an absent argument is.
460
+ if (userId !== undefined && (typeof userId !== "string" || !userId.trim())) {
461
+ throw new Error(`userId must be a non-blank string; got ${JSON.stringify(userId)}. Omit it to use the client's ` +
462
+ "default store, or pass a real store id — anything else would silently write into the default store.");
454
463
  }
455
464
  const id = userId || this.defaultUser;
456
465
  warnIfStoreIdCollapses(id);
@@ -682,9 +691,12 @@ export class Client {
682
691
  }
683
692
  /** Delete a store and ALL its memories. Returns `{ user_id, status }`. */
684
693
  deleteStore(userId) {
694
+ // Validate BEFORE warning. The warning helper lowercases the id, so a non-string
695
+ // used to die there as "id.toLowerCase is not a function" — the caller got a
696
+ // TypeError from our internals instead of being told what was wrong with the id.
697
+ if (typeof userId !== "string" || !userId.trim())
698
+ throw new Error("userId is required (a non-blank string) — deleteStore never falls back to the default store.");
685
699
  warnIfStoreIdCollapses(userId); // destructive: the collision warning belongs here too
686
- if (!userId || !userId.trim())
687
- throw new Error("userId is required (non-blank) — deleteStore never falls back to the default store.");
688
700
  return this.request("DELETE", "/api/v1/memory/collection", { user_id: userId });
689
701
  }
690
702
  // ----- speakers (who said it) -----
@@ -722,8 +734,8 @@ export class Client {
722
734
  /** Delete ALL memories for a store (GDPR erase). `userId` is required on purpose -
723
735
  * this is destructive, so it never falls back to the default store. */
724
736
  deleteAll(userId) {
725
- if (!userId || !userId.trim())
726
- throw new Error("userId is required (non-blank) for deleteAll — a blank/whitespace id would wipe the default store.");
737
+ if (typeof userId !== "string" || !userId.trim())
738
+ throw new Error("userId is required (a non-blank string) for deleteAll — anything else would wipe the default store.");
727
739
  // These two take the store id directly instead of going through uid(), so the
728
740
  // collision warning — the one that says `Alice.Smith` and `alice_smith` are ONE
729
741
  // store — never fired on the two calls that DESTROY data. Erasing the wrong
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wontopos",
3
- "version": "2.2.28",
3
+ "version": "2.2.30",
4
4
  "description": "Wontopos — long-term memory for AI agents. Pure semantic retrieval, identical recall in every language, ~100× lower LLM bill.",
5
5
  "keywords": [
6
6
  "memory",