humankey 0.2.0 → 0.3.1

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.
@@ -0,0 +1,40 @@
1
+ import {
2
+ MemoryChallengeStore,
3
+ handleChallenge,
4
+ handleRegister,
5
+ handleVerify,
6
+ resolveConfig
7
+ } from "./chunk-Y6KQC7WK.mjs";
8
+ import "./chunk-XXJAJHNP.mjs";
9
+ import "./chunk-CLQSCDXC.mjs";
10
+
11
+ // src/nextjs.ts
12
+ function createHumanKeyHandlers(config) {
13
+ const resolved = resolveConfig(config);
14
+ return {
15
+ /** POST handler for /challenge — generates and stores a challenge. */
16
+ challenge: async () => {
17
+ const result = await handleChallenge(resolved);
18
+ return toResponse(result);
19
+ },
20
+ /** POST handler for /register — verifies registration and stores credential. */
21
+ register: async (req) => {
22
+ const body = await req.json();
23
+ const result = await handleRegister(resolved, body);
24
+ return toResponse(result);
25
+ },
26
+ /** POST handler for /verify — verifies a tap proof. */
27
+ verify: async (req) => {
28
+ const body = await req.json();
29
+ const result = await handleVerify(resolved, body);
30
+ return toResponse(result);
31
+ }
32
+ };
33
+ }
34
+ function toResponse(result) {
35
+ return Response.json(result.body, { status: result.status });
36
+ }
37
+ export {
38
+ MemoryChallengeStore,
39
+ createHumanKeyHandlers
40
+ };
package/dist/react.cjs ADDED
@@ -0,0 +1,131 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }// src/react.ts
2
+ var _react = require('react');
3
+ function useHumanKey(config) {
4
+ const { rpID, apiBase = "/api" } = config;
5
+ const [status, setStatus] = _react.useState.call(void 0, "idle");
6
+ const [confirmationCode, setConfirmationCode] = _react.useState.call(void 0, null);
7
+ const [error, setError] = _react.useState.call(void 0, null);
8
+ const [proof, setProof] = _react.useState.call(void 0, null);
9
+ const flowRef = _react.useRef.call(void 0, null);
10
+ const reset = _react.useCallback.call(void 0, () => {
11
+ setStatus("idle");
12
+ setConfirmationCode(null);
13
+ setError(null);
14
+ setProof(null);
15
+ flowRef.current = null;
16
+ }, []);
17
+ const startAction = _react.useCallback.call(void 0,
18
+ async (action, credentialIds) => {
19
+ try {
20
+ setStatus("confirming");
21
+ setError(null);
22
+ setProof(null);
23
+ const challengeRes = await fetch(`${apiBase}/challenge`, { method: "POST" });
24
+ if (!challengeRes.ok) {
25
+ throw new Error("Failed to fetch challenge");
26
+ }
27
+ const { challengeId, challenge } = await challengeRes.json();
28
+ const { createConfirmation } = await Promise.resolve().then(() => _interopRequireWildcard(require("./confirm-6RXLI2SS.cjs")));
29
+ const confirmation = await createConfirmation(action);
30
+ flowRef.current = { action, confirmation, challengeId, challenge, credentialIds };
31
+ setConfirmationCode(confirmation.code);
32
+ } catch (err) {
33
+ setStatus("error");
34
+ setError({
35
+ message: err instanceof Error ? err.message : "Unknown error",
36
+ code: err.code
37
+ });
38
+ throw err;
39
+ }
40
+ },
41
+ [apiBase]
42
+ );
43
+ const confirmCode = _react.useCallback.call(void 0,
44
+ async (userInput) => {
45
+ const flow = flowRef.current;
46
+ if (!flow) {
47
+ throw new Error("No active action \u2014 call startAction first");
48
+ }
49
+ try {
50
+ setStatus("tapping");
51
+ const { requestTap } = await Promise.resolve().then(() => _interopRequireWildcard(require("./tap-N5RN26H2.cjs")));
52
+ const tapProof = await requestTap({
53
+ challenge: flow.challenge,
54
+ action: flow.action,
55
+ confirmation: flow.confirmation,
56
+ userInput,
57
+ allowCredentials: flow.credentialIds,
58
+ rpID
59
+ });
60
+ const verifyRes = await fetch(`${apiBase}/verify`, {
61
+ method: "POST",
62
+ headers: { "Content-Type": "application/json" },
63
+ body: JSON.stringify({
64
+ proof: tapProof,
65
+ challengeId: flow.challengeId,
66
+ action: flow.action
67
+ })
68
+ });
69
+ if (!verifyRes.ok) {
70
+ const errBody = await verifyRes.json().catch(() => ({}));
71
+ throw Object.assign(new Error(errBody.error || "Verification failed"), {
72
+ code: errBody.code
73
+ });
74
+ }
75
+ setStatus("verified");
76
+ setProof(tapProof);
77
+ flowRef.current = null;
78
+ return tapProof;
79
+ } catch (err) {
80
+ setStatus("error");
81
+ setError({
82
+ message: err instanceof Error ? err.message : "Unknown error",
83
+ code: err.code
84
+ });
85
+ throw err;
86
+ }
87
+ },
88
+ [rpID, apiBase]
89
+ );
90
+ const register = _react.useCallback.call(void 0,
91
+ async (userName) => {
92
+ const challengeRes = await fetch(`${apiBase}/challenge`, { method: "POST" });
93
+ if (!challengeRes.ok) {
94
+ throw new Error("Failed to fetch challenge");
95
+ }
96
+ const { challengeId, challenge } = await challengeRes.json();
97
+ const { registerKey } = await Promise.resolve().then(() => _interopRequireWildcard(require("./register-Y2ADAMHB.cjs")));
98
+ const registration = await registerKey({
99
+ challenge,
100
+ rpID,
101
+ rpName: rpID,
102
+ // Server validates, this is just a display hint
103
+ userName
104
+ });
105
+ const regRes = await fetch(`${apiBase}/register`, {
106
+ method: "POST",
107
+ headers: { "Content-Type": "application/json" },
108
+ body: JSON.stringify({ response: registration.response, challengeId })
109
+ });
110
+ if (!regRes.ok) {
111
+ const errBody = await regRes.json().catch(() => ({}));
112
+ throw new Error(errBody.error || "Registration failed");
113
+ }
114
+ return registration;
115
+ },
116
+ [rpID, apiBase]
117
+ );
118
+ return {
119
+ status,
120
+ confirmationCode,
121
+ error,
122
+ proof,
123
+ startAction,
124
+ confirmCode,
125
+ register,
126
+ reset
127
+ };
128
+ }
129
+
130
+
131
+ exports.useHumanKey = useHumanKey;
@@ -0,0 +1,60 @@
1
+ import { AuthenticatorTransportFuture } from '@simplewebauthn/server';
2
+ import { a as TapProof, A as ActionPayload, b as RegistrationResult } from './types-By44RNIt.cjs';
3
+ export { C as Confirmation } from './types-By44RNIt.cjs';
4
+ import { a as HumanKeyErrorCode } from './errors-BmtCXo7w.cjs';
5
+
6
+ /** Status of the humankey flow. */
7
+ type HumanKeyStatus = 'idle' | 'confirming' | 'tapping' | 'verified' | 'error';
8
+ /** Error shape returned by the hook. */
9
+ interface HumanKeyHookError {
10
+ message: string;
11
+ code?: HumanKeyErrorCode;
12
+ }
13
+ /** Configuration for the useHumanKey hook. */
14
+ interface UseHumanKeyConfig {
15
+ /** Relying party ID, e.g. "example.com" */
16
+ rpID: string;
17
+ /** Base URL for humankey API endpoints (default: "/api") */
18
+ apiBase?: string;
19
+ }
20
+ /** Return value of the useHumanKey hook. */
21
+ interface UseHumanKeyReturn {
22
+ /** Current status of the flow. */
23
+ status: HumanKeyStatus;
24
+ /** The confirmation code the user needs to type (available when status is 'confirming'). */
25
+ confirmationCode: string | null;
26
+ /** Error details (available when status is 'error'). */
27
+ error: HumanKeyHookError | null;
28
+ /** The tap proof (available when status is 'verified'). */
29
+ proof: TapProof | null;
30
+ /** Start a new action — fetches a challenge and generates the confirmation code. */
31
+ startAction: (action: ActionPayload, credentialIds: Array<{
32
+ id: string;
33
+ transports?: AuthenticatorTransportFuture[];
34
+ }>) => Promise<void>;
35
+ /** Submit the confirmation code and trigger the hardware key tap. */
36
+ confirmCode: (userInput: string) => Promise<TapProof>;
37
+ /** Register a new hardware key. */
38
+ register: (userName: string) => Promise<RegistrationResult>;
39
+ /** Reset the hook to idle state. */
40
+ reset: () => void;
41
+ }
42
+ /**
43
+ * React hook for the humankey confirm → tap flow.
44
+ *
45
+ * Usage:
46
+ * ```tsx
47
+ * const { status, confirmationCode, startAction, confirmCode } = useHumanKey({
48
+ * rpID: 'example.com',
49
+ * });
50
+ *
51
+ * await startAction({ action: 'transfer', data: { amount: 100 } }, [{ id: credId }]);
52
+ * // status → 'confirming', confirmationCode → 'A7X3'
53
+ *
54
+ * const proof = await confirmCode('A7X3');
55
+ * // status → 'tapping' → 'verified'
56
+ * ```
57
+ */
58
+ declare function useHumanKey(config: UseHumanKeyConfig): UseHumanKeyReturn;
59
+
60
+ export { ActionPayload, HumanKeyErrorCode, type HumanKeyHookError, type HumanKeyStatus, RegistrationResult, TapProof, type UseHumanKeyConfig, type UseHumanKeyReturn, useHumanKey };
@@ -0,0 +1,60 @@
1
+ import { AuthenticatorTransportFuture } from '@simplewebauthn/server';
2
+ import { a as TapProof, A as ActionPayload, b as RegistrationResult } from './types-By44RNIt.js';
3
+ export { C as Confirmation } from './types-By44RNIt.js';
4
+ import { a as HumanKeyErrorCode } from './errors-BmtCXo7w.js';
5
+
6
+ /** Status of the humankey flow. */
7
+ type HumanKeyStatus = 'idle' | 'confirming' | 'tapping' | 'verified' | 'error';
8
+ /** Error shape returned by the hook. */
9
+ interface HumanKeyHookError {
10
+ message: string;
11
+ code?: HumanKeyErrorCode;
12
+ }
13
+ /** Configuration for the useHumanKey hook. */
14
+ interface UseHumanKeyConfig {
15
+ /** Relying party ID, e.g. "example.com" */
16
+ rpID: string;
17
+ /** Base URL for humankey API endpoints (default: "/api") */
18
+ apiBase?: string;
19
+ }
20
+ /** Return value of the useHumanKey hook. */
21
+ interface UseHumanKeyReturn {
22
+ /** Current status of the flow. */
23
+ status: HumanKeyStatus;
24
+ /** The confirmation code the user needs to type (available when status is 'confirming'). */
25
+ confirmationCode: string | null;
26
+ /** Error details (available when status is 'error'). */
27
+ error: HumanKeyHookError | null;
28
+ /** The tap proof (available when status is 'verified'). */
29
+ proof: TapProof | null;
30
+ /** Start a new action — fetches a challenge and generates the confirmation code. */
31
+ startAction: (action: ActionPayload, credentialIds: Array<{
32
+ id: string;
33
+ transports?: AuthenticatorTransportFuture[];
34
+ }>) => Promise<void>;
35
+ /** Submit the confirmation code and trigger the hardware key tap. */
36
+ confirmCode: (userInput: string) => Promise<TapProof>;
37
+ /** Register a new hardware key. */
38
+ register: (userName: string) => Promise<RegistrationResult>;
39
+ /** Reset the hook to idle state. */
40
+ reset: () => void;
41
+ }
42
+ /**
43
+ * React hook for the humankey confirm → tap flow.
44
+ *
45
+ * Usage:
46
+ * ```tsx
47
+ * const { status, confirmationCode, startAction, confirmCode } = useHumanKey({
48
+ * rpID: 'example.com',
49
+ * });
50
+ *
51
+ * await startAction({ action: 'transfer', data: { amount: 100 } }, [{ id: credId }]);
52
+ * // status → 'confirming', confirmationCode → 'A7X3'
53
+ *
54
+ * const proof = await confirmCode('A7X3');
55
+ * // status → 'tapping' → 'verified'
56
+ * ```
57
+ */
58
+ declare function useHumanKey(config: UseHumanKeyConfig): UseHumanKeyReturn;
59
+
60
+ export { ActionPayload, HumanKeyErrorCode, type HumanKeyHookError, type HumanKeyStatus, RegistrationResult, TapProof, type UseHumanKeyConfig, type UseHumanKeyReturn, useHumanKey };
package/dist/react.mjs ADDED
@@ -0,0 +1,131 @@
1
+ // src/react.ts
2
+ import { useState, useCallback, useRef } from "react";
3
+ function useHumanKey(config) {
4
+ const { rpID, apiBase = "/api" } = config;
5
+ const [status, setStatus] = useState("idle");
6
+ const [confirmationCode, setConfirmationCode] = useState(null);
7
+ const [error, setError] = useState(null);
8
+ const [proof, setProof] = useState(null);
9
+ const flowRef = useRef(null);
10
+ const reset = useCallback(() => {
11
+ setStatus("idle");
12
+ setConfirmationCode(null);
13
+ setError(null);
14
+ setProof(null);
15
+ flowRef.current = null;
16
+ }, []);
17
+ const startAction = useCallback(
18
+ async (action, credentialIds) => {
19
+ try {
20
+ setStatus("confirming");
21
+ setError(null);
22
+ setProof(null);
23
+ const challengeRes = await fetch(`${apiBase}/challenge`, { method: "POST" });
24
+ if (!challengeRes.ok) {
25
+ throw new Error("Failed to fetch challenge");
26
+ }
27
+ const { challengeId, challenge } = await challengeRes.json();
28
+ const { createConfirmation } = await import("./confirm-TSVTFC4N.mjs");
29
+ const confirmation = await createConfirmation(action);
30
+ flowRef.current = { action, confirmation, challengeId, challenge, credentialIds };
31
+ setConfirmationCode(confirmation.code);
32
+ } catch (err) {
33
+ setStatus("error");
34
+ setError({
35
+ message: err instanceof Error ? err.message : "Unknown error",
36
+ code: err.code
37
+ });
38
+ throw err;
39
+ }
40
+ },
41
+ [apiBase]
42
+ );
43
+ const confirmCode = useCallback(
44
+ async (userInput) => {
45
+ const flow = flowRef.current;
46
+ if (!flow) {
47
+ throw new Error("No active action \u2014 call startAction first");
48
+ }
49
+ try {
50
+ setStatus("tapping");
51
+ const { requestTap } = await import("./tap-DJVQXGEJ.mjs");
52
+ const tapProof = await requestTap({
53
+ challenge: flow.challenge,
54
+ action: flow.action,
55
+ confirmation: flow.confirmation,
56
+ userInput,
57
+ allowCredentials: flow.credentialIds,
58
+ rpID
59
+ });
60
+ const verifyRes = await fetch(`${apiBase}/verify`, {
61
+ method: "POST",
62
+ headers: { "Content-Type": "application/json" },
63
+ body: JSON.stringify({
64
+ proof: tapProof,
65
+ challengeId: flow.challengeId,
66
+ action: flow.action
67
+ })
68
+ });
69
+ if (!verifyRes.ok) {
70
+ const errBody = await verifyRes.json().catch(() => ({}));
71
+ throw Object.assign(new Error(errBody.error || "Verification failed"), {
72
+ code: errBody.code
73
+ });
74
+ }
75
+ setStatus("verified");
76
+ setProof(tapProof);
77
+ flowRef.current = null;
78
+ return tapProof;
79
+ } catch (err) {
80
+ setStatus("error");
81
+ setError({
82
+ message: err instanceof Error ? err.message : "Unknown error",
83
+ code: err.code
84
+ });
85
+ throw err;
86
+ }
87
+ },
88
+ [rpID, apiBase]
89
+ );
90
+ const register = useCallback(
91
+ async (userName) => {
92
+ const challengeRes = await fetch(`${apiBase}/challenge`, { method: "POST" });
93
+ if (!challengeRes.ok) {
94
+ throw new Error("Failed to fetch challenge");
95
+ }
96
+ const { challengeId, challenge } = await challengeRes.json();
97
+ const { registerKey } = await import("./register-ZGR2LHQ6.mjs");
98
+ const registration = await registerKey({
99
+ challenge,
100
+ rpID,
101
+ rpName: rpID,
102
+ // Server validates, this is just a display hint
103
+ userName
104
+ });
105
+ const regRes = await fetch(`${apiBase}/register`, {
106
+ method: "POST",
107
+ headers: { "Content-Type": "application/json" },
108
+ body: JSON.stringify({ response: registration.response, challengeId })
109
+ });
110
+ if (!regRes.ok) {
111
+ const errBody = await regRes.json().catch(() => ({}));
112
+ throw new Error(errBody.error || "Registration failed");
113
+ }
114
+ return registration;
115
+ },
116
+ [rpID, apiBase]
117
+ );
118
+ return {
119
+ status,
120
+ confirmationCode,
121
+ error,
122
+ proof,
123
+ startAction,
124
+ confirmCode,
125
+ register,
126
+ reset
127
+ };
128
+ }
129
+ export {
130
+ useHumanKey
131
+ };
@@ -0,0 +1,7 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+ var _chunkRQSBOE7Bcjs = require('./chunk-RQSBOE7B.cjs');
4
+ require('./chunk-JI6NIMGK.cjs');
5
+
6
+
7
+ exports.registerKey = _chunkRQSBOE7Bcjs.registerKey;
@@ -0,0 +1,7 @@
1
+ import {
2
+ registerKey
3
+ } from "./chunk-U2AGXRNW.mjs";
4
+ import "./chunk-CLQSCDXC.mjs";
5
+ export {
6
+ registerKey
7
+ };
@@ -0,0 +1,8 @@
1
+ import {
2
+ requestTap
3
+ } from "./chunk-RANGHXC7.mjs";
4
+ import "./chunk-G2X46ZRM.mjs";
5
+ import "./chunk-CLQSCDXC.mjs";
6
+ export {
7
+ requestTap
8
+ };
@@ -0,0 +1,8 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+ var _chunkSZPXOH7Zcjs = require('./chunk-SZPXOH7Z.cjs');
4
+ require('./chunk-2KMBF2TH.cjs');
5
+ require('./chunk-JI6NIMGK.cjs');
6
+
7
+
8
+ exports.requestTap = _chunkSZPXOH7Zcjs.requestTap;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "humankey",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Per-action hardware key (YubiKey/FIDO2) verification SDK with built-in confirmation step",
5
5
  "type": "module",
