@wcstack/idle 1.19.1 → 1.21.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 CHANGED
@@ -7,7 +7,7 @@
7
7
  `@wcstack/state` と組み合わせると、`<wcs-idle>` はパス契約で直接バインドできます:
8
8
 
9
9
  - **入力サーフェス**: `threshold`(ms、最小60000)
10
- - **出力 state サーフェス**: `userState`、`screenState`、`active`、`error`
10
+ - **出力 state サーフェス**: `userState`、`screenState`、`active`、`error`、`errorInfo`
11
11
 
12
12
  ## なぜ存在するか — gesture-gated permission パターンの参照実装
13
13
 
@@ -69,6 +69,7 @@ npm install @wcstack/idle
69
69
  | `screenState` | `wcs-idle:change` | `"locked"` \| `"unlocked"`、`start()`前は`null`。 |
70
70
  | `active` | `wcs-idle:change` | `userState === "active"`のとき`true`。 |
71
71
  | `error` | `wcs-idle:error` | 直近の`requestPermission()`/`start()`の失敗、無ければ`null`。 |
72
+ | `errorInfo` | `wcs-idle:error-info-changed` | その同じ失敗のシリアライズ可能な失敗タクソノミ `WcsIoErrorInfo \| null`(安定した `code` / `phase` / `recoverable`)、クリア時は `null`。追加的で、`error` の形状は不変。 |
72
73
 
73
74
  ## コマンド
74
75
 
@@ -144,6 +145,7 @@ form:has(wcs-idle:state(error)) .banner { display: block; }
144
145
  - **Chromium限定、かつ secure context 限定です。** Firefox と Safari は`IdleDetector`自体を実装していません。Chromiumであっても`IdleDetector`は`[SecureContext]`専用インターフェースのため、平文の`http://`(`localhost`を除く)では`window.IdleDetector`自体が`undefined`になり——非対応ブラウザと同じ`unsupported`(`error`経由)の分岐に落ちます。
145
146
  - **Permissions-Policyでゲートされます。** アイドル検知は`idle-detection`のPermissions-Policyディレクティブ(既定allowlist: `self`)に支配されます。クロスオリジンの`<iframe>`内で`<wcs-idle>`を使うには、その`<iframe>`要素に`allow="idle-detection"`が必要です——無いと`requestPermission()`/`start()`は非対応ブラウザと同様に失敗します。
146
147
  - **`stop()`/切断では`userState`/`screenState`/`active`をリセットしません。** 次に`start()`が成功するまで直近の観測値を保持します——Generic Sensor族(`<wcs-gyroscope>`等)と同じ「直近の読み取り値を保持する」挙動です。
148
+ - **`errorInfo` タクソノミ。** `error` に現れるのと同じ `requestPermission()`/`start()` の失敗を、シリアライズ可能な `WcsIoErrorInfo`(安定した `code` / `phase` / `recoverable`)に分類する**追加的な**バインド可能出力(`wcs-idle:error-info-changed`)です。`error` の形状は変えません。`IdleDetector` の欠如(非対応ブラウザ、または `window.IdleDetector` が `undefined` になる非セキュアコンテキスト)は `capability-missing`(phase `probe`)、`NotAllowedError`(権限拒否、または user gesture 外での呼び出し——両者は意図的に区別しません)は `not-allowed`(phase `start`)、その他の失敗(生の throw、不正な `threshold` による `TypeError`、nullish な reject)は `idle-error`(phase `execute`)です。いずれも `recoverable: false`。`errorInfo` は `error` と同じタイミングで遷移し(`error` と共に `null` にクリアされる)ます。共有の `WcsIoErrorInfo` 型と `WCS_IDLE_ERROR_CODE` 定数は export 済みです。
147
149
 
148
150
  ## ヘッドレス利用(`IdleCore`)
149
151
 
package/README.md CHANGED
@@ -8,7 +8,7 @@ It is an **async primitive node** that turns `IdleDetector`'s live user/screen s
8
8
  With `@wcstack/state`, `<wcs-idle>` can be bound directly through path contracts:
9
9
 
10
10
  - **input surface**: `threshold` (ms, minimum 60000)
11
- - **output state surface**: `userState`, `screenState`, `active`, `error`
11
+ - **output state surface**: `userState`, `screenState`, `active`, `error`, `errorInfo`
12
12
 
13
13
  ## Why this exists — the reference implementation for gesture-gated permission
14
14
 
@@ -71,6 +71,7 @@ npm install @wcstack/idle
71
71
  | `screenState` | `wcs-idle:change` | `"locked"` \| `"unlocked"`, or `null` before `start()`. |
72
72
  | `active` | `wcs-idle:change` | `true` when `userState === "active"`. |
73
73
  | `error` | `wcs-idle:error` | The last `requestPermission()`/`start()` failure, or `null`. |
74
+ | `errorInfo` | `wcs-idle:error-info-changed` | Serializable failure taxonomy `WcsIoErrorInfo \| null` (stable `code` / `phase` / `recoverable`) for that same failure, or `null` when clear. Additive — the `error` shape is unchanged. |
74
75
 
75
76
  ## Commands
76
77
 
@@ -148,6 +149,7 @@ DevTools open; they are not a supported styling hook.
148
149
  - **Chromium-only, and secure-context-only.** Firefox and Safari do not implement `IdleDetector` at all. Even in Chromium, `IdleDetector` is a `[SecureContext]`-only interface, so over plain `http://` (other than `localhost`) `window.IdleDetector` itself is `undefined` — same as an unsupported browser, this falls into the `unsupported` (via `error`) path.
149
150
  - **Permissions-Policy gate.** Idle detection is governed by the `idle-detection` Permissions-Policy directive (default allowlist: `self`). Using `<wcs-idle>` inside a cross-origin `<iframe>` requires `allow="idle-detection"` on that `<iframe>` element — otherwise `requestPermission()`/`start()` fail the same way as an unsupported browser.
150
151
  - **`stop()`/disconnect does not reset `userState`/`screenState`/`active`.** They keep their last observed value until the next successful `start()` — the same "retain the last reading" behavior as the Generic Sensor family (`<wcs-gyroscope>` et al.).
152
+ - **`errorInfo` taxonomy.** An **additive** bindable output (`wcs-idle:error-info-changed`) that classifies the same `requestPermission()`/`start()` failure surfaced on `error` into a serializable `WcsIoErrorInfo` with a stable `code` / `phase` / `recoverable`, without changing the `error` shape. A missing `IdleDetector` (unsupported browser, or a non-secure context where `window.IdleDetector` is `undefined`) is `capability-missing` (phase `probe`); a `NotAllowedError` (permission denied or called outside a user gesture — the two are deliberately not distinguished) is `not-allowed` (phase `start`); any other failure (a raw throw, a `TypeError` from a bad `threshold`, a nullish rejection) is `idle-error` (phase `execute`). All are `recoverable: false`. `errorInfo` transitions exactly when `error` does (cleared to `null` alongside it). The shared `WcsIoErrorInfo` type and the `WCS_IDLE_ERROR_CODE` constants are exported.
151
153
 
152
154
  ## Headless usage (`IdleCore`)
153
155
 
