@wcstack/credential 1.16.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 +98 -0
- package/README.md +99 -0
- package/dist/auto.js +3 -0
- package/dist/auto.min.js +1 -0
- package/dist/index.d.ts +174 -0
- package/dist/index.esm.js +356 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.esm.min.js +2 -0
- package/dist/index.esm.min.js.map +1 -0
- package/package.json +70 -0
package/README.ja.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# @wcstack/credential
|
|
2
|
+
|
|
3
|
+
`@wcstack/credential` は wcstack エコシステム向けのヘッドレスな Credential Management コンポーネントです。
|
|
4
|
+
|
|
5
|
+
視覚的な UI ウィジェットではありません。`navigator.credentials.get()`/`.store()` を宣言的コマンド+観測可能stateに変える**非同期プリミティブノード**で、`@wcstack/share`が確立したバッチ3の「薄いcommand」アーキタイプを再利用します。
|
|
6
|
+
|
|
7
|
+
`@wcstack/state` と組み合わせると、`<wcs-credential>` はパス契約で直接バインドできます:
|
|
8
|
+
|
|
9
|
+
- **入力サーフェス**: 無し — `get(options)`/`store(credential)`の引数は呼び出しごと
|
|
10
|
+
- **出力 state サーフェス**: `value`、`loading`、`error`、`cancelled`
|
|
11
|
+
|
|
12
|
+
## なぜ存在するか — password/federatedのみ、WebAuthnは明示的にスコープ外
|
|
13
|
+
|
|
14
|
+
`navigator.credentials`は3種類の資格情報(`password`、`federated`、`publicKey`/WebAuthn)を1つの`get()`/`store()`サーフェスで統一的に扱います。**本パッケージのv1は`publicKey`を完全に除外します。** WebAuthnはattestation・authenticator選択・platform vs cross-platform・RP設定等、遥かに大きなサーフェスであり、専用の別ノードに値します。呼び出し元が`publicKey`オプションを渡した場合、プラットフォームAPIへは**転送せず**、スコープ違反の`error`として表面化させます——本パッケージが誤ってWebAuthnの裏口になることを防ぎます。
|
|
15
|
+
|
|
16
|
+
> **user gesture不要。** `@wcstack/share`/`@wcstack/fullscreen`と異なり、`navigator.credentials.get()`はuser gestureを必要としません——このノードはページロード時に自動的に呼び出し「サイレントサインイン」フロー(`get({ mediation: "silent" })`)を実現できます。
|
|
17
|
+
|
|
18
|
+
> **`get()`/`store()`は単一の`_gen`世代ガードを共有します** — v1で許容される簡略化です。実際の認証フローではこの2つは逐次的に使われる(ログイン成功後にstoreする、試行前にgetする)ため、同一要素で自然に並行呼び出しされることは想定しにくいです。もし両方が同一の`<wcs-credential>`に対して並行して起動されたら、後の呼び出しの完了が前の呼び出しの結果を黙って上書きします。実際にこれが問題になったら、Core自体を作り直すのではなく**2つの別々の`<wcs-credential>`インスタンス**(1つはget用、1つはstore用)を使ってください——`docs/multi-promise-io-node-design.md`参照。
|
|
19
|
+
|
|
20
|
+
## インストール
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @wcstack/credential
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## クイックスタート
|
|
27
|
+
|
|
28
|
+
### 1. ページロード時のサイレントサインイン
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<script type="module" src="https://esm.run/@wcstack/state/auto"></script>
|
|
32
|
+
<script type="module" src="https://esm.run/@wcstack/credential/auto"></script>
|
|
33
|
+
|
|
34
|
+
<wcs-state>
|
|
35
|
+
<script type="module">
|
|
36
|
+
export default {
|
|
37
|
+
user: null,
|
|
38
|
+
async trySilentSignIn() {
|
|
39
|
+
const el = document.querySelector("wcs-credential");
|
|
40
|
+
const credential = await el.get({ password: true, mediation: "silent" });
|
|
41
|
+
if (credential) this.user = credential;
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
</script>
|
|
45
|
+
</wcs-state>
|
|
46
|
+
|
|
47
|
+
<wcs-credential data-wcs="value: user"></wcs-credential>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. ログイン成功後に資格情報を保存する
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<wcs-credential data-wcs="command.store: $command.saveCredential"></wcs-credential>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 観測可能プロパティ(出力)
|
|
57
|
+
|
|
58
|
+
| プロパティ | イベント | 説明 |
|
|
59
|
+
| ----------- | ----------------------------------- | ---- |
|
|
60
|
+
| `value` | `wcs-credential:complete` | 取得/保存された資格情報、成功前は`null`。 |
|
|
61
|
+
| `loading` | `wcs-credential:loading-changed` | `get()`/`store()`呼び出し中は`true`。 |
|
|
62
|
+
| `error` | `wcs-credential:error` | 真のプラットフォーム失敗(正規化された`{ name, message }`)、無ければ`null`。 |
|
|
63
|
+
| `cancelled` | `wcs-credential:cancelled-changed` | ユーザーがブラウザのアカウント選択UIを閉じたら`true`(Credential Management APIは`NotAllowedError`でrejectする)。`error`には含めない。 |
|
|
64
|
+
|
|
65
|
+
## コマンド
|
|
66
|
+
|
|
67
|
+
| コマンド | 非同期 | 説明 |
|
|
68
|
+
| -------- | ------ | ---- |
|
|
69
|
+
| `get` | はい | `get(options)` — `options.publicKey`はスコープ違反として拒否(転送しない、上記参照)。never-throw: `NotAllowedError`(ユーザーがアカウント選択UIを閉じた)は`cancelled`へ、それ以外は`error`へ。 |
|
|
70
|
+
| `store` | はい | `store(credential)` — `value`は入力した資格情報をそのままエコーバック(`navigator.credentials.store()`自体は`Promise<void>`でresolveするため)。 |
|
|
71
|
+
|
|
72
|
+
## 属性 / 入力
|
|
73
|
+
|
|
74
|
+
**無し。**
|
|
75
|
+
|
|
76
|
+
## 注意・制限
|
|
77
|
+
|
|
78
|
+
- **WebAuthn(`publicKey`)はv1スコープ外です** — 将来の`<wcs-webauthn>`ノードで対応予定。
|
|
79
|
+
- **`get()`/`store()`は単一の`_gen`を共有します** — 並行呼び出しの注意点と回避策は上記「なぜ存在するか」参照。
|
|
80
|
+
- `@wcstack/share`/`@wcstack/eyedropper`/`@wcstack/contacts`とアーキタイプを共有: never-throw、AbortController無し。
|
|
81
|
+
|
|
82
|
+
## ヘッドレス利用(`CredentialCore`)
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { CredentialCore } from "@wcstack/credential";
|
|
86
|
+
|
|
87
|
+
const core = new CredentialCore();
|
|
88
|
+
core.addEventListener("wcs-credential:complete", (e) => {
|
|
89
|
+
console.log((e as CustomEvent).detail.value);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const credential = await core.get({ password: true });
|
|
93
|
+
core.dispose();
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## ライセンス
|
|
97
|
+
|
|
98
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# @wcstack/credential
|
|
2
|
+
|
|
3
|
+
`@wcstack/credential` is a headless Credential Management component for the wcstack ecosystem.
|
|
4
|
+
|
|
5
|
+
It is not a visual UI widget.
|
|
6
|
+
It is an **async primitive node** that turns `navigator.credentials.get()`/`.store()` into declarative commands + observable state, reusing the batch-3 "thin command" archetype `@wcstack/share` establishes.
|
|
7
|
+
|
|
8
|
+
With `@wcstack/state`, `<wcs-credential>` can be bound directly through path contracts:
|
|
9
|
+
|
|
10
|
+
- **input surface**: none — `get(options)`/`store(credential)`'s arguments are per-call
|
|
11
|
+
- **output state surface**: `value`, `loading`, `error`, `cancelled`
|
|
12
|
+
|
|
13
|
+
## Why this exists — password/federated only, WebAuthn is explicitly out of scope
|
|
14
|
+
|
|
15
|
+
`navigator.credentials` unifies three credential kinds (`password`, `federated`, `publicKey`/WebAuthn) behind one `get()`/`store()` surface. **v1 of this package excludes `publicKey` entirely.** WebAuthn is a much larger surface — attestation, authenticator selection, platform vs cross-platform, RP configuration — that deserves its own dedicated node. If a caller passes a `publicKey` option, it is **not** forwarded to the platform API; it surfaces as a scope-violation `error` instead, so this package never accidentally becomes a WebAuthn backdoor.
|
|
16
|
+
|
|
17
|
+
> **No user gesture required.** Unlike `@wcstack/share`/`@wcstack/fullscreen`, `navigator.credentials.get()` does not require a user gesture — this node can be invoked automatically on page load for a "silent sign-in" flow (`get({ mediation: "silent" })`).
|
|
18
|
+
|
|
19
|
+
> **`get()`/`store()` share a single `_gen` generation guard** — an accepted v1 simplification. These two operations are used sequentially in real auth flows (store after a successful login, get before attempting one), not naturally concurrently on the same element. If both ARE invoked concurrently on the same `<wcs-credential>`, the later call's completion silently overwrites the earlier one's. If this bites in practice, use **two separate `<wcs-credential>` instances** (one for `get`, one for `store`) rather than reworking the Core — see `docs/multi-promise-io-node-design.md`.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @wcstack/credential
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Silent sign-in on page load
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<script type="module" src="https://esm.run/@wcstack/state/auto"></script>
|
|
33
|
+
<script type="module" src="https://esm.run/@wcstack/credential/auto"></script>
|
|
34
|
+
|
|
35
|
+
<wcs-state>
|
|
36
|
+
<script type="module">
|
|
37
|
+
export default {
|
|
38
|
+
user: null,
|
|
39
|
+
async trySilentSignIn() {
|
|
40
|
+
const el = document.querySelector("wcs-credential");
|
|
41
|
+
const credential = await el.get({ password: true, mediation: "silent" });
|
|
42
|
+
if (credential) this.user = credential;
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
</script>
|
|
46
|
+
</wcs-state>
|
|
47
|
+
|
|
48
|
+
<wcs-credential data-wcs="value: user"></wcs-credential>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Store credentials after a successful login
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<wcs-credential data-wcs="command.store: $command.saveCredential"></wcs-credential>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Observable Properties (outputs)
|
|
58
|
+
|
|
59
|
+
| Property | Event | Description |
|
|
60
|
+
| ----------- | -------------------------------- | ------------ |
|
|
61
|
+
| `value` | `wcs-credential:complete` | The retrieved/stored credential, or `null` before any successful call. |
|
|
62
|
+
| `loading` | `wcs-credential:loading-changed` | `true` while a `get()`/`store()` call is in flight. |
|
|
63
|
+
| `error` | `wcs-credential:error` | A true platform failure (normalized `{ name, message }`), or `null`. |
|
|
64
|
+
| `cancelled` | `wcs-credential:cancelled-changed` | `true` when the user dismissed the browser's account-chooser UI (the Credential Management API rejects with `NotAllowedError`). Kept out of `error`. |
|
|
65
|
+
|
|
66
|
+
## Commands
|
|
67
|
+
|
|
68
|
+
| Command | Async | Description |
|
|
69
|
+
| ------- | ----- | ------------ |
|
|
70
|
+
| `get` | yes | `get(options)` — `options.publicKey` is rejected as a scope violation (see above) rather than forwarded. Never-throw: `NotAllowedError` (user dismissed the account chooser) → `cancelled`, everything else → `error`. |
|
|
71
|
+
| `store` | yes | `store(credential)` — `value` echoes the input credential (`navigator.credentials.store()` itself resolves `Promise<void>`). |
|
|
72
|
+
|
|
73
|
+
## Attributes / Inputs
|
|
74
|
+
|
|
75
|
+
**None.**
|
|
76
|
+
|
|
77
|
+
## Notes & limitations
|
|
78
|
+
|
|
79
|
+
- **WebAuthn (`publicKey`) is out of scope for v1** — a future `<wcs-webauthn>` node would cover it.
|
|
80
|
+
- **`get()`/`store()` share one `_gen`** — see "Why this exists" above for the concurrency caveat and workaround.
|
|
81
|
+
- Shares its architecture with `@wcstack/share`/`@wcstack/eyedropper`/`@wcstack/contacts`: never-throw, no `AbortController`.
|
|
82
|
+
|
|
83
|
+
## Headless usage (`CredentialCore`)
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { CredentialCore } from "@wcstack/credential";
|
|
87
|
+
|
|
88
|
+
const core = new CredentialCore();
|
|
89
|
+
core.addEventListener("wcs-credential:complete", (e) => {
|
|
90
|
+
console.log((e as CustomEvent).detail.value);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const credential = await core.get({ password: true });
|
|
94
|
+
core.dispose();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
MIT
|
package/dist/auto.js
ADDED
package/dist/auto.min.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{bootstrapCredential}from"./index.esm.min.js";bootstrapCredential();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
interface IWcBindableProperty {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly event: string;
|
|
4
|
+
readonly getter?: (event: Event) => any;
|
|
5
|
+
}
|
|
6
|
+
interface IWcBindableInput {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly attribute?: string;
|
|
9
|
+
}
|
|
10
|
+
interface IWcBindableCommand {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly async?: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface IWcBindable {
|
|
15
|
+
readonly protocol: "wc-bindable";
|
|
16
|
+
readonly version: 1;
|
|
17
|
+
readonly properties: readonly IWcBindableProperty[];
|
|
18
|
+
readonly inputs?: readonly IWcBindableInput[];
|
|
19
|
+
readonly commands?: readonly IWcBindableCommand[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface ITagNames {
|
|
23
|
+
readonly credential: string;
|
|
24
|
+
}
|
|
25
|
+
interface IWritableTagNames {
|
|
26
|
+
credential?: string;
|
|
27
|
+
}
|
|
28
|
+
interface IConfig {
|
|
29
|
+
readonly tagNames: ITagNames;
|
|
30
|
+
}
|
|
31
|
+
interface IWritableConfig {
|
|
32
|
+
tagNames?: IWritableTagNames;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* v1 scope: password/federated credentials only (docs/credential-tag-design.md
|
|
37
|
+
* §0). `publicKey` (WebAuthn) is a much larger surface — attestation,
|
|
38
|
+
* authenticator selection, platform vs cross-platform, RP configuration —
|
|
39
|
+
* that deserves its own dedicated node in a future batch. This Core validates
|
|
40
|
+
* and strips a `publicKey` key if a caller passes one, rather than silently
|
|
41
|
+
* forwarding it (which would accidentally support WebAuthn through a side
|
|
42
|
+
* door this package explicitly does not claim to support).
|
|
43
|
+
*/
|
|
44
|
+
interface CredentialGetOptions {
|
|
45
|
+
password?: boolean;
|
|
46
|
+
federated?: {
|
|
47
|
+
providers?: string[];
|
|
48
|
+
protocols?: string[];
|
|
49
|
+
};
|
|
50
|
+
mediation?: "silent" | "optional" | "required";
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
}
|
|
53
|
+
/** A password or federated credential, as accepted by `navigator.credentials.store()`. */
|
|
54
|
+
type StorableCredential = Credential;
|
|
55
|
+
/**
|
|
56
|
+
* Value types for CredentialCore (headless) — the observable state properties.
|
|
57
|
+
*/
|
|
58
|
+
interface WcsCredentialCoreValues {
|
|
59
|
+
value: Credential | null;
|
|
60
|
+
loading: boolean;
|
|
61
|
+
error: any;
|
|
62
|
+
cancelled: boolean;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Value types for the Shell (`<wcs-credential>`) — identical observable
|
|
66
|
+
* surface to the Core.
|
|
67
|
+
*/
|
|
68
|
+
type WcsCredentialValues = WcsCredentialCoreValues;
|
|
69
|
+
|
|
70
|
+
declare function bootstrapCredential(userConfig?: IWritableConfig): void;
|
|
71
|
+
|
|
72
|
+
declare function getConfig(): IConfig;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Headless Credential Management primitive. A thin, framework-agnostic
|
|
76
|
+
* wrapper around `navigator.credentials.get()`/`.store()` exposed through the
|
|
77
|
+
* wc-bindable protocol.
|
|
78
|
+
*
|
|
79
|
+
* Reuses batch3's "thin command" archetype established by `@wcstack/share`
|
|
80
|
+
* (docs/credential-tag-design.md): single `_gen` generation guard,
|
|
81
|
+
* same-value-guarded private setters, never-throw try/catch, no
|
|
82
|
+
* `AbortController`/`abort()` command.
|
|
83
|
+
*
|
|
84
|
+
* **v1 scope excludes WebAuthn (`publicKey`)** — see docs/credential-tag-design.md
|
|
85
|
+
* §0. `get()` validates and strips a `publicKey` option rather than silently
|
|
86
|
+
* forwarding it, surfacing the attempt as a scope-violation `error` instead of
|
|
87
|
+
* accidentally supporting WebAuthn through a side door.
|
|
88
|
+
*
|
|
89
|
+
* **`get()`/`store()` share one `_gen`** — an accepted v1 simplification
|
|
90
|
+
* (docs/multi-promise-io-node-design.md): these two operations are used
|
|
91
|
+
* sequentially in real auth flows (store after a successful login, get before
|
|
92
|
+
* attempting one), not naturally concurrently on the same instance. If both
|
|
93
|
+
* ARE invoked concurrently on the same `<wcs-credential>`, the later call's
|
|
94
|
+
* generation bump silently drops the earlier call's completion write. If this
|
|
95
|
+
* limitation actually bites, use two separate `<wcs-credential>` instances
|
|
96
|
+
* (one for get, one for store) rather than reworking the Core.
|
|
97
|
+
*/
|
|
98
|
+
declare class CredentialCore extends EventTarget {
|
|
99
|
+
static wcBindable: IWcBindable;
|
|
100
|
+
private _target;
|
|
101
|
+
private _value;
|
|
102
|
+
private _loading;
|
|
103
|
+
private _error;
|
|
104
|
+
private _cancelled;
|
|
105
|
+
private _gen;
|
|
106
|
+
private _ready;
|
|
107
|
+
constructor(target?: EventTarget);
|
|
108
|
+
get ready(): Promise<void>;
|
|
109
|
+
get value(): Credential | null;
|
|
110
|
+
get loading(): boolean;
|
|
111
|
+
get error(): any;
|
|
112
|
+
get cancelled(): boolean;
|
|
113
|
+
observe(): Promise<void>;
|
|
114
|
+
dispose(): void;
|
|
115
|
+
private _setLoading;
|
|
116
|
+
private _setValue;
|
|
117
|
+
private _setError;
|
|
118
|
+
private _setCancelled;
|
|
119
|
+
private _api;
|
|
120
|
+
private _normalizeError;
|
|
121
|
+
private _isCancellation;
|
|
122
|
+
/**
|
|
123
|
+
* `get(options)` — v1 scope excludes `publicKey` (WebAuthn). If present, it
|
|
124
|
+
* is stripped and the call surfaces a scope-violation `error` instead of
|
|
125
|
+
* forwarding it to the platform API (which would accidentally support
|
|
126
|
+
* WebAuthn through a side door). `navigator.credentials.get()` does not
|
|
127
|
+
* require a user gesture (unlike Web Share/Fullscreen), so this can be
|
|
128
|
+
* invoked automatically on page load for a "silent sign-in" flow.
|
|
129
|
+
*/
|
|
130
|
+
get(options?: CredentialGetOptions & {
|
|
131
|
+
publicKey?: unknown;
|
|
132
|
+
}): Promise<Credential | null>;
|
|
133
|
+
/**
|
|
134
|
+
* `store(credential)` — shares the same single `_gen` as `get()` (see class
|
|
135
|
+
* docs). `navigator.credentials.store()` resolves `Promise<void>` (per
|
|
136
|
+
* `lib.dom.d.ts`) — there is no payload to read off the API, so `value` is
|
|
137
|
+
* synthesized as an echo of the caller's `credential`, mirroring
|
|
138
|
+
* `ShareCore.share()`'s same accommodation for `navigator.share()`.
|
|
139
|
+
*
|
|
140
|
+
* A `PublicKeyCredential` (`type === "public-key"`, WebAuthn) is rejected as a
|
|
141
|
+
* scope violation before touching the platform API — the same v1 boundary
|
|
142
|
+
* `get()` enforces on the `publicKey` option (docs/credential-tag-design.md
|
|
143
|
+
* §3.2), so this node never becomes a WebAuthn store backdoor.
|
|
144
|
+
*/
|
|
145
|
+
store(credential: StorableCredential): Promise<Credential | null>;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* `<wcs-credential>` — declarative Credential Management API primitive
|
|
150
|
+
* (password/federated only — see docs/credential-tag-design.md §0 for the
|
|
151
|
+
* WebAuthn scope exclusion).
|
|
152
|
+
*
|
|
153
|
+
* A thin command-only Shell (mirrors `<wcs-share>`): no attributes at all.
|
|
154
|
+
* `get(options)`/`store(credential)`'s arguments are per-call.
|
|
155
|
+
*/
|
|
156
|
+
declare class WcsCredential extends HTMLElement {
|
|
157
|
+
static hasConnectedCallbackPromise: boolean;
|
|
158
|
+
static wcBindable: IWcBindable;
|
|
159
|
+
private _core;
|
|
160
|
+
private _connectedCallbackPromise;
|
|
161
|
+
constructor();
|
|
162
|
+
get value(): Credential | null;
|
|
163
|
+
get loading(): boolean;
|
|
164
|
+
get error(): any;
|
|
165
|
+
get cancelled(): boolean;
|
|
166
|
+
get connectedCallbackPromise(): Promise<void>;
|
|
167
|
+
get(options?: CredentialGetOptions): Promise<Credential | null>;
|
|
168
|
+
store(credential: StorableCredential): Promise<Credential | null>;
|
|
169
|
+
connectedCallback(): void;
|
|
170
|
+
disconnectedCallback(): void;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export { CredentialCore, WcsCredential, bootstrapCredential, getConfig };
|
|
174
|
+
export type { CredentialGetOptions, IWritableConfig, IWritableTagNames, StorableCredential, WcsCredentialCoreValues, WcsCredentialValues };
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
const _config = {
|
|
2
|
+
tagNames: {
|
|
3
|
+
credential: "wcs-credential",
|
|
4
|
+
},
|
|
5
|
+
};
|
|
6
|
+
function deepFreeze(obj) {
|
|
7
|
+
if (obj === null || typeof obj !== "object")
|
|
8
|
+
return obj;
|
|
9
|
+
Object.freeze(obj);
|
|
10
|
+
for (const key of Object.keys(obj)) {
|
|
11
|
+
deepFreeze(obj[key]);
|
|
12
|
+
}
|
|
13
|
+
return obj;
|
|
14
|
+
}
|
|
15
|
+
function deepClone(obj) {
|
|
16
|
+
if (obj === null || typeof obj !== "object")
|
|
17
|
+
return obj;
|
|
18
|
+
const clone = {};
|
|
19
|
+
for (const key of Object.keys(obj)) {
|
|
20
|
+
clone[key] = deepClone(obj[key]);
|
|
21
|
+
}
|
|
22
|
+
return clone;
|
|
23
|
+
}
|
|
24
|
+
let frozenConfig = null;
|
|
25
|
+
// Note: this is the live, mutable internal config. It is not part of the public
|
|
26
|
+
// package exports (see exports.ts) — only `getConfig()` (a frozen snapshot) is
|
|
27
|
+
// surfaced. `setConfig()` is applied internally via `bootstrapCredential()` and
|
|
28
|
+
// is not re-exported from the package root, though a deep path import
|
|
29
|
+
// (`.../src/config.js`) can still reach and mutate it. Accepted as-is for
|
|
30
|
+
// cross-package consistency: every @wcstack package follows this same shape.
|
|
31
|
+
// Use `getConfig()` for a frozen, safe read.
|
|
32
|
+
const config = _config;
|
|
33
|
+
function getConfig() {
|
|
34
|
+
if (!frozenConfig) {
|
|
35
|
+
frozenConfig = deepFreeze(deepClone(_config));
|
|
36
|
+
}
|
|
37
|
+
return frozenConfig;
|
|
38
|
+
}
|
|
39
|
+
function setConfig(partialConfig) {
|
|
40
|
+
if (partialConfig.tagNames) {
|
|
41
|
+
Object.assign(_config.tagNames, partialConfig.tagNames);
|
|
42
|
+
}
|
|
43
|
+
frozenConfig = null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Headless Credential Management primitive. A thin, framework-agnostic
|
|
48
|
+
* wrapper around `navigator.credentials.get()`/`.store()` exposed through the
|
|
49
|
+
* wc-bindable protocol.
|
|
50
|
+
*
|
|
51
|
+
* Reuses batch3's "thin command" archetype established by `@wcstack/share`
|
|
52
|
+
* (docs/credential-tag-design.md): single `_gen` generation guard,
|
|
53
|
+
* same-value-guarded private setters, never-throw try/catch, no
|
|
54
|
+
* `AbortController`/`abort()` command.
|
|
55
|
+
*
|
|
56
|
+
* **v1 scope excludes WebAuthn (`publicKey`)** — see docs/credential-tag-design.md
|
|
57
|
+
* §0. `get()` validates and strips a `publicKey` option rather than silently
|
|
58
|
+
* forwarding it, surfacing the attempt as a scope-violation `error` instead of
|
|
59
|
+
* accidentally supporting WebAuthn through a side door.
|
|
60
|
+
*
|
|
61
|
+
* **`get()`/`store()` share one `_gen`** — an accepted v1 simplification
|
|
62
|
+
* (docs/multi-promise-io-node-design.md): these two operations are used
|
|
63
|
+
* sequentially in real auth flows (store after a successful login, get before
|
|
64
|
+
* attempting one), not naturally concurrently on the same instance. If both
|
|
65
|
+
* ARE invoked concurrently on the same `<wcs-credential>`, the later call's
|
|
66
|
+
* generation bump silently drops the earlier call's completion write. If this
|
|
67
|
+
* limitation actually bites, use two separate `<wcs-credential>` instances
|
|
68
|
+
* (one for get, one for store) rather than reworking the Core.
|
|
69
|
+
*/
|
|
70
|
+
class CredentialCore extends EventTarget {
|
|
71
|
+
static wcBindable = {
|
|
72
|
+
protocol: "wc-bindable",
|
|
73
|
+
version: 1,
|
|
74
|
+
properties: [
|
|
75
|
+
{ name: "value", event: "wcs-credential:complete", getter: (e) => e.detail.value },
|
|
76
|
+
{ name: "loading", event: "wcs-credential:loading-changed" },
|
|
77
|
+
{ name: "error", event: "wcs-credential:error" },
|
|
78
|
+
{ name: "cancelled", event: "wcs-credential:cancelled-changed" },
|
|
79
|
+
],
|
|
80
|
+
commands: [
|
|
81
|
+
{ name: "get", async: true },
|
|
82
|
+
{ name: "store", async: true },
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
_target;
|
|
86
|
+
_value = null;
|
|
87
|
+
_loading = false;
|
|
88
|
+
_error = null;
|
|
89
|
+
_cancelled = false;
|
|
90
|
+
// Generation guard (§3.4): shared by get() and store() (see class docs on
|
|
91
|
+
// the accepted concurrency limitation this implies).
|
|
92
|
+
_gen = 0;
|
|
93
|
+
// SSR (§3.8): no asynchronous probe to await, so readiness is immediate.
|
|
94
|
+
_ready = Promise.resolve();
|
|
95
|
+
constructor(target) {
|
|
96
|
+
super();
|
|
97
|
+
this._target = target ?? this;
|
|
98
|
+
}
|
|
99
|
+
get ready() {
|
|
100
|
+
return this._ready;
|
|
101
|
+
}
|
|
102
|
+
get value() {
|
|
103
|
+
return this._value;
|
|
104
|
+
}
|
|
105
|
+
get loading() {
|
|
106
|
+
return this._loading;
|
|
107
|
+
}
|
|
108
|
+
get error() {
|
|
109
|
+
return this._error;
|
|
110
|
+
}
|
|
111
|
+
get cancelled() {
|
|
112
|
+
return this._cancelled;
|
|
113
|
+
}
|
|
114
|
+
// Lifecycle (§3.5). Command-driven with no subscription to establish, so
|
|
115
|
+
// observe() is an idempotent no-op that resolves once ready; dispose() only
|
|
116
|
+
// invalidates any in-flight get()/store() (there is nothing to unsubscribe).
|
|
117
|
+
observe() {
|
|
118
|
+
return this._ready;
|
|
119
|
+
}
|
|
120
|
+
dispose() {
|
|
121
|
+
this._gen++;
|
|
122
|
+
}
|
|
123
|
+
_setLoading(loading) {
|
|
124
|
+
if (this._loading === loading)
|
|
125
|
+
return;
|
|
126
|
+
this._loading = loading;
|
|
127
|
+
this._target.dispatchEvent(new CustomEvent("wcs-credential:loading-changed", {
|
|
128
|
+
detail: loading,
|
|
129
|
+
bubbles: true,
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
// Deliberately NO same-value guard (unlike error/loading/cancelled below).
|
|
133
|
+
// `value` is a success-completion signal, not idempotent state: it is written
|
|
134
|
+
// only on a successful get()/store(), and wcs-credential:complete is the *sole*
|
|
135
|
+
// success notification. store() echoes the caller's credential argument, so two
|
|
136
|
+
// consecutive successful store() calls with the same object reference are two
|
|
137
|
+
// distinct completions and must each re-fire wcs-credential:complete so an
|
|
138
|
+
// `$on`/eventToken consumer (and a `value:` binding) sees every success. This
|
|
139
|
+
// matches clipboard `_setRead` / broadcast `_setMessage`, which carve
|
|
140
|
+
// result/event values out of the §3.3 guard for the same reason.
|
|
141
|
+
_setValue(value) {
|
|
142
|
+
this._value = value;
|
|
143
|
+
this._target.dispatchEvent(new CustomEvent("wcs-credential:complete", {
|
|
144
|
+
detail: { value },
|
|
145
|
+
bubbles: true,
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
_setError(error) {
|
|
149
|
+
if (this._error === error)
|
|
150
|
+
return;
|
|
151
|
+
this._error = error;
|
|
152
|
+
this._target.dispatchEvent(new CustomEvent("wcs-credential:error", {
|
|
153
|
+
detail: error,
|
|
154
|
+
bubbles: true,
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
_setCancelled(cancelled) {
|
|
158
|
+
if (this._cancelled === cancelled)
|
|
159
|
+
return;
|
|
160
|
+
this._cancelled = cancelled;
|
|
161
|
+
this._target.dispatchEvent(new CustomEvent("wcs-credential:cancelled-changed", {
|
|
162
|
+
detail: cancelled,
|
|
163
|
+
bubbles: true,
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
_api() {
|
|
167
|
+
const nav = globalThis.navigator;
|
|
168
|
+
return nav?.credentials;
|
|
169
|
+
}
|
|
170
|
+
// Normalizes a rejection reason to a consistent { name, message } shape,
|
|
171
|
+
// mirroring WorkerCore._normalizeError (packages/worker/src/core/WorkerCore.ts).
|
|
172
|
+
_normalizeError(e) {
|
|
173
|
+
if (e instanceof Error) {
|
|
174
|
+
return { name: e.name, message: e.message };
|
|
175
|
+
}
|
|
176
|
+
return { name: "Error", message: String(e) };
|
|
177
|
+
}
|
|
178
|
+
// Classifies a get()/store() rejection as a user cancellation vs a real
|
|
179
|
+
// failure (docs/credential-tag-design.md §2/§5). For the Credential
|
|
180
|
+
// Management API the browser rejects with `NotAllowedError` when the user
|
|
181
|
+
// dismisses/declines the native account-chooser UI — this is a routine "the
|
|
182
|
+
// user did not pick" outcome, not a platform failure, so it maps to
|
|
183
|
+
// `cancelled` and is kept out of `error`. Note this is `NotAllowedError`,
|
|
184
|
+
// NOT `AbortError`: unlike Web Share/Contact Picker (whose APIs reject with
|
|
185
|
+
// `AbortError` on dismissal), credentials.get()/store() signal user refusal
|
|
186
|
+
// via `NotAllowedError`. Every other name (SecurityError, NetworkError, a
|
|
187
|
+
// programmatic signal abort, etc.) flows to `error`.
|
|
188
|
+
_isCancellation(e) {
|
|
189
|
+
return e?.name === "NotAllowedError";
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* `get(options)` — v1 scope excludes `publicKey` (WebAuthn). If present, it
|
|
193
|
+
* is stripped and the call surfaces a scope-violation `error` instead of
|
|
194
|
+
* forwarding it to the platform API (which would accidentally support
|
|
195
|
+
* WebAuthn through a side door). `navigator.credentials.get()` does not
|
|
196
|
+
* require a user gesture (unlike Web Share/Fullscreen), so this can be
|
|
197
|
+
* invoked automatically on page load for a "silent sign-in" flow.
|
|
198
|
+
*/
|
|
199
|
+
async get(options = {}) {
|
|
200
|
+
if ("publicKey" in options) {
|
|
201
|
+
this._setError({ name: "NotSupportedError", message: "WebAuthn (publicKey) is out of scope for @wcstack/credential v1. Use a dedicated WebAuthn node instead." });
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
const api = this._api();
|
|
205
|
+
if (!api) {
|
|
206
|
+
this._setError({ message: "Credential Management API is not supported in this browser." });
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
const gen = ++this._gen;
|
|
210
|
+
this._setLoading(true);
|
|
211
|
+
// Reset the previous outcome before starting a new get so a stale
|
|
212
|
+
// cancelled/error does not linger into this call's result.
|
|
213
|
+
this._setError(null);
|
|
214
|
+
this._setCancelled(false);
|
|
215
|
+
try {
|
|
216
|
+
const credential = await api.get(options);
|
|
217
|
+
if (gen !== this._gen)
|
|
218
|
+
return null; // stale (dispose() ran while awaiting)
|
|
219
|
+
this._setValue(credential);
|
|
220
|
+
this._setLoading(false);
|
|
221
|
+
return credential;
|
|
222
|
+
}
|
|
223
|
+
catch (e) {
|
|
224
|
+
if (gen !== this._gen)
|
|
225
|
+
return null;
|
|
226
|
+
if (this._isCancellation(e)) {
|
|
227
|
+
this._setCancelled(true);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
this._setError(this._normalizeError(e));
|
|
231
|
+
}
|
|
232
|
+
this._setLoading(false);
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* `store(credential)` — shares the same single `_gen` as `get()` (see class
|
|
238
|
+
* docs). `navigator.credentials.store()` resolves `Promise<void>` (per
|
|
239
|
+
* `lib.dom.d.ts`) — there is no payload to read off the API, so `value` is
|
|
240
|
+
* synthesized as an echo of the caller's `credential`, mirroring
|
|
241
|
+
* `ShareCore.share()`'s same accommodation for `navigator.share()`.
|
|
242
|
+
*
|
|
243
|
+
* A `PublicKeyCredential` (`type === "public-key"`, WebAuthn) is rejected as a
|
|
244
|
+
* scope violation before touching the platform API — the same v1 boundary
|
|
245
|
+
* `get()` enforces on the `publicKey` option (docs/credential-tag-design.md
|
|
246
|
+
* §3.2), so this node never becomes a WebAuthn store backdoor.
|
|
247
|
+
*/
|
|
248
|
+
async store(credential) {
|
|
249
|
+
if (credential?.type === "public-key") {
|
|
250
|
+
this._setError({ name: "NotSupportedError", message: "WebAuthn (publicKey) credentials are out of scope for @wcstack/credential v1. Use a dedicated WebAuthn node instead." });
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
const api = this._api();
|
|
254
|
+
if (!api) {
|
|
255
|
+
this._setError({ message: "Credential Management API is not supported in this browser." });
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
const gen = ++this._gen;
|
|
259
|
+
this._setLoading(true);
|
|
260
|
+
// Reset the previous outcome before starting a new store so a stale
|
|
261
|
+
// cancelled/error does not linger into this call's result.
|
|
262
|
+
this._setError(null);
|
|
263
|
+
this._setCancelled(false);
|
|
264
|
+
try {
|
|
265
|
+
await api.store(credential);
|
|
266
|
+
if (gen !== this._gen)
|
|
267
|
+
return null;
|
|
268
|
+
this._setValue(credential);
|
|
269
|
+
this._setLoading(false);
|
|
270
|
+
return credential;
|
|
271
|
+
}
|
|
272
|
+
catch (e) {
|
|
273
|
+
if (gen !== this._gen)
|
|
274
|
+
return null;
|
|
275
|
+
if (this._isCancellation(e)) {
|
|
276
|
+
this._setCancelled(true);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
this._setError(this._normalizeError(e));
|
|
280
|
+
}
|
|
281
|
+
this._setLoading(false);
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* `<wcs-credential>` — declarative Credential Management API primitive
|
|
289
|
+
* (password/federated only — see docs/credential-tag-design.md §0 for the
|
|
290
|
+
* WebAuthn scope exclusion).
|
|
291
|
+
*
|
|
292
|
+
* A thin command-only Shell (mirrors `<wcs-share>`): no attributes at all.
|
|
293
|
+
* `get(options)`/`store(credential)`'s arguments are per-call.
|
|
294
|
+
*/
|
|
295
|
+
class WcsCredential extends HTMLElement {
|
|
296
|
+
static hasConnectedCallbackPromise = true;
|
|
297
|
+
static wcBindable = {
|
|
298
|
+
...CredentialCore.wcBindable,
|
|
299
|
+
inputs: [],
|
|
300
|
+
// Inherit commands from Core (single source of truth).
|
|
301
|
+
commands: CredentialCore.wcBindable.commands,
|
|
302
|
+
};
|
|
303
|
+
_core;
|
|
304
|
+
_connectedCallbackPromise = Promise.resolve();
|
|
305
|
+
constructor() {
|
|
306
|
+
super();
|
|
307
|
+
this._core = new CredentialCore(this);
|
|
308
|
+
}
|
|
309
|
+
// --- Core delegated getters ---
|
|
310
|
+
get value() {
|
|
311
|
+
return this._core.value;
|
|
312
|
+
}
|
|
313
|
+
get loading() {
|
|
314
|
+
return this._core.loading;
|
|
315
|
+
}
|
|
316
|
+
get error() {
|
|
317
|
+
return this._core.error;
|
|
318
|
+
}
|
|
319
|
+
get cancelled() {
|
|
320
|
+
return this._core.cancelled;
|
|
321
|
+
}
|
|
322
|
+
get connectedCallbackPromise() {
|
|
323
|
+
return this._connectedCallbackPromise;
|
|
324
|
+
}
|
|
325
|
+
// --- Commands ---
|
|
326
|
+
get(options) {
|
|
327
|
+
return this._core.get(options);
|
|
328
|
+
}
|
|
329
|
+
store(credential) {
|
|
330
|
+
return this._core.store(credential);
|
|
331
|
+
}
|
|
332
|
+
// --- Lifecycle ---
|
|
333
|
+
connectedCallback() {
|
|
334
|
+
this.style.display = "none";
|
|
335
|
+
this._connectedCallbackPromise = this._core.observe();
|
|
336
|
+
}
|
|
337
|
+
disconnectedCallback() {
|
|
338
|
+
this._core.dispose();
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function registerComponents() {
|
|
343
|
+
if (!customElements.get(config.tagNames.credential)) {
|
|
344
|
+
customElements.define(config.tagNames.credential, WcsCredential);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function bootstrapCredential(userConfig) {
|
|
349
|
+
if (userConfig) {
|
|
350
|
+
setConfig(userConfig);
|
|
351
|
+
}
|
|
352
|
+
registerComponents();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export { CredentialCore, WcsCredential, bootstrapCredential, getConfig };
|
|
356
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/config.ts","../src/core/CredentialCore.ts","../src/components/Credential.ts","../src/registerComponents.ts","../src/bootstrapCredential.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n credential: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n credential: \"wcs-credential\",\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\n// Note: this is the live, mutable internal config. It is not part of the public\n// package exports (see exports.ts) — only `getConfig()` (a frozen snapshot) is\n// surfaced. `setConfig()` is applied internally via `bootstrapCredential()` and\n// is not re-exported from the package root, though a deep path import\n// (`.../src/config.js`) can still reach and mutate it. Accepted as-is for\n// cross-package consistency: every @wcstack package follows this same shape.\n// Use `getConfig()` for a frozen, safe read.\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 { CredentialGetOptions, IWcBindable, StorableCredential } from \"../types.js\";\n\n/**\n * Headless Credential Management primitive. A thin, framework-agnostic\n * wrapper around `navigator.credentials.get()`/`.store()` exposed through the\n * wc-bindable protocol.\n *\n * Reuses batch3's \"thin command\" archetype established by `@wcstack/share`\n * (docs/credential-tag-design.md): single `_gen` generation guard,\n * same-value-guarded private setters, never-throw try/catch, no\n * `AbortController`/`abort()` command.\n *\n * **v1 scope excludes WebAuthn (`publicKey`)** — see docs/credential-tag-design.md\n * §0. `get()` validates and strips a `publicKey` option rather than silently\n * forwarding it, surfacing the attempt as a scope-violation `error` instead of\n * accidentally supporting WebAuthn through a side door.\n *\n * **`get()`/`store()` share one `_gen`** — an accepted v1 simplification\n * (docs/multi-promise-io-node-design.md): these two operations are used\n * sequentially in real auth flows (store after a successful login, get before\n * attempting one), not naturally concurrently on the same instance. If both\n * ARE invoked concurrently on the same `<wcs-credential>`, the later call's\n * generation bump silently drops the earlier call's completion write. If this\n * limitation actually bites, use two separate `<wcs-credential>` instances\n * (one for get, one for store) rather than reworking the Core.\n */\nexport class CredentialCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"value\", event: \"wcs-credential:complete\", getter: (e: Event) => (e as CustomEvent).detail.value },\n { name: \"loading\", event: \"wcs-credential:loading-changed\" },\n { name: \"error\", event: \"wcs-credential:error\" },\n { name: \"cancelled\", event: \"wcs-credential:cancelled-changed\" },\n ],\n commands: [\n { name: \"get\", async: true },\n { name: \"store\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _value: Credential | null = null;\n private _loading: boolean = false;\n private _error: any = null;\n private _cancelled: boolean = false;\n // Generation guard (§3.4): shared by get() and store() (see class docs on\n // the accepted concurrency limitation this implies).\n private _gen = 0;\n // SSR (§3.8): no asynchronous probe to await, so readiness is immediate.\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 value(): Credential | null {\n return this._value;\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): any {\n return this._error;\n }\n\n get cancelled(): boolean {\n return this._cancelled;\n }\n\n // Lifecycle (§3.5). Command-driven with no subscription to establish, so\n // observe() is an idempotent no-op that resolves once ready; dispose() only\n // invalidates any in-flight get()/store() (there is nothing to unsubscribe).\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n }\n\n private _setLoading(loading: boolean): void {\n if (this._loading === loading) return;\n this._loading = loading;\n this._target.dispatchEvent(new CustomEvent(\"wcs-credential:loading-changed\", {\n detail: loading,\n bubbles: true,\n }));\n }\n\n // Deliberately NO same-value guard (unlike error/loading/cancelled below).\n // `value` is a success-completion signal, not idempotent state: it is written\n // only on a successful get()/store(), and wcs-credential:complete is the *sole*\n // success notification. store() echoes the caller's credential argument, so two\n // consecutive successful store() calls with the same object reference are two\n // distinct completions and must each re-fire wcs-credential:complete so an\n // `$on`/eventToken consumer (and a `value:` binding) sees every success. This\n // matches clipboard `_setRead` / broadcast `_setMessage`, which carve\n // result/event values out of the §3.3 guard for the same reason.\n private _setValue(value: Credential | null): void {\n this._value = value;\n this._target.dispatchEvent(new CustomEvent(\"wcs-credential:complete\", {\n detail: { value },\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-credential:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n private _setCancelled(cancelled: boolean): void {\n if (this._cancelled === cancelled) return;\n this._cancelled = cancelled;\n this._target.dispatchEvent(new CustomEvent(\"wcs-credential:cancelled-changed\", {\n detail: cancelled,\n bubbles: true,\n }));\n }\n\n private _api(): typeof navigator.credentials | undefined {\n const nav = (globalThis as any).navigator;\n return nav?.credentials;\n }\n\n // Normalizes a rejection reason to a consistent { name, message } shape,\n // mirroring WorkerCore._normalizeError (packages/worker/src/core/WorkerCore.ts).\n private _normalizeError(e: unknown): { name: string; message: string } {\n if (e instanceof Error) {\n return { name: e.name, message: e.message };\n }\n return { name: \"Error\", message: String(e) };\n }\n\n // Classifies a get()/store() rejection as a user cancellation vs a real\n // failure (docs/credential-tag-design.md §2/§5). For the Credential\n // Management API the browser rejects with `NotAllowedError` when the user\n // dismisses/declines the native account-chooser UI — this is a routine \"the\n // user did not pick\" outcome, not a platform failure, so it maps to\n // `cancelled` and is kept out of `error`. Note this is `NotAllowedError`,\n // NOT `AbortError`: unlike Web Share/Contact Picker (whose APIs reject with\n // `AbortError` on dismissal), credentials.get()/store() signal user refusal\n // via `NotAllowedError`. Every other name (SecurityError, NetworkError, a\n // programmatic signal abort, etc.) flows to `error`.\n private _isCancellation(e: unknown): boolean {\n return (e as { name?: unknown } | null)?.name === \"NotAllowedError\";\n }\n\n /**\n * `get(options)` — v1 scope excludes `publicKey` (WebAuthn). If present, it\n * is stripped and the call surfaces a scope-violation `error` instead of\n * forwarding it to the platform API (which would accidentally support\n * WebAuthn through a side door). `navigator.credentials.get()` does not\n * require a user gesture (unlike Web Share/Fullscreen), so this can be\n * invoked automatically on page load for a \"silent sign-in\" flow.\n */\n async get(options: CredentialGetOptions & { publicKey?: unknown } = {}): Promise<Credential | null> {\n if (\"publicKey\" in options) {\n this._setError({ name: \"NotSupportedError\", message: \"WebAuthn (publicKey) is out of scope for @wcstack/credential v1. Use a dedicated WebAuthn node instead.\" });\n return null;\n }\n\n const api = this._api();\n if (!api) {\n this._setError({ message: \"Credential Management API is not supported in this browser.\" });\n return null;\n }\n\n const gen = ++this._gen;\n\n this._setLoading(true);\n // Reset the previous outcome before starting a new get so a stale\n // cancelled/error does not linger into this call's result.\n this._setError(null);\n this._setCancelled(false);\n\n try {\n const credential = await api.get(options as CredentialRequestOptions);\n\n if (gen !== this._gen) return null; // stale (dispose() ran while awaiting)\n\n this._setValue(credential);\n this._setLoading(false);\n return credential;\n } catch (e: any) {\n if (gen !== this._gen) return null;\n if (this._isCancellation(e)) {\n this._setCancelled(true);\n } else {\n this._setError(this._normalizeError(e));\n }\n this._setLoading(false);\n return null;\n }\n }\n\n /**\n * `store(credential)` — shares the same single `_gen` as `get()` (see class\n * docs). `navigator.credentials.store()` resolves `Promise<void>` (per\n * `lib.dom.d.ts`) — there is no payload to read off the API, so `value` is\n * synthesized as an echo of the caller's `credential`, mirroring\n * `ShareCore.share()`'s same accommodation for `navigator.share()`.\n *\n * A `PublicKeyCredential` (`type === \"public-key\"`, WebAuthn) is rejected as a\n * scope violation before touching the platform API — the same v1 boundary\n * `get()` enforces on the `publicKey` option (docs/credential-tag-design.md\n * §3.2), so this node never becomes a WebAuthn store backdoor.\n */\n async store(credential: StorableCredential): Promise<Credential | null> {\n if ((credential as { type?: unknown } | null)?.type === \"public-key\") {\n this._setError({ name: \"NotSupportedError\", message: \"WebAuthn (publicKey) credentials are out of scope for @wcstack/credential v1. Use a dedicated WebAuthn node instead.\" });\n return null;\n }\n\n const api = this._api();\n if (!api) {\n this._setError({ message: \"Credential Management API is not supported in this browser.\" });\n return null;\n }\n\n const gen = ++this._gen;\n\n this._setLoading(true);\n // Reset the previous outcome before starting a new store so a stale\n // cancelled/error does not linger into this call's result.\n this._setError(null);\n this._setCancelled(false);\n\n try {\n await api.store(credential);\n\n if (gen !== this._gen) return null;\n\n this._setValue(credential);\n this._setLoading(false);\n return credential;\n } catch (e: any) {\n if (gen !== this._gen) return null;\n if (this._isCancellation(e)) {\n this._setCancelled(true);\n } else {\n this._setError(this._normalizeError(e));\n }\n this._setLoading(false);\n return null;\n }\n }\n}\n","import { CredentialGetOptions, IWcBindable, StorableCredential } from \"../types.js\";\nimport { CredentialCore } from \"../core/CredentialCore.js\";\n\n/**\n * `<wcs-credential>` — declarative Credential Management API primitive\n * (password/federated only — see docs/credential-tag-design.md §0 for the\n * WebAuthn scope exclusion).\n *\n * A thin command-only Shell (mirrors `<wcs-share>`): no attributes at all.\n * `get(options)`/`store(credential)`'s arguments are per-call.\n */\nexport class WcsCredential extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...CredentialCore.wcBindable,\n inputs: [],\n // Inherit commands from Core (single source of truth).\n commands: CredentialCore.wcBindable.commands,\n };\n\n private _core: CredentialCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new CredentialCore(this);\n }\n\n // --- Core delegated getters ---\n\n get value(): Credential | null {\n return this._core.value;\n }\n\n get loading(): boolean {\n return this._core.loading;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get cancelled(): boolean {\n return this._core.cancelled;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands ---\n\n get(options?: CredentialGetOptions): Promise<Credential | null> {\n return this._core.get(options);\n }\n\n store(credential: StorableCredential): Promise<Credential | null> {\n return this._core.store(credential);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\n this._connectedCallbackPromise = this._core.observe();\n }\n\n disconnectedCallback(): void {\n this._core.dispose();\n }\n}\n","import { WcsCredential } from \"./components/Credential.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.credential)) {\n customElements.define(config.tagNames.credential, WcsCredential);\n }\n}\n","import { setConfig } from \"./config.js\";\nimport { registerComponents } from \"./registerComponents.js\";\nimport { IWritableConfig } from \"./types.js\";\n\nexport function bootstrapCredential(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e={tagNames:{credential:"wcs-credential"}};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 n of Object.keys(e))t[n]=r(e[n]);return t}let n=null;const s=e;function a(){return n||(n=t(r(e))),n}class i extends EventTarget{static wcBindable={protocol:"wc-bindable",version:1,properties:[{name:"value",event:"wcs-credential:complete",getter:e=>e.detail.value},{name:"loading",event:"wcs-credential:loading-changed"},{name:"error",event:"wcs-credential:error"},{name:"cancelled",event:"wcs-credential:cancelled-changed"}],commands:[{name:"get",async:!0},{name:"store",async:!0}]};_target;_value=null;_loading=!1;_error=null;_cancelled=!1;_gen=0;_ready=Promise.resolve();constructor(e){super(),this._target=e??this}get ready(){return this._ready}get value(){return this._value}get loading(){return this._loading}get error(){return this._error}get cancelled(){return this._cancelled}observe(){return this._ready}dispose(){this._gen++}_setLoading(e){this._loading!==e&&(this._loading=e,this._target.dispatchEvent(new CustomEvent("wcs-credential:loading-changed",{detail:e,bubbles:!0})))}_setValue(e){this._value=e,this._target.dispatchEvent(new CustomEvent("wcs-credential:complete",{detail:{value:e},bubbles:!0}))}_setError(e){this._error!==e&&(this._error=e,this._target.dispatchEvent(new CustomEvent("wcs-credential:error",{detail:e,bubbles:!0})))}_setCancelled(e){this._cancelled!==e&&(this._cancelled=e,this._target.dispatchEvent(new CustomEvent("wcs-credential:cancelled-changed",{detail:e,bubbles:!0})))}_api(){const e=globalThis.navigator;return e?.credentials}_normalizeError(e){return e instanceof Error?{name:e.name,message:e.message}:{name:"Error",message:String(e)}}_isCancellation(e){return"NotAllowedError"===e?.name}async get(e={}){if("publicKey"in e)return this._setError({name:"NotSupportedError",message:"WebAuthn (publicKey) is out of scope for @wcstack/credential v1. Use a dedicated WebAuthn node instead."}),null;const t=this._api();if(!t)return this._setError({message:"Credential Management API is not supported in this browser."}),null;const r=++this._gen;this._setLoading(!0),this._setError(null),this._setCancelled(!1);try{const n=await t.get(e);return r!==this._gen?null:(this._setValue(n),this._setLoading(!1),n)}catch(e){return r!==this._gen||(this._isCancellation(e)?this._setCancelled(!0):this._setError(this._normalizeError(e)),this._setLoading(!1)),null}}async store(e){if("public-key"===e?.type)return this._setError({name:"NotSupportedError",message:"WebAuthn (publicKey) credentials are out of scope for @wcstack/credential v1. Use a dedicated WebAuthn node instead."}),null;const t=this._api();if(!t)return this._setError({message:"Credential Management API is not supported in this browser."}),null;const r=++this._gen;this._setLoading(!0),this._setError(null),this._setCancelled(!1);try{return await t.store(e),r!==this._gen?null:(this._setValue(e),this._setLoading(!1),e)}catch(e){return r!==this._gen||(this._isCancellation(e)?this._setCancelled(!0):this._setError(this._normalizeError(e)),this._setLoading(!1)),null}}}class l extends HTMLElement{static hasConnectedCallbackPromise=!0;static wcBindable={...i.wcBindable,inputs:[],commands:i.wcBindable.commands};_core;_connectedCallbackPromise=Promise.resolve();constructor(){super(),this._core=new i(this)}get value(){return this._core.value}get loading(){return this._core.loading}get error(){return this._core.error}get cancelled(){return this._core.cancelled}get connectedCallbackPromise(){return this._connectedCallbackPromise}get(e){return this._core.get(e)}store(e){return this._core.store(e)}connectedCallback(){this.style.display="none",this._connectedCallbackPromise=this._core.observe()}disconnectedCallback(){this._core.dispose()}}function c(t){var r;t&&((r=t).tagNames&&Object.assign(e.tagNames,r.tagNames),n=null),customElements.get(s.tagNames.credential)||customElements.define(s.tagNames.credential,l)}export{i as CredentialCore,l as WcsCredential,c as bootstrapCredential,a as getConfig};
|
|
2
|
+
//# sourceMappingURL=index.esm.min.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.min.js","sources":["../src/config.ts","../src/core/CredentialCore.ts","../src/components/Credential.ts","../src/bootstrapCredential.ts","../src/registerComponents.ts"],"sourcesContent":["import { IConfig, IWritableConfig } from \"./types.js\";\n\ninterface IInternalConfig extends IConfig {\n tagNames: {\n credential: string;\n };\n}\n\nconst _config: IInternalConfig = {\n tagNames: {\n credential: \"wcs-credential\",\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\n// Note: this is the live, mutable internal config. It is not part of the public\n// package exports (see exports.ts) — only `getConfig()` (a frozen snapshot) is\n// surfaced. `setConfig()` is applied internally via `bootstrapCredential()` and\n// is not re-exported from the package root, though a deep path import\n// (`.../src/config.js`) can still reach and mutate it. Accepted as-is for\n// cross-package consistency: every @wcstack package follows this same shape.\n// Use `getConfig()` for a frozen, safe read.\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 { CredentialGetOptions, IWcBindable, StorableCredential } from \"../types.js\";\n\n/**\n * Headless Credential Management primitive. A thin, framework-agnostic\n * wrapper around `navigator.credentials.get()`/`.store()` exposed through the\n * wc-bindable protocol.\n *\n * Reuses batch3's \"thin command\" archetype established by `@wcstack/share`\n * (docs/credential-tag-design.md): single `_gen` generation guard,\n * same-value-guarded private setters, never-throw try/catch, no\n * `AbortController`/`abort()` command.\n *\n * **v1 scope excludes WebAuthn (`publicKey`)** — see docs/credential-tag-design.md\n * §0. `get()` validates and strips a `publicKey` option rather than silently\n * forwarding it, surfacing the attempt as a scope-violation `error` instead of\n * accidentally supporting WebAuthn through a side door.\n *\n * **`get()`/`store()` share one `_gen`** — an accepted v1 simplification\n * (docs/multi-promise-io-node-design.md): these two operations are used\n * sequentially in real auth flows (store after a successful login, get before\n * attempting one), not naturally concurrently on the same instance. If both\n * ARE invoked concurrently on the same `<wcs-credential>`, the later call's\n * generation bump silently drops the earlier call's completion write. If this\n * limitation actually bites, use two separate `<wcs-credential>` instances\n * (one for get, one for store) rather than reworking the Core.\n */\nexport class CredentialCore extends EventTarget {\n static wcBindable: IWcBindable = {\n protocol: \"wc-bindable\",\n version: 1,\n properties: [\n { name: \"value\", event: \"wcs-credential:complete\", getter: (e: Event) => (e as CustomEvent).detail.value },\n { name: \"loading\", event: \"wcs-credential:loading-changed\" },\n { name: \"error\", event: \"wcs-credential:error\" },\n { name: \"cancelled\", event: \"wcs-credential:cancelled-changed\" },\n ],\n commands: [\n { name: \"get\", async: true },\n { name: \"store\", async: true },\n ],\n };\n\n private _target: EventTarget;\n private _value: Credential | null = null;\n private _loading: boolean = false;\n private _error: any = null;\n private _cancelled: boolean = false;\n // Generation guard (§3.4): shared by get() and store() (see class docs on\n // the accepted concurrency limitation this implies).\n private _gen = 0;\n // SSR (§3.8): no asynchronous probe to await, so readiness is immediate.\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 value(): Credential | null {\n return this._value;\n }\n\n get loading(): boolean {\n return this._loading;\n }\n\n get error(): any {\n return this._error;\n }\n\n get cancelled(): boolean {\n return this._cancelled;\n }\n\n // Lifecycle (§3.5). Command-driven with no subscription to establish, so\n // observe() is an idempotent no-op that resolves once ready; dispose() only\n // invalidates any in-flight get()/store() (there is nothing to unsubscribe).\n observe(): Promise<void> {\n return this._ready;\n }\n\n dispose(): void {\n this._gen++;\n }\n\n private _setLoading(loading: boolean): void {\n if (this._loading === loading) return;\n this._loading = loading;\n this._target.dispatchEvent(new CustomEvent(\"wcs-credential:loading-changed\", {\n detail: loading,\n bubbles: true,\n }));\n }\n\n // Deliberately NO same-value guard (unlike error/loading/cancelled below).\n // `value` is a success-completion signal, not idempotent state: it is written\n // only on a successful get()/store(), and wcs-credential:complete is the *sole*\n // success notification. store() echoes the caller's credential argument, so two\n // consecutive successful store() calls with the same object reference are two\n // distinct completions and must each re-fire wcs-credential:complete so an\n // `$on`/eventToken consumer (and a `value:` binding) sees every success. This\n // matches clipboard `_setRead` / broadcast `_setMessage`, which carve\n // result/event values out of the §3.3 guard for the same reason.\n private _setValue(value: Credential | null): void {\n this._value = value;\n this._target.dispatchEvent(new CustomEvent(\"wcs-credential:complete\", {\n detail: { value },\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-credential:error\", {\n detail: error,\n bubbles: true,\n }));\n }\n\n private _setCancelled(cancelled: boolean): void {\n if (this._cancelled === cancelled) return;\n this._cancelled = cancelled;\n this._target.dispatchEvent(new CustomEvent(\"wcs-credential:cancelled-changed\", {\n detail: cancelled,\n bubbles: true,\n }));\n }\n\n private _api(): typeof navigator.credentials | undefined {\n const nav = (globalThis as any).navigator;\n return nav?.credentials;\n }\n\n // Normalizes a rejection reason to a consistent { name, message } shape,\n // mirroring WorkerCore._normalizeError (packages/worker/src/core/WorkerCore.ts).\n private _normalizeError(e: unknown): { name: string; message: string } {\n if (e instanceof Error) {\n return { name: e.name, message: e.message };\n }\n return { name: \"Error\", message: String(e) };\n }\n\n // Classifies a get()/store() rejection as a user cancellation vs a real\n // failure (docs/credential-tag-design.md §2/§5). For the Credential\n // Management API the browser rejects with `NotAllowedError` when the user\n // dismisses/declines the native account-chooser UI — this is a routine \"the\n // user did not pick\" outcome, not a platform failure, so it maps to\n // `cancelled` and is kept out of `error`. Note this is `NotAllowedError`,\n // NOT `AbortError`: unlike Web Share/Contact Picker (whose APIs reject with\n // `AbortError` on dismissal), credentials.get()/store() signal user refusal\n // via `NotAllowedError`. Every other name (SecurityError, NetworkError, a\n // programmatic signal abort, etc.) flows to `error`.\n private _isCancellation(e: unknown): boolean {\n return (e as { name?: unknown } | null)?.name === \"NotAllowedError\";\n }\n\n /**\n * `get(options)` — v1 scope excludes `publicKey` (WebAuthn). If present, it\n * is stripped and the call surfaces a scope-violation `error` instead of\n * forwarding it to the platform API (which would accidentally support\n * WebAuthn through a side door). `navigator.credentials.get()` does not\n * require a user gesture (unlike Web Share/Fullscreen), so this can be\n * invoked automatically on page load for a \"silent sign-in\" flow.\n */\n async get(options: CredentialGetOptions & { publicKey?: unknown } = {}): Promise<Credential | null> {\n if (\"publicKey\" in options) {\n this._setError({ name: \"NotSupportedError\", message: \"WebAuthn (publicKey) is out of scope for @wcstack/credential v1. Use a dedicated WebAuthn node instead.\" });\n return null;\n }\n\n const api = this._api();\n if (!api) {\n this._setError({ message: \"Credential Management API is not supported in this browser.\" });\n return null;\n }\n\n const gen = ++this._gen;\n\n this._setLoading(true);\n // Reset the previous outcome before starting a new get so a stale\n // cancelled/error does not linger into this call's result.\n this._setError(null);\n this._setCancelled(false);\n\n try {\n const credential = await api.get(options as CredentialRequestOptions);\n\n if (gen !== this._gen) return null; // stale (dispose() ran while awaiting)\n\n this._setValue(credential);\n this._setLoading(false);\n return credential;\n } catch (e: any) {\n if (gen !== this._gen) return null;\n if (this._isCancellation(e)) {\n this._setCancelled(true);\n } else {\n this._setError(this._normalizeError(e));\n }\n this._setLoading(false);\n return null;\n }\n }\n\n /**\n * `store(credential)` — shares the same single `_gen` as `get()` (see class\n * docs). `navigator.credentials.store()` resolves `Promise<void>` (per\n * `lib.dom.d.ts`) — there is no payload to read off the API, so `value` is\n * synthesized as an echo of the caller's `credential`, mirroring\n * `ShareCore.share()`'s same accommodation for `navigator.share()`.\n *\n * A `PublicKeyCredential` (`type === \"public-key\"`, WebAuthn) is rejected as a\n * scope violation before touching the platform API — the same v1 boundary\n * `get()` enforces on the `publicKey` option (docs/credential-tag-design.md\n * §3.2), so this node never becomes a WebAuthn store backdoor.\n */\n async store(credential: StorableCredential): Promise<Credential | null> {\n if ((credential as { type?: unknown } | null)?.type === \"public-key\") {\n this._setError({ name: \"NotSupportedError\", message: \"WebAuthn (publicKey) credentials are out of scope for @wcstack/credential v1. Use a dedicated WebAuthn node instead.\" });\n return null;\n }\n\n const api = this._api();\n if (!api) {\n this._setError({ message: \"Credential Management API is not supported in this browser.\" });\n return null;\n }\n\n const gen = ++this._gen;\n\n this._setLoading(true);\n // Reset the previous outcome before starting a new store so a stale\n // cancelled/error does not linger into this call's result.\n this._setError(null);\n this._setCancelled(false);\n\n try {\n await api.store(credential);\n\n if (gen !== this._gen) return null;\n\n this._setValue(credential);\n this._setLoading(false);\n return credential;\n } catch (e: any) {\n if (gen !== this._gen) return null;\n if (this._isCancellation(e)) {\n this._setCancelled(true);\n } else {\n this._setError(this._normalizeError(e));\n }\n this._setLoading(false);\n return null;\n }\n }\n}\n","import { CredentialGetOptions, IWcBindable, StorableCredential } from \"../types.js\";\nimport { CredentialCore } from \"../core/CredentialCore.js\";\n\n/**\n * `<wcs-credential>` — declarative Credential Management API primitive\n * (password/federated only — see docs/credential-tag-design.md §0 for the\n * WebAuthn scope exclusion).\n *\n * A thin command-only Shell (mirrors `<wcs-share>`): no attributes at all.\n * `get(options)`/`store(credential)`'s arguments are per-call.\n */\nexport class WcsCredential extends HTMLElement {\n static hasConnectedCallbackPromise = true;\n\n static wcBindable: IWcBindable = {\n ...CredentialCore.wcBindable,\n inputs: [],\n // Inherit commands from Core (single source of truth).\n commands: CredentialCore.wcBindable.commands,\n };\n\n private _core: CredentialCore;\n private _connectedCallbackPromise: Promise<void> = Promise.resolve();\n\n constructor() {\n super();\n this._core = new CredentialCore(this);\n }\n\n // --- Core delegated getters ---\n\n get value(): Credential | null {\n return this._core.value;\n }\n\n get loading(): boolean {\n return this._core.loading;\n }\n\n get error(): any {\n return this._core.error;\n }\n\n get cancelled(): boolean {\n return this._core.cancelled;\n }\n\n get connectedCallbackPromise(): Promise<void> {\n return this._connectedCallbackPromise;\n }\n\n // --- Commands ---\n\n get(options?: CredentialGetOptions): Promise<Credential | null> {\n return this._core.get(options);\n }\n\n store(credential: StorableCredential): Promise<Credential | null> {\n return this._core.store(credential);\n }\n\n // --- Lifecycle ---\n\n connectedCallback(): void {\n this.style.display = \"none\";\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 bootstrapCredential(userConfig?: IWritableConfig): void {\n if (userConfig) {\n setConfig(userConfig);\n }\n registerComponents();\n}\n","import { WcsCredential } from \"./components/Credential.js\";\nimport { config } from \"./config.js\";\n\nexport function registerComponents(): void {\n if (!customElements.get(config.tagNames.credential)) {\n customElements.define(config.tagNames.credential, WcsCredential);\n }\n}\n"],"names":["_config","tagNames","credential","deepFreeze","obj","Object","freeze","key","keys","deepClone","clone","frozenConfig","config","getConfig","CredentialCore","EventTarget","static","protocol","version","properties","name","event","getter","e","detail","value","commands","async","_target","_value","_loading","_error","_cancelled","_gen","_ready","Promise","resolve","constructor","target","super","this","ready","loading","error","cancelled","observe","dispose","_setLoading","dispatchEvent","CustomEvent","bubbles","_setValue","_setError","_setCancelled","_api","nav","globalThis","navigator","credentials","_normalizeError","Error","message","String","_isCancellation","get","options","api","gen","store","type","WcsCredential","HTMLElement","wcBindable","inputs","_core","_connectedCallbackPromise","connectedCallbackPromise","connectedCallback","style","display","disconnectedCallback","bootstrapCredential","userConfig","partialConfig","assign","customElements","define"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wcstack/credential",
|
|
3
|
+
"version": "1.16.0",
|
|
4
|
+
"description": "Declarative Credential Management component for Web Components. Framework-agnostic navigator.credentials get/store wrapper (password/federated only) via wc-bindable-protocol.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.esm.js",
|
|
7
|
+
"module": "./dist/index.esm.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.esm.js"
|
|
13
|
+
},
|
|
14
|
+
"./auto": "./dist/auto.min.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"clean": "rimraf dist .tsc-out",
|
|
21
|
+
"build": "rimraf dist .tsc-out && tsc && rollup -c",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"lint": "eslint src",
|
|
26
|
+
"version:patch": "npm version patch",
|
|
27
|
+
"version:minor": "npm version minor",
|
|
28
|
+
"version:major": "npm version major",
|
|
29
|
+
"prepublishOnly": "npm run build && npm run test:coverage"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"web-components",
|
|
33
|
+
"credential-management",
|
|
34
|
+
"sign-in",
|
|
35
|
+
"custom-elements",
|
|
36
|
+
"wc-bindable",
|
|
37
|
+
"declarative",
|
|
38
|
+
"zero-dependencies",
|
|
39
|
+
"framework-agnostic"
|
|
40
|
+
],
|
|
41
|
+
"author": "mogera551",
|
|
42
|
+
"homepage": "https://wcstack.github.io",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/wcstack/wcstack.git",
|
|
46
|
+
"directory": "packages/credential"
|
|
47
|
+
},
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/wcstack/wcstack/issues"
|
|
50
|
+
},
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@eslint/js": "^9.39.1",
|
|
54
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
55
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
56
|
+
"@vitest/coverage-v8": "^4.0.15",
|
|
57
|
+
"@vitest/ui": "^4.0.15",
|
|
58
|
+
"eslint": "^9.39.1",
|
|
59
|
+
"globals": "^16.5.0",
|
|
60
|
+
"happy-dom": "^20.0.11",
|
|
61
|
+
"rimraf": "^6.0.1",
|
|
62
|
+
"rollup": "^4.22.4",
|
|
63
|
+
"rollup-plugin-dts": "^6.1.1",
|
|
64
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
65
|
+
"tslib": "^2.8.1",
|
|
66
|
+
"typescript": "^5.9.3",
|
|
67
|
+
"typescript-eslint": "^8.49.0",
|
|
68
|
+
"vitest": "^4.0.15"
|
|
69
|
+
}
|
|
70
|
+
}
|