@wcstack/storage 1.10.0 → 1.11.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.ja.md +44 -7
- package/README.md +44 -7
- package/dist/index.d.ts +14 -1
- package/dist/index.esm.js +173 -32
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
つまり、ブラウザストレージの永続化を HTML 内で宣言的に表現できます。UI レイヤーに `localStorage.getItem()`、`JSON.parse()`、シリアライズのグルーコードを書く必要はありません。
|
|
14
14
|
|
|
15
|
-
`@wcstack/storage` は [
|
|
15
|
+
`@wcstack/storage` は [CSBC](https://github.com/csbc-dev/arch/blob/main/README.md)(Core / Shell / Binding Contract)アーキテクチャに従います:
|
|
16
16
|
|
|
17
17
|
- **Core** (`StorageCore`) がストレージの読み書き、クロスタブ同期を処理
|
|
18
18
|
- **Shell** (`<wcs-storage>`) がその状態を DOM に接続
|
|
@@ -157,7 +157,7 @@ localStorage の変更は、別のタブからの更新も自動的に検知さ
|
|
|
157
157
|
|
|
158
158
|
### 出力ステート(バインド可能な状態)
|
|
159
159
|
|
|
160
|
-
現在のストレージの値を表し、
|
|
160
|
+
現在のストレージの値を表し、CSBC のメインサーフェスです:
|
|
161
161
|
|
|
162
162
|
| プロパティ | 型 | 説明 |
|
|
163
163
|
|------------|------|------|
|
|
@@ -179,7 +179,7 @@ HTML、JS、または `@wcstack/state` バインディングからストレー
|
|
|
179
179
|
|
|
180
180
|
## アーキテクチャ
|
|
181
181
|
|
|
182
|
-
`@wcstack/storage` は
|
|
182
|
+
`@wcstack/storage` は CSBC アーキテクチャに従います。
|
|
183
183
|
|
|
184
184
|
### Core: `StorageCore`
|
|
185
185
|
|
|
@@ -268,8 +268,18 @@ unbind();
|
|
|
268
268
|
|
|
269
269
|
`StorageCore` と `<wcs-storage>` はどちらも wc-bindable-protocol に準拠しており、プロトコル対応の任意のフレームワークやコンポーネントと相互運用できます。
|
|
270
270
|
|
|
271
|
+
宣言は wc-bindable インターフェースモデルの全体に従い、3 つの独立したサーフェスを持ちます:
|
|
272
|
+
|
|
273
|
+
- **`properties`** — `bind()` が購読する観測可能な出力(`value`, `loading`, `error`, および Shell の `trigger`)
|
|
274
|
+
- **`inputs`** — 設定可能なサーフェス(`key`, `type` など)。ツール・コード生成・リモートプロキシが読む宣言的メタデータ
|
|
275
|
+
- **`commands`** — 呼び出し可能なメソッド(`load`, `save`, `remove`)。`@wcstack/state` のようなバインディングシステムが名前で呼び出せる
|
|
276
|
+
|
|
277
|
+
プロトコル上、コアの `bind()` が解釈するのは `properties` のみです。`inputs` / `commands`(および `attribute` / `async` ヒント)は記述的なメタデータであり、暗黙の双方向データフローを生成しません。
|
|
278
|
+
|
|
271
279
|
### Core (`StorageCore`)
|
|
272
280
|
|
|
281
|
+
`StorageCore` は任意のランタイムが購読できるバインド可能な状態に加え、ポータブルな入力 / コマンドサーフェスを宣言します:
|
|
282
|
+
|
|
273
283
|
```typescript
|
|
274
284
|
static wcBindable = {
|
|
275
285
|
protocol: "wc-bindable",
|
|
@@ -280,12 +290,23 @@ static wcBindable = {
|
|
|
280
290
|
{ name: "loading", event: "wcs-storage:loading-changed" },
|
|
281
291
|
{ name: "error", event: "wcs-storage:error" },
|
|
282
292
|
],
|
|
293
|
+
inputs: [
|
|
294
|
+
{ name: "key" },
|
|
295
|
+
{ name: "type" },
|
|
296
|
+
],
|
|
297
|
+
commands: [
|
|
298
|
+
{ name: "load" },
|
|
299
|
+
{ name: "save" },
|
|
300
|
+
{ name: "remove" },
|
|
301
|
+
],
|
|
283
302
|
};
|
|
284
303
|
```
|
|
285
304
|
|
|
305
|
+
ヘッドレス利用では `core.load()` / `core.save(value)` を直接呼び出します — `trigger` は不要です。
|
|
306
|
+
|
|
286
307
|
### Shell (`<wcs-storage>`)
|
|
287
308
|
|
|
288
|
-
Shell は Core
|
|
309
|
+
Shell は Core の宣言を `trigger` 出力と DOM 駆動の入力サーフェスで拡張します。`commands`(`load` / `save` / `remove`)は Core からそのまま継承されます:
|
|
289
310
|
|
|
290
311
|
```typescript
|
|
291
312
|
static wcBindable = {
|
|
@@ -294,9 +315,18 @@ static wcBindable = {
|
|
|
294
315
|
...StorageCore.wcBindable.properties,
|
|
295
316
|
{ name: "trigger", event: "wcs-storage:trigger-changed" },
|
|
296
317
|
],
|
|
318
|
+
inputs: [
|
|
319
|
+
{ name: "key" },
|
|
320
|
+
{ name: "type" },
|
|
321
|
+
{ name: "value" },
|
|
322
|
+
{ name: "manual" },
|
|
323
|
+
{ name: "trigger" },
|
|
324
|
+
],
|
|
297
325
|
};
|
|
298
326
|
```
|
|
299
327
|
|
|
328
|
+
Shell の inputs は意図的に `attribute` ヒントを持ちません: `key` / `type` / `manual` のセッターは既に各属性へ反映するため、`inputs[].attribute` を反映するバインディングシステムだと属性を二重に設定してしまうからです。
|
|
329
|
+
|
|
300
330
|
## TypeScript 型
|
|
301
331
|
|
|
302
332
|
```typescript
|
|
@@ -341,7 +371,7 @@ interface WcsStorageValues<T = unknown> extends WcsStorageCoreValues<T> {
|
|
|
341
371
|
|
|
342
372
|
## フレームワーク連携
|
|
343
373
|
|
|
344
|
-
`<wcs-storage>` は
|
|
374
|
+
`<wcs-storage>` は CSBC + `wc-bindable-protocol` なので、`@wc-bindable/*` の薄いアダプタを通じて任意のフレームワークで動作します。
|
|
345
375
|
|
|
346
376
|
### React
|
|
347
377
|
|
|
@@ -469,11 +499,18 @@ bootstrapStorage({
|
|
|
469
499
|
|
|
470
500
|
- `value`、`loading`、`error` は **出力ステート**
|
|
471
501
|
- `key`、`type`、`trigger` は **入力 / コマンドサーフェス**
|
|
472
|
-
- `trigger` は意図的に単方向: `true`
|
|
502
|
+
- `trigger` は意図的に単方向: `true` を書き込むと保存、リセットで完了を通知。内部の `save()` が失敗した場合(例: `key` 未設定)でも `trigger` は `false` へ復帰し完了イベントも発火するため、`true` で固着しない。
|
|
473
503
|
- `value` セッターは `manual` でない場合に自動保存を行う
|
|
504
|
+
- **`value` セッター vs `save()` / `trigger`**: `value` への代入(非 manual)は *代入された引数* を保存する(ライトスルー)。一方 `save()` と `trigger` は *現在の `value`*(直前の `load()` や他タブからの `storage` イベントで更新されうる)を保存する。このため `trigger`/`save()` は他タブ由来の値を書き戻す可能性がある。
|
|
505
|
+
- **`manual` モードでの `value`**: `manual` では `value` セッターは値を**ステージング**する(ストレージへは書き込まない)。`el.value = x` で読み取り値は更新される(`el.value === x`)が、ストレージには触れず、実際の書き込みは `save()` / `trigger` でのみ行われる。これにより `value: …` + `trigger: …` のバインディング対が機能する — バインドされた値がステージングされ、トリガー時にコミットされる。
|
|
506
|
+
- **非 manual の `value` 経路にはエコーガードを置かない**: 同値の `value-changed` 再発火をスキップするのは*ステージング*経路(`manual` モードで使う Core の `value` セッター)のみ。主経路である非 manual の `value` セッター → `save()` は意図的にライトスルーであり、代入値が現在値と等しくても毎回保存し `value-changed` を再発火する。これは仕様である — 上記のライトスルー契約を保つ必要があり、同一タブでは `storage` イベントが再発火しないためフィードバックループは生じない。`data-wcs="value: x"` の双方向バインディングでもエコーされる `value-changed` は無害で、`@wcstack/state` 側がラウンドトリップを重複排除する。
|
|
507
|
+
- **`save` コマンドのアリティ**: ヘッドレスな Core は `save(value)`、Shell は `save()`(現在値を保存)。どちらも同じ `commands` 名 `save` に現れるが、プロトコルの `commands` メタデータは記述的でアリティを持たないため、これは契約上の差異でありプロトコル違反ではない。
|
|
508
|
+
- **不正な `type`**: `"session"` 以外の `type` 属性はすべて `"local"` として扱う。不正値(例: `type="foo"`)は例外を投げず暗黙に `local` へフォールバックする。
|
|
509
|
+
- **実行時の `type` 変更**: 接続後に `type` 属性を変更すると以降の操作で使うストレージ領域は切り替わるが、新しい領域から**自動で再ロードはしない**(非 manual で自動再ロードするのは `key` 変更時のみ)。新領域の値が必要なら明示的に `load()` を呼ぶこと。
|
|
510
|
+
- **`error` の形状**: ストレージ失敗時、`error` には失敗した操作(`load` / `save` / `remove`)を示す `WcsStorageError`(`{ operation, message }`)が設定される。`key is required`(key 未設定での操作呼び出し)は `error` ではなく同期的に throw される。したがって実際には `error` は常に `WcsStorageError` か `null` のいずれかになる。より広い `WcsStorageError | Error | null` 型は前方互換性と兄弟パッケージとの一貫性のために維持している。
|
|
474
511
|
- JSON 自動シリアライズにより、オブジェクト / 配列 / プリミティブを透過的に扱える
|
|
475
512
|
- `null` / `undefined` の保存はストレージからのキー削除として扱われる
|
|
476
|
-
- `storage` イベントによるクロスタブ同期は localStorage
|
|
513
|
+
- `storage` イベントによるクロスタブ同期は localStorage でのみ動作。Shell は接続時(および再 attach 時)に監視を現在の `key` / `type` へ結びつけるため、自動ロードが走らない `manual` モードでもクロスタブ同期が機能する。接続後に `key` 属性を変更した場合も常に Core の key を再同期するため、`manual` モードや key を空にした場合でもクロスタブ同期は新しい key を追従する。クロスタブ更新が成功すると残存していた `error` もクリアされる(`load()` / `save()` / `remove()` が成功時に冒頭で error を null にするのと同様)。これにより、過去の失敗で残った error と新鮮な value が共存しない。
|
|
477
514
|
- `manual` は保存タイミングを明示的に制御したい場合に有用
|
|
478
515
|
|
|
479
516
|
## ライセンス
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ When combined with `@wcstack/state`, `<wcs-storage>` can be bound directly throu
|
|
|
12
12
|
|
|
13
13
|
This means you can express browser storage persistence declaratively in HTML, without writing `localStorage.getItem()`, `JSON.parse()`, or serialization glue code in the UI layer.
|
|
14
14
|
|
|
15
|
-
`@wcstack/storage` follows the [
|
|
15
|
+
`@wcstack/storage` follows the [CSBC](https://github.com/csbc-dev/arch/blob/main/README.md) (Core / Shell / Binding Contract) architecture:
|
|
16
16
|
|
|
17
17
|
- **Core** (`StorageCore`) handles storage read/write and cross-tab sync
|
|
18
18
|
- **Shell** (`<wcs-storage>`) connects that state to the DOM
|
|
@@ -156,7 +156,7 @@ localStorage changes are automatically detected from other tabs:
|
|
|
156
156
|
|
|
157
157
|
### Output State (bindable state)
|
|
158
158
|
|
|
159
|
-
Represents the current storage value and is the
|
|
159
|
+
Represents the current storage value and is the CSBC main surface:
|
|
160
160
|
|
|
161
161
|
| Property | Type | Description |
|
|
162
162
|
|----------|------|-------------|
|
|
@@ -178,7 +178,7 @@ Controls storage operations from HTML, JS, or `@wcstack/state` bindings:
|
|
|
178
178
|
|
|
179
179
|
## Architecture
|
|
180
180
|
|
|
181
|
-
`@wcstack/storage` follows the
|
|
181
|
+
`@wcstack/storage` follows the CSBC architecture.
|
|
182
182
|
|
|
183
183
|
### Core: `StorageCore`
|
|
184
184
|
|
|
@@ -265,8 +265,18 @@ unbind();
|
|
|
265
265
|
|
|
266
266
|
Both `StorageCore` and `<wcs-storage>` conform to the wc-bindable-protocol, enabling interop with any protocol-aware framework or component.
|
|
267
267
|
|
|
268
|
+
The declaration follows the full wc-bindable interface model — three independent surfaces:
|
|
269
|
+
|
|
270
|
+
- **`properties`** — observable outputs that `bind()` subscribes to (`value`, `loading`, `error`, and the Shell's `trigger`)
|
|
271
|
+
- **`inputs`** — the settable surface (`key`, `type`, …); declarative metadata that tooling, codegen, and remote proxying read
|
|
272
|
+
- **`commands`** — invocable methods (`load`, `save`, `remove`); a binding system such as `@wcstack/state` can invoke them by name
|
|
273
|
+
|
|
274
|
+
Per the protocol, only `properties` is interpreted by core `bind()`; `inputs` / `commands` (and the `attribute` / `async` hints) are descriptive. They do **not** create implicit two-way data flow.
|
|
275
|
+
|
|
268
276
|
### Core (`StorageCore`)
|
|
269
277
|
|
|
278
|
+
`StorageCore` declares the bindable state any runtime can subscribe to, plus its portable input/command surface:
|
|
279
|
+
|
|
270
280
|
```typescript
|
|
271
281
|
static wcBindable = {
|
|
272
282
|
protocol: "wc-bindable",
|
|
@@ -277,12 +287,23 @@ static wcBindable = {
|
|
|
277
287
|
{ name: "loading", event: "wcs-storage:loading-changed" },
|
|
278
288
|
{ name: "error", event: "wcs-storage:error" },
|
|
279
289
|
],
|
|
290
|
+
inputs: [
|
|
291
|
+
{ name: "key" },
|
|
292
|
+
{ name: "type" },
|
|
293
|
+
],
|
|
294
|
+
commands: [
|
|
295
|
+
{ name: "load" },
|
|
296
|
+
{ name: "save" },
|
|
297
|
+
{ name: "remove" },
|
|
298
|
+
],
|
|
280
299
|
};
|
|
281
300
|
```
|
|
282
301
|
|
|
302
|
+
Headless consumers call `core.load()` / `core.save(value)` directly — no `trigger` needed.
|
|
303
|
+
|
|
283
304
|
### Shell (`<wcs-storage>`)
|
|
284
305
|
|
|
285
|
-
The Shell extends the Core declaration
|
|
306
|
+
The Shell extends the Core declaration with the `trigger` output and the DOM-driven input surface; `commands` (`load` / `save` / `remove`) are inherited unchanged:
|
|
286
307
|
|
|
287
308
|
```typescript
|
|
288
309
|
static wcBindable = {
|
|
@@ -291,9 +312,18 @@ static wcBindable = {
|
|
|
291
312
|
...StorageCore.wcBindable.properties,
|
|
292
313
|
{ name: "trigger", event: "wcs-storage:trigger-changed" },
|
|
293
314
|
],
|
|
315
|
+
inputs: [
|
|
316
|
+
{ name: "key" },
|
|
317
|
+
{ name: "type" },
|
|
318
|
+
{ name: "value" },
|
|
319
|
+
{ name: "manual" },
|
|
320
|
+
{ name: "trigger" },
|
|
321
|
+
],
|
|
294
322
|
};
|
|
295
323
|
```
|
|
296
324
|
|
|
325
|
+
The Shell's inputs intentionally carry no `attribute` hint: the `key` / `type` / `manual` setters already reflect to their attributes, so a binding system that mirrors `inputs[].attribute` would set the attribute twice.
|
|
326
|
+
|
|
297
327
|
## TypeScript Types
|
|
298
328
|
|
|
299
329
|
```typescript
|
|
@@ -338,7 +368,7 @@ Persistence looks just like any other state update.
|
|
|
338
368
|
|
|
339
369
|
## Framework Integration
|
|
340
370
|
|
|
341
|
-
`<wcs-storage>` is
|
|
371
|
+
`<wcs-storage>` is CSBC + `wc-bindable-protocol`, so it works in any framework via thin `@wc-bindable/*` adapters.
|
|
342
372
|
|
|
343
373
|
### React
|
|
344
374
|
|
|
@@ -466,11 +496,18 @@ bootstrapStorage({
|
|
|
466
496
|
|
|
467
497
|
- `value`, `loading`, `error` are **output state**
|
|
468
498
|
- `key`, `type`, `trigger` are **input / command surface**
|
|
469
|
-
- `trigger` is intentionally one-way: writing `true` saves, reset signals completion
|
|
499
|
+
- `trigger` is intentionally one-way: writing `true` saves, reset signals completion. If the underlying `save()` throws (e.g. `key` is unset), `trigger` is still reset to `false` and the completion event still fires, so it never gets stuck in the `true` state.
|
|
470
500
|
- The `value` setter auto-saves when not in `manual` mode
|
|
501
|
+
- **`value` setter vs `save()` / `trigger`**: assigning `value` (non-manual) persists the *assigned* argument (write-through). `save()` and `trigger`, by contrast, persist the *current* `value` — which a prior `load()` or a cross-tab `storage` event may have updated. This means `trigger`/`save()` can write back a value that arrived from another tab.
|
|
502
|
+
- **`value` in `manual` mode**: the `value` setter **stages** the value (no storage write) instead of persisting it. `el.value = x` updates the readable value (`el.value === x`) but does **not** touch storage; the actual write happens only via `save()` / `trigger`. This is what makes the `value: …` + `trigger: …` binding pair work — the bound value is staged, then committed on trigger.
|
|
503
|
+
- **No echo guard on the non-manual `value` path**: only the *staging* path (the Core `value` setter, used in `manual` mode) skips a same-value `value-changed` re-dispatch. The main non-manual path (`value` setter → `save()`) is deliberately write-through: every assignment persists and re-emits `value-changed`, even when the assigned value equals the current one. This is intentional — the write-through contract above must hold, and same-tab `storage` events do not re-fire, so there is no feedback loop. In a `data-wcs="value: x"` two-way binding the echoed `value-changed` is harmless: `@wcstack/state` dedups the round-trip on its side.
|
|
504
|
+
- **`save` command arity**: the headless Core takes `save(value)`, while the Shell exposes `save()` (persists the current value). Both appear under the same `commands` name `save`; the protocol's `commands` metadata is descriptive and arity-less, so this is contractual, not a protocol violation.
|
|
505
|
+
- **Invalid `type`**: any `type` attribute other than `"session"` is treated as `"local"`. An invalid value (e.g. `type="foo"`) silently falls back to `local` rather than throwing.
|
|
506
|
+
- **Runtime `type` change**: changing the `type` attribute after connection updates the Core's storage area for subsequent operations but does **not** re-load from the new area (only `key` changes auto-reload in non-manual mode). Re-load explicitly with `load()` if you need the value from the newly selected area.
|
|
507
|
+
- **`error` shape**: on a storage failure, `error` is set to a `WcsStorageError` (`{ operation, message }`) identifying which operation (`load` / `save` / `remove`) failed. `key is required` (calling an operation with no key) is thrown synchronously, not surfaced via `error`. In practice `error` is therefore always either a `WcsStorageError` or `null`; the wider `WcsStorageError | Error | null` type is kept for forward compatibility and consistency with sibling packages.
|
|
471
508
|
- JSON auto-serialization handles objects, arrays, and primitives transparently
|
|
472
509
|
- Saving `null` / `undefined` removes the key from storage
|
|
473
|
-
- Cross-tab sync via `storage` event works only with localStorage
|
|
510
|
+
- Cross-tab sync via `storage` event works only with localStorage. The Shell binds the watcher to its current `key` / `type` on connect (and re-binds on re-attach), so cross-tab sync works even in `manual` mode where no auto-load runs. Changing the `key` attribute after connection always re-syncs the Core key, so cross-tab sync follows the new key even in `manual` mode or when the key is cleared. A successful cross-tab update also clears any stale `error` (just like `load()` / `save()` / `remove()` do at the start of a successful operation), so a fresh value never coexists with a leftover error from an earlier failure.
|
|
474
511
|
- `manual` is useful when you want explicit control over save timing
|
|
475
512
|
|
|
476
513
|
## License
|
package/dist/index.d.ts
CHANGED
|
@@ -19,10 +19,20 @@ interface IWcBindableProperty {
|
|
|
19
19
|
readonly event: string;
|
|
20
20
|
readonly getter?: (event: Event) => any;
|
|
21
21
|
}
|
|
22
|
+
interface IWcBindableInput {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly attribute?: string;
|
|
25
|
+
}
|
|
26
|
+
interface IWcBindableCommand {
|
|
27
|
+
readonly name: string;
|
|
28
|
+
readonly async?: boolean;
|
|
29
|
+
}
|
|
22
30
|
interface IWcBindable {
|
|
23
31
|
readonly protocol: "wc-bindable";
|
|
24
|
-
readonly version:
|
|
32
|
+
readonly version: 1;
|
|
25
33
|
readonly properties: IWcBindableProperty[];
|
|
34
|
+
readonly inputs?: readonly IWcBindableInput[];
|
|
35
|
+
readonly commands?: readonly IWcBindableCommand[];
|
|
26
36
|
}
|
|
27
37
|
type StorageType = "local" | "session";
|
|
28
38
|
/**
|
|
@@ -64,6 +74,7 @@ declare class StorageCore extends EventTarget {
|
|
|
64
74
|
private _storageListener;
|
|
65
75
|
constructor(target?: EventTarget);
|
|
66
76
|
get value(): any;
|
|
77
|
+
set value(v: any);
|
|
67
78
|
get loading(): boolean;
|
|
68
79
|
get error(): any;
|
|
69
80
|
get key(): string;
|
|
@@ -73,6 +84,7 @@ declare class StorageCore extends EventTarget {
|
|
|
73
84
|
private _getStorage;
|
|
74
85
|
private _setLoading;
|
|
75
86
|
private _setError;
|
|
87
|
+
private _toStorageError;
|
|
76
88
|
private _setValue;
|
|
77
89
|
load(): any;
|
|
78
90
|
save(value: any): void;
|
|
@@ -89,6 +101,7 @@ declare class Storage extends HTMLElement {
|
|
|
89
101
|
private _trigger;
|
|
90
102
|
private _connectedCallbackPromise;
|
|
91
103
|
constructor();
|
|
104
|
+
private _syncCore;
|
|
92
105
|
get key(): string;
|
|
93
106
|
set key(value: string);
|
|
94
107
|
get type(): StorageType;
|
package/dist/index.esm.js
CHANGED
|
@@ -39,11 +39,33 @@ function setConfig(partialConfig) {
|
|
|
39
39
|
_config.triggerAttribute = partialConfig.triggerAttribute;
|
|
40
40
|
}
|
|
41
41
|
if (partialConfig.tagNames) {
|
|
42
|
-
|
|
42
|
+
// Validate each tagNames entry individually instead of a blanket
|
|
43
|
+
// Object.assign: a non-string (e.g. { storage: undefined }) would otherwise
|
|
44
|
+
// poison the config and make customElements.define(undefined, …) throw at
|
|
45
|
+
// registration time. Mirrors the typeof guards on autoTrigger / triggerAttribute.
|
|
46
|
+
for (const [key, value] of Object.entries(partialConfig.tagNames)) {
|
|
47
|
+
if (typeof value === "string") {
|
|
48
|
+
_config.tagNames[key] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
43
51
|
}
|
|
44
52
|
frozenConfig = null;
|
|
45
53
|
}
|
|
46
54
|
|
|
55
|
+
// Single source of truth for the custom event names dispatched by StorageCore /
|
|
56
|
+
// Storage. These names appear in two places that must stay in lock-step:
|
|
57
|
+
// 1. the `wcBindable.properties[].event` declarations (consumed by bind())
|
|
58
|
+
// 2. the `dispatchEvent(new CustomEvent(...))` calls that emit them
|
|
59
|
+
// Hard-coding the same string literal in both places risks a silent typo that
|
|
60
|
+
// makes bind() listen for an event no one ever fires. Referencing these
|
|
61
|
+
// constants from both sites keeps them in sync.
|
|
62
|
+
const STORAGE_EVENTS = {
|
|
63
|
+
valueChanged: "wcs-storage:value-changed",
|
|
64
|
+
loadingChanged: "wcs-storage:loading-changed",
|
|
65
|
+
error: "wcs-storage:error",
|
|
66
|
+
triggerChanged: "wcs-storage:trigger-changed",
|
|
67
|
+
};
|
|
68
|
+
|
|
47
69
|
function raiseError(message) {
|
|
48
70
|
throw new Error(`[@wcstack/storage] ${message}`);
|
|
49
71
|
}
|
|
@@ -53,9 +75,19 @@ class StorageCore extends EventTarget {
|
|
|
53
75
|
protocol: "wc-bindable",
|
|
54
76
|
version: 1,
|
|
55
77
|
properties: [
|
|
56
|
-
{ name: "value", event:
|
|
57
|
-
{ name: "loading", event:
|
|
58
|
-
{ name: "error", event:
|
|
78
|
+
{ name: "value", event: STORAGE_EVENTS.valueChanged, getter: (e) => e.detail },
|
|
79
|
+
{ name: "loading", event: STORAGE_EVENTS.loadingChanged },
|
|
80
|
+
{ name: "error", event: STORAGE_EVENTS.error },
|
|
81
|
+
],
|
|
82
|
+
inputs: [
|
|
83
|
+
{ name: "key" },
|
|
84
|
+
{ name: "type" },
|
|
85
|
+
],
|
|
86
|
+
// load / save / remove are synchronous, so none carry the `async` hint.
|
|
87
|
+
commands: [
|
|
88
|
+
{ name: "load" },
|
|
89
|
+
{ name: "save" },
|
|
90
|
+
{ name: "remove" },
|
|
59
91
|
],
|
|
60
92
|
};
|
|
61
93
|
_target;
|
|
@@ -72,6 +104,20 @@ class StorageCore extends EventTarget {
|
|
|
72
104
|
get value() {
|
|
73
105
|
return this._value;
|
|
74
106
|
}
|
|
107
|
+
// Set the current value *without* persisting it. Persistence happens only via
|
|
108
|
+
// save() / remove() / a cross-tab storage event. This setter exists so the
|
|
109
|
+
// Shell (manual mode) can stage a value handed in via a `value` binding and
|
|
110
|
+
// then commit it later with save()/trigger. It mirrors the value to observers
|
|
111
|
+
// through the same `value-changed` event load()/save() use (CSBC: a Core value
|
|
112
|
+
// change is observable), but it deliberately does not touch storage.
|
|
113
|
+
//
|
|
114
|
+
// Same-value writes are skipped to break a potential feedback loop:
|
|
115
|
+
// value-changed → state binding → value setter → value-changed → …
|
|
116
|
+
set value(v) {
|
|
117
|
+
if (Object.is(v, this._value))
|
|
118
|
+
return;
|
|
119
|
+
this._setValue(v);
|
|
120
|
+
}
|
|
75
121
|
get loading() {
|
|
76
122
|
return this._loading;
|
|
77
123
|
}
|
|
@@ -82,7 +128,11 @@ class StorageCore extends EventTarget {
|
|
|
82
128
|
return this._key;
|
|
83
129
|
}
|
|
84
130
|
set key(value) {
|
|
85
|
-
|
|
131
|
+
// Defensive normalization for direct Core use (the Shell already passes a
|
|
132
|
+
// string via `getAttribute("key") || ""`). Coercing to String keeps a
|
|
133
|
+
// non-string assignment from poisoning the cross-tab `e.key !== _key`
|
|
134
|
+
// comparison; empty keys are still rejected at operation time.
|
|
135
|
+
this._key = String(value);
|
|
86
136
|
}
|
|
87
137
|
get type() {
|
|
88
138
|
return this._type;
|
|
@@ -98,21 +148,29 @@ class StorageCore extends EventTarget {
|
|
|
98
148
|
}
|
|
99
149
|
_setLoading(loading) {
|
|
100
150
|
this._loading = loading;
|
|
101
|
-
this._target.dispatchEvent(new CustomEvent(
|
|
151
|
+
this._target.dispatchEvent(new CustomEvent(STORAGE_EVENTS.loadingChanged, {
|
|
102
152
|
detail: loading,
|
|
103
153
|
bubbles: true,
|
|
104
154
|
}));
|
|
105
155
|
}
|
|
106
156
|
_setError(error) {
|
|
107
157
|
this._error = error;
|
|
108
|
-
this._target.dispatchEvent(new CustomEvent(
|
|
158
|
+
this._target.dispatchEvent(new CustomEvent(STORAGE_EVENTS.error, {
|
|
109
159
|
detail: error,
|
|
110
160
|
bubbles: true,
|
|
111
161
|
}));
|
|
112
162
|
}
|
|
163
|
+
// Wrap a caught storage exception into the documented WcsStorageError shape,
|
|
164
|
+
// tagging it with the failing operation so consumers know which call failed.
|
|
165
|
+
_toStorageError(operation, e) {
|
|
166
|
+
return {
|
|
167
|
+
operation,
|
|
168
|
+
message: e instanceof Error ? e.message : String(e),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
113
171
|
_setValue(value) {
|
|
114
172
|
this._value = value;
|
|
115
|
-
this._target.dispatchEvent(new CustomEvent(
|
|
173
|
+
this._target.dispatchEvent(new CustomEvent(STORAGE_EVENTS.valueChanged, {
|
|
116
174
|
detail: value,
|
|
117
175
|
bubbles: true,
|
|
118
176
|
}));
|
|
@@ -141,7 +199,7 @@ class StorageCore extends EventTarget {
|
|
|
141
199
|
return this._value;
|
|
142
200
|
}
|
|
143
201
|
catch (e) {
|
|
144
|
-
this._setError(e);
|
|
202
|
+
this._setError(this._toStorageError("load", e));
|
|
145
203
|
this._setLoading(false);
|
|
146
204
|
return null;
|
|
147
205
|
}
|
|
@@ -156,18 +214,24 @@ class StorageCore extends EventTarget {
|
|
|
156
214
|
const storage = this._getStorage();
|
|
157
215
|
if (value === null || value === undefined) {
|
|
158
216
|
storage.removeItem(this._key);
|
|
217
|
+
// Normalize the removed value to null (matching remove() and load() of a
|
|
218
|
+
// missing key) so saving `undefined` does not leave the getter returning
|
|
219
|
+
// `undefined`. README's serialization table documents null/undefined as
|
|
220
|
+
// "null" on read-back.
|
|
221
|
+
this._setValue(null);
|
|
159
222
|
}
|
|
160
223
|
else if (typeof value === "string") {
|
|
161
224
|
storage.setItem(this._key, value);
|
|
225
|
+
this._setValue(value);
|
|
162
226
|
}
|
|
163
227
|
else {
|
|
164
228
|
storage.setItem(this._key, JSON.stringify(value));
|
|
229
|
+
this._setValue(value);
|
|
165
230
|
}
|
|
166
|
-
this._setValue(value);
|
|
167
231
|
this._setLoading(false);
|
|
168
232
|
}
|
|
169
233
|
catch (e) {
|
|
170
|
-
this._setError(e);
|
|
234
|
+
this._setError(this._toStorageError("save", e));
|
|
171
235
|
this._setLoading(false);
|
|
172
236
|
}
|
|
173
237
|
}
|
|
@@ -184,7 +248,7 @@ class StorageCore extends EventTarget {
|
|
|
184
248
|
this._setLoading(false);
|
|
185
249
|
}
|
|
186
250
|
catch (e) {
|
|
187
|
-
this._setError(e);
|
|
251
|
+
this._setError(this._toStorageError("remove", e));
|
|
188
252
|
this._setLoading(false);
|
|
189
253
|
}
|
|
190
254
|
}
|
|
@@ -196,6 +260,12 @@ class StorageCore extends EventTarget {
|
|
|
196
260
|
return;
|
|
197
261
|
if (this._type === "session")
|
|
198
262
|
return;
|
|
263
|
+
// A fresh value arriving from another tab supersedes any stale error from
|
|
264
|
+
// a prior failed load/save/remove. Clearing it here keeps the sync path
|
|
265
|
+
// consistent with load()/save()/remove(), which all reset error to null at
|
|
266
|
+
// the start of a successful operation — otherwise an "error present + fresh
|
|
267
|
+
// value" inconsistency could persist after a cross-tab update.
|
|
268
|
+
this._setError(null);
|
|
199
269
|
if (e.newValue === null) {
|
|
200
270
|
this._setValue(null);
|
|
201
271
|
}
|
|
@@ -248,17 +318,45 @@ class Storage extends HTMLElement {
|
|
|
248
318
|
...StorageCore.wcBindable,
|
|
249
319
|
properties: [
|
|
250
320
|
...StorageCore.wcBindable.properties,
|
|
251
|
-
{ name: "trigger", event:
|
|
321
|
+
{ name: "trigger", event: STORAGE_EVENTS.triggerChanged },
|
|
322
|
+
],
|
|
323
|
+
// Shell-level input surface. The Core declares only the portable `key` / `type`;
|
|
324
|
+
// the Shell adds the DOM-driven settable surface. No `attribute` hints are given:
|
|
325
|
+
// the `key` / `type` / `manual` setters already reflect to their attributes, so a
|
|
326
|
+
// binding system that mirrors inputs[].attribute would set the attribute twice
|
|
327
|
+
// (`value` / `trigger` are not attribute-backed). `commands` (load / save / remove)
|
|
328
|
+
// are inherited unchanged from the Core via the spread above.
|
|
329
|
+
inputs: [
|
|
330
|
+
{ name: "key" },
|
|
331
|
+
{ name: "type" },
|
|
332
|
+
{ name: "value" },
|
|
333
|
+
{ name: "manual" },
|
|
334
|
+
{ name: "trigger" },
|
|
252
335
|
],
|
|
253
336
|
};
|
|
254
337
|
static get observedAttributes() { return ["key", "type"]; }
|
|
255
338
|
_core;
|
|
256
339
|
_trigger = false;
|
|
340
|
+
// Storage load()/save() are synchronous, so connection work never defers.
|
|
341
|
+
// This stays an already-resolved Promise for the whole lifecycle; it exists
|
|
342
|
+
// only to satisfy the `hasConnectedCallbackPromise` protocol (consumers may
|
|
343
|
+
// `await el.connectedCallbackPromise`). connectedCallback intentionally does
|
|
344
|
+
// not reassign it — there is nothing async to wait for, unlike <wcs-fetch>.
|
|
257
345
|
_connectedCallbackPromise = Promise.resolve();
|
|
258
346
|
constructor() {
|
|
259
347
|
super();
|
|
260
348
|
this._core = new StorageCore(this);
|
|
261
349
|
}
|
|
350
|
+
// Push the Shell's current attribute-derived key / type down into the Core.
|
|
351
|
+
// Every operation (load / save / remove / value setter) and every lifecycle
|
|
352
|
+
// hook that may run a Core operation or cross-tab sync must do this first, so
|
|
353
|
+
// the Core never acts on a stale key / type. Centralizing it here avoids the
|
|
354
|
+
// previous pattern of repeating `_core.key = …; _core.type = …;` at each call
|
|
355
|
+
// site, which risked a future call site forgetting one of the two.
|
|
356
|
+
_syncCore() {
|
|
357
|
+
this._core.key = this.key;
|
|
358
|
+
this._core.type = this.type;
|
|
359
|
+
}
|
|
262
360
|
get key() {
|
|
263
361
|
return this.getAttribute("key") || "";
|
|
264
362
|
}
|
|
@@ -266,7 +364,11 @@ class Storage extends HTMLElement {
|
|
|
266
364
|
this.setAttribute("key", value);
|
|
267
365
|
}
|
|
268
366
|
get type() {
|
|
269
|
-
|
|
367
|
+
// Normalize at the Shell boundary: any attribute value other than the
|
|
368
|
+
// exact "session" falls back to "local". This keeps an invalid attribute
|
|
369
|
+
// (e.g. type="foo") from reaching the Core's validating setter and throwing
|
|
370
|
+
// out of setAttribute / connectedCallback.
|
|
371
|
+
return this.getAttribute("type") === "session" ? "session" : "local";
|
|
270
372
|
}
|
|
271
373
|
set type(value) {
|
|
272
374
|
this.setAttribute("type", value);
|
|
@@ -275,11 +377,23 @@ class Storage extends HTMLElement {
|
|
|
275
377
|
return this._core.value;
|
|
276
378
|
}
|
|
277
379
|
set value(v) {
|
|
380
|
+
// Non-manual mode: assigning `value` auto-saves the *assigned* argument `v`
|
|
381
|
+
// (write-through). Note this differs from save()/trigger, which persist the
|
|
382
|
+
// *current* `_core.value` (which load() or a cross-tab `storage` event may
|
|
383
|
+
// have updated). See README "Design Notes" for the rationale.
|
|
384
|
+
//
|
|
385
|
+
// Manual mode: assigning `value` does NOT persist — it only stages the value
|
|
386
|
+
// into the Core (no storage write). This keeps the getter/setter consistent
|
|
387
|
+
// (`el.value = x; el.value === x`) and lets a later save()/trigger commit the
|
|
388
|
+
// staged value, so a `value: …` + `trigger: …` binding pair works as
|
|
389
|
+
// documented. The actual write still happens only via save()/trigger.
|
|
278
390
|
if (!this.manual) {
|
|
279
|
-
this.
|
|
280
|
-
this._core.type = this.type;
|
|
391
|
+
this._syncCore();
|
|
281
392
|
this._core.save(v);
|
|
282
393
|
}
|
|
394
|
+
else {
|
|
395
|
+
this._core.value = v;
|
|
396
|
+
}
|
|
283
397
|
}
|
|
284
398
|
get loading() {
|
|
285
399
|
return this._core.loading;
|
|
@@ -308,37 +422,58 @@ class Storage extends HTMLElement {
|
|
|
308
422
|
const v = !!value;
|
|
309
423
|
if (v) {
|
|
310
424
|
this._trigger = true;
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}
|
|
425
|
+
// save() may raise (e.g. key unset). Guarantee the trigger resets to
|
|
426
|
+
// false and the completion event fires even on failure, so the trigger
|
|
427
|
+
// never gets stuck in the `true` state.
|
|
428
|
+
try {
|
|
429
|
+
this.save();
|
|
430
|
+
}
|
|
431
|
+
finally {
|
|
432
|
+
this._trigger = false;
|
|
433
|
+
this.dispatchEvent(new CustomEvent(STORAGE_EVENTS.triggerChanged, {
|
|
434
|
+
detail: false,
|
|
435
|
+
bubbles: true,
|
|
436
|
+
}));
|
|
437
|
+
}
|
|
317
438
|
}
|
|
318
439
|
}
|
|
319
440
|
load() {
|
|
320
|
-
this.
|
|
321
|
-
this._core.type = this.type;
|
|
441
|
+
this._syncCore();
|
|
322
442
|
return this._core.load();
|
|
323
443
|
}
|
|
444
|
+
// The `save` command differs in arity between the two CSBC surfaces:
|
|
445
|
+
// - Core: save(value) — caller supplies the value to persist
|
|
446
|
+
// - Shell: save() — persists the current `_core.value` (no argument)
|
|
447
|
+
// Both are exposed under the same `commands` entry name "save". The protocol
|
|
448
|
+
// `commands` list is descriptive metadata only and carries no arity, so this
|
|
449
|
+
// is not a protocol violation; the difference is contractual and documented
|
|
450
|
+
// in the README ("Design Notes").
|
|
324
451
|
save() {
|
|
325
|
-
this.
|
|
326
|
-
this._core.type = this.type;
|
|
452
|
+
this._syncCore();
|
|
327
453
|
this._core.save(this._core.value);
|
|
328
454
|
}
|
|
329
455
|
remove() {
|
|
330
|
-
this.
|
|
331
|
-
this._core.type = this.type;
|
|
456
|
+
this._syncCore();
|
|
332
457
|
this._core.remove();
|
|
333
458
|
}
|
|
334
459
|
attributeChangedCallback(name, _oldValue, newValue) {
|
|
335
460
|
if (!this.isConnected)
|
|
336
461
|
return;
|
|
337
|
-
if (name === "key"
|
|
338
|
-
|
|
462
|
+
if (name === "key") {
|
|
463
|
+
// Always keep the Core's key in sync with the attribute, regardless of
|
|
464
|
+
// mode or whether the new value is empty. The cross-tab `storage` listener
|
|
465
|
+
// compares `e.key !== _core.key`, so a stale Core key would make sync watch
|
|
466
|
+
// the wrong (old/empty) key after a runtime key change. load() (which also
|
|
467
|
+
// syncs the Core) only runs for non-manual mode with a non-empty key.
|
|
468
|
+
this._syncCore();
|
|
469
|
+
if (newValue && !this.manual) {
|
|
470
|
+
this.load();
|
|
471
|
+
}
|
|
339
472
|
}
|
|
340
473
|
if (name === "type") {
|
|
341
|
-
|
|
474
|
+
// Route through the normalizing getter so an invalid attribute value
|
|
475
|
+
// (e.g. type="foo") falls back to "local" instead of throwing.
|
|
476
|
+
this._syncCore();
|
|
342
477
|
}
|
|
343
478
|
}
|
|
344
479
|
connectedCallback() {
|
|
@@ -349,8 +484,14 @@ class Storage extends HTMLElement {
|
|
|
349
484
|
if (!this.manual && this.key) {
|
|
350
485
|
this.load();
|
|
351
486
|
}
|
|
487
|
+
// Always bind the cross-tab watcher to the Shell's current key/type before
|
|
488
|
+
// starting sync. In paths where load()/save() never run (e.g. manual mode,
|
|
489
|
+
// or key set via JS without a load), _core.key/_core.type would otherwise
|
|
490
|
+
// keep a stale/empty value and the storage listener's `e.key !== _key`
|
|
491
|
+
// check would compare against the wrong key. This also covers detach →
|
|
492
|
+
// re-attach: stale Core key from a previous session is overwritten here.
|
|
493
|
+
this._syncCore();
|
|
352
494
|
this._core.startSync();
|
|
353
|
-
this._connectedCallbackPromise = Promise.resolve();
|
|
354
495
|
}
|
|
355
496
|
disconnectedCallback() {
|
|
356
497
|
this._core.stopSync();
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/raiseError.ts","../src/core/StorageCore.ts","../src/autoTrigger.ts","../src/components/Storage.ts","../src/registerComponents.ts","../src/bootstrapStorage.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n autoTrigger: boolean;\n triggerAttribute: string;\n tagNames: {\n storage: string;\n };\n}\n\nconst _config: IInternalConfig = {\n autoTrigger: true,\n triggerAttribute: \"data-storagetarget\",\n tagNames: {\n storage: \"wcs-storage\",\n },\n};\n\nfunction deepFreeze<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n Object.freeze(obj);\n for (const key of Object.keys(obj)) {\n deepFreeze((obj as Record<string, unknown>)[key]);\n }\n return obj;\n}\n\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n const clone: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n clone[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return clone as T;\n}\n\nlet frozenConfig: IConfig | null = null;\n\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n if (!frozenConfig) {\n frozenConfig = deepFreeze(deepClone(_config));\n }\n return frozenConfig;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (typeof partialConfig.autoTrigger === \"boolean\") {\n _config.autoTrigger = partialConfig.autoTrigger;\n }\n if (typeof partialConfig.triggerAttribute === \"string\") {\n _config.triggerAttribute = partialConfig.triggerAttribute;\n }\n if (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","export function raiseError(message: string): never {\n throw new Error(`[@wcstack/storage] ${message}`);\n}\n","import { raiseError } from \"../raiseError.js\";\nimport { IWcBindable, StorageType } from \"../types.js\";\n\nexport class StorageCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"value\", event: \"wcs-storage:value-changed\", getter: (e: Event) => (e as CustomEvent).detail },\n { name: \"loading\", event: \"wcs-storage:loading-changed\" },\n { name: \"error\", event: \"wcs-storage:error\" },\n ],\n };\n\n private _target: EventTarget;\n private _value: any = null;\n private _loading: boolean = false;\n private _error: any = null;\n private _key: string = \"\";\n private _type: StorageType = \"local\";\n private _storageListener: ((e: StorageEvent) => void) | null = null;\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get value(): any {\n return this._value;\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): any {\n return this._error;\n }\n\n get key(): string {\n return this._key;\n }\n\n set key(value: string) {\n this._key = value;\n }\n\n get type(): StorageType {\n return this._type;\n }\n\n set type(value: StorageType) {\n if (value !== \"local\" && value !== \"session\") {\n raiseError(`Invalid storage type: \"${value}\". Must be \"local\" or \"session\".`);\n }\n this._type = value;\n }\n\n private _getStorage(): globalThis.Storage {\n return this._type === \"session\" ? sessionStorage : localStorage;\n }\n\n private _setLoading(loading: boolean): void {\n this._loading = loading;\n this._target.dispatchEvent(new CustomEvent(\"wcs-storage:loading-changed\", {\n detail: loading,\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-storage:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n private _setValue(value: any): void {\n this._value = value;\n this._target.dispatchEvent(new CustomEvent(\"wcs-storage:value-changed\", {\n detail: value,\n bubbles: true,\n }));\n }\n\n load(): any {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n const raw = storage.getItem(this._key);\n\n if (raw === null) {\n this._setValue(null);\n } else {\n try {\n this._setValue(JSON.parse(raw));\n } catch {\n this._setValue(raw);\n }\n }\n\n this._setLoading(false);\n return this._value;\n } catch (e: any) {\n this._setError(e);\n this._setLoading(false);\n return null;\n }\n }\n\n save(value: any): void {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n\n if (value === null || value === undefined) {\n storage.removeItem(this._key);\n } else if (typeof value === \"string\") {\n storage.setItem(this._key, value);\n } else {\n storage.setItem(this._key, JSON.stringify(value));\n }\n\n this._setValue(value);\n this._setLoading(false);\n } catch (e: any) {\n this._setError(e);\n this._setLoading(false);\n }\n }\n\n remove(): void {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n storage.removeItem(this._key);\n this._setValue(null);\n this._setLoading(false);\n } catch (e: any) {\n this._setError(e);\n this._setLoading(false);\n }\n }\n\n startSync(): void {\n if (this._storageListener) return;\n\n this._storageListener = (e: StorageEvent) => {\n if (e.key !== this._key) return;\n if (this._type === \"session\") return;\n\n if (e.newValue === null) {\n this._setValue(null);\n } else {\n try {\n this._setValue(JSON.parse(e.newValue));\n } catch {\n this._setValue(e.newValue);\n }\n }\n };\n\n globalThis.addEventListener(\"storage\", this._storageListener);\n }\n\n stopSync(): void {\n if (!this._storageListener) return;\n globalThis.removeEventListener(\"storage\", this._storageListener);\n this._storageListener = null;\n }\n}\n","import { config } from \"./config.js\";\nimport { Storage } from \"./components/Storage.js\";\n\nlet registered = false;\n\nfunction handleClick(event: Event): void {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const triggerElement = target.closest<Element>(`[${config.triggerAttribute}]`);\n if (!triggerElement) return;\n\n const storageId = triggerElement.getAttribute(config.triggerAttribute);\n if (!storageId) return;\n\n const storageElement = document.getElementById(storageId) as Storage | null;\n if (!storageElement || !(storageElement instanceof Storage)) return;\n\n event.preventDefault();\n storageElement.save();\n}\n\nexport function registerAutoTrigger(): void {\n if (registered) return;\n registered = true;\n document.addEventListener(\"click\", handleClick);\n}\n\nexport function unregisterAutoTrigger(): void {\n if (!registered) return;\n registered = false;\n document.removeEventListener(\"click\", handleClick);\n}\n","import { config } from \"../config.js\";\nimport { IWcBindable, StorageType } from \"../types.js\";\nimport { StorageCore } from \"../core/StorageCore.js\";\nimport { registerAutoTrigger } from \"../autoTrigger.js\";\n\nexport class Storage extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n static wcBindable: IWcBindable = {\n ...StorageCore.wcBindable,\n properties: [\n ...StorageCore.wcBindable.properties,\n { name: \"trigger\", event: \"wcs-storage:trigger-changed\" },\n ],\n };\n static get observedAttributes(): string[] { return [\"key\", \"type\"]; }\n\n private _core: StorageCore;\n private _trigger: boolean = false;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new StorageCore(this);\n }\n\n get key(): string {\n return this.getAttribute(\"key\") || \"\";\n }\n\n set key(value: string) {\n this.setAttribute(\"key\", value);\n }\n\n get type(): StorageType {\n return (this.getAttribute(\"type\") as StorageType) || \"local\";\n }\n\n set type(value: StorageType) {\n this.setAttribute(\"type\", value);\n }\n\n get value(): any {\n return this._core.value;\n }\n\n set value(v: any) {\n if (!this.manual) {\n this._core.key = this.key;\n this._core.type = this.type;\n this._core.save(v);\n }\n }\n\n get loading(): boolean {\n return this._core.loading;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n get manual(): boolean {\n return this.hasAttribute(\"manual\");\n }\n\n set manual(value: boolean) {\n if (value) {\n this.setAttribute(\"manual\", \"\");\n } else {\n this.removeAttribute(\"manual\");\n }\n }\n\n get trigger(): boolean {\n return this._trigger;\n }\n\n set trigger(value: boolean) {\n const v = !!value;\n if (v) {\n this._trigger = true;\n this.save();\n this._trigger = false;\n this.dispatchEvent(new CustomEvent(\"wcs-storage:trigger-changed\", {\n detail: false,\n bubbles: true,\n }));\n }\n }\n\n load(): any {\n this._core.key = this.key;\n this._core.type = this.type;\n return this._core.load();\n }\n\n save(): void {\n this._core.key = this.key;\n this._core.type = this.type;\n this._core.save(this._core.value);\n }\n\n remove(): void {\n this._core.key = this.key;\n this._core.type = this.type;\n this._core.remove();\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n if (!this.isConnected) return;\n if (name === \"key\" && newValue && !this.manual) {\n this.load();\n }\n if (name === \"type\") {\n this._core.type = (newValue as StorageType) || \"local\";\n }\n }\n\n connectedCallback(): void {\n this.style.display = \"none\";\n if (config.autoTrigger) {\n registerAutoTrigger();\n }\n if (!this.manual && this.key) {\n this.load();\n }\n this._core.startSync();\n this._connectedCallbackPromise = Promise.resolve();\n }\n\n disconnectedCallback(): void {\n this._core.stopSync();\n }\n}\n","import { Storage } from \"./components/Storage.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.storage)) {\n customElements.define(config.tagNames.storage, Storage);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapStorage(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/events.ts","../src/raiseError.ts","../src/core/StorageCore.ts","../src/autoTrigger.ts","../src/components/Storage.ts","../src/registerComponents.ts","../src/bootstrapStorage.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n autoTrigger: boolean;\n triggerAttribute: string;\n tagNames: {\n storage: string;\n };\n}\n\nconst _config: IInternalConfig = {\n autoTrigger: true,\n triggerAttribute: \"data-storagetarget\",\n tagNames: {\n storage: \"wcs-storage\",\n },\n};\n\nfunction deepFreeze<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n Object.freeze(obj);\n for (const key of Object.keys(obj)) {\n deepFreeze((obj as Record<string, unknown>)[key]);\n }\n return obj;\n}\n\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n const clone: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n clone[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return clone as T;\n}\n\nlet frozenConfig: IConfig | null = null;\n\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n if (!frozenConfig) {\n frozenConfig = deepFreeze(deepClone(_config));\n }\n return frozenConfig;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (typeof partialConfig.autoTrigger === \"boolean\") {\n _config.autoTrigger = partialConfig.autoTrigger;\n }\n if (typeof partialConfig.triggerAttribute === \"string\") {\n _config.triggerAttribute = partialConfig.triggerAttribute;\n }\n if (partialConfig.tagNames) {\n // Validate each tagNames entry individually instead of a blanket\n // Object.assign: a non-string (e.g. { storage: undefined }) would otherwise\n // poison the config and make customElements.define(undefined, …) throw at\n // registration time. Mirrors the typeof guards on autoTrigger / triggerAttribute.\n for (const [key, value] of Object.entries(partialConfig.tagNames)) {\n if (typeof value === \"string\") {\n (_config.tagNames as Record<string, string>)[key] = value;\n }\n }\n }\n frozenConfig = null;\n}\n","// Single source of truth for the custom event names dispatched by StorageCore /\n// Storage. These names appear in two places that must stay in lock-step:\n// 1. the `wcBindable.properties[].event` declarations (consumed by bind())\n// 2. the `dispatchEvent(new CustomEvent(...))` calls that emit them\n// Hard-coding the same string literal in both places risks a silent typo that\n// makes bind() listen for an event no one ever fires. Referencing these\n// constants from both sites keeps them in sync.\nexport const STORAGE_EVENTS = {\n valueChanged: \"wcs-storage:value-changed\",\n loadingChanged: \"wcs-storage:loading-changed\",\n error: \"wcs-storage:error\",\n triggerChanged: \"wcs-storage:trigger-changed\",\n} as const;\n","export function raiseError(message: string): never {\n throw new Error(`[@wcstack/storage] ${message}`);\n}\n","import { raiseError } from \"../raiseError.js\";\nimport { STORAGE_EVENTS } from \"../events.js\";\nimport { IWcBindable, StorageType, WcsStorageError } from \"../types.js\";\n\nexport class StorageCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"value\", event: STORAGE_EVENTS.valueChanged, getter: (e: Event) => (e as CustomEvent).detail },\n { name: \"loading\", event: STORAGE_EVENTS.loadingChanged },\n { name: \"error\", event: STORAGE_EVENTS.error },\n ],\n inputs: [\n { name: \"key\" },\n { name: \"type\" },\n ],\n // load / save / remove are synchronous, so none carry the `async` hint.\n commands: [\n { name: \"load\" },\n { name: \"save\" },\n { name: \"remove\" },\n ],\n };\n\n private _target: EventTarget;\n private _value: any = null;\n private _loading: boolean = false;\n private _error: any = null;\n private _key: string = \"\";\n private _type: StorageType = \"local\";\n private _storageListener: ((e: StorageEvent) => void) | null = null;\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get value(): any {\n return this._value;\n }\n\n // Set the current value *without* persisting it. Persistence happens only via\n // save() / remove() / a cross-tab storage event. This setter exists so the\n // Shell (manual mode) can stage a value handed in via a `value` binding and\n // then commit it later with save()/trigger. It mirrors the value to observers\n // through the same `value-changed` event load()/save() use (CSBC: a Core value\n // change is observable), but it deliberately does not touch storage.\n //\n // Same-value writes are skipped to break a potential feedback loop:\n // value-changed → state binding → value setter → value-changed → …\n set value(v: any) {\n if (Object.is(v, this._value)) return;\n this._setValue(v);\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): any {\n return this._error;\n }\n\n get key(): string {\n return this._key;\n }\n\n set key(value: string) {\n // Defensive normalization for direct Core use (the Shell already passes a\n // string via `getAttribute(\"key\") || \"\"`). Coercing to String keeps a\n // non-string assignment from poisoning the cross-tab `e.key !== _key`\n // comparison; empty keys are still rejected at operation time.\n this._key = String(value);\n }\n\n get type(): StorageType {\n return this._type;\n }\n\n set type(value: StorageType) {\n if (value !== \"local\" && value !== \"session\") {\n raiseError(`Invalid storage type: \"${value}\". Must be \"local\" or \"session\".`);\n }\n this._type = value;\n }\n\n private _getStorage(): globalThis.Storage {\n return this._type === \"session\" ? sessionStorage : localStorage;\n }\n\n private _setLoading(loading: boolean): void {\n this._loading = loading;\n this._target.dispatchEvent(new CustomEvent(STORAGE_EVENTS.loadingChanged, {\n detail: loading,\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(STORAGE_EVENTS.error, {\n detail: error,\n bubbles: true,\n }));\n }\n\n // Wrap a caught storage exception into the documented WcsStorageError shape,\n // tagging it with the failing operation so consumers know which call failed.\n private _toStorageError(operation: WcsStorageError[\"operation\"], e: unknown): WcsStorageError {\n return {\n operation,\n message: e instanceof Error ? e.message : String(e),\n };\n }\n\n private _setValue(value: any): void {\n this._value = value;\n this._target.dispatchEvent(new CustomEvent(STORAGE_EVENTS.valueChanged, {\n detail: value,\n bubbles: true,\n }));\n }\n\n load(): any {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n const raw = storage.getItem(this._key);\n\n if (raw === null) {\n this._setValue(null);\n } else {\n try {\n this._setValue(JSON.parse(raw));\n } catch {\n this._setValue(raw);\n }\n }\n\n this._setLoading(false);\n return this._value;\n } catch (e: any) {\n this._setError(this._toStorageError(\"load\", e));\n this._setLoading(false);\n return null;\n }\n }\n\n save(value: any): void {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n\n if (value === null || value === undefined) {\n storage.removeItem(this._key);\n // Normalize the removed value to null (matching remove() and load() of a\n // missing key) so saving `undefined` does not leave the getter returning\n // `undefined`. README's serialization table documents null/undefined as\n // \"null\" on read-back.\n this._setValue(null);\n } else if (typeof value === \"string\") {\n storage.setItem(this._key, value);\n this._setValue(value);\n } else {\n storage.setItem(this._key, JSON.stringify(value));\n this._setValue(value);\n }\n\n this._setLoading(false);\n } catch (e: any) {\n this._setError(this._toStorageError(\"save\", e));\n this._setLoading(false);\n }\n }\n\n remove(): void {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n storage.removeItem(this._key);\n this._setValue(null);\n this._setLoading(false);\n } catch (e: any) {\n this._setError(this._toStorageError(\"remove\", e));\n this._setLoading(false);\n }\n }\n\n startSync(): void {\n if (this._storageListener) return;\n\n this._storageListener = (e: StorageEvent) => {\n if (e.key !== this._key) return;\n if (this._type === \"session\") return;\n\n // A fresh value arriving from another tab supersedes any stale error from\n // a prior failed load/save/remove. Clearing it here keeps the sync path\n // consistent with load()/save()/remove(), which all reset error to null at\n // the start of a successful operation — otherwise an \"error present + fresh\n // value\" inconsistency could persist after a cross-tab update.\n this._setError(null);\n\n if (e.newValue === null) {\n this._setValue(null);\n } else {\n try {\n this._setValue(JSON.parse(e.newValue));\n } catch {\n this._setValue(e.newValue);\n }\n }\n };\n\n globalThis.addEventListener(\"storage\", this._storageListener);\n }\n\n stopSync(): void {\n if (!this._storageListener) return;\n globalThis.removeEventListener(\"storage\", this._storageListener);\n this._storageListener = null;\n }\n}\n","import { config } from \"./config.js\";\nimport { Storage } from \"./components/Storage.js\";\n\nlet registered = false;\n\nfunction handleClick(event: Event): void {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const triggerElement = target.closest<Element>(`[${config.triggerAttribute}]`);\n if (!triggerElement) return;\n\n const storageId = triggerElement.getAttribute(config.triggerAttribute);\n if (!storageId) return;\n\n const storageElement = document.getElementById(storageId) as Storage | null;\n if (!storageElement || !(storageElement instanceof Storage)) return;\n\n event.preventDefault();\n storageElement.save();\n}\n\nexport function registerAutoTrigger(): void {\n if (registered) return;\n registered = true;\n document.addEventListener(\"click\", handleClick);\n}\n\nexport function unregisterAutoTrigger(): void {\n if (!registered) return;\n registered = false;\n document.removeEventListener(\"click\", handleClick);\n}\n","import { config } from \"../config.js\";\nimport { STORAGE_EVENTS } from \"../events.js\";\nimport { IWcBindable, StorageType } from \"../types.js\";\nimport { StorageCore } from \"../core/StorageCore.js\";\nimport { registerAutoTrigger } from \"../autoTrigger.js\";\n\nexport class Storage extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n static wcBindable: IWcBindable = {\n ...StorageCore.wcBindable,\n properties: [\n ...StorageCore.wcBindable.properties,\n { name: \"trigger\", event: STORAGE_EVENTS.triggerChanged },\n ],\n // Shell-level input surface. The Core declares only the portable `key` / `type`;\n // the Shell adds the DOM-driven settable surface. No `attribute` hints are given:\n // the `key` / `type` / `manual` setters already reflect to their attributes, so a\n // binding system that mirrors inputs[].attribute would set the attribute twice\n // (`value` / `trigger` are not attribute-backed). `commands` (load / save / remove)\n // are inherited unchanged from the Core via the spread above.\n inputs: [\n { name: \"key\" },\n { name: \"type\" },\n { name: \"value\" },\n { name: \"manual\" },\n { name: \"trigger\" },\n ],\n };\n static get observedAttributes(): string[] { return [\"key\", \"type\"]; }\n\n private _core: StorageCore;\n private _trigger: boolean = false;\n // Storage load()/save() are synchronous, so connection work never defers.\n // This stays an already-resolved Promise for the whole lifecycle; it exists\n // only to satisfy the `hasConnectedCallbackPromise` protocol (consumers may\n // `await el.connectedCallbackPromise`). connectedCallback intentionally does\n // not reassign it — there is nothing async to wait for, unlike <wcs-fetch>.\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new StorageCore(this);\n }\n\n // Push the Shell's current attribute-derived key / type down into the Core.\n // Every operation (load / save / remove / value setter) and every lifecycle\n // hook that may run a Core operation or cross-tab sync must do this first, so\n // the Core never acts on a stale key / type. Centralizing it here avoids the\n // previous pattern of repeating `_core.key = …; _core.type = …;` at each call\n // site, which risked a future call site forgetting one of the two.\n private _syncCore(): void {\n this._core.key = this.key;\n this._core.type = this.type;\n }\n\n get key(): string {\n return this.getAttribute(\"key\") || \"\";\n }\n\n set key(value: string) {\n this.setAttribute(\"key\", value);\n }\n\n get type(): StorageType {\n // Normalize at the Shell boundary: any attribute value other than the\n // exact \"session\" falls back to \"local\". This keeps an invalid attribute\n // (e.g. type=\"foo\") from reaching the Core's validating setter and throwing\n // out of setAttribute / connectedCallback.\n return this.getAttribute(\"type\") === \"session\" ? \"session\" : \"local\";\n }\n\n set type(value: StorageType) {\n this.setAttribute(\"type\", value);\n }\n\n get value(): any {\n return this._core.value;\n }\n\n set value(v: any) {\n // Non-manual mode: assigning `value` auto-saves the *assigned* argument `v`\n // (write-through). Note this differs from save()/trigger, which persist the\n // *current* `_core.value` (which load() or a cross-tab `storage` event may\n // have updated). See README \"Design Notes\" for the rationale.\n //\n // Manual mode: assigning `value` does NOT persist — it only stages the value\n // into the Core (no storage write). This keeps the getter/setter consistent\n // (`el.value = x; el.value === x`) and lets a later save()/trigger commit the\n // staged value, so a `value: …` + `trigger: …` binding pair works as\n // documented. The actual write still happens only via save()/trigger.\n if (!this.manual) {\n this._syncCore();\n this._core.save(v);\n } else {\n this._core.value = v;\n }\n }\n\n get loading(): boolean {\n return this._core.loading;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n get manual(): boolean {\n return this.hasAttribute(\"manual\");\n }\n\n set manual(value: boolean) {\n if (value) {\n this.setAttribute(\"manual\", \"\");\n } else {\n this.removeAttribute(\"manual\");\n }\n }\n\n get trigger(): boolean {\n return this._trigger;\n }\n\n set trigger(value: boolean) {\n const v = !!value;\n if (v) {\n this._trigger = true;\n // save() may raise (e.g. key unset). Guarantee the trigger resets to\n // false and the completion event fires even on failure, so the trigger\n // never gets stuck in the `true` state.\n try {\n this.save();\n } finally {\n this._trigger = false;\n this.dispatchEvent(new CustomEvent(STORAGE_EVENTS.triggerChanged, {\n detail: false,\n bubbles: true,\n }));\n }\n }\n }\n\n load(): any {\n this._syncCore();\n return this._core.load();\n }\n\n // The `save` command differs in arity between the two CSBC surfaces:\n // - Core: save(value) — caller supplies the value to persist\n // - Shell: save() — persists the current `_core.value` (no argument)\n // Both are exposed under the same `commands` entry name \"save\". The protocol\n // `commands` list is descriptive metadata only and carries no arity, so this\n // is not a protocol violation; the difference is contractual and documented\n // in the README (\"Design Notes\").\n save(): void {\n this._syncCore();\n this._core.save(this._core.value);\n }\n\n remove(): void {\n this._syncCore();\n this._core.remove();\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n if (!this.isConnected) return;\n if (name === \"key\") {\n // Always keep the Core's key in sync with the attribute, regardless of\n // mode or whether the new value is empty. The cross-tab `storage` listener\n // compares `e.key !== _core.key`, so a stale Core key would make sync watch\n // the wrong (old/empty) key after a runtime key change. load() (which also\n // syncs the Core) only runs for non-manual mode with a non-empty key.\n this._syncCore();\n if (newValue && !this.manual) {\n this.load();\n }\n }\n if (name === \"type\") {\n // Route through the normalizing getter so an invalid attribute value\n // (e.g. type=\"foo\") falls back to \"local\" instead of throwing.\n this._syncCore();\n }\n }\n\n connectedCallback(): void {\n this.style.display = \"none\";\n if (config.autoTrigger) {\n registerAutoTrigger();\n }\n if (!this.manual && this.key) {\n this.load();\n }\n // Always bind the cross-tab watcher to the Shell's current key/type before\n // starting sync. In paths where load()/save() never run (e.g. manual mode,\n // or key set via JS without a load), _core.key/_core.type would otherwise\n // keep a stale/empty value and the storage listener's `e.key !== _key`\n // check would compare against the wrong key. This also covers detach →\n // re-attach: stale Core key from a previous session is overwritten here.\n this._syncCore();\n this._core.startSync();\n }\n\n disconnectedCallback(): void {\n this._core.stopSync();\n }\n}\n","import { Storage } from \"./components/Storage.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.storage)) {\n customElements.define(config.tagNames.storage, Storage);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapStorage(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.esm.min.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e={autoTrigger:!0,triggerAttribute:"data-storagetarget",tagNames:{storage:"wcs-storage"}};function t(e){if(null===e||"object"!=typeof e)return e;Object.freeze(e);for(const s of Object.keys(e))t(e[s]);return e}function s(e){if(null===e||"object"!=typeof e)return e;const t={};for(const r of Object.keys(e))t[r]=s(e[r]);return t}let r=null;const i=e;function
|
|
1
|
+
const e={autoTrigger:!0,triggerAttribute:"data-storagetarget",tagNames:{storage:"wcs-storage"}};function t(e){if(null===e||"object"!=typeof e)return e;Object.freeze(e);for(const s of Object.keys(e))t(e[s]);return e}function s(e){if(null===e||"object"!=typeof e)return e;const t={};for(const r of Object.keys(e))t[r]=s(e[r]);return t}let r=null;const i=e;function n(){return r||(r=t(s(e))),r}const a="wcs-storage:value-changed",o="wcs-storage:loading-changed",l="wcs-storage:error",g="wcs-storage:trigger-changed";function u(e){throw new Error(`[@wcstack/storage] ${e}`)}class c extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"value",event:a,getter:e=>e.detail},{name:"loading",event:o},{name:"error",event:l}],inputs:[{name:"key"},{name:"type"}],commands:[{name:"load"},{name:"save"},{name:"remove"}]};_target;_value=null;_loading=!1;_error=null;_key="";_type="local";_storageListener=null;constructor(e){super(),this._target=e??this}get value(){return this._value}set value(e){Object.is(e,this._value)||this._setValue(e)}get loading(){return this._loading}get error(){return this._error}get key(){return this._key}set key(e){this._key=String(e)}get type(){return this._type}set type(e){"local"!==e&&"session"!==e&&u(`Invalid storage type: "${e}". Must be "local" or "session".`),this._type=e}_getStorage(){return"session"===this._type?sessionStorage:localStorage}_setLoading(e){this._loading=e,this._target.dispatchEvent(new CustomEvent(o,{detail:e,bubbles:!0}))}_setError(e){this._error=e,this._target.dispatchEvent(new CustomEvent(l,{detail:e,bubbles:!0}))}_toStorageError(e,t){return{operation:e,message:t instanceof Error?t.message:String(t)}}_setValue(e){this._value=e,this._target.dispatchEvent(new CustomEvent(a,{detail:e,bubbles:!0}))}load(){this._key||u("key is required."),this._setLoading(!0),this._setError(null);try{const e=this._getStorage().getItem(this._key);if(null===e)this._setValue(null);else try{this._setValue(JSON.parse(e))}catch{this._setValue(e)}return this._setLoading(!1),this._value}catch(e){return this._setError(this._toStorageError("load",e)),this._setLoading(!1),null}}save(e){this._key||u("key is required."),this._setLoading(!0),this._setError(null);try{const t=this._getStorage();null==e?(t.removeItem(this._key),this._setValue(null)):"string"==typeof e?(t.setItem(this._key,e),this._setValue(e)):(t.setItem(this._key,JSON.stringify(e)),this._setValue(e)),this._setLoading(!1)}catch(e){this._setError(this._toStorageError("save",e)),this._setLoading(!1)}}remove(){this._key||u("key is required."),this._setLoading(!0),this._setError(null);try{this._getStorage().removeItem(this._key),this._setValue(null),this._setLoading(!1)}catch(e){this._setError(this._toStorageError("remove",e)),this._setLoading(!1)}}startSync(){this._storageListener||(this._storageListener=e=>{if(e.key===this._key&&"session"!==this._type)if(this._setError(null),null===e.newValue)this._setValue(null);else try{this._setValue(JSON.parse(e.newValue))}catch{this._setValue(e.newValue)}},globalThis.addEventListener("storage",this._storageListener))}stopSync(){this._storageListener&&(globalThis.removeEventListener("storage",this._storageListener),this._storageListener=null)}}let h=!1;function _(e){const t=e.target;if(!(t instanceof Element))return;const s=t.closest(`[${i.triggerAttribute}]`);if(!s)return;const r=s.getAttribute(i.triggerAttribute);if(!r)return;const n=document.getElementById(r);n&&n instanceof y&&(e.preventDefault(),n.save())}class y extends HTMLElement{static hasConnectedCallbackPromise=!0;static wcBindable={...c.wcBindable,properties:[...c.wcBindable.properties,{name:"trigger",event:g}],inputs:[{name:"key"},{name:"type"},{name:"value"},{name:"manual"},{name:"trigger"}]};static get observedAttributes(){return["key","type"]}_core;_trigger=!1;_connectedCallbackPromise=Promise.resolve();constructor(){super(),this._core=new c(this)}_syncCore(){this._core.key=this.key,this._core.type=this.type}get key(){return this.getAttribute("key")||""}set key(e){this.setAttribute("key",e)}get type(){return"session"===this.getAttribute("type")?"session":"local"}set type(e){this.setAttribute("type",e)}get value(){return this._core.value}set value(e){this.manual?this._core.value=e:(this._syncCore(),this._core.save(e))}get loading(){return this._core.loading}get error(){return this._core.error}get connectedCallbackPromise(){return this._connectedCallbackPromise}get manual(){return this.hasAttribute("manual")}set manual(e){e?this.setAttribute("manual",""):this.removeAttribute("manual")}get trigger(){return this._trigger}set trigger(e){if(!!e){this._trigger=!0;try{this.save()}finally{this._trigger=!1,this.dispatchEvent(new CustomEvent(g,{detail:!1,bubbles:!0}))}}}load(){return this._syncCore(),this._core.load()}save(){this._syncCore(),this._core.save(this._core.value)}remove(){this._syncCore(),this._core.remove()}attributeChangedCallback(e,t,s){this.isConnected&&("key"===e&&(this._syncCore(),s&&!this.manual&&this.load()),"type"===e&&this._syncCore())}connectedCallback(){this.style.display="none",i.autoTrigger&&(h||(h=!0,document.addEventListener("click",_))),!this.manual&&this.key&&this.load(),this._syncCore(),this._core.startSync()}disconnectedCallback(){this._core.stopSync()}}function d(t){t&&function(t){if("boolean"==typeof t.autoTrigger&&(e.autoTrigger=t.autoTrigger),"string"==typeof t.triggerAttribute&&(e.triggerAttribute=t.triggerAttribute),t.tagNames)for(const[s,r]of Object.entries(t.tagNames))"string"==typeof r&&(e.tagNames[s]=r);r=null}(t),customElements.get(i.tagNames.storage)||customElements.define(i.tagNames.storage,y)}export{c as StorageCore,y as WcsStorage,d as bootstrapStorage,n as getConfig};
|
|
2
2
|
//# sourceMappingURL=index.esm.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.min.js","sources":["../src/config.ts","../src/raiseError.ts","../src/core/StorageCore.ts","../src/autoTrigger.ts","../src/components/Storage.ts","../src/bootstrapStorage.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n autoTrigger: boolean;\n triggerAttribute: string;\n tagNames: {\n storage: string;\n };\n}\n\nconst _config: IInternalConfig = {\n autoTrigger: true,\n triggerAttribute: \"data-storagetarget\",\n tagNames: {\n storage: \"wcs-storage\",\n },\n};\n\nfunction deepFreeze<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n Object.freeze(obj);\n for (const key of Object.keys(obj)) {\n deepFreeze((obj as Record<string, unknown>)[key]);\n }\n return obj;\n}\n\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n const clone: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n clone[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return clone as T;\n}\n\nlet frozenConfig: IConfig | null = null;\n\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n if (!frozenConfig) {\n frozenConfig = deepFreeze(deepClone(_config));\n }\n return frozenConfig;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (typeof partialConfig.autoTrigger === \"boolean\") {\n _config.autoTrigger = partialConfig.autoTrigger;\n }\n if (typeof partialConfig.triggerAttribute === \"string\") {\n _config.triggerAttribute = partialConfig.triggerAttribute;\n }\n if (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","export function raiseError(message: string): never {\n throw new Error(`[@wcstack/storage] ${message}`);\n}\n","import { raiseError } from \"../raiseError.js\";\nimport { IWcBindable, StorageType } from \"../types.js\";\n\nexport class StorageCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"value\", event: \"wcs-storage:value-changed\", getter: (e: Event) => (e as CustomEvent).detail },\n { name: \"loading\", event: \"wcs-storage:loading-changed\" },\n { name: \"error\", event: \"wcs-storage:error\" },\n ],\n };\n\n private _target: EventTarget;\n private _value: any = null;\n private _loading: boolean = false;\n private _error: any = null;\n private _key: string = \"\";\n private _type: StorageType = \"local\";\n private _storageListener: ((e: StorageEvent) => void) | null = null;\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get value(): any {\n return this._value;\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): any {\n return this._error;\n }\n\n get key(): string {\n return this._key;\n }\n\n set key(value: string) {\n this._key = value;\n }\n\n get type(): StorageType {\n return this._type;\n }\n\n set type(value: StorageType) {\n if (value !== \"local\" && value !== \"session\") {\n raiseError(`Invalid storage type: \"${value}\". Must be \"local\" or \"session\".`);\n }\n this._type = value;\n }\n\n private _getStorage(): globalThis.Storage {\n return this._type === \"session\" ? sessionStorage : localStorage;\n }\n\n private _setLoading(loading: boolean): void {\n this._loading = loading;\n this._target.dispatchEvent(new CustomEvent(\"wcs-storage:loading-changed\", {\n detail: loading,\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-storage:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n private _setValue(value: any): void {\n this._value = value;\n this._target.dispatchEvent(new CustomEvent(\"wcs-storage:value-changed\", {\n detail: value,\n bubbles: true,\n }));\n }\n\n load(): any {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n const raw = storage.getItem(this._key);\n\n if (raw === null) {\n this._setValue(null);\n } else {\n try {\n this._setValue(JSON.parse(raw));\n } catch {\n this._setValue(raw);\n }\n }\n\n this._setLoading(false);\n return this._value;\n } catch (e: any) {\n this._setError(e);\n this._setLoading(false);\n return null;\n }\n }\n\n save(value: any): void {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n\n if (value === null || value === undefined) {\n storage.removeItem(this._key);\n } else if (typeof value === \"string\") {\n storage.setItem(this._key, value);\n } else {\n storage.setItem(this._key, JSON.stringify(value));\n }\n\n this._setValue(value);\n this._setLoading(false);\n } catch (e: any) {\n this._setError(e);\n this._setLoading(false);\n }\n }\n\n remove(): void {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n storage.removeItem(this._key);\n this._setValue(null);\n this._setLoading(false);\n } catch (e: any) {\n this._setError(e);\n this._setLoading(false);\n }\n }\n\n startSync(): void {\n if (this._storageListener) return;\n\n this._storageListener = (e: StorageEvent) => {\n if (e.key !== this._key) return;\n if (this._type === \"session\") return;\n\n if (e.newValue === null) {\n this._setValue(null);\n } else {\n try {\n this._setValue(JSON.parse(e.newValue));\n } catch {\n this._setValue(e.newValue);\n }\n }\n };\n\n globalThis.addEventListener(\"storage\", this._storageListener);\n }\n\n stopSync(): void {\n if (!this._storageListener) return;\n globalThis.removeEventListener(\"storage\", this._storageListener);\n this._storageListener = null;\n }\n}\n","import { config } from \"./config.js\";\nimport { Storage } from \"./components/Storage.js\";\n\nlet registered = false;\n\nfunction handleClick(event: Event): void {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const triggerElement = target.closest<Element>(`[${config.triggerAttribute}]`);\n if (!triggerElement) return;\n\n const storageId = triggerElement.getAttribute(config.triggerAttribute);\n if (!storageId) return;\n\n const storageElement = document.getElementById(storageId) as Storage | null;\n if (!storageElement || !(storageElement instanceof Storage)) return;\n\n event.preventDefault();\n storageElement.save();\n}\n\nexport function registerAutoTrigger(): void {\n if (registered) return;\n registered = true;\n document.addEventListener(\"click\", handleClick);\n}\n\nexport function unregisterAutoTrigger(): void {\n if (!registered) return;\n registered = false;\n document.removeEventListener(\"click\", handleClick);\n}\n","import { config } from \"../config.js\";\nimport { IWcBindable, StorageType } from \"../types.js\";\nimport { StorageCore } from \"../core/StorageCore.js\";\nimport { registerAutoTrigger } from \"../autoTrigger.js\";\n\nexport class Storage extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n static wcBindable: IWcBindable = {\n ...StorageCore.wcBindable,\n properties: [\n ...StorageCore.wcBindable.properties,\n { name: \"trigger\", event: \"wcs-storage:trigger-changed\" },\n ],\n };\n static get observedAttributes(): string[] { return [\"key\", \"type\"]; }\n\n private _core: StorageCore;\n private _trigger: boolean = false;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new StorageCore(this);\n }\n\n get key(): string {\n return this.getAttribute(\"key\") || \"\";\n }\n\n set key(value: string) {\n this.setAttribute(\"key\", value);\n }\n\n get type(): StorageType {\n return (this.getAttribute(\"type\") as StorageType) || \"local\";\n }\n\n set type(value: StorageType) {\n this.setAttribute(\"type\", value);\n }\n\n get value(): any {\n return this._core.value;\n }\n\n set value(v: any) {\n if (!this.manual) {\n this._core.key = this.key;\n this._core.type = this.type;\n this._core.save(v);\n }\n }\n\n get loading(): boolean {\n return this._core.loading;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n get manual(): boolean {\n return this.hasAttribute(\"manual\");\n }\n\n set manual(value: boolean) {\n if (value) {\n this.setAttribute(\"manual\", \"\");\n } else {\n this.removeAttribute(\"manual\");\n }\n }\n\n get trigger(): boolean {\n return this._trigger;\n }\n\n set trigger(value: boolean) {\n const v = !!value;\n if (v) {\n this._trigger = true;\n this.save();\n this._trigger = false;\n this.dispatchEvent(new CustomEvent(\"wcs-storage:trigger-changed\", {\n detail: false,\n bubbles: true,\n }));\n }\n }\n\n load(): any {\n this._core.key = this.key;\n this._core.type = this.type;\n return this._core.load();\n }\n\n save(): void {\n this._core.key = this.key;\n this._core.type = this.type;\n this._core.save(this._core.value);\n }\n\n remove(): void {\n this._core.key = this.key;\n this._core.type = this.type;\n this._core.remove();\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n if (!this.isConnected) return;\n if (name === \"key\" && newValue && !this.manual) {\n this.load();\n }\n if (name === \"type\") {\n this._core.type = (newValue as StorageType) || \"local\";\n }\n }\n\n connectedCallback(): void {\n this.style.display = \"none\";\n if (config.autoTrigger) {\n registerAutoTrigger();\n }\n if (!this.manual && this.key) {\n this.load();\n }\n this._core.startSync();\n this._connectedCallbackPromise = Promise.resolve();\n }\n\n disconnectedCallback(): void {\n this._core.stopSync();\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapStorage(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { Storage } from \"./components/Storage.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.storage)) {\n customElements.define(config.tagNames.storage, Storage);\n }\n}\n"],"names":["_config","autoTrigger","triggerAttribute","tagNames","storage","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","raiseError","message","Error","StorageCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","_target","_value","_loading","_error","_key","_type","_storageListener","constructor","target","super","this","value","loading","error","type","_getStorage","sessionStorage","localStorage","_setLoading","dispatchEvent","CustomEvent","bubbles","_setError","_setValue","load","raw","getItem","JSON","parse","save","removeItem","setItem","stringify","remove","startSync","newValue","globalThis","addEventListener","stopSync","removeEventListener","registered","handleClick","Element","triggerElement","closest","storageId","getAttribute","storageElement","document","getElementById","Storage","preventDefault","HTMLElement","wcBindable","observedAttributes","_core","_trigger","_connectedCallbackPromise","Promise","resolve","setAttribute","v","manual","connectedCallbackPromise","hasAttribute","removeAttribute","trigger","attributeChangedCallback","_oldValue","isConnected","connectedCallback","style","display","disconnectedCallback","bootstrapStorage","userConfig","partialConfig","assign","customElements","get","define"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.esm.min.js","sources":["../src/config.ts","../src/events.ts","../src/raiseError.ts","../src/core/StorageCore.ts","../src/autoTrigger.ts","../src/components/Storage.ts","../src/bootstrapStorage.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n autoTrigger: boolean;\n triggerAttribute: string;\n tagNames: {\n storage: string;\n };\n}\n\nconst _config: IInternalConfig = {\n autoTrigger: true,\n triggerAttribute: \"data-storagetarget\",\n tagNames: {\n storage: \"wcs-storage\",\n },\n};\n\nfunction deepFreeze<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n Object.freeze(obj);\n for (const key of Object.keys(obj)) {\n deepFreeze((obj as Record<string, unknown>)[key]);\n }\n return obj;\n}\n\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== \"object\") return obj;\n const clone: Record<string, unknown> = {};\n for (const key of Object.keys(obj)) {\n clone[key] = deepClone((obj as Record<string, unknown>)[key]);\n }\n return clone as T;\n}\n\nlet frozenConfig: IConfig | null = null;\n\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n if (!frozenConfig) {\n frozenConfig = deepFreeze(deepClone(_config));\n }\n return frozenConfig;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (typeof partialConfig.autoTrigger === \"boolean\") {\n _config.autoTrigger = partialConfig.autoTrigger;\n }\n if (typeof partialConfig.triggerAttribute === \"string\") {\n _config.triggerAttribute = partialConfig.triggerAttribute;\n }\n if (partialConfig.tagNames) {\n // Validate each tagNames entry individually instead of a blanket\n // Object.assign: a non-string (e.g. { storage: undefined }) would otherwise\n // poison the config and make customElements.define(undefined, …) throw at\n // registration time. Mirrors the typeof guards on autoTrigger / triggerAttribute.\n for (const [key, value] of Object.entries(partialConfig.tagNames)) {\n if (typeof value === \"string\") {\n (_config.tagNames as Record<string, string>)[key] = value;\n }\n }\n }\n frozenConfig = null;\n}\n","// Single source of truth for the custom event names dispatched by StorageCore /\n// Storage. These names appear in two places that must stay in lock-step:\n// 1. the `wcBindable.properties[].event` declarations (consumed by bind())\n// 2. the `dispatchEvent(new CustomEvent(...))` calls that emit them\n// Hard-coding the same string literal in both places risks a silent typo that\n// makes bind() listen for an event no one ever fires. Referencing these\n// constants from both sites keeps them in sync.\nexport const STORAGE_EVENTS = {\n valueChanged: \"wcs-storage:value-changed\",\n loadingChanged: \"wcs-storage:loading-changed\",\n error: \"wcs-storage:error\",\n triggerChanged: \"wcs-storage:trigger-changed\",\n} as const;\n","export function raiseError(message: string): never {\n throw new Error(`[@wcstack/storage] ${message}`);\n}\n","import { raiseError } from \"../raiseError.js\";\nimport { STORAGE_EVENTS } from \"../events.js\";\nimport { IWcBindable, StorageType, WcsStorageError } from \"../types.js\";\n\nexport class StorageCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"value\", event: STORAGE_EVENTS.valueChanged, getter: (e: Event) => (e as CustomEvent).detail },\n { name: \"loading\", event: STORAGE_EVENTS.loadingChanged },\n { name: \"error\", event: STORAGE_EVENTS.error },\n ],\n inputs: [\n { name: \"key\" },\n { name: \"type\" },\n ],\n // load / save / remove are synchronous, so none carry the `async` hint.\n commands: [\n { name: \"load\" },\n { name: \"save\" },\n { name: \"remove\" },\n ],\n };\n\n private _target: EventTarget;\n private _value: any = null;\n private _loading: boolean = false;\n private _error: any = null;\n private _key: string = \"\";\n private _type: StorageType = \"local\";\n private _storageListener: ((e: StorageEvent) => void) | null = null;\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get value(): any {\n return this._value;\n }\n\n // Set the current value *without* persisting it. Persistence happens only via\n // save() / remove() / a cross-tab storage event. This setter exists so the\n // Shell (manual mode) can stage a value handed in via a `value` binding and\n // then commit it later with save()/trigger. It mirrors the value to observers\n // through the same `value-changed` event load()/save() use (CSBC: a Core value\n // change is observable), but it deliberately does not touch storage.\n //\n // Same-value writes are skipped to break a potential feedback loop:\n // value-changed → state binding → value setter → value-changed → …\n set value(v: any) {\n if (Object.is(v, this._value)) return;\n this._setValue(v);\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): any {\n return this._error;\n }\n\n get key(): string {\n return this._key;\n }\n\n set key(value: string) {\n // Defensive normalization for direct Core use (the Shell already passes a\n // string via `getAttribute(\"key\") || \"\"`). Coercing to String keeps a\n // non-string assignment from poisoning the cross-tab `e.key !== _key`\n // comparison; empty keys are still rejected at operation time.\n this._key = String(value);\n }\n\n get type(): StorageType {\n return this._type;\n }\n\n set type(value: StorageType) {\n if (value !== \"local\" && value !== \"session\") {\n raiseError(`Invalid storage type: \"${value}\". Must be \"local\" or \"session\".`);\n }\n this._type = value;\n }\n\n private _getStorage(): globalThis.Storage {\n return this._type === \"session\" ? sessionStorage : localStorage;\n }\n\n private _setLoading(loading: boolean): void {\n this._loading = loading;\n this._target.dispatchEvent(new CustomEvent(STORAGE_EVENTS.loadingChanged, {\n detail: loading,\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(STORAGE_EVENTS.error, {\n detail: error,\n bubbles: true,\n }));\n }\n\n // Wrap a caught storage exception into the documented WcsStorageError shape,\n // tagging it with the failing operation so consumers know which call failed.\n private _toStorageError(operation: WcsStorageError[\"operation\"], e: unknown): WcsStorageError {\n return {\n operation,\n message: e instanceof Error ? e.message : String(e),\n };\n }\n\n private _setValue(value: any): void {\n this._value = value;\n this._target.dispatchEvent(new CustomEvent(STORAGE_EVENTS.valueChanged, {\n detail: value,\n bubbles: true,\n }));\n }\n\n load(): any {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n const raw = storage.getItem(this._key);\n\n if (raw === null) {\n this._setValue(null);\n } else {\n try {\n this._setValue(JSON.parse(raw));\n } catch {\n this._setValue(raw);\n }\n }\n\n this._setLoading(false);\n return this._value;\n } catch (e: any) {\n this._setError(this._toStorageError(\"load\", e));\n this._setLoading(false);\n return null;\n }\n }\n\n save(value: any): void {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n\n if (value === null || value === undefined) {\n storage.removeItem(this._key);\n // Normalize the removed value to null (matching remove() and load() of a\n // missing key) so saving `undefined` does not leave the getter returning\n // `undefined`. README's serialization table documents null/undefined as\n // \"null\" on read-back.\n this._setValue(null);\n } else if (typeof value === \"string\") {\n storage.setItem(this._key, value);\n this._setValue(value);\n } else {\n storage.setItem(this._key, JSON.stringify(value));\n this._setValue(value);\n }\n\n this._setLoading(false);\n } catch (e: any) {\n this._setError(this._toStorageError(\"save\", e));\n this._setLoading(false);\n }\n }\n\n remove(): void {\n if (!this._key) {\n raiseError(\"key is required.\");\n }\n\n this._setLoading(true);\n this._setError(null);\n\n try {\n const storage = this._getStorage();\n storage.removeItem(this._key);\n this._setValue(null);\n this._setLoading(false);\n } catch (e: any) {\n this._setError(this._toStorageError(\"remove\", e));\n this._setLoading(false);\n }\n }\n\n startSync(): void {\n if (this._storageListener) return;\n\n this._storageListener = (e: StorageEvent) => {\n if (e.key !== this._key) return;\n if (this._type === \"session\") return;\n\n // A fresh value arriving from another tab supersedes any stale error from\n // a prior failed load/save/remove. Clearing it here keeps the sync path\n // consistent with load()/save()/remove(), which all reset error to null at\n // the start of a successful operation — otherwise an \"error present + fresh\n // value\" inconsistency could persist after a cross-tab update.\n this._setError(null);\n\n if (e.newValue === null) {\n this._setValue(null);\n } else {\n try {\n this._setValue(JSON.parse(e.newValue));\n } catch {\n this._setValue(e.newValue);\n }\n }\n };\n\n globalThis.addEventListener(\"storage\", this._storageListener);\n }\n\n stopSync(): void {\n if (!this._storageListener) return;\n globalThis.removeEventListener(\"storage\", this._storageListener);\n this._storageListener = null;\n }\n}\n","import { config } from \"./config.js\";\nimport { Storage } from \"./components/Storage.js\";\n\nlet registered = false;\n\nfunction handleClick(event: Event): void {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const triggerElement = target.closest<Element>(`[${config.triggerAttribute}]`);\n if (!triggerElement) return;\n\n const storageId = triggerElement.getAttribute(config.triggerAttribute);\n if (!storageId) return;\n\n const storageElement = document.getElementById(storageId) as Storage | null;\n if (!storageElement || !(storageElement instanceof Storage)) return;\n\n event.preventDefault();\n storageElement.save();\n}\n\nexport function registerAutoTrigger(): void {\n if (registered) return;\n registered = true;\n document.addEventListener(\"click\", handleClick);\n}\n\nexport function unregisterAutoTrigger(): void {\n if (!registered) return;\n registered = false;\n document.removeEventListener(\"click\", handleClick);\n}\n","import { config } from \"../config.js\";\nimport { STORAGE_EVENTS } from \"../events.js\";\nimport { IWcBindable, StorageType } from \"../types.js\";\nimport { StorageCore } from \"../core/StorageCore.js\";\nimport { registerAutoTrigger } from \"../autoTrigger.js\";\n\nexport class Storage extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n static wcBindable: IWcBindable = {\n ...StorageCore.wcBindable,\n properties: [\n ...StorageCore.wcBindable.properties,\n { name: \"trigger\", event: STORAGE_EVENTS.triggerChanged },\n ],\n // Shell-level input surface. The Core declares only the portable `key` / `type`;\n // the Shell adds the DOM-driven settable surface. No `attribute` hints are given:\n // the `key` / `type` / `manual` setters already reflect to their attributes, so a\n // binding system that mirrors inputs[].attribute would set the attribute twice\n // (`value` / `trigger` are not attribute-backed). `commands` (load / save / remove)\n // are inherited unchanged from the Core via the spread above.\n inputs: [\n { name: \"key\" },\n { name: \"type\" },\n { name: \"value\" },\n { name: \"manual\" },\n { name: \"trigger\" },\n ],\n };\n static get observedAttributes(): string[] { return [\"key\", \"type\"]; }\n\n private _core: StorageCore;\n private _trigger: boolean = false;\n // Storage load()/save() are synchronous, so connection work never defers.\n // This stays an already-resolved Promise for the whole lifecycle; it exists\n // only to satisfy the `hasConnectedCallbackPromise` protocol (consumers may\n // `await el.connectedCallbackPromise`). connectedCallback intentionally does\n // not reassign it — there is nothing async to wait for, unlike <wcs-fetch>.\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new StorageCore(this);\n }\n\n // Push the Shell's current attribute-derived key / type down into the Core.\n // Every operation (load / save / remove / value setter) and every lifecycle\n // hook that may run a Core operation or cross-tab sync must do this first, so\n // the Core never acts on a stale key / type. Centralizing it here avoids the\n // previous pattern of repeating `_core.key = …; _core.type = …;` at each call\n // site, which risked a future call site forgetting one of the two.\n private _syncCore(): void {\n this._core.key = this.key;\n this._core.type = this.type;\n }\n\n get key(): string {\n return this.getAttribute(\"key\") || \"\";\n }\n\n set key(value: string) {\n this.setAttribute(\"key\", value);\n }\n\n get type(): StorageType {\n // Normalize at the Shell boundary: any attribute value other than the\n // exact \"session\" falls back to \"local\". This keeps an invalid attribute\n // (e.g. type=\"foo\") from reaching the Core's validating setter and throwing\n // out of setAttribute / connectedCallback.\n return this.getAttribute(\"type\") === \"session\" ? \"session\" : \"local\";\n }\n\n set type(value: StorageType) {\n this.setAttribute(\"type\", value);\n }\n\n get value(): any {\n return this._core.value;\n }\n\n set value(v: any) {\n // Non-manual mode: assigning `value` auto-saves the *assigned* argument `v`\n // (write-through). Note this differs from save()/trigger, which persist the\n // *current* `_core.value` (which load() or a cross-tab `storage` event may\n // have updated). See README \"Design Notes\" for the rationale.\n //\n // Manual mode: assigning `value` does NOT persist — it only stages the value\n // into the Core (no storage write). This keeps the getter/setter consistent\n // (`el.value = x; el.value === x`) and lets a later save()/trigger commit the\n // staged value, so a `value: …` + `trigger: …` binding pair works as\n // documented. The actual write still happens only via save()/trigger.\n if (!this.manual) {\n this._syncCore();\n this._core.save(v);\n } else {\n this._core.value = v;\n }\n }\n\n get loading(): boolean {\n return this._core.loading;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n get manual(): boolean {\n return this.hasAttribute(\"manual\");\n }\n\n set manual(value: boolean) {\n if (value) {\n this.setAttribute(\"manual\", \"\");\n } else {\n this.removeAttribute(\"manual\");\n }\n }\n\n get trigger(): boolean {\n return this._trigger;\n }\n\n set trigger(value: boolean) {\n const v = !!value;\n if (v) {\n this._trigger = true;\n // save() may raise (e.g. key unset). Guarantee the trigger resets to\n // false and the completion event fires even on failure, so the trigger\n // never gets stuck in the `true` state.\n try {\n this.save();\n } finally {\n this._trigger = false;\n this.dispatchEvent(new CustomEvent(STORAGE_EVENTS.triggerChanged, {\n detail: false,\n bubbles: true,\n }));\n }\n }\n }\n\n load(): any {\n this._syncCore();\n return this._core.load();\n }\n\n // The `save` command differs in arity between the two CSBC surfaces:\n // - Core: save(value) — caller supplies the value to persist\n // - Shell: save() — persists the current `_core.value` (no argument)\n // Both are exposed under the same `commands` entry name \"save\". The protocol\n // `commands` list is descriptive metadata only and carries no arity, so this\n // is not a protocol violation; the difference is contractual and documented\n // in the README (\"Design Notes\").\n save(): void {\n this._syncCore();\n this._core.save(this._core.value);\n }\n\n remove(): void {\n this._syncCore();\n this._core.remove();\n }\n\n attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void {\n if (!this.isConnected) return;\n if (name === \"key\") {\n // Always keep the Core's key in sync with the attribute, regardless of\n // mode or whether the new value is empty. The cross-tab `storage` listener\n // compares `e.key !== _core.key`, so a stale Core key would make sync watch\n // the wrong (old/empty) key after a runtime key change. load() (which also\n // syncs the Core) only runs for non-manual mode with a non-empty key.\n this._syncCore();\n if (newValue && !this.manual) {\n this.load();\n }\n }\n if (name === \"type\") {\n // Route through the normalizing getter so an invalid attribute value\n // (e.g. type=\"foo\") falls back to \"local\" instead of throwing.\n this._syncCore();\n }\n }\n\n connectedCallback(): void {\n this.style.display = \"none\";\n if (config.autoTrigger) {\n registerAutoTrigger();\n }\n if (!this.manual && this.key) {\n this.load();\n }\n // Always bind the cross-tab watcher to the Shell's current key/type before\n // starting sync. In paths where load()/save() never run (e.g. manual mode,\n // or key set via JS without a load), _core.key/_core.type would otherwise\n // keep a stale/empty value and the storage listener's `e.key !== _key`\n // check would compare against the wrong key. This also covers detach →\n // re-attach: stale Core key from a previous session is overwritten here.\n this._syncCore();\n this._core.startSync();\n }\n\n disconnectedCallback(): void {\n this._core.stopSync();\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapStorage(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { Storage } from \"./components/Storage.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.storage)) {\n customElements.define(config.tagNames.storage, Storage);\n }\n}\n"],"names":["_config","autoTrigger","triggerAttribute","tagNames","storage","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","STORAGE_EVENTS","raiseError","message","Error","StorageCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","inputs","commands","_target","_value","_loading","_error","_key","_type","_storageListener","constructor","target","super","this","value","v","is","_setValue","loading","error","String","type","_getStorage","sessionStorage","localStorage","_setLoading","dispatchEvent","CustomEvent","bubbles","_setError","_toStorageError","operation","load","raw","getItem","JSON","parse","save","removeItem","setItem","stringify","remove","startSync","newValue","globalThis","addEventListener","stopSync","removeEventListener","registered","handleClick","Element","triggerElement","closest","storageId","getAttribute","storageElement","document","getElementById","Storage","preventDefault","HTMLElement","wcBindable","observedAttributes","_core","_trigger","_connectedCallbackPromise","Promise","resolve","_syncCore","setAttribute","manual","connectedCallbackPromise","hasAttribute","removeAttribute","trigger","attributeChangedCallback","_oldValue","isConnected","connectedCallback","style","display","disconnectedCallback","bootstrapStorage","userConfig","partialConfig","entries","setConfig","customElements","get","define"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wcstack/storage",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Declarative persistent storage component for Web Components. Framework-agnostic localStorage/sessionStorage via wc-bindable-protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.esm.js",
|