package/dist/index.d.ts CHANGED
@@ -1,3 +1,14 @@
1
+ /** operation error の phase(taxonomy)。 */
2
+ type WcsIoErrorPhase = "probe" | "start" | "execute" | "decode" | "commit" | "dispose";
3
+ /** serializable な error info(non-cloneable な cause とは分離。DevTools / remote へは info のみ)。 */
4
+ interface WcsIoErrorInfo {
5
+ readonly code: string;
6
+ readonly phase: WcsIoErrorPhase;
7
+ readonly recoverable: boolean;
8
+ readonly capabilityId?: string;
9
+ readonly message: string;
10
+ }
11
+
1
12
  interface IWcBindableProperty {
2
13
  readonly name: string;
3
14
  readonly event: string;
@@ -13,7 +24,8 @@ interface IWcBindableCommand {
13
24
  }
14
25
  interface IWcBindable {
15
26
  readonly protocol: "wc-bindable";
16
- readonly version: 1;
27
+ /** Integer protocol version. All versions >= 1 are core-compatible. */
28
+ readonly version: number;
17
29
  readonly properties: readonly IWcBindableProperty[];
18
30
  readonly inputs?: readonly IWcBindableInput[];
19
31
  readonly commands?: readonly IWcBindableCommand[];
@@ -45,6 +57,8 @@ interface WcsIdleCoreValues {
45
57
  screenState: IdleScreenState | null;
46
58
  active: boolean;
47
59
  error: any;
60
+ /** Additive failure taxonomy derived from `error` (stable code / phase / recoverable). */
61
+ errorInfo: WcsIoErrorInfo | null;
48
62
  }
49
63
  /**
50
64
  * Value types for the Shell (`<wcs-idle>`) — identical observable surface to
@@ -79,6 +93,7 @@ declare class IdleCore extends EventTarget {
79
93
  private _userState;
80
94
  private _screenState;
81
95
  private _error;
96
+ private _errorInfo;
82
97
  private _detector;
83
98
  private _abortController;
84
99
  private _gen;
@@ -89,11 +104,20 @@ declare class IdleCore extends EventTarget {
89
104
  get screenState(): IdleScreenState | null;
90
105
  get active(): boolean;
91
106
  get error(): any;
107
+ /**
108
+ * The last failure's serializable `WcsIoErrorInfo` (stable `code` / `phase` /
109
+ * `recoverable`), or null. Additive wc-bindable property (event
110
+ * `wcs-idle:error-info-changed`), derived from `error`; the existing `error`
111
+ * property/event are unchanged.
112
+ */
113
+ get errorInfo(): WcsIoErrorInfo | null;
92
114
  observe(): Promise<void>;
93
115
  dispose(): void;
94
116
  private _api;
95
117
  private _setState;
96
118
  private _setError;
119
+ private _errorInfoMessage;
120
+ private _commitErrorInfo;
97
121
  /**
98
122
  * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.
99
123
  * MUST be invoked from within a real user gesture handler by the caller —
@@ -150,6 +174,7 @@ declare class WcsIdle extends HTMLElement {
150
174
  get screenState(): IdleScreenState | null;
151
175
  get active(): boolean;
152
176
  get error(): any;
177
+ get errorInfo(): WcsIoErrorInfo | null;
153
178
  get connectedCallbackPromise(): Promise<void>;
154
179
  requestPermission(): Promise<"granted" | "denied">;
155
180
  start(threshold?: number): Promise<void>;
@@ -158,5 +183,38 @@ declare class WcsIdle extends HTMLElement {
158
183
  disconnectedCallback(): void;
159
184
  }
160
185
 
161
- export { IdleCore, WcsIdle, bootstrapIdle, getConfig };
162
- export type { IWritableConfig, IWritableTagNames, IdleScreenState, IdleUserState, WcsIdleCoreValues, WcsIdleValues };
186
+ /**
187
+ * idleCapabilities.ts
188
+ *
189
+ * Idle Detection node 固有の error code(taxonomy)と derivation。汎用の error info 型は
190
+ * `./platformCapability.js`(/io-core/ から copy-distribution される生成ファイル)から
191
+ * import する。idle は requestPermission()/start()/stop() の単一コマンド経路で、競合する
192
+ * operation を持たない(2 回目の start() は前を stop() してから開始する supersede)ため
193
+ * lane は持たず、error taxonomy(errorInfo)のみを採用する。
194
+ *
195
+ * この node の `_setError` は 2 形態の入力を受ける:
196
+ * 1. synthetic な非対応マーカー(`{ message: "IdleDetector is not supported…" }`、
197
+ * `.name` 無し)— `globalThis.IdleDetector` 不在。
198
+ * 2. caught された rejection を包んだ `{ error: e }`(`e.name` が実 Error.name)。
199
+ * 両者を message coupling 無しに弁別するため、呼び出し側が明示的な `name` ヒントを渡す
200
+ * (storage の `deriveStorageErrorInfo(error, name)` / screen-orientation と同じ
201
+ * discriminator 技法)。非対応経路は `"unsupported"` を、caught 経路は wrap した
202
+ * `e?.name` を渡す。
203
+ *
204
+ * requestPermission()/start() の実 rejection 名は spec のとおり gesture 文脈外 /
205
+ * 権限未許可で `NotAllowedError`。それ以外(生の Error / TypeError(threshold 不正)/
206
+ * `.name` 欠如の nullish reject 等)は一括して `idle-error`。
207
+ */
208
+
209
+ /** 安定した idle error code(taxonomy)。値は公開キーとして固定。 */
210
+ declare const WCS_IDLE_ERROR_CODE: {
211
+ /** Idle Detection API 非対応(`globalThis.IdleDetector` 不在)。 */
212
+ readonly CapabilityMissing: "capability-missing";
213
+ /** `NotAllowedError` — 権限拒否 / user-gesture 文脈外。retry では回復しない。 */
214
+ readonly NotAllowed: "not-allowed";
215
+ /** その他の requestPermission()/start() 失敗(生 throw / TypeError / nullish reject 等)。 */
216
+ readonly IdleError: "idle-error";
217
+ };
218
+
219
+ export { IdleCore, WCS_IDLE_ERROR_CODE, WcsIdle, bootstrapIdle, getConfig };
220
+ export type { IWritableConfig, IWritableTagNames, IdleScreenState, IdleUserState, WcsIdleCoreValues, WcsIdleValues, WcsIoErrorInfo, WcsIoErrorPhase };
package/dist/index.esm.js CHANGED
@@ -36,6 +36,60 @@ function setConfig(partialConfig) {
36
36
  frozenConfig = null;
37
37
  }
38
38
 
39
+ /**
40
+ * idleCapabilities.ts
41
+ *
42
+ * Idle Detection node 固有の error code(taxonomy)と derivation。汎用の error info 型は
43
+ * `./platformCapability.js`(/io-core/ から copy-distribution される生成ファイル)から
44
+ * import する。idle は requestPermission()/start()/stop() の単一コマンド経路で、競合する
45
+ * operation を持たない(2 回目の start() は前を stop() してから開始する supersede)ため
46
+ * lane は持たず、error taxonomy(errorInfo)のみを採用する。
47
+ *
48
+ * この node の `_setError` は 2 形態の入力を受ける:
49
+ * 1. synthetic な非対応マーカー(`{ message: "IdleDetector is not supported…" }`、
50
+ * `.name` 無し)— `globalThis.IdleDetector` 不在。
51
+ * 2. caught された rejection を包んだ `{ error: e }`(`e.name` が実 Error.name)。
52
+ * 両者を message coupling 無しに弁別するため、呼び出し側が明示的な `name` ヒントを渡す
53
+ * (storage の `deriveStorageErrorInfo(error, name)` / screen-orientation と同じ
54
+ * discriminator 技法)。非対応経路は `"unsupported"` を、caught 経路は wrap した
55
+ * `e?.name` を渡す。
56
+ *
57
+ * requestPermission()/start() の実 rejection 名は spec のとおり gesture 文脈外 /
58
+ * 権限未許可で `NotAllowedError`。それ以外(生の Error / TypeError(threshold 不正)/
59
+ * `.name` 欠如の nullish reject 等)は一括して `idle-error`。
60
+ */
61
+ /** 安定した idle error code(taxonomy)。値は公開キーとして固定。 */
62
+ const WCS_IDLE_ERROR_CODE = {
63
+ /** Idle Detection API 非対応(`globalThis.IdleDetector` 不在)。 */
64
+ CapabilityMissing: "capability-missing",
65
+ /** `NotAllowedError` — 権限拒否 / user-gesture 文脈外。retry では回復しない。 */
66
+ NotAllowed: "not-allowed",
67
+ /** その他の requestPermission()/start() 失敗(生 throw / TypeError / nullish reject 等)。 */
68
+ IdleError: "idle-error",
69
+ };
70
+ /**
71
+ * idle の失敗を serializable な error taxonomy に写す。
72
+ *
73
+ * `name` は呼び出し側が渡す discriminator:synthetic 非対応なら `"unsupported"`、
74
+ * caught 例外なら wrap した `e?.name`(生の非 Error / nullish reject では `undefined`)。
75
+ * `message` は wrap を解いた下位値から抽出済みの文言(非対応なら synthetic の message)。
76
+ *
77
+ * - `"unsupported"` は利用直前の能力欠如 → phase="probe" / capability-missing。
78
+ * - `NotAllowedError` は requestPermission()/start() の権限ゲート失敗 → phase="start" /
79
+ * not-allowed / recoverable=false(gesture 違反と実 "denied" は区別しない設計 §4.1)。
80
+ * - それ以外(生の throw、TypeError、`.name` 欠如等)は実行中の失敗 → phase="execute" /
81
+ * idle-error / recoverable=false。
82
+ */
83
+ function deriveIdleErrorInfo(name, message) {
84
+ if (name === "unsupported") {
85
+ return { code: WCS_IDLE_ERROR_CODE.CapabilityMissing, phase: "probe", recoverable: false, message };
86
+ }
87
+ if (name === "NotAllowedError") {
88
+ return { code: WCS_IDLE_ERROR_CODE.NotAllowed, phase: "start", recoverable: false, message };
89
+ }
90
+ return { code: WCS_IDLE_ERROR_CODE.IdleError, phase: "execute", recoverable: false, message };
91
+ }
92
+
39
93
  const MIN_THRESHOLD = 60000;
40
94
  /**
41
95
  * Headless Idle Detection primitive. A thin, framework-agnostic wrapper around
@@ -70,6 +124,12 @@ class IdleCore extends EventTarget {
70
124
  // instead of rejecting/throwing. Mirrors every other bidirectional IO
71
125
  // node in this batch (fetch, share, screen-orientation).
72
126
  { name: "error", event: "wcs-idle:error" },
127
+ // Serializable failure taxonomy (stable code / phase / recoverable), or null.
128
+ // Additive bindable output derived from `error` (capability-missing / not-allowed
129
+ // / idle-error); the existing `error` property/event are unchanged. Fires
130
+ // wcs-idle:error-info-changed. No lane — requestPermission()/start()/stop() form a
131
+ // single command path (a 2nd start() supersedes the 1st), not competing operations.
132
+ { name: "errorInfo", event: "wcs-idle:error-info-changed" },
73
133
  ],
74
134
  // No `inputs`: the Core has no settable `threshold` state — `threshold` is a
75
135
  // per-call argument to `start(threshold)`, not a property/setter. The DOM-driven
@@ -86,6 +146,9 @@ class IdleCore extends EventTarget {
86
146
  _userState = null;
87
147
  _screenState = null;
88
148
  _error = null;
149
+ // Additive failure taxonomy, kept strictly in sync with `_error` (derived on
150
+ // every _setError, cleared to null when error clears). The two transition together.
151
+ _errorInfo = null;
89
152
  _detector = null;
90
153
  _abortController = null;
91
154
  // Generation guard (§3.4): bumped on dispose()/stop() and each start().
@@ -112,6 +175,15 @@ class IdleCore extends EventTarget {
112
175
  get error() {
113
176
  return this._error;
114
177
  }
178
+ /**
179
+ * The last failure's serializable `WcsIoErrorInfo` (stable `code` / `phase` /
180
+ * `recoverable`), or null. Additive wc-bindable property (event
181
+ * `wcs-idle:error-info-changed`), derived from `error`; the existing `error`
182
+ * property/event are unchanged.
183
+ */
184
+ get errorInfo() {
185
+ return this._errorInfo;
186
+ }
115
187
  // Lifecycle (§3.5). observe() is a synchronous no-op: unlike most IO nodes,
116
188
  // this Core deliberately does NOT auto-start on connect (§6) — permission
117
189
  // is gesture-gated, so attempting start() before it is granted is
@@ -136,15 +208,47 @@ class IdleCore extends EventTarget {
136
208
  bubbles: true,
137
209
  }));
138
210
  }
