-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new session, kvSession and cookieSession middlewares
- Loading branch information
Showing
7 changed files
with
209 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { | ||
CookieOptions, | ||
SessionData, | ||
createCookieSessionStorage, | ||
} from "@remix-run/cloudflare"; | ||
import { Context, Hono, MiddlewareHandler } from "hono"; | ||
|
||
import { session } from "./session"; | ||
|
||
type GetSecretsFunction<Secret extends string> = ( | ||
context: Context<{ Bindings: BindingsObject<Secret> }>, | ||
) => string[]; | ||
|
||
type BindingsObject<Secret extends string> = { | ||
[K in Secret]: string; | ||
}; | ||
|
||
export function kvSession< | ||
SecretBinding extends string, | ||
Data = SessionData, | ||
FlashData = Data, | ||
>(options: { | ||
autoCommit?: boolean; | ||
cookie: Omit<CookieOptions, "secrets"> & { | ||
name: string; | ||
secrets: GetSecretsFunction<SecretBinding>; | ||
}; | ||
}): MiddlewareHandler { | ||
return session< | ||
{ Bindings: BindingsObject<SecretBinding> }, | ||
"", | ||
Record<string, unknown>, | ||
Data, | ||
FlashData | ||
>({ | ||
autoCommit: options.autoCommit, | ||
createSessionStorage(context) { | ||
let secrets = options.cookie.secrets(context); | ||
|
||
if (secrets.length === 0) { | ||
throw new ReferenceError("The secrets for the kvSession are not set."); | ||
} | ||
|
||
return createCookieSessionStorage<Data, FlashData>({ | ||
cookie: { ...options.cookie, secrets }, | ||
}); | ||
}, | ||
}); | ||
} | ||
|
||
new Hono().use( | ||
"*", | ||
kvSession({ | ||
autoCommit: true, | ||
cookie: { | ||
name: "__session", | ||
httpOnly: true, | ||
secrets(context) { | ||
return [context.env.SECRET]; | ||
}, | ||
}, | ||
}), | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { | ||
CookieOptions, | ||
SessionData, | ||
createWorkersKVSessionStorage, | ||
} from "@remix-run/cloudflare"; | ||
import { Context, Hono, MiddlewareHandler } from "hono"; | ||
|
||
import { session } from "./session"; | ||
|
||
type GetSecretsFunction<KV extends string, Secret extends string> = ( | ||
context: Context<{ Bindings: BindingsObject<KV, Secret> }>, | ||
) => string[]; | ||
|
||
type BindingsObject<KV extends string, Secret extends string> = { | ||
[K in KV | Secret]: K extends KV ? KVNamespace : string; | ||
}; | ||
|
||
export function kvSession< | ||
KVBinding extends string, | ||
SecretBinding extends string, | ||
Data = SessionData, | ||
FlashData = Data, | ||
>(options: { | ||
autoCommit?: boolean; | ||
cookie: Omit<CookieOptions, "secrets"> & { | ||
name: string; | ||
secrets: GetSecretsFunction<KVBinding, SecretBinding>; | ||
}; | ||
binding: KVBinding; | ||
}): MiddlewareHandler { | ||
return session< | ||
{ Bindings: BindingsObject<KVBinding, SecretBinding> }, | ||
"", | ||
Record<string, unknown>, | ||
Data, | ||
FlashData | ||
>({ | ||
autoCommit: options.autoCommit, | ||
createSessionStorage(context) { | ||
if (!(options.binding in context.env)) { | ||
throw new ReferenceError("The binding for the kvSession is not set."); | ||
} | ||
|
||
let secrets = options.cookie.secrets(context); | ||
|
||
if (secrets.length === 0) { | ||
throw new ReferenceError("The secrets for the kvSession are not set."); | ||
} | ||
|
||
return createWorkersKVSessionStorage<Data, FlashData>({ | ||
kv: context.env[options.binding] as KVNamespace, | ||
cookie: { ...options.cookie, secrets }, | ||
}); | ||
}, | ||
}); | ||
} | ||
|
||
new Hono().use( | ||
"*", | ||
kvSession({ | ||
autoCommit: true, | ||
cookie: { | ||
name: "session", | ||
secrets(context) { | ||
return [context.env.SECRET]; | ||
}, | ||
}, | ||
binding: "KV_BINDING", | ||
}), | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { Session, SessionData, SessionStorage } from "@remix-run/cloudflare"; | ||
import { Context, Env, Input, MiddlewareHandler } from "hono"; | ||
|
||
const sessionStorageSymbol = Symbol(); | ||
const sessionSymbol = Symbol(); | ||
|
||
export function session< | ||
E extends Env = Record<string, never>, | ||
P extends string = "", | ||
I extends Input = Record<string, never>, | ||
Data = SessionData, | ||
FlashData = Data, | ||
>(options: { | ||
autoCommit?: boolean; | ||
createSessionStorage(env: Context<E, P, I>): SessionStorage<Data, FlashData>; | ||
}): MiddlewareHandler { | ||
return async function middleware(context, next) { | ||
let sessionStorage = options.createSessionStorage(context.env); | ||
|
||
context.set(sessionStorageSymbol, sessionStorage); | ||
|
||
// If autoCommit is disabled, we just create the SessionStorage and make it | ||
// available with context.get(sessionStorageSymbol), then call next() and | ||
// return. | ||
if (!options.autoCommit) return await next(); | ||
|
||
// If autoCommit is enabled, we get the Session from the request. | ||
let session = await sessionStorage.getSession( | ||
context.req.raw.headers.get("cookie"), | ||
); | ||
|
||
// And make it available with context.get(sessionSymbol). | ||
context.set(sessionSymbol, session); | ||
|
||
// Then we call next() to let the rest of the middlewares run. | ||
await next(); | ||
|
||
// Finally, we commit the session before the response is sent. | ||
context.header("set-cookie", await sessionStorage.commitSession(session), { | ||
append: true, | ||
}); | ||
}; | ||
} | ||
|
||
export function getSessionStorage<Data = SessionData, FlashData = Data>( | ||
context: Context, | ||
): SessionStorage<Data, FlashData> { | ||
return context.get(sessionStorageSymbol); | ||
} | ||
|
||
export function getSession<Data = SessionData, FlashData = Data>( | ||
context: Context, | ||
): Session<Data, FlashData> { | ||
return context.get(sessionSymbol); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters