@orangecheck/me-client 0.5.0 → 0.7.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/dist/server.js ADDED
@@ -0,0 +1,73 @@
1
+ 'use strict';
2
+
3
+ var authCore = require('@orangecheck/auth-core');
4
+
5
+ // src/server.ts
6
+ async function getOcSession(headers, options = {}) {
7
+ return authCore.getOcSession(headers, options);
8
+ }
9
+ function withOcAuth(handler, options = {}) {
10
+ const wrapped = async (req, res) => {
11
+ res.setHeader("Cache-Control", "no-store, private");
12
+ res.setHeader("Vary", "Cookie, Authorization");
13
+ const session = await getOcSession(
14
+ {
15
+ cookie: typeof req.headers.cookie === "string" ? req.headers.cookie : null,
16
+ authorization: typeof req.headers.authorization === "string" ? req.headers.authorization : null
17
+ },
18
+ options
19
+ );
20
+ req.ocSession = session;
21
+ if (options.required && !session) {
22
+ return res.status(401).json({ ok: false, reason: "unauthenticated" });
23
+ }
24
+ return handler(req, res);
25
+ };
26
+ return wrapped;
27
+ }
28
+ function ocAuthExpress(options = {}) {
29
+ return async (req, res, next) => {
30
+ try {
31
+ res.setHeader("Cache-Control", "no-store, private");
32
+ res.setHeader("Vary", "Cookie, Authorization");
33
+ const session = await getOcSession(
34
+ {
35
+ cookie: typeof req.headers.cookie === "string" ? req.headers.cookie : null,
36
+ authorization: typeof req.headers.authorization === "string" ? req.headers.authorization : null
37
+ },
38
+ options
39
+ );
40
+ req.ocSession = session;
41
+ if (options.required && !session) {
42
+ res.status(401).json({ ok: false, reason: "unauthenticated" });
43
+ return;
44
+ }
45
+ next();
46
+ } catch (err) {
47
+ next(err);
48
+ }
49
+ };
50
+ }
51
+ function ocAuthHono(options = {}) {
52
+ return async (c, next) => {
53
+ c.header("Cache-Control", "no-store, private");
54
+ c.header("Vary", "Cookie, Authorization");
55
+ const session = await getOcSession(c.req.raw.headers, options);
56
+ c.set("ocSession", session);
57
+ if (options.required && !session) {
58
+ return c.json({ ok: false, reason: "unauthenticated" }, 401);
59
+ }
60
+ await next();
61
+ };
62
+ }
63
+
64
+ Object.defineProperty(exports, "verifyOcToken", {
65
+ enumerable: true,
66
+ get: function () { return authCore.verifyOcToken; }
67
+ });
68
+ exports.getOcSession = getOcSession;
69
+ exports.ocAuthExpress = ocAuthExpress;
70
+ exports.ocAuthHono = ocAuthHono;
71
+ exports.withOcAuth = withOcAuth;
72
+ //# sourceMappingURL=server.js.map
73
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server.ts"],"names":["getOcSessionCore"],"mappings":"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","file":"server.js","sourcesContent":["/**\n * @orangecheck/me-client/server\n *\n * Server-side verification helpers for OC integrators.\n *\n * import { withOcAuth, getOcSession, verifyOcToken } from '@orangecheck/me-client/server';\n *\n * Zero env vars, zero JWK handling. Internally lazy-fetches the auth\n * host's JWKS at https://ochk.io/.well-known/jwks.json and caches it\n * in-process. Integrators write code; we handle the crypto.\n *\n * Three layers, smallest to thickest:\n *\n * verifyOcToken(token) → SessionPayload | null\n * getOcSession(headers) → SessionPayload | null (cookie OR Bearer)\n * withOcAuth(handler) → Next.js Pages adapter that injects\n * req.ocSession on the request object\n * ocAuthExpress(opts?) → Express / Connect middleware\n * ocAuthHono(opts?) → Hono middleware\n *\n * All thin wrappers around `getOcSession`. Bring your own framework.\n */\n\nimport {\n getOcSession as getOcSessionCore,\n verifyOcToken,\n type SessionPayload,\n type VerifyOcOptions,\n type SessionRequestHeaders,\n} from '@orangecheck/auth-core';\n\nexport { verifyOcToken };\nexport type { SessionPayload, VerifyOcOptions };\n\n/**\n * Verify the OC session for a request. Accepts either:\n *\n * - A Web Headers object (Hono / edge / Fetch API): `c.req.raw.headers`\n * - A plain `{ cookie, authorization }` object (Express / Next.js Pages /\n * Fastify / etc.): `{ cookie: req.headers.cookie, authorization: req.headers.authorization }`\n *\n * Reads the `oc_session` cookie first; falls back to\n * `Authorization: Bearer <token>` so cross-domain integrators (no\n * .ochk.io cookie reach) verify the same way.\n *\n * Returns `null` for unauthenticated requests. Never throws.\n */\nexport async function getOcSession(\n headers: SessionRequestHeaders | Headers,\n options: VerifyOcOptions = {}\n): Promise<SessionPayload | null> {\n return getOcSessionCore(headers, options);\n}\n\n// ─── Next.js Pages Router adapter ────────────────────────────────────────\n\ninterface NextApiRequestLike {\n headers: { cookie?: string; authorization?: string; [k: string]: unknown };\n ocSession?: SessionPayload | null;\n}\ninterface NextApiResponseLike {\n status(code: number): NextApiResponseLike;\n json(body: unknown): unknown;\n setHeader(name: string, value: string | number | readonly string[]): unknown;\n}\ntype NextApiHandlerLike = (req: NextApiRequestLike, res: NextApiResponseLike) => unknown | Promise<unknown>;\n\nexport interface WithOcAuthOptions extends VerifyOcOptions {\n /** When true, unauthenticated requests get a 401 + `{ok:false}` response\n * before the wrapped handler runs. Default: false — handler runs and\n * receives `req.ocSession === null`, useful when the route serves both\n * signed-in and anonymous users. */\n required?: boolean;\n}\n\n/**\n * Wrap a Next.js Pages-Router API route handler. Adds `req.ocSession` —\n * the verified SessionPayload, or null when unauthenticated.\n *\n * // pages/api/me/profile.ts\n * import { withOcAuth } from '@orangecheck/me-client/server';\n *\n * export default withOcAuth(async (req, res) => {\n * if (!req.ocSession) return res.status(401).json({ ok: false });\n * res.status(200).json({ account: { address: req.ocSession.addr } });\n * }, { required: true });\n *\n * `Cache-Control: no-store, private` and `Vary: Cookie, Authorization`\n * are set on every authenticated response — without them a cached 401\n * leaks anonymous to authenticated callers.\n */\nexport function withOcAuth<T extends NextApiHandlerLike>(\n handler: T,\n options: WithOcAuthOptions = {}\n): T {\n const wrapped = async (req: NextApiRequestLike, res: NextApiResponseLike) => {\n res.setHeader('Cache-Control', 'no-store, private');\n res.setHeader('Vary', 'Cookie, Authorization');\n const session = await getOcSession(\n {\n cookie: typeof req.headers.cookie === 'string' ? req.headers.cookie : null,\n authorization:\n typeof req.headers.authorization === 'string'\n ? req.headers.authorization\n : null,\n },\n options\n );\n req.ocSession = session;\n if (options.required && !session) {\n return res.status(401).json({ ok: false, reason: 'unauthenticated' });\n }\n return handler(req, res);\n };\n return wrapped as unknown as T;\n}\n\n// ─── Express / Connect middleware ────────────────────────────────────────\n\ninterface ExpressRequestLike {\n headers: { cookie?: string; authorization?: string; [k: string]: unknown };\n ocSession?: SessionPayload | null;\n}\ninterface ExpressResponseLike {\n status(code: number): ExpressResponseLike;\n json(body: unknown): unknown;\n setHeader(name: string, value: string | number | readonly string[]): unknown;\n}\ntype ExpressNextLike = (err?: unknown) => void;\n\n/**\n * Express / Connect middleware. Attaches `req.ocSession` (verified\n * SessionPayload | null) and calls next(). Use it as a global middleware\n * or per-route.\n *\n * import express from 'express';\n * import { ocAuthExpress } from '@orangecheck/me-client/server';\n *\n * const app = express();\n * app.use(ocAuthExpress());\n *\n * app.get('/api/profile', (req, res) => {\n * if (!req.ocSession) return res.status(401).json({ error: 'sign in' });\n * res.json({ address: req.ocSession.addr });\n * });\n *\n * Pass `{ required: true }` to short-circuit unauthenticated requests\n * with a 401 before they reach your handler.\n */\nexport function ocAuthExpress(options: WithOcAuthOptions = {}) {\n return async (req: ExpressRequestLike, res: ExpressResponseLike, next: ExpressNextLike) => {\n try {\n res.setHeader('Cache-Control', 'no-store, private');\n res.setHeader('Vary', 'Cookie, Authorization');\n const session = await getOcSession(\n {\n cookie: typeof req.headers.cookie === 'string' ? req.headers.cookie : null,\n authorization:\n typeof req.headers.authorization === 'string'\n ? req.headers.authorization\n : null,\n },\n options\n );\n req.ocSession = session;\n if (options.required && !session) {\n res.status(401).json({ ok: false, reason: 'unauthenticated' });\n return;\n }\n next();\n } catch (err) {\n next(err);\n }\n };\n}\n\n// ─── Hono middleware ─────────────────────────────────────────────────────\n\ninterface HonoContextLike {\n req: { raw: { headers: Headers } };\n set(key: string, value: unknown): void;\n json(body: unknown, status?: number): unknown;\n header(name: string, value: string): void;\n}\ntype HonoNextLike = () => Promise<void>;\n\n/**\n * Hono middleware. Attaches the verified session at `c.get('ocSession')`.\n *\n * import { Hono } from 'hono';\n * import { ocAuthHono } from '@orangecheck/me-client/server';\n *\n * const app = new Hono();\n * app.use('*', ocAuthHono());\n *\n * app.get('/api/profile', (c) => {\n * const session = c.get('ocSession');\n * if (!session) return c.json({ error: 'sign in' }, 401);\n * return c.json({ address: session.addr });\n * });\n */\nexport function ocAuthHono(options: WithOcAuthOptions = {}) {\n return async (c: HonoContextLike, next: HonoNextLike) => {\n c.header('Cache-Control', 'no-store, private');\n c.header('Vary', 'Cookie, Authorization');\n const session = await getOcSession(c.req.raw.headers, options);\n c.set('ocSession', session);\n if (options.required && !session) {\n return c.json({ ok: false, reason: 'unauthenticated' }, 401);\n }\n await next();\n };\n}\n"]}
@@ -0,0 +1,65 @@
1
+ import { getOcSession as getOcSession$1 } from '@orangecheck/auth-core';
2
+ export { verifyOcToken } from '@orangecheck/auth-core';
3
+
4
+ // src/server.ts
5
+ async function getOcSession(headers, options = {}) {
6
+ return getOcSession$1(headers, options);
7
+ }
8
+ function withOcAuth(handler, options = {}) {
9
+ const wrapped = async (req, res) => {
10
+ res.setHeader("Cache-Control", "no-store, private");
11
+ res.setHeader("Vary", "Cookie, Authorization");
12
+ const session = await getOcSession(
13
+ {
14
+ cookie: typeof req.headers.cookie === "string" ? req.headers.cookie : null,
15
+ authorization: typeof req.headers.authorization === "string" ? req.headers.authorization : null
16
+ },
17
+ options
18
+ );
19
+ req.ocSession = session;
20
+ if (options.required && !session) {
21
+ return res.status(401).json({ ok: false, reason: "unauthenticated" });
22
+ }
23
+ return handler(req, res);
24
+ };
25
+ return wrapped;
26
+ }
27
+ function ocAuthExpress(options = {}) {
28
+ return async (req, res, next) => {
29
+ try {
30
+ res.setHeader("Cache-Control", "no-store, private");
31
+ res.setHeader("Vary", "Cookie, Authorization");
32
+ const session = await getOcSession(
33
+ {
34
+ cookie: typeof req.headers.cookie === "string" ? req.headers.cookie : null,
35
+ authorization: typeof req.headers.authorization === "string" ? req.headers.authorization : null
36
+ },
37
+ options
38
+ );
39
+ req.ocSession = session;
40
+ if (options.required && !session) {
41
+ res.status(401).json({ ok: false, reason: "unauthenticated" });
42
+ return;
43
+ }
44
+ next();
45
+ } catch (err) {
46
+ next(err);
47
+ }
48
+ };
49
+ }
50
+ function ocAuthHono(options = {}) {
51
+ return async (c, next) => {
52
+ c.header("Cache-Control", "no-store, private");
53
+ c.header("Vary", "Cookie, Authorization");
54
+ const session = await getOcSession(c.req.raw.headers, options);
55
+ c.set("ocSession", session);
56
+ if (options.required && !session) {
57
+ return c.json({ ok: false, reason: "unauthenticated" }, 401);
58
+ }
59
+ await next();
60
+ };
61
+ }
62
+
63
+ export { getOcSession, ocAuthExpress, ocAuthHono, withOcAuth };
64
+ //# sourceMappingURL=server.mjs.map
65
+ //# sourceMappingURL=server.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server.ts"],"names":["getOcSessionCore"],"mappings":"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","file":"server.mjs","sourcesContent":["/**\n * @orangecheck/me-client/server\n *\n * Server-side verification helpers for OC integrators.\n *\n * import { withOcAuth, getOcSession, verifyOcToken } from '@orangecheck/me-client/server';\n *\n * Zero env vars, zero JWK handling. Internally lazy-fetches the auth\n * host's JWKS at https://ochk.io/.well-known/jwks.json and caches it\n * in-process. Integrators write code; we handle the crypto.\n *\n * Three layers, smallest to thickest:\n *\n * verifyOcToken(token) → SessionPayload | null\n * getOcSession(headers) → SessionPayload | null (cookie OR Bearer)\n * withOcAuth(handler) → Next.js Pages adapter that injects\n * req.ocSession on the request object\n * ocAuthExpress(opts?) → Express / Connect middleware\n * ocAuthHono(opts?) → Hono middleware\n *\n * All thin wrappers around `getOcSession`. Bring your own framework.\n */\n\nimport {\n getOcSession as getOcSessionCore,\n verifyOcToken,\n type SessionPayload,\n type VerifyOcOptions,\n type SessionRequestHeaders,\n} from '@orangecheck/auth-core';\n\nexport { verifyOcToken };\nexport type { SessionPayload, VerifyOcOptions };\n\n/**\n * Verify the OC session for a request. Accepts either:\n *\n * - A Web Headers object (Hono / edge / Fetch API): `c.req.raw.headers`\n * - A plain `{ cookie, authorization }` object (Express / Next.js Pages /\n * Fastify / etc.): `{ cookie: req.headers.cookie, authorization: req.headers.authorization }`\n *\n * Reads the `oc_session` cookie first; falls back to\n * `Authorization: Bearer <token>` so cross-domain integrators (no\n * .ochk.io cookie reach) verify the same way.\n *\n * Returns `null` for unauthenticated requests. Never throws.\n */\nexport async function getOcSession(\n headers: SessionRequestHeaders | Headers,\n options: VerifyOcOptions = {}\n): Promise<SessionPayload | null> {\n return getOcSessionCore(headers, options);\n}\n\n// ─── Next.js Pages Router adapter ────────────────────────────────────────\n\ninterface NextApiRequestLike {\n headers: { cookie?: string; authorization?: string; [k: string]: unknown };\n ocSession?: SessionPayload | null;\n}\ninterface NextApiResponseLike {\n status(code: number): NextApiResponseLike;\n json(body: unknown): unknown;\n setHeader(name: string, value: string | number | readonly string[]): unknown;\n}\ntype NextApiHandlerLike = (req: NextApiRequestLike, res: NextApiResponseLike) => unknown | Promise<unknown>;\n\nexport interface WithOcAuthOptions extends VerifyOcOptions {\n /** When true, unauthenticated requests get a 401 + `{ok:false}` response\n * before the wrapped handler runs. Default: false — handler runs and\n * receives `req.ocSession === null`, useful when the route serves both\n * signed-in and anonymous users. */\n required?: boolean;\n}\n\n/**\n * Wrap a Next.js Pages-Router API route handler. Adds `req.ocSession` —\n * the verified SessionPayload, or null when unauthenticated.\n *\n * // pages/api/me/profile.ts\n * import { withOcAuth } from '@orangecheck/me-client/server';\n *\n * export default withOcAuth(async (req, res) => {\n * if (!req.ocSession) return res.status(401).json({ ok: false });\n * res.status(200).json({ account: { address: req.ocSession.addr } });\n * }, { required: true });\n *\n * `Cache-Control: no-store, private` and `Vary: Cookie, Authorization`\n * are set on every authenticated response — without them a cached 401\n * leaks anonymous to authenticated callers.\n */\nexport function withOcAuth<T extends NextApiHandlerLike>(\n handler: T,\n options: WithOcAuthOptions = {}\n): T {\n const wrapped = async (req: NextApiRequestLike, res: NextApiResponseLike) => {\n res.setHeader('Cache-Control', 'no-store, private');\n res.setHeader('Vary', 'Cookie, Authorization');\n const session = await getOcSession(\n {\n cookie: typeof req.headers.cookie === 'string' ? req.headers.cookie : null,\n authorization:\n typeof req.headers.authorization === 'string'\n ? req.headers.authorization\n : null,\n },\n options\n );\n req.ocSession = session;\n if (options.required && !session) {\n return res.status(401).json({ ok: false, reason: 'unauthenticated' });\n }\n return handler(req, res);\n };\n return wrapped as unknown as T;\n}\n\n// ─── Express / Connect middleware ────────────────────────────────────────\n\ninterface ExpressRequestLike {\n headers: { cookie?: string; authorization?: string; [k: string]: unknown };\n ocSession?: SessionPayload | null;\n}\ninterface ExpressResponseLike {\n status(code: number): ExpressResponseLike;\n json(body: unknown): unknown;\n setHeader(name: string, value: string | number | readonly string[]): unknown;\n}\ntype ExpressNextLike = (err?: unknown) => void;\n\n/**\n * Express / Connect middleware. Attaches `req.ocSession` (verified\n * SessionPayload | null) and calls next(). Use it as a global middleware\n * or per-route.\n *\n * import express from 'express';\n * import { ocAuthExpress } from '@orangecheck/me-client/server';\n *\n * const app = express();\n * app.use(ocAuthExpress());\n *\n * app.get('/api/profile', (req, res) => {\n * if (!req.ocSession) return res.status(401).json({ error: 'sign in' });\n * res.json({ address: req.ocSession.addr });\n * });\n *\n * Pass `{ required: true }` to short-circuit unauthenticated requests\n * with a 401 before they reach your handler.\n */\nexport function ocAuthExpress(options: WithOcAuthOptions = {}) {\n return async (req: ExpressRequestLike, res: ExpressResponseLike, next: ExpressNextLike) => {\n try {\n res.setHeader('Cache-Control', 'no-store, private');\n res.setHeader('Vary', 'Cookie, Authorization');\n const session = await getOcSession(\n {\n cookie: typeof req.headers.cookie === 'string' ? req.headers.cookie : null,\n authorization:\n typeof req.headers.authorization === 'string'\n ? req.headers.authorization\n : null,\n },\n options\n );\n req.ocSession = session;\n if (options.required && !session) {\n res.status(401).json({ ok: false, reason: 'unauthenticated' });\n return;\n }\n next();\n } catch (err) {\n next(err);\n }\n };\n}\n\n// ─── Hono middleware ─────────────────────────────────────────────────────\n\ninterface HonoContextLike {\n req: { raw: { headers: Headers } };\n set(key: string, value: unknown): void;\n json(body: unknown, status?: number): unknown;\n header(name: string, value: string): void;\n}\ntype HonoNextLike = () => Promise<void>;\n\n/**\n * Hono middleware. Attaches the verified session at `c.get('ocSession')`.\n *\n * import { Hono } from 'hono';\n * import { ocAuthHono } from '@orangecheck/me-client/server';\n *\n * const app = new Hono();\n * app.use('*', ocAuthHono());\n *\n * app.get('/api/profile', (c) => {\n * const session = c.get('ocSession');\n * if (!session) return c.json({ error: 'sign in' }, 401);\n * return c.json({ address: session.addr });\n * });\n */\nexport function ocAuthHono(options: WithOcAuthOptions = {}) {\n return async (c: HonoContextLike, next: HonoNextLike) => {\n c.header('Cache-Control', 'no-store, private');\n c.header('Vary', 'Cookie, Authorization');\n const session = await getOcSession(c.req.raw.headers, options);\n c.set('ocSession', session);\n if (options.required && !session) {\n return c.json({ ok: false, reason: 'unauthenticated' }, 401);\n }\n await next();\n };\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orangecheck/me-client",
3
- "version": "0.5.0",
4
- "description": "Drop-in client for me.ochk.io. Sign-in-with-OC button, useOcSession, oc.session/payment/config/delegation/webhook/event, the canonical billable-event taxonomy as types.",
3
+ "version": "0.7.0",
4
+ "description": "Drop-in client for me.ochk.io. Three entry points: React surface (OcSignInButton, useOcSession), server-side verification (withOcAuth for Next.js, ocAuthExpress, ocAuthHono — zero env vars, zero JWK handling), and a browser-only popup orchestrator (signInWithOc). Plus session lifecycle hooks, payment authorization, and the canonical billable-event taxonomy as types.",
5
5
  "keywords": [
6
6
  "orangecheck",
7
7
  "bitcoin",
@@ -30,6 +30,16 @@
30
30
  "types": "./dist/index.d.ts",
31
31
  "import": "./dist/index.mjs",
32
32
  "require": "./dist/index.js"
33
+ },
34
+ "./server": {
35
+ "types": "./dist/server.d.ts",
36
+ "import": "./dist/server.mjs",
37
+ "require": "./dist/server.js"
38
+ },
39
+ "./popup": {
40
+ "types": "./dist/popup.d.ts",
41
+ "import": "./dist/popup.mjs",
42
+ "require": "./dist/popup.js"
33
43
  }
34
44
  },
35
45
  "files": [
@@ -46,14 +56,29 @@
46
56
  "prepublishOnly": "npm run clean && npm run build"
47
57
  },
48
58
  "dependencies": {
49
- "@noble/curves": "^1.6.0",
50
- "@noble/hashes": "^1.5.0"
59
+ "@orangecheck/auth-core": "^0.3.1"
51
60
  },
52
61
  "peerDependencies": {
53
62
  "@orangecheck/auth-client": "^0.4.0",
63
+ "express": "^4.0.0 || ^5.0.0",
64
+ "hono": "^3.0.0 || ^4.0.0",
54
65
  "react": "^18.0.0 || ^19.0.0",
55
66
  "react-dom": "^18.0.0 || ^19.0.0"
56
67
  },
68
+ "peerDependenciesMeta": {
69
+ "express": {
70
+ "optional": true
71
+ },
72
+ "hono": {
73
+ "optional": true
74
+ },
75
+ "react": {
76
+ "optional": true
77
+ },
78
+ "react-dom": {
79
+ "optional": true
80
+ }
81
+ },
57
82
  "devDependencies": {
58
83
  "@orangecheck/auth-client": "^0.4.0",
59
84
  "@testing-library/react": "^16.3.2",