@aiquants/contact-map 0.4.0 → 0.6.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 +86 -25
- package/dist/client.d.mts +55 -37
- package/dist/client.d.ts +55 -37
- package/dist/client.js +2 -2
- package/dist/client.mjs +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/server.d.mts +6 -6
- package/dist/server.d.ts +6 -6
- package/dist/server.js +4 -4
- package/dist/server.mjs +4 -4
- package/dist/styles/contact-map.standalone.css +1 -1
- package/dist/{wire-CFgYO13H.d.mts → wire-hAxBVVH6.d.mts} +2 -1
- package/dist/{wire-CFgYO13H.d.ts → wire-hAxBVVH6.d.ts} +2 -1
- package/dist/worker/treeWorker.mjs +1 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -84,16 +84,19 @@ Peer dependencies:
|
|
|
84
84
|
```typescript
|
|
85
85
|
// app/routes/api.contact_map.stream.ts
|
|
86
86
|
import { createContactMapStreamHandler } from "@aiquants/contact-map/server"
|
|
87
|
-
import { db } from "~/services/drizzle-db/client.server.ts"
|
|
87
|
+
import { db, ensureDbConnection } from "~/services/drizzle-db/client.server.ts"
|
|
88
88
|
import { contactTable } from "~/services/drizzle-db/schema/contacts.table.ts"
|
|
89
89
|
import { authenticateInLoader } from "~/services/auth.server.ts"
|
|
90
90
|
|
|
91
91
|
const handler = createContactMapStreamHandler({
|
|
92
92
|
db,
|
|
93
93
|
table: contactTable,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
// Awaited before every query. A pool that is always connected passes `async () => {}`.
|
|
95
|
+
ensureConnection: ensureDbConnection,
|
|
96
|
+
// Called with { failureRedirect: null }; return the session cookie the call refreshed, if any.
|
|
97
|
+
authenticate: async (request, options) => {
|
|
98
|
+
const { user, cookie } = await authenticateInLoader(request, options)
|
|
99
|
+
return { user: user ?? null, cookie }
|
|
97
100
|
},
|
|
98
101
|
})
|
|
99
102
|
|
|
@@ -102,6 +105,13 @@ export async function loader({ request }: { request: Request }) {
|
|
|
102
105
|
}
|
|
103
106
|
```
|
|
104
107
|
|
|
108
|
+
`db`, `table`, `ensureConnection` and `authenticate` are required, and `createContactMapStreamHandler` / `createContactMapServer` throw a `TypeError` when `db` or `table` is missing, `ensureConnection` or `authenticate` is not a function, or `firstBatchSize` / `nextBatchSize` is given but is not a number, and a `RangeError` when `firstBatchSize` or `nextBatchSize` is a number but not an integer from 1 to `Number.MAX_SAFE_INTEGER`.
|
|
109
|
+
Each message names the setting and ends with the value given (`[contact-map] server config authenticate must be the function that returns the request's user (…); got undefined`). A stream open to everyone says so with an `authenticate` that returns a user; leaving the setting out never serves the contacts unauthenticated.
|
|
110
|
+
The handler calls `authenticate(request, { failureRedirect: null })` after checking the resume cursor (a malformed cursor gets 400 without authenticating), answers 401 when no user comes back, and sends a returned `cookie` as `Set-Cookie` on the 401 and on the stream response alike, so a session the call refreshed reaches the browser. The stream is sent with `Cache-Control: no-store, no-transform`.
|
|
111
|
+
|
|
112
|
+
`db`・`table`・`ensureConnection`・`authenticate` は必須で、`db` か `table` が無い、`ensureConnection` か `authenticate` が関数でない、または `firstBatchSize` / `nextBatchSize` が数値でなければ `createContactMapStreamHandler` / `createContactMapServer` は `TypeError` を、`firstBatchSize` か `nextBatchSize` が 1 から `Number.MAX_SAFE_INTEGER` までの整数でない数値なら `RangeError` を投げる。
|
|
113
|
+
どの文言も設定を名指し、与えた値で終わる (`[contact-map] server config authenticate must be the function that returns the request's user (…); got undefined`)。誰にでも開くストリームは user を返す `authenticate` で明示し、設定を書き漏らしても認証なしで連絡先を配ることはない。ハンドラーは再開カーソルを検査してから (不正な形は認証せずに 400) `authenticate(request, { failureRedirect: null })` を呼び、user が無ければ 401 を返し、返された `cookie` は 401 にもストリームの応答にも `Set-Cookie` で載せる (呼び出しが更新したセッションをブラウザへ届ける)。ストリームは `Cache-Control: no-store, no-transform` で送る。
|
|
114
|
+
|
|
105
115
|
### 2. Client Page Setup / クライアント側ページの設定
|
|
106
116
|
|
|
107
117
|
```tsx
|
|
@@ -123,6 +133,44 @@ export default function ContactMapRoute() {
|
|
|
123
133
|
}
|
|
124
134
|
```
|
|
125
135
|
|
|
136
|
+
### 3. Stream Endpoint / ストリームのエンドポイント
|
|
137
|
+
|
|
138
|
+
The stream endpoint is a setting like `locale` and `workerUrls`: set `streamEndpoint` on `ContactMapAppView` or on a surrounding `ContactMapConfigProvider`, and when both set it the view's prop wins. It has no default; the stream reads the one value that results.
|
|
139
|
+
|
|
140
|
+
- It must be a same-origin absolute path, such as `/api/contact_map/stream` (a query string is allowed). The following throw a `RangeError`: an empty or blank value, a relative path, an absolute or protocol-relative URL (`https://…`, `//host`, `/\host`), whitespace, a control character, or `#`. A non-string throws a `TypeError`, and so does a stream that starts with no endpoint configured.
|
|
141
|
+
- One module-lifetime client streams the endpoint for as long as the app stays loaded. Every contact-map view in the browser tab must use the same endpoint, on every route; a second, different endpoint throws an `Error` that names both, and switching endpoints needs a full page reload.
|
|
142
|
+
- The load is not tied to the page. Leaving the route does not abort it: it runs to completion, and the records stay in memory, so returning to the page shows them at once instead of loading again. Only `resetContactMapStreamClientForTesting()` (tests) disposes the client; after changing `streamEndpoint` during development, reload the page.
|
|
143
|
+
- `ContactMapSearchPage` connects to the stream only when it is not given `streamState`. To render records you load yourself, pass a `streamState` whose `contactMapRecordMap` is one `Map` you keep while it grows; the tree rebuilds its nodes from that map.
|
|
144
|
+
|
|
145
|
+
ストリームのエンドポイントは `locale` や `workerUrls` と同じ扱いの設定で、`ContactMapAppView` か外側の `ContactMapConfigProvider` の `streamEndpoint` に設定する。両方にあれば、ビューの prop が優先する。既定値は無く、ストリームはこうして決まった 1 つの値を読む。
|
|
146
|
+
|
|
147
|
+
- 同一オリジンの絶対パスでなければならない (例 `/api/contact_map/stream`。クエリ文字列は可)。次の場合は `RangeError`: 空や空白だけの値、相対パス、絶対 URL やプロトコル相対の URL (`https://…`、`//host`、`/\host`)、空白・制御文字・`#` を含む値。文字列でない値は `TypeError`。エンドポイントを設定しないままストリームを始めた場合も `TypeError`。
|
|
148
|
+
- 読み込んだアプリの寿命の間、モジュール寿命のクライアント 1 つがエンドポイントを読む。ブラウザのタブの contact-map のビューは、どのルートでもすべて同じエンドポイントを使う。2 つ目の別のエンドポイントは両方の値を示す `Error` になり、エンドポイントを替えるにはページの再読み込みが要る。
|
|
149
|
+
- 読み込みはページに縛られない。ルートを離れても中断せず、完了まで続き、レコードはメモリに残る。ページへ戻ると、読み込み直さずにその場で表示される。クライアントを破棄するのは `resetContactMapStreamClientForTesting()` (テスト用) だけで、開発中に `streamEndpoint` を変えたらページを再読込する。
|
|
150
|
+
- `ContactMapSearchPage` は、`streamState` を渡されないときだけストリームへ接続する。自分で読み込んだレコードを描画するには、`contactMapRecordMap` に、増える間も同じ `Map` を保った `streamState` を渡す (ツリーはこのマップからノードを復元する)。
|
|
151
|
+
|
|
152
|
+
The tree is built in a Web Worker by one module-resident session, so returning to the tree shows its last snapshot at once. `treeWorkerFactory` (on the config) replaces the Worker construction for bundlers that need their own: it must return a new Worker on every call, the hook owns that Worker and terminates it on unmount, and each hook instance gets its own session, so no snapshot survives a remount. A view hidden in `<Activity>` (or StrictMode's replayed effects) only stops the Worker and keeps the tree on screen; showing it again rebuilds on a new Worker behind that tree.
|
|
153
|
+
The function may be inline (a new identity on each render): the session keeps its Worker and calls the latest factory when it needs a new one, and it does not read `workerUrls.treeWorker`. Leave it out (and point `workerUrls.treeWorker` at the Worker file if needed) to keep the module-resident session.
|
|
154
|
+
The module-resident session reads `workerUrls.treeWorker` once per browser tab: give every contact-map view the same value on every route (or none, for the bundled Worker file). A view that asks for another URL throws an `Error` naming both, a value that is not a string (a `URL` object, `null`) throws a `TypeError`, and an empty or blank URL throws a `RangeError`; after changing the URL, reload the page.
|
|
155
|
+
`ContactMapConfigProvider` checks the value's shape in every render, a server render included, like `locale` and `labels`, even while `treeWorkerFactory` is set, so a view that has not opened its tree yet still refuses it. The session itself, and with it the one-URL rule, exists only in the browser, so the rule holds per browser tab and not across a server's requests.
|
|
156
|
+
`workerUrls` on `ContactMapAppView` is layered over the provider's key by key: a key the view leaves out or sets to `undefined` keeps the provider's value (`layerContactMapWorkerUrls`). `ContactMapSearchPage` layers only `indexWorker` and `levenshteinWorker` the same way and refuses a `treeWorker`, because its tree reads the provider's; set that on the provider or the view. Errors name the surface that holds the bad value (`workerUrls`, `ContactMapAppView workerUrls`, `ContactMapSearchPage workerUrls`).
|
|
157
|
+
Every surface reads each own property of its `workerUrls` once per render and hands down only the checked copy: `useContactMapConfig().workerUrls` is a frozen object holding all three keys (`undefined` where none is set), so a getter that returns another value after the check, or a key inherited from `Object.prototype`, never reaches a Worker.
|
|
158
|
+
|
|
159
|
+
The same holds for every setting: `useContactMapConfig()` is a frozen object without a prototype that owns every setting (`undefined` where left out), inside a provider and outside one, so no setting is ever inherited, from a polluted `Object.prototype` either.
|
|
160
|
+
The provider reads only the documented settings its `config` owns, refuses a `config` that is not a plain object (`TypeError`), and keeps handing down the same object while the settings' values stay the same, so a host may rebuild `config` on every render.
|
|
161
|
+
The settings a view layers in (`streamEndpoint`, `workerUrls`, `locale` and `labels` of `ContactMapAppView`; `workerUrls` of `ContactMapSearchPage`) are read only when its props own them.
|
|
162
|
+
A Worker that cannot be created or fails is recreated twice, 250 ms and then 500 ms later (records that arrive during the wait are sent to the new Worker, which is not created any earlier). Each failure is logged as a `[TreeWorker]` warning with the error, and the third failure in a row as an error naming the setting the Workers came from and what brings the tree back: the page reloading for the module-resident session (`workerUrls.treeWorker`), the view remounting for a factory session (`treeWorkerFactory`). Until then the tree stops updating. A Worker that finishes a build resets the count.
|
|
163
|
+
|
|
164
|
+
ツリーは Web Worker の中で、モジュール常駐の 1 つのセッションが組み立てるので、ツリーへ戻ると直前のスナップショットがすぐに出る。設定の `treeWorkerFactory` は、Worker の作り方が決まっているバンドラー向けに Worker の生成を差し替える。呼ぶたびに新しい Worker を返すこと (フックがその Worker を所有し、外すときに止める)。フックのインスタンスごとにセッションを持つので、再マウントでスナップショットは残らない。`<Activity>` で隠したビュー (と StrictMode が繰り返す副作用) は Worker を止めるだけでツリーを画面に残し、再び表示すると、そのツリーの裏で新しい Worker に作り直す。描画のたびに別の関数になってよく (インラインの関数でよい)、セッションは Worker を持ち続けて、新しく作るときに最後の factory を呼ぶ (`workerUrls.treeWorker` は読まない)。モジュール常駐のセッションを使うなら指定せず、必要なら `workerUrls.treeWorker` で Worker のファイルを指す。
|
|
165
|
+
モジュール常駐のセッションは `workerUrls.treeWorker` をブラウザのタブにつき 1 回だけ読む。全ルートの全ビューに同じ値を渡す (同梱の Worker ファイルなら全て指定しない)。別の URL を求めたビューは両方の値を挙げた `Error` を、文字列でない値 (`URL` オブジェクト、`null`) は `TypeError` を、空や空白だけの URL は `RangeError` を投げる。URL を変えたらページを再読み込みする。値の形は `ContactMapConfigProvider` が `locale` / `labels` と同じくサーバーでの描画を含むどの描画でも検査し、`treeWorkerFactory` がある間も検査するので、まだツリーを開いていないビューでも拒む。セッション自体とその 1 つの URL の規則はブラウザにだけあるので、規則はサーバーの要求をまたがず、ブラウザのタブごとに効く。`ContactMapAppView` の `workerUrls` は外側のプロバイダーの値へキーごとに重ね、ビューが省略か `undefined` にしたキーはプロバイダーの値を保つ (`layerContactMapWorkerUrls`)。
|
|
166
|
+
`ContactMapSearchPage` は `indexWorker` と `levenshteinWorker` だけを同じく重ね、`treeWorker` は拒否する (ツリーはプロバイダーの値を読むので、プロバイダーかビューに設定する)。例外は誤った値を持つ設定 (`workerUrls`・`ContactMapAppView workerUrls`・`ContactMapSearchPage workerUrls`) を名指す。
|
|
167
|
+
どの面も `workerUrls` の各プロパティを描画ごとに 1 回だけ読み、検査した複製だけを下へ配る。`useContactMapConfig().workerUrls` は 3 つのキーを全て持つ凍結したオブジェクト (どこにも無いキーは `undefined`) なので、検査の後で別の値を返す getter や `Object.prototype` から継承したキーが Worker に届くことは無い。
|
|
168
|
+
|
|
169
|
+
これは全ての設定に当てはまる。`useContactMapConfig()` は、プロバイダーの中でも外でも、全ての設定を自身で持つ (省略したものは `undefined`) プロトタイプの無い凍結したオブジェクトなので、汚染された `Object.prototype` からも設定を継承しない。
|
|
170
|
+
プロバイダーは `config` が自身で持つ文書化された設定だけを読み、素のオブジェクトでない `config` は `TypeError` で拒み、設定の値が同じ間は同じオブジェクトを配り続ける (ホストは描画のたびに `config` を作り直してよい)。
|
|
171
|
+
ビューが重ねる設定 (`ContactMapAppView` の `streamEndpoint`・`workerUrls`・`locale`・`labels`、`ContactMapSearchPage` の `workerUrls`) も、props が自身で持つときだけ読む。
|
|
172
|
+
Worker を作れないか Worker が落ちると、250 ms 後と 500 ms 後の 2 回作り直す (待つ間に届いたレコードは新しい Worker へ送り、Worker を前倒しでは作らない)。障害ごとに `[TreeWorker]` の警告をエラーと共にログへ出し、続けて 3 回目の障害は、Worker の出どころの設定とツリーを戻すものを挙げたエラーとして出す。モジュール常駐のセッション (`workerUrls.treeWorker`) はページの再読み込み、factory のセッション (`treeWorkerFactory`) はビューの再マウントで戻り、それまでツリーの更新は止まる。Worker が構築を終えると回数は 0 に戻る。
|
|
173
|
+
|
|
126
174
|
## Search Normalization / 検索語の正規化
|
|
127
175
|
|
|
128
176
|
The search page normalizes the typed query with `normalizeSearchInput` (exported from `@aiquants/contact-map`) into the fuzzy search term. The contact fields (name, company, department, title, email, phone numbers) are matched as stored. The query is therefore only brought into a form those fields can hold:
|
|
@@ -130,7 +178,7 @@ The search page normalizes the typed query with `normalizeSearchInput` (exported
|
|
|
130
178
|
- Invisible characters (U+200B, U+FEFF) are removed, and surrounding whitespace (U+3000 and U+00A0 included) is trimmed.
|
|
131
179
|
- Width, kana (hiragana → katakana) and case are unified with select-box's `normalizeText` (`ABC商事` → `abc商事`, `さとう` → `サトウ`). Kana stays as written (`つづき` → `ツヅキ`).
|
|
132
180
|
- The query is replaced by its katakana reading only when the whole query is romaji that reads completely. It must hold only Latin letters and whitespace, and select-box's `romajiToKatakana` must leave no letter untransliterated (`tanaka` → `タナカ`, `yamada taro` → `ヤマダ タロ`, `tsuduki` → `ツヅキ`).
|
|
133
|
-
- Mixed text, digits and symbols, and words that do not read completely keep their width / kana / case form (`user@
|
|
181
|
+
- Mixed text, digits and symbols, and words that do not read completely keep their width / kana / case form (`user@example.com`, `営業部 tanaka`, `tanaka1`, `ke-su`, `sony`).
|
|
134
182
|
|
|
135
183
|
The result highlight and the exact-match ranking are one derivation from the query as typed. `createSearchQueryPattern(query)` finds the spellings that `getSearchQuerySpellings(query)` lists (select-box's `getNormalizedVariants` of each word of the query and of its normalized form), longest first and case-insensitively.
|
|
136
184
|
`HighlightedText` marks its matches, and `createExactMatchRanker(query, fields)` moves the results with a match in one of the fields to the top, keeping the fuzzy order within each group. A field is therefore highlighted exactly when it ranks its record as an exact match. A kana reading is marked only when the whole query reads as romaji.
|
|
@@ -142,7 +190,7 @@ The typed query is used because normalization can drop a spelling it holds. sele
|
|
|
142
190
|
- 不可視文字 (U+200B・U+FEFF) を除き、端の空白 (U+3000・U+00A0 を含む) を除く。
|
|
143
191
|
- select-box の `normalizeText` で全角/半角・かな (ひらがな → カタカナ)・大文字小文字を統一する (`ABC商事` → `abc商事`、`さとう` → `サトウ`)。かなは書いたまま (`つづき` → `ツヅキ`)。
|
|
144
192
|
- 検索語全体が完全に読めるローマ字のときだけ、カタカナの読みに置き換える。ラテン文字と空白だけで、select-box の `romajiToKatakana` が音訳しない文字を残さないことが条件 (`tanaka` → `タナカ`、`yamada taro` → `ヤマダ タロ`、`tsuduki` → `ツヅキ`)。
|
|
145
|
-
- 混在テキスト・数字や記号・完全には読めない語は、全角/半角・かな・大文字小文字の形のまま (`user@
|
|
193
|
+
- 混在テキスト・数字や記号・完全には読めない語は、全角/半角・かな・大文字小文字の形のまま (`user@example.com`、`営業部 tanaka`、`tanaka1`、`ke-su`、`sony`)。
|
|
146
194
|
|
|
147
195
|
検索結果のハイライトと完全一致による並べ替えは、入力されたままの検索語からの 1 つの導出。`createSearchQueryPattern(query)` は `getSearchQuerySpellings(query)` が並べる表記 (検索語の各語とその正規化形の各語に対する select-box の `getNormalizedVariants`) を、最長のものから大文字小文字を区別せずに探す。`HighlightedText` はその一致に印を付け、`createExactMatchRanker(query, fields)` はいずれかのフィールドに一致を持つ結果を先頭へ移す (各グループ内ではあいまい検索の順序を保つ)。そのため、フィールドにハイライトが付くのは、そのフィールドがレコードを完全一致として並べさせるときちょうど。かなの読みに印が付くのは検索語全体がローマ字として読めるときだけ。
|
|
148
196
|
|
|
@@ -160,11 +208,17 @@ Every string the client components render on their own (tabs, buttons, headings,
|
|
|
160
208
|
|
|
161
209
|
| Surface | Prop | Type | Notes |
|
|
162
210
|
| --- | --- | --- | --- |
|
|
163
|
-
| `ContactMapConfigProvider` | `config
|
|
164
|
-
| `ContactMapConfigProvider` | `config.
|
|
165
|
-
| `
|
|
166
|
-
| `
|
|
211
|
+
| `ContactMapConfigProvider` | `config` | `ContactMapConfig` | A plain object (`TypeError` otherwise: `[contact-map] config must be a plain object; got <value>`). Only the documented settings it owns are read, once per render; the views read the frozen copy without a prototype (`useContactMapConfig()`), the same shape outside any provider, kept while the settings' values stay the same. |
|
|
212
|
+
| `ContactMapConfigProvider` | `config.streamEndpoint` | `string` | Same-origin absolute path of the NDJSON stream. No default; it or the view's `streamEndpoint` must be set (see Stream Endpoint). |
|
|
213
|
+
| `ContactMapConfigProvider` | `config.locale` | `ContactMapLocale` (`"en" \| "ja"`) | Omitted ⇒ `"en"`. At mount a non-string throws a `TypeError` and any other string a `RangeError`, both naming `locale`. |
|
|
214
|
+
| `ContactMapConfigProvider` | `config.labels` | `ContactMapLabelOverrides` | Partial overrides over `CONTACT_MAP_LABEL_CATALOGS[locale]`, validated at mount; errors name `labels`. |
|
|
215
|
+
| `ContactMapConfigProvider` | `config.workerUrls` | `ContactMapWorkerUrls` | A plain object of only `indexWorker`, `levenshteinWorker` and `treeWorker`, each left out or a string with non-whitespace; checked in every render, a server render included (`assertContactMapWorkerUrls`: `TypeError` / `RangeError`); the views read only the checked copy. One `treeWorker` per browser tab (see the tree paragraph above). |
|
|
216
|
+
| `ContactMapAppView` | `streamEndpoint` | `string` | When given it wins over the surrounding provider's `streamEndpoint`. |
|
|
217
|
+
| `ContactMapAppView` | `locale` | `ContactMapLocale` | When given it wins over the surrounding provider's `locale`; its errors name `ContactMapAppView locale`. |
|
|
218
|
+
| `ContactMapAppView` | `labels` | `ContactMapLabelOverrides` | When given the whole object replaces the surrounding provider's `labels` (no key-wise merge); its errors name `ContactMapAppView labels`. |
|
|
219
|
+
| `ContactMapAppView` | `workerUrls` | `ContactMapWorkerUrls` | Checked like `config.workerUrls`, then layered over the surrounding provider's key by key: a key left out or `undefined` keeps the provider's value (`layerContactMapWorkerUrls`). |
|
|
167
220
|
| `ContactMapAppView` | `title` | `string` | Per-instance heading; omitted ⇒ the `appTitle` label. |
|
|
221
|
+
| `ContactMapSearchPage` | `workerUrls` | `{ indexWorker?, levenshteinWorker? }` | Layered over the provider's like the view's; a `treeWorker` with a value throws a `RangeError` that says to set it on the provider or the view (`treeWorker: undefined` counts as left out). |
|
|
168
222
|
| `SwipeOverlay` | `title` | `string` | Per-instance dialog name; omitted ⇒ the `overlayTitle` label. |
|
|
169
223
|
|
|
170
224
|
Components rendered outside any provider use the `en` catalog. `useContactMapLabels()` returns the resolved labels of the nearest provider, for host chrome that should speak the same language (for example the component a custom `renderHeader` renders).
|
|
@@ -174,28 +228,35 @@ Components rendered outside any provider use the `en` catalog. `useContactMapLab
|
|
|
174
228
|
import { ContactMapAppView } from "@aiquants/contact-map/client"
|
|
175
229
|
|
|
176
230
|
export default function ContactMapRoute() {
|
|
177
|
-
return <ContactMapAppView locale="ja" labels={{ appTitle: "連絡先マップ" }} />
|
|
231
|
+
return <ContactMapAppView streamEndpoint="/api/contact_map/stream" locale="ja" labels={{ appTitle: "連絡先マップ" }} />
|
|
178
232
|
}
|
|
179
233
|
```
|
|
180
234
|
|
|
181
235
|
### Resolver contract / 解決規則
|
|
182
236
|
|
|
183
|
-
`resolveContactMapLabels(locale, overrides)` is the single fold point (the provider calls it once per change):
|
|
184
|
-
`resolveContactMapLabels(locale, overrides)` が唯一の畳込み点 (
|
|
237
|
+
`resolveContactMapLabels(locale, overrides, surface?)` is the single fold point (the provider calls it once per change; `surface` names the two settings in its errors, `locale` / `labels` when left out):
|
|
238
|
+
`resolveContactMapLabels(locale, overrides, surface?)` が唯一の畳込み点 (プロバイダーは変化時にだけ呼ぶ。`surface` は例外が 2 つの設定を呼ぶ名前で、省略時は `locale` / `labels`):
|
|
185
239
|
|
|
186
240
|
- `overrides` omitted ⇒ the frozen catalog itself (same identity).
|
|
187
|
-
- `overrides` must be a plain object (prototype `Object.prototype` or `null`);
|
|
188
|
-
- An own key outside `CONTACT_MAP_LABEL_KEYS` throws a `RangeError` (`[contact-map] labels
|
|
189
|
-
- A string key must be a string with non-whitespace content; a function key (the keys shown with arguments in the table below) must be a function. An explicit `undefined` keeps the catalog value.
|
|
241
|
+
- `overrides` must be a plain object (prototype `Object.prototype` or `null`); anything else (`null`, a primitive, an array, a class instance, an object inheriting from another object) throws a `TypeError`. Only own properties are read, each exactly once, and the label bag is built from the values that were checked.
|
|
242
|
+
- An own key outside `CONTACT_MAP_LABEL_KEYS` throws a short `RangeError` that suggests the nearest key (`[contact-map] labels has a key that is not a label key (did you mean "searchTab"? CONTACT_MAP_LABEL_KEYS lists every key); got "serchTab"`).
|
|
243
|
+
- A string key must be a string (else a `TypeError`) with non-whitespace content (else a `RangeError`); a function key (the keys shown with arguments in the table below) must be a function (else a `TypeError`). An explicit `undefined` keeps the catalog value.
|
|
244
|
+
- Every error the package throws starts with `[contact-map]`, with one exception: a cancelled query (`countActiveContactsQuery`, `getContactsStreamChunkQuery`) rejects with the standard `DOMException` named `AbortError`, as `fetch` does, so tell a cancellation by `error.name === "AbortError"`.
|
|
245
|
+
- A setting check (`locale`, `labels`, `streamEndpoint`, `workerUrls`, the server config, row counts, tree names) throws a `TypeError` for a value of the wrong type or shape, a missing required setting included, and a `RangeError` for a value of the right type that is not allowed, a key the setting does not take included.
|
|
246
|
+
It names the setting as the surface calls it (`labels`, `ContactMapAppView labels`, `server config firstBatchSize`), and it ends with `; got <value>`: the rejected value, or the rejected key, written the same way everywhere (a quoted string, `undefined`, `null`, `-0`, `10n`, `Symbol(x)`, `[object URL]`).
|
|
247
|
+
- Two views of one browser tab that disagree on `streamEndpoint` or `workerUrls.treeWorker`, and a CommonJS build without `workerUrls.treeWorker`, throw a plain `Error` (no single value is wrong).
|
|
190
248
|
- A unit key (`recordUnit`, `companyUnit`, `resultUnit`, `timesUnit`, `itemsUnit`, `charactersUnit`) receives the number exactly as it is displayed (`"1"`, `"1,001"`, `"1.0"`), so the English singular / plural follows what the reader sees: only a displayed `"1"` is singular (`"1.0 items"`). `timesUnit` / `itemsUnit` / `charactersUnit` / `throughputUnit` are appended to the number without a separator and carry their own leading space.
|
|
191
|
-
- The 7 engine keys
|
|
249
|
+
- The 7 engine keys and the 2 row kind words are checked here under the same rule before they are handed to `@aiquants/virtualscroll` and `@aiquants/directory-tree`, so their errors follow the package's rule too.
|
|
192
250
|
- The result is frozen. The list VirtualScroll receives exactly the 7 engine keys and the DirectoryTree exactly its 9 keys, both kept value-stable, so an inline `labels` object recreated on every render does not rebuild the embedded scroll chrome.
|
|
193
251
|
- `overrides` 未指定なら凍結カタログそのもの (同一 identity) を返す。
|
|
194
|
-
- `overrides` は素の object (プロトタイプが `Object.prototype` か `null`)
|
|
195
|
-
- `CONTACT_MAP_LABEL_KEYS`
|
|
196
|
-
-
|
|
252
|
+
- `overrides` は素の object (プロトタイプが `Object.prototype` か `null`) に限り、それ以外 (`null`・プリミティブ・配列・クラスインスタンス・他 object 継承) は `TypeError`。読むのは自身のプロパティのみで、各プロパティをちょうど 1 回読み、ラベル集合は検査した値そのものから作る。
|
|
253
|
+
- `CONTACT_MAP_LABEL_KEYS` 外の自身のキーは、最も近いキーを示す短い `RangeError` (`[contact-map] labels has a key that is not a label key (did you mean "searchTab"? CONTACT_MAP_LABEL_KEYS lists every key); got "serchTab"`)。
|
|
254
|
+
- 文字列キーは文字列 (でなければ `TypeError`) で空白以外を含むこと (でなければ `RangeError`)、関数キー (下表で引数付きのキー) は関数であること (でなければ `TypeError`) が必須。明示 `undefined` はカタログ値のまま。
|
|
255
|
+
- パッケージが投げる例外は全て `[contact-map]` で始まる。例外は 1 つで、取り消した照会 (`countActiveContactsQuery`・`getContactsStreamChunkQuery`) は `fetch` と同じく名前が `AbortError` の標準の `DOMException` で拒否するので、取消は `error.name === "AbortError"` で見分ける。
|
|
256
|
+
- 設定の検査 (`locale`・`labels`・`streamEndpoint`・`workerUrls`・サーバーの設定・行数・代替名) は、型や形の誤り (必須の設定が無い場合を含む) を `TypeError`、型は合うが許されない値 (設定が受け取らないキーを含む) を `RangeError` にする。設定は面の呼び名で名指し (`labels`・`ContactMapAppView labels`・`server config firstBatchSize`)、末尾は `; got <値>` で、拒否した値か拒否したキーをどこでも同じ表記で書く (引用符付きの文字列・`undefined`・`null`・`-0`・`10n`・`Symbol(x)`・`[object URL]`)。
|
|
257
|
+
- ブラウザのタブの 2 つのビューが `streamEndpoint` か `workerUrls.treeWorker` で食い違う場合と、`workerUrls.treeWorker` の無い CommonJS のビルドは、どの値 1 つが誤りでもないので素の `Error`。
|
|
197
258
|
- 単位キー (`recordUnit`、`companyUnit`、`resultUnit`、`timesUnit`、`itemsUnit`、`charactersUnit`) は表示どおりの数値文字列 (`"1"`、`"1,001"`、`"1.0"`) を受け取るため、英語の単数 / 複数は読み手が見る値に従う (単数は表示 `"1"` のときだけで `"1.0 items"`)。`timesUnit` / `itemsUnit` / `charactersUnit` / `throughputUnit` は数値の直後に区切りなしで連結されるため、先頭の空白は単位側が持つ。
|
|
198
|
-
- エンジン 7
|
|
259
|
+
- エンジン 7 キーと行種別語 2 キーも、`@aiquants/virtualscroll` と `@aiquants/directory-tree` へ渡す前にここで同じ規則で検査するので、その例外もパッケージの規則に従う。
|
|
199
260
|
- 結果は凍結される。一覧の VirtualScroll にはエンジン 7 キーだけ、DirectoryTree には 9 キーだけを値安定のまま渡すため、毎レンダー作り直すインライン `labels` でも埋込みスクロールのクロームは再構築されない。
|
|
200
261
|
|
|
201
262
|
### Chrome locale and number formatting / クロームロケールと数値書式
|
|
@@ -211,11 +272,11 @@ The tree is built in a Web Worker by the isomorphic `IncrementalTreeBuilder`, wh
|
|
|
211
272
|
- `useTreeWorker` reads the nearest provider's labels and sends `{ uncategorizedCompany, unnamedPerson: noName }` (`ContactMapTreeNaming`) in the `RESET_TREE` message that opens every worker generation. When the names change (a locale switch or a `labels` override), the session opens a new generation and re-posts every record, so no node keeps a name in the previous language.
|
|
212
273
|
- A contact without a company is placed under the `uncategorizedCompany` node (`"Uncategorized"` / `"未分類"`); a person without a name is called `noName` (`"(No Name)"` / `"名前未設定"`) on every path — the tree row, its accessible name, the list, the detail panel and the popup.
|
|
213
274
|
- Directory entries carry the bare company / department `name` plus `memberCount`; the client composes the display name with the `treeDirectoryName(name, memberCount)` label, so the member count is grouped in the chrome locale and a host can override the format.
|
|
214
|
-
- `IncrementalTreeBuilder` / `buildDirectoryTree` take the names as a required argument and reject
|
|
275
|
+
- `IncrementalTreeBuilder` / `buildDirectoryTree` take the names as a required argument and reject a non-string name with a `TypeError` and a blank one with a `RangeError` (`assertContactMapTreeNaming`).
|
|
215
276
|
- `useTreeWorker` は直近プロバイダーのラベルを読み、各 Worker 世代を開く `RESET_TREE` メッセージで `{ uncategorizedCompany, unnamedPerson: noName }` (`ContactMapTreeNaming`) を送る。代替名が変わると (ロケール切替や `labels` の上書き) セッションは新しい世代を開いて全レコードを再送するため、旧言語の名前を持つノードは残らない。
|
|
216
277
|
- 会社名の無い連絡先は `uncategorizedCompany` のノード (`"Uncategorized"` / `"未分類"`) の下に置き、氏名の無い人物はツリー行・そのアクセシブルネーム・一覧・詳細パネル・ポップアップのすべてで `noName` (`"(No Name)"` / `"名前未設定"`) と呼ぶ。
|
|
217
278
|
- ディレクトリエントリは会社名 / 部署名そのもの (`name`) と `memberCount` を持ち、表示名はクライアントが `treeDirectoryName(name, memberCount)` ラベルで組み立てる (所属人数をクロームロケールで桁区切りし、書式をホストが上書きできる)。
|
|
218
|
-
- `IncrementalTreeBuilder` / `buildDirectoryTree`
|
|
279
|
+
- `IncrementalTreeBuilder` / `buildDirectoryTree` は代替名を必須引数で受け取り、文字列以外の代替名は `TypeError`、空白だけの代替名は `RangeError` (`assertContactMapTreeNaming`)。
|
|
219
280
|
|
|
220
281
|
Not part of the catalog / カタログ対象外:
|
|
221
282
|
|
|
@@ -525,7 +586,7 @@ Function keys are shown with their arguments; the cells show sample output (`cou
|
|
|
525
586
|
Breaking changes / 破壊的変更:
|
|
526
587
|
|
|
527
588
|
- **Default chrome language is `en`.** Hosts that relied on the former Japanese chrome must opt in with `locale="ja"` on `ContactMapAppView` or `config.locale = "ja"` in `ContactMapConfigProvider`. `locale` is the chrome language only; there is no `formatLocale` prop (digit grouping follows `locale`, see above).
|
|
528
|
-
- **Invalid chrome settings fail fast.**
|
|
589
|
+
- **Invalid chrome settings fail fast.** When the provider or the view mounts, an unsupported `locale` string (`"ja-JP"`, `"EN"`, `""`, ...), an unknown label key or a blank label throws a `RangeError`, and a value of the wrong type (a non-string `locale`, a `labels` that is not a plain object, a non-string for a string key, a non-function for a function key) a `TypeError`.
|
|
529
590
|
- **`WorkerStatsSection`** takes `kind: "index" | "levenshtein"` instead of `title: string`.
|
|
530
591
|
- **`SwipeOverlay`'s `title`** no longer defaults to `"詳細"` and **`ContactMapAppView`'s `title`** has no hard-coded default; omitted, they use the `overlayTitle` / `appTitle` labels.
|
|
531
592
|
- **Tree builder API.** `new IncrementalTreeBuilder(naming)` and `buildDirectoryTree(records, naming)` require `naming: ContactMapTreeNaming`. A directory entry's `name` is now the bare company / department name and its member count is `memberCount` (the former `"<name> (N)"` is composed by the client with `treeDirectoryName`).
|
|
@@ -535,7 +596,7 @@ Breaking changes / 破壊的変更:
|
|
|
535
596
|
- **Peer floors.** `@aiquants/virtualscroll` ^3.7.0, `@aiquants/directory-tree` ^3.12.0 and `@aiquants/select-box` ^0.10.0 (all expanded from `workspace:^` at publish). contact-map uses only the text normalization helpers of select-box and renders no `SelectBox`, so the select-box floor comes from the `workspace:^` expansion, not from a new API.
|
|
536
597
|
|
|
537
598
|
- **既定のクローム言語は `en`。** 従来の日本語クロームに依存していたホストは `ContactMapAppView` に `locale="ja"`、または `ContactMapConfigProvider` の `config.locale = "ja"` で明示的に選ぶ。`locale` はクローム言語だけで、`formatLocale` prop は無い (桁区切りは `locale` に従う。上記参照)。
|
|
538
|
-
- **不正なクローム設定は即座に失敗。**
|
|
599
|
+
- **不正なクローム設定は即座に失敗。** プロバイダーかビューのマウント時に、非対応の `locale` の文字列 (`"ja-JP"`、`"EN"`、`""` など)・未知のラベルキー・空白のラベルは `RangeError`、型の誤り (文字列でない `locale`、素の object でない `labels`、文字列キーに文字列以外、関数キーに関数以外) は `TypeError`。
|
|
539
600
|
- **`WorkerStatsSection`** は `title: string` の代わりに `kind: "index" | "levenshtein"` を受け取る。
|
|
540
601
|
- **`SwipeOverlay` の `title`** は `"詳細"` を既定にせず、**`ContactMapAppView` の `title`** も固定の既定値を持たない。省略時は `overlayTitle` / `appTitle` ラベル。
|
|
541
602
|
- **ツリービルダー API。** `new IncrementalTreeBuilder(naming)` と `buildDirectoryTree(records, naming)` は `naming: ContactMapTreeNaming` が必須。ディレクトリエントリの `name` は会社名 / 部署名そのもので、所属人数は `memberCount` (従来の `"<名前> (N)"` はクライアントが `treeDirectoryName` で組み立てる)。
|
package/dist/client.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from "react";
|
|
2
2
|
import { CSSProperties, ReactNode, RefObject, PointerEvent, MouseEvent } from "react";
|
|
3
3
|
import { UseFuzzySearchOptions } from "@aiquants/fuzzy-search/react";
|
|
4
|
-
import { C as ContactRecord, a as ContactMapStreamPhase, b as ContactMapSearchOutletContext, c as ContactMapOutletContext, d as ContactMapLogger, S as SerializedContactStreamRow } from "./wire-
|
|
4
|
+
import { C as ContactRecord, a as ContactMapStreamPhase, b as ContactMapSearchOutletContext, c as ContactMapOutletContext, d as ContactMapLogger, S as SerializedContactStreamRow } from "./wire-hAxBVVH6.mjs";
|
|
5
5
|
import { DirectoryTreeLabels, DirectoryTreeVirtualScrollOptions } from "@aiquants/directory-tree";
|
|
6
6
|
import * as _aiquants_virtualscroll from "@aiquants/virtualscroll";
|
|
7
7
|
import { VirtualScrollLocale } from "@aiquants/virtualscroll";
|
|
@@ -93,6 +93,7 @@ type ContactMapOwnLabels = {
|
|
|
93
93
|
readonly annotationStreamingProgress: (progress: ContactMapStreamProgress) => string;
|
|
94
94
|
readonly annotationStreamingCount: (loaded: number) => string;
|
|
95
95
|
readonly annotationLoadFailed: (loaded: number) => string;
|
|
96
|
+
readonly annotationAuthRequired: string;
|
|
96
97
|
readonly annotationRetry: string;
|
|
97
98
|
readonly recordUnit: (displayed: string) => string;
|
|
98
99
|
readonly companyUnit: (displayed: string) => string;
|
|
@@ -375,7 +376,25 @@ type ContactMapLabelOverrides = {
|
|
|
375
376
|
};
|
|
376
377
|
declare const CONTACT_MAP_LABEL_KEYS: readonly (keyof ContactMapLabels)[];
|
|
377
378
|
declare const CONTACT_MAP_LABEL_CATALOGS: Readonly<Record<ContactMapLocale, ContactMapLabels>>;
|
|
378
|
-
|
|
379
|
+
type ContactMapChromeSurface = {
|
|
380
|
+
readonly locale: string;
|
|
381
|
+
readonly labels: string;
|
|
382
|
+
};
|
|
383
|
+
declare const resolveContactMapLabels: (locale: ContactMapLocale | undefined, overrides: ContactMapLabelOverrides | undefined, surface?: ContactMapChromeSurface) => ContactMapLabels;
|
|
384
|
+
type ContactMapWorkerUrls = {
|
|
385
|
+
indexWorker?: string;
|
|
386
|
+
levenshteinWorker?: string;
|
|
387
|
+
treeWorker?: string;
|
|
388
|
+
};
|
|
389
|
+
type ContactMapWorkerUrlKey = keyof ContactMapWorkerUrls;
|
|
390
|
+
type ContactMapWorkerUrlsSurface = {
|
|
391
|
+
readonly setting: string;
|
|
392
|
+
readonly keys?: readonly ContactMapWorkerUrlKey[];
|
|
393
|
+
readonly hints?: Partial<Record<ContactMapWorkerUrlKey, string>>;
|
|
394
|
+
};
|
|
395
|
+
declare function assertContactMapWorkerUrls(workerUrls: unknown, surface?: ContactMapWorkerUrlsSurface): asserts workerUrls is ContactMapWorkerUrls | undefined;
|
|
396
|
+
declare function assertContactMapTreeWorkerUrl(treeWorkerUrl: unknown): asserts treeWorkerUrl is string | undefined;
|
|
397
|
+
declare const layerContactMapWorkerUrls: (provided: ContactMapWorkerUrls | undefined, own: ContactMapWorkerUrls | undefined, surface?: ContactMapWorkerUrlsSurface) => ContactMapWorkerUrls;
|
|
379
398
|
interface ContactMapAppViewProps {
|
|
380
399
|
renderHeader?: (props: {
|
|
381
400
|
title: string;
|
|
@@ -385,11 +404,7 @@ interface ContactMapAppViewProps {
|
|
|
385
404
|
locale?: ContactMapLocale;
|
|
386
405
|
labels?: ContactMapLabelOverrides;
|
|
387
406
|
streamEndpoint?: string;
|
|
388
|
-
workerUrls?:
|
|
389
|
-
indexWorker?: string;
|
|
390
|
-
levenshteinWorker?: string;
|
|
391
|
-
treeWorker?: string;
|
|
392
|
-
};
|
|
407
|
+
workerUrls?: ContactMapWorkerUrls;
|
|
393
408
|
onFooterVisibilityChange?: (mode: "visible" | "mobile-hidden") => void;
|
|
394
409
|
}
|
|
395
410
|
declare const ContactMapAppView: (props: ContactMapAppViewProps) => react.JSX.Element;
|
|
@@ -419,14 +434,11 @@ declare const ContactMapSearchListView: ({ context }: ContactMapSearchListViewPr
|
|
|
419
434
|
type ContactMapTab = "search" | "settings" | "statistics";
|
|
420
435
|
interface ContactMapSearchPageProps {
|
|
421
436
|
streamState?: ContactMapOutletContext;
|
|
422
|
-
workerUrls?:
|
|
423
|
-
indexWorker?: string;
|
|
424
|
-
levenshteinWorker?: string;
|
|
425
|
-
};
|
|
437
|
+
workerUrls?: Pick<ContactMapWorkerUrls, "indexWorker" | "levenshteinWorker">;
|
|
426
438
|
onFooterVisibilityChange?: (mode: "visible" | "mobile-hidden") => void;
|
|
427
439
|
children?: (context: ContactMapSearchOutletContext) => ReactNode;
|
|
428
440
|
}
|
|
429
|
-
declare const ContactMapSearchPage: ({ streamState,
|
|
441
|
+
declare const ContactMapSearchPage: ({ streamState, ...rest }?: ContactMapSearchPageProps) => react.JSX.Element;
|
|
430
442
|
interface ContactMapSearchTabGroupProps {
|
|
431
443
|
context: ContactMapSearchOutletContext;
|
|
432
444
|
}
|
|
@@ -524,21 +536,13 @@ interface ContactMapConfig {
|
|
|
524
536
|
streamEndpoint?: string;
|
|
525
537
|
openEmailsWithGmail?: boolean;
|
|
526
538
|
treeWorkerFactory?: () => Worker;
|
|
527
|
-
workerUrls?:
|
|
528
|
-
indexWorker?: string;
|
|
529
|
-
levenshteinWorker?: string;
|
|
530
|
-
treeWorker?: string;
|
|
531
|
-
};
|
|
532
|
-
fuzzyWorkerUrls?: {
|
|
533
|
-
indexWorkerUrl?: string;
|
|
534
|
-
levenshteinWorkerUrl?: string;
|
|
535
|
-
};
|
|
539
|
+
workerUrls?: ContactMapWorkerUrls;
|
|
536
540
|
layoutSpec?: Partial<ResponsiveLayoutSpec>;
|
|
537
541
|
locale?: ContactMapLocale;
|
|
538
542
|
labels?: ContactMapLabelOverrides;
|
|
539
543
|
}
|
|
540
544
|
declare function ContactMapConfigProvider({ config, children }: {
|
|
541
|
-
config
|
|
545
|
+
config: ContactMapConfig;
|
|
542
546
|
children: ReactNode;
|
|
543
547
|
}): react.JSX.Element;
|
|
544
548
|
declare function useContactMapConfig(): ContactMapConfig;
|
|
@@ -553,18 +557,19 @@ type ContactMapStreamState = {
|
|
|
553
557
|
};
|
|
554
558
|
type ContactMapStreamClientDeps = {
|
|
555
559
|
fetchFn?: typeof fetch;
|
|
556
|
-
endpoint
|
|
560
|
+
endpoint: string;
|
|
557
561
|
initialRetryDelayMs?: number;
|
|
558
562
|
maxRetryDelayMs?: number;
|
|
559
563
|
maxConsecutiveFailures?: number;
|
|
560
564
|
logger?: ContactMapLogger;
|
|
561
565
|
};
|
|
566
|
+
declare function assertContactMapStreamEndpoint(endpoint: unknown): asserts endpoint is string;
|
|
562
567
|
declare const deserializeStreamRecord: (row: SerializedContactStreamRow) => ContactRecord;
|
|
563
568
|
declare class ContactMapStreamClient {
|
|
564
569
|
private readonly recordMap;
|
|
565
570
|
private readonly listeners;
|
|
566
571
|
private readonly fetchFn;
|
|
567
|
-
|
|
572
|
+
readonly endpoint: string;
|
|
568
573
|
private readonly initialRetryDelayMs;
|
|
569
574
|
private readonly maxRetryDelayMs;
|
|
570
575
|
private readonly maxConsecutiveFailures;
|
|
@@ -576,12 +581,11 @@ declare class ContactMapStreamClient {
|
|
|
576
581
|
private activeController;
|
|
577
582
|
private wakeRetryWait;
|
|
578
583
|
private state;
|
|
579
|
-
constructor(deps
|
|
584
|
+
constructor(deps: ContactMapStreamClientDeps);
|
|
580
585
|
getState(): ContactMapStreamState;
|
|
581
586
|
getRecordMap(): ReadonlyMap<number, ContactRecord>;
|
|
582
587
|
subscribe(listener: (state: ContactMapStreamState) => void): () => void;
|
|
583
588
|
start(): void;
|
|
584
|
-
retry(): void;
|
|
585
589
|
retryNow(): void;
|
|
586
590
|
dispose(): void;
|
|
587
591
|
private readonly handleOnline;
|
|
@@ -593,11 +597,17 @@ declare class ContactMapStreamClient {
|
|
|
593
597
|
private streamOnce;
|
|
594
598
|
}
|
|
595
599
|
declare const useAnimatedNumber: (targetValue: number, durationMs?: number) => number;
|
|
596
|
-
|
|
600
|
+
type ContactMapStreamHandle = ContactMapStreamState & {
|
|
601
|
+
readonly recordMap: ReadonlyMap<number, ContactRecord>;
|
|
602
|
+
readonly retryNow: () => void;
|
|
603
|
+
};
|
|
604
|
+
declare const getContactMapStreamClient: (endpoint: string) => ContactMapStreamClient;
|
|
597
605
|
declare const resetContactMapStreamClientForTesting: () => void;
|
|
598
|
-
declare
|
|
599
|
-
declare
|
|
600
|
-
|
|
606
|
+
declare function useContactMapStream(): ContactMapStreamHandle;
|
|
607
|
+
declare const countContactMapCompanies: (records: readonly ContactRecord[]) => number;
|
|
608
|
+
declare function useStreamedContactMapContext(): {
|
|
609
|
+
readonly context: ContactMapOutletContext;
|
|
610
|
+
readonly retryNow: () => void;
|
|
601
611
|
};
|
|
602
612
|
interface UseDynamicViewportHeightOptions {
|
|
603
613
|
enableMutationObserver?: boolean;
|
|
@@ -656,6 +666,11 @@ interface TreeWorkerState {
|
|
|
656
666
|
snapshot: TreeWorkerSnapshot | null;
|
|
657
667
|
isBuilding: boolean;
|
|
658
668
|
}
|
|
669
|
+
type TreeWorkerSource = "treeWorkerFactory" | "workerUrls.treeWorker";
|
|
670
|
+
interface TreeWorkerSessionOptions {
|
|
671
|
+
readonly workerSource: TreeWorkerSource;
|
|
672
|
+
readonly logger?: ContactMapLogger;
|
|
673
|
+
}
|
|
659
674
|
declare class TreeWorkerSession {
|
|
660
675
|
private worker;
|
|
661
676
|
private generation;
|
|
@@ -666,12 +681,15 @@ declare class TreeWorkerSession {
|
|
|
666
681
|
private postedNaming;
|
|
667
682
|
private lastSyncedNaming;
|
|
668
683
|
private consecutiveFailures;
|
|
669
|
-
private
|
|
684
|
+
private finalizeRequest;
|
|
685
|
+
private finalizedPostedCount;
|
|
670
686
|
private retryTimer;
|
|
671
687
|
private readonly listeners;
|
|
672
688
|
private readonly workerFactory;
|
|
689
|
+
private readonly workerSource;
|
|
690
|
+
private readonly logger;
|
|
673
691
|
private state;
|
|
674
|
-
constructor(workerFactory: () => Worker);
|
|
692
|
+
constructor(workerFactory: () => Worker, { workerSource, logger }: TreeWorkerSessionOptions);
|
|
675
693
|
getState: () => TreeWorkerState;
|
|
676
694
|
private updateState;
|
|
677
695
|
subscribe: (listener: () => void) => (() => void);
|
|
@@ -681,11 +699,11 @@ declare class TreeWorkerSession {
|
|
|
681
699
|
private readonly handleFailure;
|
|
682
700
|
syncRecords(records: readonly ContactRecordForTree[], naming: ContactMapTreeNaming): void;
|
|
683
701
|
finalize(): void;
|
|
684
|
-
|
|
702
|
+
private cancelWorker;
|
|
703
|
+
stop(): void;
|
|
704
|
+
reset(): void;
|
|
685
705
|
}
|
|
686
|
-
declare const getTreeWorkerSession: (
|
|
687
|
-
declare const syncTreeWorkerRecords: (records: readonly ContactRecordForTree[], naming: ContactMapTreeNaming) => void;
|
|
688
|
-
declare const finalizeTreeWorker: () => void;
|
|
706
|
+
declare const getTreeWorkerSession: (treeWorkerUrl?: string) => TreeWorkerSession;
|
|
689
707
|
declare const resetTreeWorkerSessionForTesting: () => void;
|
|
690
708
|
declare function useTreeWorker(records: readonly ContactRecordForTree[], isComplete?: boolean): TreeWorkerState;
|
|
691
709
|
declare const useContactMapLabels: () => ContactMapLabels;
|
|
@@ -709,4 +727,4 @@ declare const Tabs: react.ForwardRefExoticComponent<TabsPrimitive.TabsProps & re
|
|
|
709
727
|
declare const TabsList: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsListProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
|
|
710
728
|
declare const TabsTrigger: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsTriggerProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
711
729
|
declare const TabsContent: react.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
|
|
712
|
-
export { AdvancedSearchSettings, type AdvancedSearchSettingsProps, BasicSearchSettings, type BasicSearchSettingsProps, CONTACT_MAP_LABEL_CATALOGS, CONTACT_MAP_LABEL_KEYS, ContactDetailGrid, type ContactDetailGridProps, type ContactDetailGridSkeletonProps, ContactDetailPanel, type ContactDetailPanelProps, ContactDetailPopup, type ContactDetailPopupProps, ContactDetailRowLayout, type ContactDetailRowLayoutProps, ContactMapAnnotation, type ContactMapAnnotationProps, ContactMapAppView, type ContactMapAppViewProps, type ContactMapConfig, ContactMapConfigProvider, type ContactMapHistoryEntry, type ContactMapLabelOverrides, type ContactMapLabels, type ContactMapLocale, type ContactMapOwnLabels, type ContactMapQueryLengthStat, ContactMapSearchListView, ContactMapSearchPage, type ContactMapSearchPageProps, ContactMapSearchTabGroup, type ContactMapSearchTabGroupProps, ContactMapSearchTreeView, type ContactMapSearchTreeViewProps, ContactMapStreamClient, type ContactMapStreamClientDeps, ContactMapStreamPhase, type ContactMapStreamProgress, type ContactMapStreamState, type ContactMapTab, HighlightedText, type HighlightedTextProps, type HorizontalDragScrollHandlers, IndexWorkerSettings, type IndexWorkerSettingsProps, LIST_COLLAPSE_THRESHOLD, LIST_DETAIL_PANEL_MIN_WIDTH, LIST_EXPAND_THRESHOLD, LIST_PANEL_MIN_WIDTH, LIST_RESIZE_HANDLE_THICKNESS, LevenshteinWorkerSettings, type LevenshteinWorkerSettingsProps, type PopupCloseOptions, Progress, type ProgressProps, SearchOptionsPanel, type SearchOptionsPanelProps, type SearchOptionsPanelTab, StatItem, type StatItemProps, StatisticsPanel, type StatisticsPanelProps, type StatisticsPanelTab, SwipeOverlay, type SwipeOverlayProps, TREE_COLLAPSE_THRESHOLD, TREE_DETAIL_PANEL_MIN_WIDTH, TREE_EXPAND_THRESHOLD, TREE_PANEL_MIN_WIDTH, TREE_RESIZE_HANDLE_THICKNESS, Tabs, TabsContent, TabsList, TabsTrigger, TreeWorkerSession, type TreeWorkerSnapshot, type TreeWorkerState, type UseDynamicViewportHeightOptions, type UseDynamicViewportHeightResult, type UseHorizontalDragScrollOptions, type UseLongPressPopupOptions, type UseLongPressPopupReturn, type UseResponsiveTwoColumnLayoutOptions, type UseResponsiveTwoColumnLayoutResult, type WorkerStatsKind, WorkerStatsSection, type WorkerStatsSectionProps, composeTreeVirtualScrollOptions, contactMapShouldRevalidate,
|
|
730
|
+
export { AdvancedSearchSettings, type AdvancedSearchSettingsProps, BasicSearchSettings, type BasicSearchSettingsProps, CONTACT_MAP_LABEL_CATALOGS, CONTACT_MAP_LABEL_KEYS, ContactDetailGrid, type ContactDetailGridProps, type ContactDetailGridSkeletonProps, ContactDetailPanel, type ContactDetailPanelProps, ContactDetailPopup, type ContactDetailPopupProps, ContactDetailRowLayout, type ContactDetailRowLayoutProps, ContactMapAnnotation, type ContactMapAnnotationProps, ContactMapAppView, type ContactMapAppViewProps, type ContactMapChromeSurface, type ContactMapConfig, ContactMapConfigProvider, type ContactMapHistoryEntry, type ContactMapLabelOverrides, type ContactMapLabels, type ContactMapLocale, type ContactMapOwnLabels, type ContactMapQueryLengthStat, ContactMapSearchListView, ContactMapSearchPage, type ContactMapSearchPageProps, ContactMapSearchTabGroup, type ContactMapSearchTabGroupProps, ContactMapSearchTreeView, type ContactMapSearchTreeViewProps, ContactMapStreamClient, type ContactMapStreamClientDeps, type ContactMapStreamHandle, ContactMapStreamPhase, type ContactMapStreamProgress, type ContactMapStreamState, type ContactMapTab, type ContactMapWorkerUrlKey, type ContactMapWorkerUrls, type ContactMapWorkerUrlsSurface, HighlightedText, type HighlightedTextProps, type HorizontalDragScrollHandlers, IndexWorkerSettings, type IndexWorkerSettingsProps, LIST_COLLAPSE_THRESHOLD, LIST_DETAIL_PANEL_MIN_WIDTH, LIST_EXPAND_THRESHOLD, LIST_PANEL_MIN_WIDTH, LIST_RESIZE_HANDLE_THICKNESS, LevenshteinWorkerSettings, type LevenshteinWorkerSettingsProps, type PopupCloseOptions, Progress, type ProgressProps, SearchOptionsPanel, type SearchOptionsPanelProps, type SearchOptionsPanelTab, StatItem, type StatItemProps, StatisticsPanel, type StatisticsPanelProps, type StatisticsPanelTab, SwipeOverlay, type SwipeOverlayProps, TREE_COLLAPSE_THRESHOLD, TREE_DETAIL_PANEL_MIN_WIDTH, TREE_EXPAND_THRESHOLD, TREE_PANEL_MIN_WIDTH, TREE_RESIZE_HANDLE_THICKNESS, Tabs, TabsContent, TabsList, TabsTrigger, TreeWorkerSession, type TreeWorkerSessionOptions, type TreeWorkerSnapshot, type TreeWorkerSource, type TreeWorkerState, type UseDynamicViewportHeightOptions, type UseDynamicViewportHeightResult, type UseHorizontalDragScrollOptions, type UseLongPressPopupOptions, type UseLongPressPopupReturn, type UseResponsiveTwoColumnLayoutOptions, type UseResponsiveTwoColumnLayoutResult, type WorkerStatsKind, WorkerStatsSection, type WorkerStatsSectionProps, assertContactMapStreamEndpoint, assertContactMapTreeWorkerUrl, assertContactMapWorkerUrls, composeTreeVirtualScrollOptions, contactMapShouldRevalidate, countContactMapCompanies, deserializeStreamRecord, getContactMapStreamClient, getTreeWorkerSession, layerContactMapWorkerUrls, resetContactMapStreamClientForTesting, resetTreeWorkerSessionForTesting, resolveContactMapLabels, useAnimatedNumber, useContactMapConfig, useContactMapLabels, useContactMapStream, useContactPanelSizing, useDynamicViewportHeight, useHorizontalDragScroll, useLongPressPopup, useReportPopupVisibility, useResponsiveTwoColumnLayout, useRowPopupRegistry, useStreamedContactMapContext, useTreeWorker };
|