@nerdsystem/sdk 0.0.6 → 0.0.7

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.
@@ -21,8 +21,12 @@ export declare class AuthServiceError extends Error {
21
21
  export declare class AuthServiceClient {
22
22
  private readonly env;
23
23
  private readonly fetchImpl;
24
+ /** The visitor's address, forwarded so the platform rate-limits per person rather than per app. */
25
+ private readonly clientIp?;
24
26
  private readonly base;
25
- constructor(env: Pick<NerdEnv, "NERD_AUTH_URL" | "NERD_PROJECT_ID" | "NERD_AUTH_SECRET">, fetchImpl?: typeof fetch);
27
+ constructor(env: Pick<NerdEnv, "NERD_AUTH_URL" | "NERD_PROJECT_ID" | "NERD_AUTH_SECRET">, fetchImpl?: typeof fetch,
28
+ /** The visitor's address, forwarded so the platform rate-limits per person rather than per app. */
29
+ clientIp?: string | undefined);
26
30
  get jwksUrl(): string;
27
31
  private call;
28
32
  signup(input: {
@@ -13,12 +13,16 @@ export class AuthServiceError extends Error {
13
13
  export class AuthServiceClient {
14
14
  env;
15
15
  fetchImpl;
16
+ clientIp;
16
17
  base;
17
18
  constructor(env,
18
19
  // Wrapped, not bare: calling a stored `fetch` as a method breaks in workerd (illegal invocation).
19
- fetchImpl = (input, init) => fetch(input, init)) {
20
+ fetchImpl = (input, init) => fetch(input, init),
21
+ /** The visitor's address, forwarded so the platform rate-limits per person rather than per app. */
22
+ clientIp) {
20
23
  this.env = env;
21
24
  this.fetchImpl = fetchImpl;
25
+ this.clientIp = clientIp;
22
26
  this.base = `${env.NERD_AUTH_URL.replace(/\/$/, "")}/t/${env.NERD_PROJECT_ID}`;
23
27
  }
24
28
  get jwksUrl() {
@@ -30,6 +34,7 @@ export class AuthServiceClient {
30
34
  headers: {
31
35
  ...(body !== undefined ? { "content-type": "application/json" } : {}),
32
36
  ...(auth ? { authorization: `Bearer ${auth}` } : {}),
37
+ ...(this.clientIp ? { "x-nerd-client-ip": this.clientIp } : {}),
33
38
  },
34
39
  body: body !== undefined ? JSON.stringify(body) : null,
35
40
  });
@@ -16,7 +16,7 @@ export async function resolveUser(c) {
16
16
  const token = bearer?.toLowerCase().startsWith("bearer ") ? bearer.slice(7) : readAccessCookie(c);
17
17
  if (!token)
18
18
  return null;
19
- const client = new AuthServiceClient(c.env);
19
+ const client = new AuthServiceClient(c.env, undefined, c.req.header("cf-connecting-ip"));
20
20
  const verified = await verifyAccessToken(token, { jwksUrl: client.jwksUrl, projectId: c.env.NERD_PROJECT_ID });
21
21
  if (!verified)
22
22
  return null;
@@ -39,7 +39,7 @@ export function authRoutes() {
39
39
  if (c.env.NERD_TURNSTILE_SECRET && !(await verifyTurnstile(c.env.NERD_TURNSTILE_SECRET, str(body.turnstileToken), c.req.header("cf-connecting-ip")))) {
40
40
  return c.json({ error: { code: "bad_request", message: "Please complete the verification challenge" } }, 400);
41
41
  }
42
- const session = await new AuthServiceClient(c.env).signup({ email, password, name });
42
+ const session = await new AuthServiceClient(c.env, undefined, c.req.header("cf-connecting-ip")).signup({ email, password, name });
43
43
  setSessionCookies(c, session);
44
44
  return c.json({ user: session.user }, 201);
45
45
  });
@@ -49,7 +49,7 @@ export function authRoutes() {
49
49
  const password = str(body.password);
50
50
  if (!email || !password)
51
51
  return c.json({ error: { code: "bad_request", message: "email and password are required" } }, 400);
52
- const session = await new AuthServiceClient(c.env).login({ email, password });
52
+ const session = await new AuthServiceClient(c.env, undefined, c.req.header("cf-connecting-ip")).login({ email, password });
53
53
  setSessionCookies(c, session);
54
54
  return c.json({ user: session.user }, 200);
55
55
  });
@@ -58,7 +58,7 @@ export function authRoutes() {
58
58
  if (!refreshToken)
59
59
  return c.json({ error: { code: "unauthorized", message: "No session" } }, 401);
60
60
  try {
61
- const session = await new AuthServiceClient(c.env).refresh(refreshToken);
61
+ const session = await new AuthServiceClient(c.env, undefined, c.req.header("cf-connecting-ip")).refresh(refreshToken);
62
62
  setSessionCookies(c, session);
63
63
  return c.json({ user: session.user }, 200);
64
64
  }
@@ -73,7 +73,7 @@ export function authRoutes() {
73
73
  r.post("/logout", async (c) => {
74
74
  const refreshToken = readRefreshCookie(c);
75
75
  if (refreshToken)
76
- await new AuthServiceClient(c.env).logout(refreshToken).catch(() => { });
76
+ await new AuthServiceClient(c.env, undefined, c.req.header("cf-connecting-ip")).logout(refreshToken).catch(() => { });
77
77
  clearSessionCookies(c);
78
78
  return c.json({ ok: true }, 200);
79
79
  });
@@ -84,7 +84,7 @@ export function authRoutes() {
84
84
  if (!email)
85
85
  return c.json({ error: { code: "bad_request", message: "email is required" } }, 400);
86
86
  const origin = new URL(c.req.url).origin;
87
- await new AuthServiceClient(c.env).forgotPassword({ email, resetUrl: `${origin}/reset-password`, ...(c.env.NERD_APP_NAME ? { appName: c.env.NERD_APP_NAME } : {}) });
87
+ await new AuthServiceClient(c.env, undefined, c.req.header("cf-connecting-ip")).forgotPassword({ email, resetUrl: `${origin}/reset-password`, ...(c.env.NERD_APP_NAME ? { appName: c.env.NERD_APP_NAME } : {}) });
88
88
  return c.json({ ok: true }, 200);
89
89
  });
90
90
  r.post("/reset", async (c) => {
@@ -93,7 +93,7 @@ export function authRoutes() {
93
93
  const password = str(body.password);
94
94
  if (!token || !password)
95
95
  return c.json({ error: { code: "bad_request", message: "token and password are required" } }, 400);
96
- const session = await new AuthServiceClient(c.env).resetPassword({ token, password });
96
+ const session = await new AuthServiceClient(c.env, undefined, c.req.header("cf-connecting-ip")).resetPassword({ token, password });
97
97
  setSessionCookies(c, session);
98
98
  return c.json({ user: session.user }, 200);
99
99
  });
@@ -106,7 +106,7 @@ export function authRoutes() {
106
106
  if (!refreshToken || readAccessCookie(c))
107
107
  return c.json({ user: null }, 200);
108
108
  try {
109
- const session = await new AuthServiceClient(c.env).refresh(refreshToken);
109
+ const session = await new AuthServiceClient(c.env, undefined, c.req.header("cf-connecting-ip")).refresh(refreshToken);
110
110
  setSessionCookies(c, session);
111
111
  return c.json({ user: { id: session.user.id, email: session.user.email, name: session.user.name, roles: session.user.roles } }, 200);
112
112
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nerdsystem/sdk",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "Runtime for apps deployed on nerdsystem: auth, authorization, and platform bindings.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",