6
6
  "exports": {
@@ -33,6 +33,46 @@
33
33
  "types": "./dist/express.d.cts",
34
34
  "default": "./dist/express.cjs"
35
35
  }
36
+ },
37
+ "./nextjs": {
38
+ "import": {
39
+ "types": "./dist/nextjs.d.ts",
40
+ "default": "./dist/nextjs.mjs"
41
+ },
42
+ "require": {
43
+ "types": "./dist/nextjs.d.cts",
44
+ "default": "./dist/nextjs.cjs"
45
+ }
46
+ },
47
+ "./hono": {
48
+ "import": {
49
+ "types": "./dist/hono.d.ts",
50
+ "default": "./dist/hono.mjs"
51
+ },
52
+ "require": {
53
+ "types": "./dist/hono.d.cts",
54
+ "default": "./dist/hono.cjs"
55
+ }
56
+ },
57
+ "./fastify": {
58
+ "import": {
59
+ "types": "./dist/fastify.d.ts",
60
+ "default": "./dist/fastify.mjs"
61
+ },
62
+ "require": {
63
+ "types": "./dist/fastify.d.cts",
64
+ "default": "./dist/fastify.cjs"
65
+ }
66
+ },
67
+ "./react": {
68
+ "import": {
69
+ "types": "./dist/react.d.ts",
70
+ "default": "./dist/react.mjs"
71
+ },
72
+ "require": {
73
+ "types": "./dist/react.d.cts",
74
+ "default": "./dist/react.cjs"
75
+ }
36
76
  }
