thaizip 0.7.4 → 0.7.6

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
@@ -20,7 +20,7 @@ npm install thaizip
20
20
  |---|---|
21
21
  | `thaizip` | core functions + types (no React code, 4.4 KB gzip) |
22
22
  | `thaizip/react` | `useThaiAddressAutocomplete` (ships `"use client"`) |
23
- | `thaizip/data` | `loadDefaultIndex`, `clearDefaultIndex` (132 KB gzip) |
23
+ | `thaizip/data` | `loadDefaultIndex`, `clearDefaultIndex`, `getDefaultIndexIfLoaded` (2.3 KB gzip, plus a 114 KB gzip data chunk fetched lazily on the first `loadDefaultIndex()` call) |
24
24
 
25
25
  ## Quick start
26
26
 
@@ -28,7 +28,7 @@ npm install thaizip
28
28
  import { loadDefaultIndex } from 'thaizip/data'
29
29
  import { searchThaiAddress, formatThaiAddressSuggestion, resolveThaiAddress } from 'thaizip'
30
30
 
31
- const index = await loadDefaultIndex() // ~40ms of synchronous work, cached after
31
+ const index = await loadDefaultIndex() // ~50ms on the measured device, cached after
32
32
 
33
33
  searchThaiAddress(index, 'ลาดพร้าว')
34
34
  searchThaiAddress(index, 'bang rak')
@@ -39,7 +39,8 @@ formatThaiAddressSuggestion(record, { locale: 'en' })
39
39
  resolveThaiAddress(record) // for saving
40
40
  ```
41
41
 
42
- Call `loadDefaultIndex()` at mount or route load — deferring it to the user's first keystroke costs ~2 dropped frames.
42
+ Call `loadDefaultIndex()` at mount or route load — deferring it to the user's first keystroke can block the UI briefly.
43
+ The cached default index is shared. Ordinary writes to its records and lookup structures throw; build a separate index with `buildThaiAddressIndex` if you need to edit address data. This is protection against accidental changes, not a security boundary against hostile code already running in the same JavaScript realm.
43
44
 
44
45
  ## Search
45
46
 
@@ -135,9 +136,9 @@ const index = buildThaiAddressIndex({ provinces, amphures, tambons }, {
135
136
  })
136
137
  ```
137
138
 
138
- Input is validated by default, so a stray non-string field fails with `[thaizip] tambon 100404: expected string for name_th, got number` instead of crashing inside the normalizer. It costs nothing measurable on a full-size dataset. `validateRawData(data)` runs the same checks standalone.
139
+ Input is validated by default, so a stray non-string field fails with `[thaizip] tambon 100404: expected string for name_th, got number` instead of crashing inside the normalizer. `validateRawData(data)` runs the same checks standalone.
139
140
 
140
- `RawData` is meant to be trusted, application-controlled input — your own dataset, not arbitrary end-user uploads. `buildThaiAddressIndex` has no built-in cap on row count or field length; build cost scales linearly with total input size, but an unbounded or maliciously oversized payload (e.g. an admin importer fed directly to this function) can still cost real time and memory with nothing to stop it. If you ever build an index from untrusted input, enforce your own size limits (row count, field length) before calling `buildThaiAddressIndex`.
141
+ Validation also rejects more than 50,000 total rows, names longer than 256 UTF-16 code units, ZIP values longer than 32 code units, or an estimated trigram posting cost above 1,000,000. The estimate counts each province/district's unique trigrams once for every active child subdistrict, so it catches parent-name fan-out. These bounds are suitable for the bundled-size dataset, not a guarantee that arbitrary uploads are safe to process. For larger trusted datasets, pass `{ validate: false }` and apply your own resource limits before building.
141
142
 
142
143
  Types: `RawData`, `RawProvince`, `RawAmphure`, `RawTambon`.
143
144