139
- _setError(error) {
211
+ // `name` is the discriminator for the additive `errorInfo` taxonomy only (it
212
+ // stays out of the public `error` shape): the synthetic unsupported marker has
213
+ // no `.name`, so the unsupported call sites pass an explicit `"unsupported"`
214
+ // hint (storage/screen-orientation-style — avoids coupling to `error.message`),
215
+ // while the caught paths pass the wrapped rejection's `Error.name` (`e?.name`).
216
+ // `null` clears (no name).
217
+ _setError(error, name) {
140
218
  if (this._error === error)
141
219
  return;
142
220
  this._error = error;
221
+ // Keep the additive `errorInfo` taxonomy in sync with `error`: derive from the
222
+ // discriminator + extracted message (or null on clear). Fires before the `error`
223
+ // event so an observer binding both sees the classification first, mirroring the
224
+ // io-node family.
225
+ this._commitErrorInfo(error === null ? null : deriveIdleErrorInfo(name, this._errorInfoMessage(error)));
143
226
  this._target.dispatchEvent(new CustomEvent("wcs-idle:error", {
144
227
  detail: error,
145
228
  bubbles: true,
146
229
  }));
147
230
  }
231
+ // Extract a serializable string message for `errorInfo` WITHOUT normalizing the
232
+ // public `error` shape. The public error is either the synthetic `{ message }`
233
+ // (unsupported) or a wrapped `{ error: e }` (a caught rejection). For the wrapped
234
+ // form the meaningful message lives on `e`, so unwrap one level before reading
235
+ // `.message`; a non-conformant / nullish value (e.g. `Promise.reject(undefined)`)
236
+ // falls back to `String(...)` so it still classifies instead of throwing
237
+ // (never-throw §3.6).
238
+ _errorInfoMessage(error) {
239
+ const src = error != null && typeof error === "object" && "error" in error ? error.error : error;
240
+ return typeof src?.message === "string" ? src.message : String(src);
241
+ }
242
+ // Called only from _setError (which already same-value-guards on the error
243
+ // reference), so errorInfo transitions exactly when error does — no separate
244
+ // guard needed here.
245
+ _commitErrorInfo(info) {
246
+ this._errorInfo = info;
247
+ this._target.dispatchEvent(new CustomEvent("wcs-idle:error-info-changed", {
248
+ detail: info,
249
+ bubbles: true,
250
+ }));
251
+ }
148
252
  /**
149
253
  * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.
150
254
  * MUST be invoked from within a real user gesture handler by the caller —
@@ -156,7 +260,7 @@ class IdleCore extends EventTarget {
156
260
  async requestPermission() {
157
261
  const Ctor = this._api();
158
262
  if (!Ctor) {
159
- this._setError({ message: "IdleDetector is not supported in this browser" });
263
+ this._setError({ message: "IdleDetector is not supported in this browser" }, "unsupported");
160
264
  return "denied";
161
265
  }
162
266
  try {
@@ -168,7 +272,7 @@ class IdleCore extends EventTarget {
168
272
  return result === "granted" ? "granted" : "denied";
169
273
  }
170
274
  catch (e) {
171
- this._setError({ error: e });
275
+ this._setError({ error: e }, e?.name);
172
276
  return "denied";
173
277
  }
174
278
  }
@@ -181,7 +285,7 @@ class IdleCore extends EventTarget {
181
285
  this.stop(); // supersede any in-flight session (mirrors FetchCore's "cancel then start")
182
286
  const Ctor = this._api();
183
287
  if (!Ctor) {
184
- this._setError({ message: "IdleDetector is not supported in this browser" });
288
+ this._setError({ message: "IdleDetector is not supported in this browser" }, "unsupported");
185
289
  return;
186
290
  }
187
291
  const ac = new AbortController();
@@ -212,7 +316,7 @@ class IdleCore extends EventTarget {
212
316
  this._detector?.removeEventListener("change", this._onChange);
213
317
  this._detector = null;
214
318
  this._abortController = null;
215
- this._setError({ error: e });
319
+ this._setError({ error: e }, e?.name);
216
320
  }
217
321
  }
218
322
  /** Stop the current session (if any) and detach its listener. Safe to call when not started. */
@@ -350,6 +454,9 @@ class WcsIdle extends HTMLElement {
350
454
  get error() {
351
455
  return this._core.error;
352
456
  }
457
+ get errorInfo() {
458
+ return this._core.errorInfo;
459
+ }
353
460
  get connectedCallbackPromise() {
354
461
  return this._connectedCallbackPromise;
355
462
  }
@@ -388,5 +495,5 @@ function bootstrapIdle(userConfig) {
388
495
  registerComponents();
389
496
  }
390
497
 
391
- export { IdleCore, WcsIdle, bootstrapIdle, getConfig };
498
+ export { IdleCore, WCS_IDLE_ERROR_CODE, WcsIdle, bootstrapIdle, getConfig };
392
499
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/core/IdleCore.ts","../src/components/Idle.ts","../src/registerComponents.ts","../src/bootstrapIdle.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n idle: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n idle: \"wcs-idle\",\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 (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\n\ninterface IdleDetectorLike extends EventTarget {\n userState: IdleUserState;\n screenState: IdleScreenState;\n start(options: { threshold: number; signal: AbortSignal }): Promise<void>;\n}\n\ninterface IdleDetectorCtor {\n new (): IdleDetectorLike;\n requestPermission(): Promise<\"granted\" | \"denied\">;\n}\n\nconst MIN_THRESHOLD = 60000;\n\n/**\n * Headless Idle Detection primitive. A thin, framework-agnostic wrapper around\n * `IdleDetector` exposed through the wc-bindable protocol.\n *\n * Reference implementation for batch2's \"gesture-gated permission\" archetype\n * (docs/idle-detection-tag-design.md). `requestPermission()` wraps the static,\n * user-gesture-gated `IdleDetector.requestPermission()` — this Core never\n * calls it automatically; the caller must invoke it from within a real\n * gesture handler.\n *\n * Deliberately does NOT track the 4-value permission state (prompt/granted/\n * denied/unsupported) itself: `navigator.permissions.query({name:\n * \"idle-detection\"})` exists, so compose with `<wcs-permission\n * name=\"idle-detection\">` for that instead (§0). This Core only exposes the\n * actual idle state (userState/screenState) plus the one-time\n * requestPermission()/start()/stop() actions.\n */\nexport class IdleCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"userState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.userState },\n { name: \"screenState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.screenState },\n {\n name: \"active\",\n event: \"wcs-idle:change\",\n getter: (e: Event) => (e as CustomEvent).detail.userState === \"active\",\n },\n // never-throw (§3.6): requestPermission()/start() failures land here\n // instead of rejecting/throwing. Mirrors every other bidirectional IO\n // node in this batch (fetch, share, screen-orientation).\n { name: \"error\", event: \"wcs-idle:error\" },\n ],\n // No `inputs`: the Core has no settable `threshold` state — `threshold` is a\n // per-call argument to `start(threshold)`, not a property/setter. The DOM-driven\n // `threshold` input surface belongs to the Shell (which declares it and backs it\n // with the `threshold` attribute), mirroring geolocation/intersection where the\n // Core declares no inputs and the Shell adds them.\n commands: [\n { name: \"requestPermission\", async: true },\n { name: \"start\", async: true },\n { name: \"stop\" },\n ],\n };\n\n private _target: EventTarget;\n private _userState: IdleUserState | null = null;\n private _screenState: IdleScreenState | null = null;\n private _error: any = null;\n private _detector: IdleDetectorLike | null = null;\n private _abortController: AbortController | null = null;\n\n // Generation guard (§3.4): bumped on dispose()/stop() and each start().\n private _gen = 0;\n\n // SSR (§3.8): never auto-starts on connect, so there is no probe to await —\n // readiness is always immediate (docs/idle-detection-tag-design.md §7).\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get userState(): IdleUserState | null {\n return this._userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._screenState;\n }\n\n get active(): boolean {\n return this._userState === \"active\";\n }\n\n get error(): any {\n return this._error;\n }\n\n // Lifecycle (§3.5). observe() is a synchronous no-op: unlike most IO nodes,\n // this Core deliberately does NOT auto-start on connect (§6) — permission\n // is gesture-gated, so attempting start() before it is granted is\n // guaranteed to fail.\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this.stop();\n }\n\n private _api(): IdleDetectorCtor | undefined {\n const g = globalThis as any;\n return typeof g.IdleDetector === \"function\" ? g.IdleDetector : undefined;\n }\n\n private _setState(userState: IdleUserState, screenState: IdleScreenState): void {\n if (this._userState === userState && this._screenState === screenState) return;\n this._userState = userState;\n this._screenState = screenState;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:change\", {\n detail: { userState, screenState },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n if (this._error === error) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n /**\n * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.\n * MUST be invoked from within a real user gesture handler by the caller —\n * this Core cannot manufacture one. never-throw: a gesture-context\n * rejection resolves to `\"denied\"` and lands in `error`. Gesture violation\n * and an actual \"denied\" outcome are not distinguished — both mean \"not\n * usable right now\" (§4.1).\n */\n async requestPermission(): Promise<\"granted\" | \"denied\"> {\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return \"denied\";\n }\n try {\n const result = await Ctor.requestPermission();\n // Symmetric with start()'s success path: any settled (non-throwing)\n // outcome — granted or a plain \"denied\" — supersedes a stale error from\n // an earlier attempt (e.g. a prior gesture-context rejection).\n this._setError(null);\n return result === \"granted\" ? \"granted\" : \"denied\";\n } catch (e) {\n this._setError({ error: e });\n return \"denied\";\n }\n }\n\n /**\n * Start an idle-detection session. `threshold` (ms) must be >= 60000 per\n * spec — not validated here (§3): an out-of-range value is left to the\n * browser's own TypeError, which never-throw absorbs into `error`.\n */\n async start(threshold: number = MIN_THRESHOLD): Promise<void> {\n this.stop(); // supersede any in-flight session (mirrors FetchCore's \"cancel then start\")\n\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return;\n }\n\n const ac = new AbortController();\n this._abortController = ac;\n const gen = ++this._gen;\n\n try {\n const detector = new Ctor();\n detector.addEventListener(\"change\", this._onChange);\n this._detector = detector;\n await detector.start({ threshold, signal: ac.signal });\n if (gen !== this._gen) return; // stale (stop()/dispose() ran during the await)\n this._setError(null);\n this._setState(detector.userState, detector.screenState);\n } catch (e: any) {\n // No separate AbortError check: stop()/dispose() bump `_gen` *before*\n // calling `ac.abort()` (see stop() below), so a stop()-triggered\n // AbortError always has a stale `gen` here and is already caught by\n // the check above. The signal is private and never exposed, so an\n // AbortError from any other source cannot occur.\n if (gen !== this._gen) return;\n // Tear down the failed session's listener/controller (mirrors stop()):\n // without this, the failed `_detector` stays wired to `_onChange` and a\n // later `change` on that same (never-truly-started) instance would\n // still write state, contradicting the error just recorded.\n this._detector?.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n this._abortController = null;\n this._setError({ error: e });\n }\n }\n\n /** Stop the current session (if any) and detach its listener. Safe to call when not started. */\n stop(): void {\n this._gen++;\n this._abortController?.abort();\n this._abortController = null;\n if (this._detector) {\n this._detector.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n }\n }\n\n private _onChange = (event: Event): void => {\n const detector = event.target as IdleDetectorLike;\n this._setState(detector.userState, detector.screenState);\n };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { IdleCore } from \"../core/IdleCore.js\";\n\n/**\n * `<wcs-idle>` — declarative Idle Detection API primitive.\n *\n * Does NOT auto-start on connect (docs/idle-detection-tag-design.md §6): the\n * permission gate sits in front of `start()`, so an unconditional\n * connectedCallback start would be guaranteed to fail before permission is\n * granted. Callers drive `requestPermission()` → `start()` explicitly, e.g.\n * from a click handler.\n *\n * Compose with `<wcs-permission name=\"idle-detection\">` for prompt/granted/\n * denied status — this Shell only exposes the actual idle state.\n */\nexport class WcsIdle extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...IdleCore.wcBindable,\n inputs: [\n { name: \"threshold\", attribute: \"threshold\" },\n ],\n // Core の commands をそのまま継承(単一情報源)。\n commands: IdleCore.wcBindable.commands,\n };\n\n private _core: IdleCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new IdleCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-idle:change\": (d) => ({ active: d.userState === \"active\" }),\n \"wcs-idle:error\": (d) => ({ error: d != null }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (docs/custom-state-reflection-design.md §3.1/§3.4): attachInternals\n // is absent in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n // --- Attribute accessors ---\n\n /**\n * Minimum idle time (ms) before `userState` becomes `\"idle\"`. This value is\n * read only at `start()` time — there is no `attributeChangedCallback`\n * (deliberately not declared in `observedAttributes`, mirroring\n * `<wcs-gyroscope>`'s `frequency`), so mutating the attribute/property on an\n * already-running session has no effect until the caller `stop()`s and\n * `start()`s again.\n */\n get threshold(): number {\n const attr = this.getAttribute(\"threshold\");\n // An absent, empty, or whitespace-only attribute all mean \"no value\n // supplied\" and must fall back to the default — without this check,\n // `Number(\"\")`/`Number(\" \")` coerce to `0` (finite), which would slip\n // past the `Number.isFinite` fallback below and silently return `0`\n // instead of the documented 60000ms default.\n if (attr === null || attr.trim() === \"\") return 60000;\n const n = Number(attr);\n return Number.isFinite(n) ? n : 60000;\n }\n\n set threshold(value: number) {\n this.setAttribute(\"threshold\", String(value));\n }\n\n // --- Core delegated getters ---\n\n get userState(): IdleUserState | null {\n return this._core.userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._core.screenState;\n }\n\n get active(): boolean {\n return this._core.active;\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 // --- Commands (delegated to Core) ---\n\n requestPermission(): Promise<\"granted\" | \"denied\"> {\n return this._core.requestPermission();\n }\n\n start(threshold?: number): Promise<void> {\n return this._core.start(threshold ?? this.threshold);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\n // No auto-start (§6) — observe() is a synchronous no-op, kept only for\n // API uniformity with other IO nodes' lifecycle.\n this._connectedCallbackPromise = this._core.observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n}\n","import { WcsIdle } from \"./components/Idle.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.idle)) {\n customElements.define(config.tagNames.idle, WcsIdle);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapIdle(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/core/idleCapabilities.ts","../src/core/IdleCore.ts","../src/components/Idle.ts","../src/registerComponents.ts","../src/bootstrapIdle.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n idle: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n idle: \"wcs-idle\",\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 (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","/**\n * idleCapabilities.ts\n *\n * Idle Detection node 固有の error code(taxonomy)と derivation。汎用の error info 型は\n * `./platformCapability.js`(/io-core/ から copy-distribution される生成ファイル)から\n * import する。idle は requestPermission()/start()/stop() の単一コマンド経路で、競合する\n * operation を持たない(2 回目の start() は前を stop() してから開始する supersede)ため\n * lane は持たず、error taxonomy(errorInfo)のみを採用する。\n *\n * この node の `_setError` は 2 形態の入力を受ける:\n * 1. synthetic な非対応マーカー(`{ message: \"IdleDetector is not supported…\" }`、\n * `.name` 無し)— `globalThis.IdleDetector` 不在。\n * 2. caught された rejection を包んだ `{ error: e }`(`e.name` が実 Error.name)。\n * 両者を message coupling 無しに弁別するため、呼び出し側が明示的な `name` ヒントを渡す\n * (storage の `deriveStorageErrorInfo(error, name)` / screen-orientation と同じ\n * discriminator 技法)。非対応経路は `\"unsupported\"` を、caught 経路は wrap した\n * `e?.name` を渡す。\n *\n * requestPermission()/start() の実 rejection 名は spec のとおり gesture 文脈外 /\n * 権限未許可で `NotAllowedError`。それ以外(生の Error / TypeError(threshold 不正)/\n * `.name` 欠如の nullish reject 等)は一括して `idle-error`。\n */\n\nimport type { WcsIoErrorInfo } from \"./platformCapability.js\";\n\n/** 安定した idle error code(taxonomy)。値は公開キーとして固定。 */\nexport const WCS_IDLE_ERROR_CODE = {\n /** Idle Detection API 非対応(`globalThis.IdleDetector` 不在)。 */\n CapabilityMissing: \"capability-missing\",\n /** `NotAllowedError` — 権限拒否 / user-gesture 文脈外。retry では回復しない。 */\n NotAllowed: \"not-allowed\",\n /** その他の requestPermission()/start() 失敗(生 throw / TypeError / nullish reject 等)。 */\n IdleError: \"idle-error\",\n} as const;\n\n/**\n * idle の失敗を serializable な error taxonomy に写す。\n *\n * `name` は呼び出し側が渡す discriminator:synthetic 非対応なら `\"unsupported\"`、\n * caught 例外なら wrap した `e?.name`(生の非 Error / nullish reject では `undefined`)。\n * `message` は wrap を解いた下位値から抽出済みの文言(非対応なら synthetic の message)。\n *\n * - `\"unsupported\"` は利用直前の能力欠如 → phase=\"probe\" / capability-missing。\n * - `NotAllowedError` は requestPermission()/start() の権限ゲート失敗 → phase=\"start\" /\n * not-allowed / recoverable=false(gesture 違反と実 \"denied\" は区別しない設計 §4.1)。\n * - それ以外(生の throw、TypeError、`.name` 欠如等)は実行中の失敗 → phase=\"execute\" /\n * idle-error / recoverable=false。\n */\nexport function deriveIdleErrorInfo(name: string | undefined, message: string): WcsIoErrorInfo {\n if (name === \"unsupported\") {\n return { code: WCS_IDLE_ERROR_CODE.CapabilityMissing, phase: \"probe\", recoverable: false, message };\n }\n if (name === \"NotAllowedError\") {\n return { code: WCS_IDLE_ERROR_CODE.NotAllowed, phase: \"start\", recoverable: false, message };\n }\n return { code: WCS_IDLE_ERROR_CODE.IdleError, phase: \"execute\", recoverable: false, message };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { WcsIoErrorInfo } from \"./platformCapability.js\";\nimport { deriveIdleErrorInfo } from \"./idleCapabilities.js\";\n\ninterface IdleDetectorLike extends EventTarget {\n userState: IdleUserState;\n screenState: IdleScreenState;\n start(options: { threshold: number; signal: AbortSignal }): Promise<void>;\n}\n\ninterface IdleDetectorCtor {\n new (): IdleDetectorLike;\n requestPermission(): Promise<\"granted\" | \"denied\">;\n}\n\nconst MIN_THRESHOLD = 60000;\n\n/**\n * Headless Idle Detection primitive. A thin, framework-agnostic wrapper around\n * `IdleDetector` exposed through the wc-bindable protocol.\n *\n * Reference implementation for batch2's \"gesture-gated permission\" archetype\n * (docs/idle-detection-tag-design.md). `requestPermission()` wraps the static,\n * user-gesture-gated `IdleDetector.requestPermission()` — this Core never\n * calls it automatically; the caller must invoke it from within a real\n * gesture handler.\n *\n * Deliberately does NOT track the 4-value permission state (prompt/granted/\n * denied/unsupported) itself: `navigator.permissions.query({name:\n * \"idle-detection\"})` exists, so compose with `<wcs-permission\n * name=\"idle-detection\">` for that instead (§0). This Core only exposes the\n * actual idle state (userState/screenState) plus the one-time\n * requestPermission()/start()/stop() actions.\n */\nexport class IdleCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"userState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.userState },\n { name: \"screenState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.screenState },\n {\n name: \"active\",\n event: \"wcs-idle:change\",\n getter: (e: Event) => (e as CustomEvent).detail.userState === \"active\",\n },\n // never-throw (§3.6): requestPermission()/start() failures land here\n // instead of rejecting/throwing. Mirrors every other bidirectional IO\n // node in this batch (fetch, share, screen-orientation).\n { name: \"error\", event: \"wcs-idle:error\" },\n // Serializable failure taxonomy (stable code / phase / recoverable), or null.\n // Additive bindable output derived from `error` (capability-missing / not-allowed\n // / idle-error); the existing `error` property/event are unchanged. Fires\n // wcs-idle:error-info-changed. No lane — requestPermission()/start()/stop() form a\n // single command path (a 2nd start() supersedes the 1st), not competing operations.\n { name: \"errorInfo\", event: \"wcs-idle:error-info-changed\" },\n ],\n // No `inputs`: the Core has no settable `threshold` state — `threshold` is a\n // per-call argument to `start(threshold)`, not a property/setter. The DOM-driven\n // `threshold` input surface belongs to the Shell (which declares it and backs it\n // with the `threshold` attribute), mirroring geolocation/intersection where the\n // Core declares no inputs and the Shell adds them.\n commands: [\n { name: \"requestPermission\", async: true },\n { name: \"start\", async: true },\n { name: \"stop\" },\n ],\n };\n\n private _target: EventTarget;\n private _userState: IdleUserState | null = null;\n private _screenState: IdleScreenState | null = null;\n private _error: any = null;\n // Additive failure taxonomy, kept strictly in sync with `_error` (derived on\n // every _setError, cleared to null when error clears). The two transition together.\n private _errorInfo: WcsIoErrorInfo | null = null;\n private _detector: IdleDetectorLike | null = null;\n private _abortController: AbortController | null = null;\n\n // Generation guard (§3.4): bumped on dispose()/stop() and each start().\n private _gen = 0;\n\n // SSR (§3.8): never auto-starts on connect, so there is no probe to await —\n // readiness is always immediate (docs/idle-detection-tag-design.md §7).\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get userState(): IdleUserState | null {\n return this._userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._screenState;\n }\n\n get active(): boolean {\n return this._userState === \"active\";\n }\n\n get error(): any {\n return this._error;\n }\n\n /**\n * The last failure's serializable `WcsIoErrorInfo` (stable `code` / `phase` /\n * `recoverable`), or null. Additive wc-bindable property (event\n * `wcs-idle:error-info-changed`), derived from `error`; the existing `error`\n * property/event are unchanged.\n */\n get errorInfo(): WcsIoErrorInfo | null {\n return this._errorInfo;\n }\n\n // Lifecycle (§3.5). observe() is a synchronous no-op: unlike most IO nodes,\n // this Core deliberately does NOT auto-start on connect (§6) — permission\n // is gesture-gated, so attempting start() before it is granted is\n // guaranteed to fail.\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this.stop();\n }\n\n private _api(): IdleDetectorCtor | undefined {\n const g = globalThis as any;\n return typeof g.IdleDetector === \"function\" ? g.IdleDetector : undefined;\n }\n\n private _setState(userState: IdleUserState, screenState: IdleScreenState): void {\n if (this._userState === userState && this._screenState === screenState) return;\n this._userState = userState;\n this._screenState = screenState;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:change\", {\n detail: { userState, screenState },\n bubbles: true,\n }));\n }\n\n // `name` is the discriminator for the additive `errorInfo` taxonomy only (it\n // stays out of the public `error` shape): the synthetic unsupported marker has\n // no `.name`, so the unsupported call sites pass an explicit `\"unsupported\"`\n // hint (storage/screen-orientation-style — avoids coupling to `error.message`),\n // while the caught paths pass the wrapped rejection's `Error.name` (`e?.name`).\n // `null` clears (no name).\n private _setError(error: any, name?: string): void {\n if (this._error === error) return;\n this._error = error;\n // Keep the additive `errorInfo` taxonomy in sync with `error`: derive from the\n // discriminator + extracted message (or null on clear). Fires before the `error`\n // event so an observer binding both sees the classification first, mirroring the\n // io-node family.\n this._commitErrorInfo(error === null ? null : deriveIdleErrorInfo(name, this._errorInfoMessage(error)));\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n // Extract a serializable string message for `errorInfo` WITHOUT normalizing the\n // public `error` shape. The public error is either the synthetic `{ message }`\n // (unsupported) or a wrapped `{ error: e }` (a caught rejection). For the wrapped\n // form the meaningful message lives on `e`, so unwrap one level before reading\n // `.message`; a non-conformant / nullish value (e.g. `Promise.reject(undefined)`)\n // falls back to `String(...)` so it still classifies instead of throwing\n // (never-throw §3.6).\n private _errorInfoMessage(error: any): string {\n const src = error != null && typeof error === \"object\" && \"error\" in error ? error.error : error;\n return typeof src?.message === \"string\" ? src.message : String(src);\n }\n\n // Called only from _setError (which already same-value-guards on the error\n // reference), so errorInfo transitions exactly when error does — no separate\n // guard needed here.\n private _commitErrorInfo(info: WcsIoErrorInfo | null): void {\n this._errorInfo = info;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error-info-changed\", {\n detail: info,\n bubbles: true,\n }));\n }\n\n /**\n * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.\n * MUST be invoked from within a real user gesture handler by the caller —\n * this Core cannot manufacture one. never-throw: a gesture-context\n * rejection resolves to `\"denied\"` and lands in `error`. Gesture violation\n * and an actual \"denied\" outcome are not distinguished — both mean \"not\n * usable right now\" (§4.1).\n */\n async requestPermission(): Promise<\"granted\" | \"denied\"> {\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" }, \"unsupported\");\n return \"denied\";\n }\n try {\n const result = await Ctor.requestPermission();\n // Symmetric with start()'s success path: any settled (non-throwing)\n // outcome — granted or a plain \"denied\" — supersedes a stale error from\n // an earlier attempt (e.g. a prior gesture-context rejection).\n this._setError(null);\n return result === \"granted\" ? \"granted\" : \"denied\";\n } catch (e: any) {\n this._setError({ error: e }, e?.name);\n return \"denied\";\n }\n }\n\n /**\n * Start an idle-detection session. `threshold` (ms) must be >= 60000 per\n * spec — not validated here (§3): an out-of-range value is left to the\n * browser's own TypeError, which never-throw absorbs into `error`.\n */\n async start(threshold: number = MIN_THRESHOLD): Promise<void> {\n this.stop(); // supersede any in-flight session (mirrors FetchCore's \"cancel then start\")\n\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" }, \"unsupported\");\n return;\n }\n\n const ac = new AbortController();\n this._abortController = ac;\n const gen = ++this._gen;\n\n try {\n const detector = new Ctor();\n detector.addEventListener(\"change\", this._onChange);\n this._detector = detector;\n await detector.start({ threshold, signal: ac.signal });\n if (gen !== this._gen) return; // stale (stop()/dispose() ran during the await)\n this._setError(null);\n this._setState(detector.userState, detector.screenState);\n } catch (e: any) {\n // No separate AbortError check: stop()/dispose() bump `_gen` *before*\n // calling `ac.abort()` (see stop() below), so a stop()-triggered\n // AbortError always has a stale `gen` here and is already caught by\n // the check above. The signal is private and never exposed, so an\n // AbortError from any other source cannot occur.\n if (gen !== this._gen) return;\n // Tear down the failed session's listener/controller (mirrors stop()):\n // without this, the failed `_detector` stays wired to `_onChange` and a\n // later `change` on that same (never-truly-started) instance would\n // still write state, contradicting the error just recorded.\n this._detector?.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n this._abortController = null;\n this._setError({ error: e }, e?.name);\n }\n }\n\n /** Stop the current session (if any) and detach its listener. Safe to call when not started. */\n stop(): void {\n this._gen++;\n this._abortController?.abort();\n this._abortController = null;\n if (this._detector) {\n this._detector.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n }\n }\n\n private _onChange = (event: Event): void => {\n const detector = event.target as IdleDetectorLike;\n this._setState(detector.userState, detector.screenState);\n };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { IdleCore } from \"../core/IdleCore.js\";\nimport { WcsIoErrorInfo } from \"../core/platformCapability.js\";\n\n/**\n * `<wcs-idle>` — declarative Idle Detection API primitive.\n *\n * Does NOT auto-start on connect (docs/idle-detection-tag-design.md §6): the\n * permission gate sits in front of `start()`, so an unconditional\n * connectedCallback start would be guaranteed to fail before permission is\n * granted. Callers drive `requestPermission()` → `start()` explicitly, e.g.\n * from a click handler.\n *\n * Compose with `<wcs-permission name=\"idle-detection\">` for prompt/granted/\n * denied status — this Shell only exposes the actual idle state.\n */\nexport class WcsIdle extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...IdleCore.wcBindable,\n inputs: [\n { name: \"threshold\", attribute: \"threshold\" },\n ],\n // Core の commands をそのまま継承(単一情報源)。\n commands: IdleCore.wcBindable.commands,\n };\n\n private _core: IdleCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new IdleCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-idle:change\": (d) => ({ active: d.userState === \"active\" }),\n \"wcs-idle:error\": (d) => ({ error: d != null }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (docs/custom-state-reflection-design.md §3.1/§3.4): attachInternals\n // is absent in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n // --- Attribute accessors ---\n\n /**\n * Minimum idle time (ms) before `userState` becomes `\"idle\"`. This value is\n * read only at `start()` time — there is no `attributeChangedCallback`\n * (deliberately not declared in `observedAttributes`, mirroring\n * `<wcs-gyroscope>`'s `frequency`), so mutating the attribute/property on an\n * already-running session has no effect until the caller `stop()`s and\n * `start()`s again.\n */\n get threshold(): number {\n const attr = this.getAttribute(\"threshold\");\n // An absent, empty, or whitespace-only attribute all mean \"no value\n // supplied\" and must fall back to the default — without this check,\n // `Number(\"\")`/`Number(\" \")` coerce to `0` (finite), which would slip\n // past the `Number.isFinite` fallback below and silently return `0`\n // instead of the documented 60000ms default.\n if (attr === null || attr.trim() === \"\") return 60000;\n const n = Number(attr);\n return Number.isFinite(n) ? n : 60000;\n }\n\n set threshold(value: number) {\n this.setAttribute(\"threshold\", String(value));\n }\n\n // --- Core delegated getters ---\n\n get userState(): IdleUserState | null {\n return this._core.userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._core.screenState;\n }\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get errorInfo(): WcsIoErrorInfo | null {\n return this._core.errorInfo;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands (delegated to Core) ---\n\n requestPermission(): Promise<\"granted\" | \"denied\"> {\n return this._core.requestPermission();\n }\n\n start(threshold?: number): Promise<void> {\n return this._core.start(threshold ?? this.threshold);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\n // No auto-start (§6) — observe() is a synchronous no-op, kept only for\n // API uniformity with other IO nodes' lifecycle.\n this._connectedCallbackPromise = this._core.observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n}\n","import { WcsIdle } from \"./components/Idle.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.idle)) {\n customElements.define(config.tagNames.idle, WcsIdle);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapIdle(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const t={tagNames:{idle:"wcs-idle"}};function e(t){if(null===t||"object"!=typeof t)return t;Object.freeze(t);for(const r of Object.keys(t))e(t[r]);return t}function r(t){if(null===t||"object"!=typeof t)return t;const e={};for(const s of Object.keys(t))e[s]=r(t[s]);return e}let s=null;const n=t;function i(){return s||(s=e(r(t))),s}class a extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"userState",event:"wcs-idle:change",getter:t=>t.detail.userState},{name:"screenState",event:"wcs-idle:change",getter:t=>t.detail.screenState},{name:"active",event:"wcs-idle:change",getter:t=>"active"===t.detail.userState},{name:"error",event:"wcs-idle:error"}],commands:[{name:"requestPermission",async:!0},{name:"start",async:!0},{name:"stop"}]};_target;_userState=null;_screenState=null;_error=null;_detector=null;_abortController=null;_gen=0;_ready=Promise.resolve();constructor(t){super(),this._target=t??this}get ready(){return this._ready}get userState(){return this._userState}get screenState(){return this._screenState}get active(){return"active"===this._userState}get error(){return this._error}observe(){return this._ready}dispose(){this.stop()}_api(){const t=globalThis;return"function"==typeof t.IdleDetector?t.IdleDetector:void 0}_setState(t,e){this._userState===t&&this._screenState===e||(this._userState=t,this._screenState=e,this._target.dispatchEvent(new CustomEvent("wcs-idle:change",{detail:{userState:t,screenState:e},bubbles:!0})))}_setError(t){this._error!==t&&(this._error=t,this._target.dispatchEvent(new CustomEvent("wcs-idle:error",{detail:t,bubbles:!0})))}async requestPermission(){const t=this._api();if(!t)return this._setError({message:"IdleDetector is not supported in this browser"}),"denied";try{const e=await t.requestPermission();return this._setError(null),"granted"===e?"granted":"denied"}catch(t){return this._setError({error:t}),"denied"}}async start(t=6e4){this.stop();const e=this._api();if(!e)return void this._setError({message:"IdleDetector is not supported in this browser"});const r=new AbortController;this._abortController=r;const s=++this._gen;try{const n=new e;if(n.addEventListener("change",this._onChange),this._detector=n,await n.start({threshold:t,signal:r.signal}),s!==this._gen)return;this._setError(null),this._setState(n.userState,n.screenState)}catch(t){if(s!==this._gen)return;this._detector?.removeEventListener("change",this._onChange),this._detector=null,this._abortController=null,this._setError({error:t})}}stop(){this._gen++,this._abortController?.abort(),this._abortController=null,this._detector&&(this._detector.removeEventListener("change",this._onChange),this._detector=null)}_onChange=t=>{const e=t.target;this._setState(e.userState,e.screenState)}}class o extends HTMLElement{static hasConnectedCallbackPromise=!0;static wcBindable={...a.wcBindable,inputs:[{name:"threshold",attribute:"threshold"}],commands:a.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();_internals=null;constructor(){super(),this._core=new a(this),this._internals=this._initInternals(),this._wireStates({"wcs-idle:change":t=>({active:"active"===t.userState}),"wcs-idle:error":t=>({error:null!=t})})}get debugStates(){return this._internals?[...this._internals.states]:[]}_initInternals(){try{if("function"!=typeof this.attachInternals)return null;const t=this.attachInternals();return t.states.add("wcs-probe"),t.states.delete("wcs-probe"),t}catch{return null}}_wireStates(t){if(null===this._internals)return;const e=this._internals.states;for(const[r,s]of Object.entries(t))this.addEventListener(r,t=>{const r=this.hasAttribute("debug-states");for(const[n,i]of Object.entries(s(t.detail))){try{i?e.add(n):e.delete(n)}catch{}r&&this.toggleAttribute(`data-wcs-state-${n}`,i)}})}get threshold(){const t=this.getAttribute("threshold");if(null===t||""===t.trim())return 6e4;const e=Number(t);return Number.isFinite(e)?e:6e4}set threshold(t){this.setAttribute("threshold",String(t))}get userState(){return this._core.userState}get screenState(){return this._core.screenState}get active(){return this._core.active}get error(){return this._core.error}get connectedCallbackPromise(){return this._connectedCallbackPromise}requestPermission(){return this._core.requestPermission()}start(t){return this._core.start(t??this.threshold)}stop(){this._core.stop()}connectedCallback(){this.style.display="none",this._connectedCallbackPromise=this._core.observe()}disconnectedCallback(){this._core.dispose()}}function c(e){var r;e&&((r=e).tagNames&&Object.assign(t.tagNames,r.tagNames),s=null),customElements.get(n.tagNames.idle)||customElements.define(n.tagNames.idle,o)}export{a as IdleCore,o as WcsIdle,c as bootstrapIdle,i as getConfig};
1
+ const e={tagNames:{idle:"wcs-idle"}};function t(e){if(null===e||"object"!=typeof e)return e;Object.freeze(e);for(const r of Object.keys(e))t(e[r]);return e}function r(e){if(null===e||"object"!=typeof e)return e;const t={};for(const s of Object.keys(e))t[s]=r(e[s]);return t}let s=null;const n=e;function o(){return s||(s=t(r(e))),s}const i={CapabilityMissing:"capability-missing",NotAllowed:"not-allowed",IdleError:"idle-error"};class a extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"userState",event:"wcs-idle:change",getter:e=>e.detail.userState},{name:"screenState",event:"wcs-idle:change",getter:e=>e.detail.screenState},{name:"active",event:"wcs-idle:change",getter:e=>"active"===e.detail.userState},{name:"error",event:"wcs-idle:error"},{name:"errorInfo",event:"wcs-idle:error-info-changed"}],commands:[{name:"requestPermission",async:!0},{name:"start",async:!0},{name:"stop"}]};_target;_userState=null;_screenState=null;_error=null;_errorInfo=null;_detector=null;_abortController=null;_gen=0;_ready=Promise.resolve();constructor(e){super(),this._target=e??this}get ready(){return this._ready}get userState(){return this._userState}get screenState(){return this._screenState}get active(){return"active"===this._userState}get error(){return this._error}get errorInfo(){return this._errorInfo}observe(){return this._ready}dispose(){this.stop()}_api(){const e=globalThis;return"function"==typeof e.IdleDetector?e.IdleDetector:void 0}_setState(e,t){this._userState===e&&this._screenState===t||(this._userState=e,this._screenState=t,this._target.dispatchEvent(new CustomEvent("wcs-idle:change",{detail:{userState:e,screenState:t},bubbles:!0})))}_setError(e,t){this._error!==e&&(this._error=e,this._commitErrorInfo(null===e?null:function(e,t){return"unsupported"===e?{code:i.CapabilityMissing,phase:"probe",recoverable:!1,message:t}:"NotAllowedError"===e?{code:i.NotAllowed,phase:"start",recoverable:!1,message:t}:{code:i.IdleError,phase:"execute",recoverable:!1,message:t}}(t,this._errorInfoMessage(e))),this._target.dispatchEvent(new CustomEvent("wcs-idle:error",{detail:e,bubbles:!0})))}_errorInfoMessage(e){const t=null!=e&&"object"==typeof e&&"error"in e?e.error:e;return"string"==typeof t?.message?t.message:String(t)}_commitErrorInfo(e){this._errorInfo=e,this._target.dispatchEvent(new CustomEvent("wcs-idle:error-info-changed",{detail:e,bubbles:!0}))}async requestPermission(){const e=this._api();if(!e)return this._setError({message:"IdleDetector is not supported in this browser"},"unsupported"),"denied";try{const t=await e.requestPermission();return this._setError(null),"granted"===t?"granted":"denied"}catch(e){return this._setError({error:e},e?.name),"denied"}}async start(e=6e4){this.stop();const t=this._api();if(!t)return void this._setError({message:"IdleDetector is not supported in this browser"},"unsupported");const r=new AbortController;this._abortController=r;const s=++this._gen;try{const n=new t;if(n.addEventListener("change",this._onChange),this._detector=n,await n.start({threshold:e,signal:r.signal}),s!==this._gen)return;this._setError(null),this._setState(n.userState,n.screenState)}catch(e){if(s!==this._gen)return;this._detector?.removeEventListener("change",this._onChange),this._detector=null,this._abortController=null,this._setError({error:e},e?.name)}}stop(){this._gen++,this._abortController?.abort(),this._abortController=null,this._detector&&(this._detector.removeEventListener("change",this._onChange),this._detector=null)}_onChange=e=>{const t=e.target;this._setState(t.userState,t.screenState)}}class c extends HTMLElement{static hasConnectedCallbackPromise=!0;static wcBindable={...a.wcBindable,inputs:[{name:"threshold",attribute:"threshold"}],commands:a.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();_internals=null;constructor(){super(),this._core=new a(this),this._internals=this._initInternals(),this._wireStates({"wcs-idle:change":e=>({active:"active"===e.userState}),"wcs-idle:error":e=>({error:null!=e})})}get debugStates(){return this._internals?[...this._internals.states]:[]}_initInternals(){try{if("function"!=typeof this.attachInternals)return null;const e=this.attachInternals();return e.states.add("wcs-probe"),e.states.delete("wcs-probe"),e}catch{return null}}_wireStates(e){if(null===this._internals)return;const t=this._internals.states;for(const[r,s]of Object.entries(e))this.addEventListener(r,e=>{const r=this.hasAttribute("debug-states");for(const[n,o]of Object.entries(s(e.detail))){try{o?t.add(n):t.delete(n)}catch{}r&&this.toggleAttribute(`data-wcs-state-${n}`,o)}})}get threshold(){const e=this.getAttribute("threshold");if(null===e||""===e.trim())return 6e4;const t=Number(e);return Number.isFinite(t)?t:6e4}set threshold(e){this.setAttribute("threshold",String(e))}get userState(){return this._core.userState}get screenState(){return this._core.screenState}get active(){return this._core.active}get error(){return this._core.error}get errorInfo(){return this._core.errorInfo}get connectedCallbackPromise(){return this._connectedCallbackPromise}requestPermission(){return this._core.requestPermission()}start(e){return this._core.start(e??this.threshold)}stop(){this._core.stop()}connectedCallback(){this.style.display="none",this._connectedCallbackPromise=this._core.observe()}disconnectedCallback(){this._core.dispose()}}function l(t){var r;t&&((r=t).tagNames&&Object.assign(e.tagNames,r.tagNames),s=null),customElements.get(n.tagNames.idle)||customElements.define(n.tagNames.idle,c)}export{a as IdleCore,i as WCS_IDLE_ERROR_CODE,c as WcsIdle,l as bootstrapIdle,o 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/core/IdleCore.ts","../src/components/Idle.ts","../src/bootstrapIdle.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n idle: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n idle: \"wcs-idle\",\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 (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\n\ninterface IdleDetectorLike extends EventTarget {\n userState: IdleUserState;\n screenState: IdleScreenState;\n start(options: { threshold: number; signal: AbortSignal }): Promise<void>;\n}\n\ninterface IdleDetectorCtor {\n new (): IdleDetectorLike;\n requestPermission(): Promise<\"granted\" | \"denied\">;\n}\n\nconst MIN_THRESHOLD = 60000;\n\n/**\n * Headless Idle Detection primitive. A thin, framework-agnostic wrapper around\n * `IdleDetector` exposed through the wc-bindable protocol.\n *\n * Reference implementation for batch2's \"gesture-gated permission\" archetype\n * (docs/idle-detection-tag-design.md). `requestPermission()` wraps the static,\n * user-gesture-gated `IdleDetector.requestPermission()` — this Core never\n * calls it automatically; the caller must invoke it from within a real\n * gesture handler.\n *\n * Deliberately does NOT track the 4-value permission state (prompt/granted/\n * denied/unsupported) itself: `navigator.permissions.query({name:\n * \"idle-detection\"})` exists, so compose with `<wcs-permission\n * name=\"idle-detection\">` for that instead (§0). This Core only exposes the\n * actual idle state (userState/screenState) plus the one-time\n * requestPermission()/start()/stop() actions.\n */\nexport class IdleCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"userState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.userState },\n { name: \"screenState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.screenState },\n {\n name: \"active\",\n event: \"wcs-idle:change\",\n getter: (e: Event) => (e as CustomEvent).detail.userState === \"active\",\n },\n // never-throw (§3.6): requestPermission()/start() failures land here\n // instead of rejecting/throwing. Mirrors every other bidirectional IO\n // node in this batch (fetch, share, screen-orientation).\n { name: \"error\", event: \"wcs-idle:error\" },\n ],\n // No `inputs`: the Core has no settable `threshold` state — `threshold` is a\n // per-call argument to `start(threshold)`, not a property/setter. The DOM-driven\n // `threshold` input surface belongs to the Shell (which declares it and backs it\n // with the `threshold` attribute), mirroring geolocation/intersection where the\n // Core declares no inputs and the Shell adds them.\n commands: [\n { name: \"requestPermission\", async: true },\n { name: \"start\", async: true },\n { name: \"stop\" },\n ],\n };\n\n private _target: EventTarget;\n private _userState: IdleUserState | null = null;\n private _screenState: IdleScreenState | null = null;\n private _error: any = null;\n private _detector: IdleDetectorLike | null = null;\n private _abortController: AbortController | null = null;\n\n // Generation guard (§3.4): bumped on dispose()/stop() and each start().\n private _gen = 0;\n\n // SSR (§3.8): never auto-starts on connect, so there is no probe to await —\n // readiness is always immediate (docs/idle-detection-tag-design.md §7).\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get userState(): IdleUserState | null {\n return this._userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._screenState;\n }\n\n get active(): boolean {\n return this._userState === \"active\";\n }\n\n get error(): any {\n return this._error;\n }\n\n // Lifecycle (§3.5). observe() is a synchronous no-op: unlike most IO nodes,\n // this Core deliberately does NOT auto-start on connect (§6) — permission\n // is gesture-gated, so attempting start() before it is granted is\n // guaranteed to fail.\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this.stop();\n }\n\n private _api(): IdleDetectorCtor | undefined {\n const g = globalThis as any;\n return typeof g.IdleDetector === \"function\" ? g.IdleDetector : undefined;\n }\n\n private _setState(userState: IdleUserState, screenState: IdleScreenState): void {\n if (this._userState === userState && this._screenState === screenState) return;\n this._userState = userState;\n this._screenState = screenState;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:change\", {\n detail: { userState, screenState },\n bubbles: true,\n }));\n }\n\n private _setError(error: any): void {\n if (this._error === error) return;\n this._error = error;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n /**\n * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.\n * MUST be invoked from within a real user gesture handler by the caller —\n * this Core cannot manufacture one. never-throw: a gesture-context\n * rejection resolves to `\"denied\"` and lands in `error`. Gesture violation\n * and an actual \"denied\" outcome are not distinguished — both mean \"not\n * usable right now\" (§4.1).\n */\n async requestPermission(): Promise<\"granted\" | \"denied\"> {\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return \"denied\";\n }\n try {\n const result = await Ctor.requestPermission();\n // Symmetric with start()'s success path: any settled (non-throwing)\n // outcome — granted or a plain \"denied\" — supersedes a stale error from\n // an earlier attempt (e.g. a prior gesture-context rejection).\n this._setError(null);\n return result === \"granted\" ? \"granted\" : \"denied\";\n } catch (e) {\n this._setError({ error: e });\n return \"denied\";\n }\n }\n\n /**\n * Start an idle-detection session. `threshold` (ms) must be >= 60000 per\n * spec — not validated here (§3): an out-of-range value is left to the\n * browser's own TypeError, which never-throw absorbs into `error`.\n */\n async start(threshold: number = MIN_THRESHOLD): Promise<void> {\n this.stop(); // supersede any in-flight session (mirrors FetchCore's \"cancel then start\")\n\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" });\n return;\n }\n\n const ac = new AbortController();\n this._abortController = ac;\n const gen = ++this._gen;\n\n try {\n const detector = new Ctor();\n detector.addEventListener(\"change\", this._onChange);\n this._detector = detector;\n await detector.start({ threshold, signal: ac.signal });\n if (gen !== this._gen) return; // stale (stop()/dispose() ran during the await)\n this._setError(null);\n this._setState(detector.userState, detector.screenState);\n } catch (e: any) {\n // No separate AbortError check: stop()/dispose() bump `_gen` *before*\n // calling `ac.abort()` (see stop() below), so a stop()-triggered\n // AbortError always has a stale `gen` here and is already caught by\n // the check above. The signal is private and never exposed, so an\n // AbortError from any other source cannot occur.\n if (gen !== this._gen) return;\n // Tear down the failed session's listener/controller (mirrors stop()):\n // without this, the failed `_detector` stays wired to `_onChange` and a\n // later `change` on that same (never-truly-started) instance would\n // still write state, contradicting the error just recorded.\n this._detector?.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n this._abortController = null;\n this._setError({ error: e });\n }\n }\n\n /** Stop the current session (if any) and detach its listener. Safe to call when not started. */\n stop(): void {\n this._gen++;\n this._abortController?.abort();\n this._abortController = null;\n if (this._detector) {\n this._detector.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n }\n }\n\n private _onChange = (event: Event): void => {\n const detector = event.target as IdleDetectorLike;\n this._setState(detector.userState, detector.screenState);\n };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { IdleCore } from \"../core/IdleCore.js\";\n\n/**\n * `<wcs-idle>` — declarative Idle Detection API primitive.\n *\n * Does NOT auto-start on connect (docs/idle-detection-tag-design.md §6): the\n * permission gate sits in front of `start()`, so an unconditional\n * connectedCallback start would be guaranteed to fail before permission is\n * granted. Callers drive `requestPermission()` → `start()` explicitly, e.g.\n * from a click handler.\n *\n * Compose with `<wcs-permission name=\"idle-detection\">` for prompt/granted/\n * denied status — this Shell only exposes the actual idle state.\n */\nexport class WcsIdle extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...IdleCore.wcBindable,\n inputs: [\n { name: \"threshold\", attribute: \"threshold\" },\n ],\n // Core の commands をそのまま継承(単一情報源)。\n commands: IdleCore.wcBindable.commands,\n };\n\n private _core: IdleCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new IdleCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-idle:change\": (d) => ({ active: d.userState === \"active\" }),\n \"wcs-idle:error\": (d) => ({ error: d != null }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (docs/custom-state-reflection-design.md §3.1/§3.4): attachInternals\n // is absent in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n // --- Attribute accessors ---\n\n /**\n * Minimum idle time (ms) before `userState` becomes `\"idle\"`. This value is\n * read only at `start()` time — there is no `attributeChangedCallback`\n * (deliberately not declared in `observedAttributes`, mirroring\n * `<wcs-gyroscope>`'s `frequency`), so mutating the attribute/property on an\n * already-running session has no effect until the caller `stop()`s and\n * `start()`s again.\n */\n get threshold(): number {\n const attr = this.getAttribute(\"threshold\");\n // An absent, empty, or whitespace-only attribute all mean \"no value\n // supplied\" and must fall back to the default — without this check,\n // `Number(\"\")`/`Number(\" \")` coerce to `0` (finite), which would slip\n // past the `Number.isFinite` fallback below and silently return `0`\n // instead of the documented 60000ms default.\n if (attr === null || attr.trim() === \"\") return 60000;\n const n = Number(attr);\n return Number.isFinite(n) ? n : 60000;\n }\n\n set threshold(value: number) {\n this.setAttribute(\"threshold\", String(value));\n }\n\n // --- Core delegated getters ---\n\n get userState(): IdleUserState | null {\n return this._core.userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._core.screenState;\n }\n\n get active(): boolean {\n return this._core.active;\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 // --- Commands (delegated to Core) ---\n\n requestPermission(): Promise<\"granted\" | \"denied\"> {\n return this._core.requestPermission();\n }\n\n start(threshold?: number): Promise<void> {\n return this._core.start(threshold ?? this.threshold);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\n // No auto-start (§6) — observe() is a synchronous no-op, kept only for\n // API uniformity with other IO nodes' lifecycle.\n this._connectedCallbackPromise = this._core.observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapIdle(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsIdle } from \"./components/Idle.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.idle)) {\n customElements.define(config.tagNames.idle, WcsIdle);\n }\n}\n"],"names":["_config","tagNames","idle","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","IdleCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","userState","screenState","commands","async","_target","_userState","_screenState","_error","_detector","_abortController","_gen","_ready","Promise","resolve","constructor","target","super","this","ready","active","error","observe","dispose","stop","_api","g","globalThis","IdleDetector","undefined","_setState","dispatchEvent","CustomEvent","bubbles","_setError","requestPermission","Ctor","message","result","start","threshold","ac","AbortController","gen","detector","addEventListener","_onChange","signal","removeEventListener","abort","WcsIdle","HTMLElement","wcBindable","inputs","attribute","_core","_connectedCallbackPromise","_internals","_initInternals","_wireStates","d","debugStates","states","attachInternals","internals","add","delete","map","toStates","entries","debug","hasAttribute","on","toggleAttribute","attr","getAttribute","trim","n","Number","isFinite","value","setAttribute","String","connectedCallbackPromise","connectedCallback","style","display","disconnectedCallback","bootstrapIdle","userConfig","partialConfig","assign","customElements","get","define"],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.min.js","sources":["../src/config.ts","../src/core/idleCapabilities.ts","../src/core/IdleCore.ts","../src/components/Idle.ts","../src/bootstrapIdle.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n idle: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n idle: \"wcs-idle\",\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 (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n frozenConfig = null;\n}\n","/**\n * idleCapabilities.ts\n *\n * Idle Detection node 固有の error code(taxonomy)と derivation。汎用の error info 型は\n * `./platformCapability.js`(/io-core/ から copy-distribution される生成ファイル)から\n * import する。idle は requestPermission()/start()/stop() の単一コマンド経路で、競合する\n * operation を持たない(2 回目の start() は前を stop() してから開始する supersede)ため\n * lane は持たず、error taxonomy(errorInfo)のみを採用する。\n *\n * この node の `_setError` は 2 形態の入力を受ける:\n * 1. synthetic な非対応マーカー(`{ message: \"IdleDetector is not supported…\" }`、\n * `.name` 無し)— `globalThis.IdleDetector` 不在。\n * 2. caught された rejection を包んだ `{ error: e }`(`e.name` が実 Error.name)。\n * 両者を message coupling 無しに弁別するため、呼び出し側が明示的な `name` ヒントを渡す\n * (storage の `deriveStorageErrorInfo(error, name)` / screen-orientation と同じ\n * discriminator 技法)。非対応経路は `\"unsupported\"` を、caught 経路は wrap した\n * `e?.name` を渡す。\n *\n * requestPermission()/start() の実 rejection 名は spec のとおり gesture 文脈外 /\n * 権限未許可で `NotAllowedError`。それ以外(生の Error / TypeError(threshold 不正)/\n * `.name` 欠如の nullish reject 等)は一括して `idle-error`。\n */\n\nimport type { WcsIoErrorInfo } from \"./platformCapability.js\";\n\n/** 安定した idle error code(taxonomy)。値は公開キーとして固定。 */\nexport const WCS_IDLE_ERROR_CODE = {\n /** Idle Detection API 非対応(`globalThis.IdleDetector` 不在)。 */\n CapabilityMissing: \"capability-missing\",\n /** `NotAllowedError` — 権限拒否 / user-gesture 文脈外。retry では回復しない。 */\n NotAllowed: \"not-allowed\",\n /** その他の requestPermission()/start() 失敗(生 throw / TypeError / nullish reject 等)。 */\n IdleError: \"idle-error\",\n} as const;\n\n/**\n * idle の失敗を serializable な error taxonomy に写す。\n *\n * `name` は呼び出し側が渡す discriminator:synthetic 非対応なら `\"unsupported\"`、\n * caught 例外なら wrap した `e?.name`(生の非 Error / nullish reject では `undefined`)。\n * `message` は wrap を解いた下位値から抽出済みの文言(非対応なら synthetic の message)。\n *\n * - `\"unsupported\"` は利用直前の能力欠如 → phase=\"probe\" / capability-missing。\n * - `NotAllowedError` は requestPermission()/start() の権限ゲート失敗 → phase=\"start\" /\n * not-allowed / recoverable=false(gesture 違反と実 \"denied\" は区別しない設計 §4.1)。\n * - それ以外(生の throw、TypeError、`.name` 欠如等)は実行中の失敗 → phase=\"execute\" /\n * idle-error / recoverable=false。\n */\nexport function deriveIdleErrorInfo(name: string | undefined, message: string): WcsIoErrorInfo {\n if (name === \"unsupported\") {\n return { code: WCS_IDLE_ERROR_CODE.CapabilityMissing, phase: \"probe\", recoverable: false, message };\n }\n if (name === \"NotAllowedError\") {\n return { code: WCS_IDLE_ERROR_CODE.NotAllowed, phase: \"start\", recoverable: false, message };\n }\n return { code: WCS_IDLE_ERROR_CODE.IdleError, phase: \"execute\", recoverable: false, message };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { WcsIoErrorInfo } from \"./platformCapability.js\";\nimport { deriveIdleErrorInfo } from \"./idleCapabilities.js\";\n\ninterface IdleDetectorLike extends EventTarget {\n userState: IdleUserState;\n screenState: IdleScreenState;\n start(options: { threshold: number; signal: AbortSignal }): Promise<void>;\n}\n\ninterface IdleDetectorCtor {\n new (): IdleDetectorLike;\n requestPermission(): Promise<\"granted\" | \"denied\">;\n}\n\nconst MIN_THRESHOLD = 60000;\n\n/**\n * Headless Idle Detection primitive. A thin, framework-agnostic wrapper around\n * `IdleDetector` exposed through the wc-bindable protocol.\n *\n * Reference implementation for batch2's \"gesture-gated permission\" archetype\n * (docs/idle-detection-tag-design.md). `requestPermission()` wraps the static,\n * user-gesture-gated `IdleDetector.requestPermission()` — this Core never\n * calls it automatically; the caller must invoke it from within a real\n * gesture handler.\n *\n * Deliberately does NOT track the 4-value permission state (prompt/granted/\n * denied/unsupported) itself: `navigator.permissions.query({name:\n * \"idle-detection\"})` exists, so compose with `<wcs-permission\n * name=\"idle-detection\">` for that instead (§0). This Core only exposes the\n * actual idle state (userState/screenState) plus the one-time\n * requestPermission()/start()/stop() actions.\n */\nexport class IdleCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"userState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.userState },\n { name: \"screenState\", event: \"wcs-idle:change\", getter: (e: Event) => (e as CustomEvent).detail.screenState },\n {\n name: \"active\",\n event: \"wcs-idle:change\",\n getter: (e: Event) => (e as CustomEvent).detail.userState === \"active\",\n },\n // never-throw (§3.6): requestPermission()/start() failures land here\n // instead of rejecting/throwing. Mirrors every other bidirectional IO\n // node in this batch (fetch, share, screen-orientation).\n { name: \"error\", event: \"wcs-idle:error\" },\n // Serializable failure taxonomy (stable code / phase / recoverable), or null.\n // Additive bindable output derived from `error` (capability-missing / not-allowed\n // / idle-error); the existing `error` property/event are unchanged. Fires\n // wcs-idle:error-info-changed. No lane — requestPermission()/start()/stop() form a\n // single command path (a 2nd start() supersedes the 1st), not competing operations.\n { name: \"errorInfo\", event: \"wcs-idle:error-info-changed\" },\n ],\n // No `inputs`: the Core has no settable `threshold` state — `threshold` is a\n // per-call argument to `start(threshold)`, not a property/setter. The DOM-driven\n // `threshold` input surface belongs to the Shell (which declares it and backs it\n // with the `threshold` attribute), mirroring geolocation/intersection where the\n // Core declares no inputs and the Shell adds them.\n commands: [\n { name: \"requestPermission\", async: true },\n { name: \"start\", async: true },\n { name: \"stop\" },\n ],\n };\n\n private _target: EventTarget;\n private _userState: IdleUserState | null = null;\n private _screenState: IdleScreenState | null = null;\n private _error: any = null;\n // Additive failure taxonomy, kept strictly in sync with `_error` (derived on\n // every _setError, cleared to null when error clears). The two transition together.\n private _errorInfo: WcsIoErrorInfo | null = null;\n private _detector: IdleDetectorLike | null = null;\n private _abortController: AbortController | null = null;\n\n // Generation guard (§3.4): bumped on dispose()/stop() and each start().\n private _gen = 0;\n\n // SSR (§3.8): never auto-starts on connect, so there is no probe to await —\n // readiness is always immediate (docs/idle-detection-tag-design.md §7).\n private _ready: Promise<void> = Promise.resolve();\n\n constructor(target?: EventTarget) {\n super();\n this._target = target ?? this;\n }\n\n get ready(): Promise<void> {\n return this._ready;\n }\n\n get userState(): IdleUserState | null {\n return this._userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._screenState;\n }\n\n get active(): boolean {\n return this._userState === \"active\";\n }\n\n get error(): any {\n return this._error;\n }\n\n /**\n * The last failure's serializable `WcsIoErrorInfo` (stable `code` / `phase` /\n * `recoverable`), or null. Additive wc-bindable property (event\n * `wcs-idle:error-info-changed`), derived from `error`; the existing `error`\n * property/event are unchanged.\n */\n get errorInfo(): WcsIoErrorInfo | null {\n return this._errorInfo;\n }\n\n // Lifecycle (§3.5). observe() is a synchronous no-op: unlike most IO nodes,\n // this Core deliberately does NOT auto-start on connect (§6) — permission\n // is gesture-gated, so attempting start() before it is granted is\n // guaranteed to fail.\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this.stop();\n }\n\n private _api(): IdleDetectorCtor | undefined {\n const g = globalThis as any;\n return typeof g.IdleDetector === \"function\" ? g.IdleDetector : undefined;\n }\n\n private _setState(userState: IdleUserState, screenState: IdleScreenState): void {\n if (this._userState === userState && this._screenState === screenState) return;\n this._userState = userState;\n this._screenState = screenState;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:change\", {\n detail: { userState, screenState },\n bubbles: true,\n }));\n }\n\n // `name` is the discriminator for the additive `errorInfo` taxonomy only (it\n // stays out of the public `error` shape): the synthetic unsupported marker has\n // no `.name`, so the unsupported call sites pass an explicit `\"unsupported\"`\n // hint (storage/screen-orientation-style — avoids coupling to `error.message`),\n // while the caught paths pass the wrapped rejection's `Error.name` (`e?.name`).\n // `null` clears (no name).\n private _setError(error: any, name?: string): void {\n if (this._error === error) return;\n this._error = error;\n // Keep the additive `errorInfo` taxonomy in sync with `error`: derive from the\n // discriminator + extracted message (or null on clear). Fires before the `error`\n // event so an observer binding both sees the classification first, mirroring the\n // io-node family.\n this._commitErrorInfo(error === null ? null : deriveIdleErrorInfo(name, this._errorInfoMessage(error)));\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n // Extract a serializable string message for `errorInfo` WITHOUT normalizing the\n // public `error` shape. The public error is either the synthetic `{ message }`\n // (unsupported) or a wrapped `{ error: e }` (a caught rejection). For the wrapped\n // form the meaningful message lives on `e`, so unwrap one level before reading\n // `.message`; a non-conformant / nullish value (e.g. `Promise.reject(undefined)`)\n // falls back to `String(...)` so it still classifies instead of throwing\n // (never-throw §3.6).\n private _errorInfoMessage(error: any): string {\n const src = error != null && typeof error === \"object\" && \"error\" in error ? error.error : error;\n return typeof src?.message === \"string\" ? src.message : String(src);\n }\n\n // Called only from _setError (which already same-value-guards on the error\n // reference), so errorInfo transitions exactly when error does — no separate\n // guard needed here.\n private _commitErrorInfo(info: WcsIoErrorInfo | null): void {\n this._errorInfo = info;\n this._target.dispatchEvent(new CustomEvent(\"wcs-idle:error-info-changed\", {\n detail: info,\n bubbles: true,\n }));\n }\n\n /**\n * Wraps the static, user-gesture-gated `IdleDetector.requestPermission()`.\n * MUST be invoked from within a real user gesture handler by the caller —\n * this Core cannot manufacture one. never-throw: a gesture-context\n * rejection resolves to `\"denied\"` and lands in `error`. Gesture violation\n * and an actual \"denied\" outcome are not distinguished — both mean \"not\n * usable right now\" (§4.1).\n */\n async requestPermission(): Promise<\"granted\" | \"denied\"> {\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" }, \"unsupported\");\n return \"denied\";\n }\n try {\n const result = await Ctor.requestPermission();\n // Symmetric with start()'s success path: any settled (non-throwing)\n // outcome — granted or a plain \"denied\" — supersedes a stale error from\n // an earlier attempt (e.g. a prior gesture-context rejection).\n this._setError(null);\n return result === \"granted\" ? \"granted\" : \"denied\";\n } catch (e: any) {\n this._setError({ error: e }, e?.name);\n return \"denied\";\n }\n }\n\n /**\n * Start an idle-detection session. `threshold` (ms) must be >= 60000 per\n * spec — not validated here (§3): an out-of-range value is left to the\n * browser's own TypeError, which never-throw absorbs into `error`.\n */\n async start(threshold: number = MIN_THRESHOLD): Promise<void> {\n this.stop(); // supersede any in-flight session (mirrors FetchCore's \"cancel then start\")\n\n const Ctor = this._api();\n if (!Ctor) {\n this._setError({ message: \"IdleDetector is not supported in this browser\" }, \"unsupported\");\n return;\n }\n\n const ac = new AbortController();\n this._abortController = ac;\n const gen = ++this._gen;\n\n try {\n const detector = new Ctor();\n detector.addEventListener(\"change\", this._onChange);\n this._detector = detector;\n await detector.start({ threshold, signal: ac.signal });\n if (gen !== this._gen) return; // stale (stop()/dispose() ran during the await)\n this._setError(null);\n this._setState(detector.userState, detector.screenState);\n } catch (e: any) {\n // No separate AbortError check: stop()/dispose() bump `_gen` *before*\n // calling `ac.abort()` (see stop() below), so a stop()-triggered\n // AbortError always has a stale `gen` here and is already caught by\n // the check above. The signal is private and never exposed, so an\n // AbortError from any other source cannot occur.\n if (gen !== this._gen) return;\n // Tear down the failed session's listener/controller (mirrors stop()):\n // without this, the failed `_detector` stays wired to `_onChange` and a\n // later `change` on that same (never-truly-started) instance would\n // still write state, contradicting the error just recorded.\n this._detector?.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n this._abortController = null;\n this._setError({ error: e }, e?.name);\n }\n }\n\n /** Stop the current session (if any) and detach its listener. Safe to call when not started. */\n stop(): void {\n this._gen++;\n this._abortController?.abort();\n this._abortController = null;\n if (this._detector) {\n this._detector.removeEventListener(\"change\", this._onChange);\n this._detector = null;\n }\n }\n\n private _onChange = (event: Event): void => {\n const detector = event.target as IdleDetectorLike;\n this._setState(detector.userState, detector.screenState);\n };\n}\n","import { IdleScreenState, IdleUserState, IWcBindable } from \"../types.js\";\nimport { IdleCore } from \"../core/IdleCore.js\";\nimport { WcsIoErrorInfo } from \"../core/platformCapability.js\";\n\n/**\n * `<wcs-idle>` — declarative Idle Detection API primitive.\n *\n * Does NOT auto-start on connect (docs/idle-detection-tag-design.md §6): the\n * permission gate sits in front of `start()`, so an unconditional\n * connectedCallback start would be guaranteed to fail before permission is\n * granted. Callers drive `requestPermission()` → `start()` explicitly, e.g.\n * from a click handler.\n *\n * Compose with `<wcs-permission name=\"idle-detection\">` for prompt/granted/\n * denied status — this Shell only exposes the actual idle state.\n */\nexport class WcsIdle extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...IdleCore.wcBindable,\n inputs: [\n { name: \"threshold\", attribute: \"threshold\" },\n ],\n // Core の commands をそのまま継承(単一情報源)。\n commands: IdleCore.wcBindable.commands,\n };\n\n private _core: IdleCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n private _internals: ElementInternals | null = null;\n\n constructor() {\n super();\n this._core = new IdleCore(this);\n this._internals = this._initInternals();\n this._wireStates({\n \"wcs-idle:change\": (d) => ({ active: d.userState === \"active\" }),\n \"wcs-idle:error\": (d) => ({ error: d != null }),\n });\n }\n\n // CSS state reflection (:state()) — debug-only snapshot getter. NOT part of\n // wc-bindable (not a bind target); see README \"CSS styling with :state()\".\n // MUST NOT return the live CustomStateSet (that would let callers write\n // states from outside, defeating the point of :state() being read-only).\n get debugStates(): string[] {\n return this._internals ? [...this._internals.states] : [];\n }\n\n private _initInternals(): ElementInternals | null {\n // never-throw (docs/custom-state-reflection-design.md §3.1/§3.4): attachInternals\n // is absent in happy-dom / older environments, and pre-125 Chromium rejects\n // non-dashed state names from states.add() (probed and discarded here).\n // Either case silently disables reflection — the component still works,\n // it just doesn't expose :state() selectors.\n try {\n if (typeof this.attachInternals !== \"function\") return null;\n const internals = this.attachInternals();\n internals.states.add(\"wcs-probe\");\n internals.states.delete(\"wcs-probe\");\n return internals;\n } catch {\n return null;\n }\n }\n\n private _wireStates(map: Record<string, (detail: any) => Record<string, boolean>>): void {\n if (this._internals === null) return;\n const states = this._internals.states;\n for (const [event, toStates] of Object.entries(map)) {\n this.addEventListener(event, (e) => {\n const debug = this.hasAttribute(\"debug-states\");\n for (const [name, on] of Object.entries(toStates((e as CustomEvent).detail))) {\n try {\n if (on) { states.add(name); } else { states.delete(name); }\n } catch { /* never-throw */ }\n if (debug) this.toggleAttribute(`data-wcs-state-${name}`, on);\n }\n });\n }\n }\n\n // --- Attribute accessors ---\n\n /**\n * Minimum idle time (ms) before `userState` becomes `\"idle\"`. This value is\n * read only at `start()` time — there is no `attributeChangedCallback`\n * (deliberately not declared in `observedAttributes`, mirroring\n * `<wcs-gyroscope>`'s `frequency`), so mutating the attribute/property on an\n * already-running session has no effect until the caller `stop()`s and\n * `start()`s again.\n */\n get threshold(): number {\n const attr = this.getAttribute(\"threshold\");\n // An absent, empty, or whitespace-only attribute all mean \"no value\n // supplied\" and must fall back to the default — without this check,\n // `Number(\"\")`/`Number(\" \")` coerce to `0` (finite), which would slip\n // past the `Number.isFinite` fallback below and silently return `0`\n // instead of the documented 60000ms default.\n if (attr === null || attr.trim() === \"\") return 60000;\n const n = Number(attr);\n return Number.isFinite(n) ? n : 60000;\n }\n\n set threshold(value: number) {\n this.setAttribute(\"threshold\", String(value));\n }\n\n // --- Core delegated getters ---\n\n get userState(): IdleUserState | null {\n return this._core.userState;\n }\n\n get screenState(): IdleScreenState | null {\n return this._core.screenState;\n }\n\n get active(): boolean {\n return this._core.active;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get errorInfo(): WcsIoErrorInfo | null {\n return this._core.errorInfo;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands (delegated to Core) ---\n\n requestPermission(): Promise<\"granted\" | \"denied\"> {\n return this._core.requestPermission();\n }\n\n start(threshold?: number): Promise<void> {\n return this._core.start(threshold ?? this.threshold);\n }\n\n stop(): void {\n this._core.stop();\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\n // No auto-start (§6) — observe() is a synchronous no-op, kept only for\n // API uniformity with other IO nodes' lifecycle.\n this._connectedCallbackPromise = this._core.observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapIdle(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsIdle } from \"./components/Idle.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.idle)) {\n customElements.define(config.tagNames.idle, WcsIdle);\n }\n}\n"],"names":["_config","tagNames","idle","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","WCS_IDLE_ERROR_CODE","CapabilityMissing","NotAllowed","IdleError","IdleCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","userState","screenState","commands","async","_target","_userState","_screenState","_error","_errorInfo","_detector","_abortController","_gen","_ready","Promise","resolve","constructor","target","super","this","ready","active","error","errorInfo","observe","dispose","stop","_api","g","globalThis","IdleDetector","undefined","_setState","dispatchEvent","CustomEvent","bubbles","_setError","_commitErrorInfo","message","code","phase","recoverable","deriveIdleErrorInfo","_errorInfoMessage","src","String","info","requestPermission","Ctor","result","start","threshold","ac","AbortController","gen","detector","addEventListener","_onChange","signal","removeEventListener","abort","WcsIdle","HTMLElement","wcBindable","inputs","attribute","_core","_connectedCallbackPromise","_internals","_initInternals","_wireStates","d","debugStates","states","attachInternals","internals","add","delete","map","toStates","entries","debug","hasAttribute","on","toggleAttribute","attr","getAttribute","trim","n","Number","isFinite","value","setAttribute","connectedCallbackPromise","connectedCallback","style","display","disconnectedCallback","bootstrapIdle","userConfig","partialConfig","assign","customElements","get","define"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/idle",
3
- "version": "1.19.1",
3
+ "version": "1.21.0",
4
4
  "description": "Declarative Idle Detection component for Web Components. Framework-agnostic IdleDetector wrapper via wc-bindable-protocol.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",