37
77
  },
38
78
  "files": [
@@ -64,7 +104,10 @@
64
104
  },
65
105
  "peerDependencies": {
66
106
  "@simplewebauthn/browser": "^13.3.0",
67
- "express": "^4.18.0 || ^5.0.0"
107
+ "express": "^4.18.0 || ^5.0.0",
108
+ "fastify": "^5.0.0",
109
+ "hono": "^4.0.0",
110
+ "react": "^18.0.0 || ^19.0.0"
68
111
  },
69
112
  "peerDependenciesMeta": {
70
113
  "@simplewebauthn/browser": {
@@ -72,13 +115,26 @@
72
115
  },
73
116
  "express": {
74
117
  "optional": true
118
+ },
119
+ "hono": {
120
+ "optional": true
121
+ },
122
+ "fastify": {
123
+ "optional": true
124
+ },
125
+ "react": {
126
+ "optional": true
75
127
  }
76
128
  },
77
129
  "devDependencies": {
78
130
  "@simplewebauthn/browser": "^13.3.0",
79
131
  "@types/express": "^5.0.6",
132
+ "@types/react": "^19.2.14",
80
133
  "@types/supertest": "^7.2.0",
81
134
  "express": "^5.2.1",
135
+ "fastify": "^5.8.4",
136
+ "hono": "^4.12.12",
137
+ "react": "^19.2.5",
82
138
  "supertest": "^7.2.2",
83
139
  "tsup": "^8.0.0",
84
140
  "typescript": "^5.7.0",