- You have visited this page {data.session.views} times.
-
-{/if}
-
-{#if data && data.user}
-
-
{JSON.stringify(data.user, null, 2)}
-
-{/if}
diff --git a/apps/web/src/routes/en/auth/+page.md b/apps/web/src/routes/en/auth/+page.md
new file mode 100644
index 0000000..4436e38
--- /dev/null
+++ b/apps/web/src/routes/en/auth/+page.md
@@ -0,0 +1,204 @@
+---
+title: '@svelte-dev/auth'
+desc: A simple and easy-to-use Svelte identity management library
+---
+
+
+
+![Logo](https://repository-images.githubusercontent.com/726691357/f09bf6fc-3844-4584-8eee-6bfb425d8a38)
+
+## Features
+
+- Full **Server-Side** Authentication
+- Complete **TypeScript** Support
+- **Strategy**-based Authentication
+- Easily handle **success and failure**
+- Implement **custom** strategies
+- Supports persistent **sessions**
+
+## Overview
+
+Svelte Auth is a complete open-source authentication solution for Svelte applications.
+
+Heavily inspired by [Passport.js](https://passportjs.org) and [Remix-Auth](https://github.com/sergiodxa/remix-auth), but completely rewrote it from scratch to work on top of the [Web Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). Svelte Auth can be dropped in to any Svelte-based application with minimal setup.
+
+As with Passport.js, it uses the strategy pattern to support the different authentication flows. Each strategy is published individually as a separate npm package.
+
+## Demo
+
+{#if $page && $page.data.user}
+
+
+
{JSON.stringify($page.data.user, null, 2)}
+
+{:else}
+
+
+ Github Login
+
+{/if}
+
+## Installation
+
+To use it, install it from npm (yarn or bun):
+
+```bash
+npm install @svelte-dev/auth @svelte-dev/session
+```
+
+## Usage
+
+Here's an simple Example:
+
+```ts
+// hooks.server.ts
+import { env } from '$env/dynamic/private';
+import { sequence } from '@sveltejs/kit/hooks';
+import { handleAuth } from '@svelte-dev/auth';
+import { OAuth2Strategy } from '@svelte-dev/auth-oauth2';
+
+const oauthStrategy = new OAuth2Strategy(
+ {
+ clientID: env.SSO_ID,
+ clientSecret: env.SSO_SECRET,
+ callbackURL: env.SSO_CALLBACK_URL || 'http://localhost:8788/auth/oauth2/callback'
+ },
+ async ({ profile }) => {
+ // Get the user data from your DB or API using the tokens and profile
+ return profile;
+ }
+);
+
+export const handle = handleAuth({
+ // Auth Options
+ autoRouting: true,
+ strategies: [oauthStrategy],
+ sessionKey: 'user',
+ sessionErrorKey: 'auth:error',
+ sessionStrategyKey: 'strategy',
+ successRedirect: '/',
+ failureRedirect: '/',
+ // Session Storage Options
+ adapter: {
+ name: 'cookie',
+ options: {
+ chunk: true
+ }
+ },
+ session: {
+ secrets: ['s3cr3t']
+ },
+ cookie: {
+ secure: !!env.SSO_CALLBACK_URL,
+ sameSite: 'lax',
+ path: '/',
+ httpOnly: !!env.SSO_CALLBACK_URL
+ }
+});
+```
+
+That's it.
+
+## Advanced Usage
+
+### Custom Handle
+
+If you did not set `authRouting`. You need to add a login handler `src/routes/auth/[provider]/+server.ts`:
+
+```ts
+import { redirect, type RequestEvent } from '@sveltejs/kit';
+
+export const GET = async (event: RequestEvent) => {
+ const { request } = event;
+ const provider = event.params.provider ?? 'github';
+ return await event.locals.auth.authenticate(event, provider, {
+ successRedirect: '/dashboard',
+ failureRedirect: '/error'
+ });
+};
+```
+
+Then, add a callback handler `src/routes/auth/[provider]/callback/+server.ts.ts`:
+
+```ts
+// same as before...
+import type { RequestEvent } from '@sveltejs/kit';
+
+export const GET = async (event: RequestEvent) => {
+ const provider = event.params.provider ?? 'github';
+
+ return await event.locals.auth.authenticate(event, provider, {
+ successRedirect: '/dashboard',
+ failureRedirect: '/error'
+ });
+};
+```
+
+### Typescript
+
+Modify `app.d.ts`, here is an example:
+
+```ts
+// See https://kit.svelte.dev/docs/types#app
+// for information about these interfaces
+declare global {
+ namespace App {
+ // interface Error {}
+ interface Locals {
+ auth: Auth;
+ session: SessionStorage<{ user: any }>;
+ user:
+ | {
+ invalid?: boolean;
+ [key: string]: unknown;
+ }
+ | unknown;
+ }
+ // interface PageData {}
+ interface Platform {
+ env: {
+ SSO_ID: string;
+ SSO_SECRET: string;
+ };
+ context: {
+ waitUntil(promise: Promise): void;
+ };
+ caches: CacheStorage & { default: Cache };
+ }
+ }
+}
+
+export {};
+```
+
+### Strategies
+
+| Package | Meta | Changelog |
+| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
+| [@svelte-dev/auth-oauth2](packages/auth-oauth2/) | [![npm](https://img.shields.io/npm/v/@svelte-dev/auth-oauth2?style=flat-square&logo=npm)](https://npmjs.org/package/@svelte-dev/auth-oauth2) [![npm](https://img.shields.io/npm/dm/@svelte-dev/auth-oauth2?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-oauth2) [![npm](https://img.shields.io/npm/dt/@svelte-dev/auth-oauth2?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-oauth2) | [Changelog](packages/auth-oauth2/CHANGELOG.md) |
+| [@svelte-dev/auth-github](packages/auth-github/) | [![npm](https://img.shields.io/npm/v/@svelte-dev/auth-github?style=flat-square&logo=npm)](https://npmjs.org/package/@svelte-dev/auth-github) [![npm](https://img.shields.io/npm/dm/@svelte-dev/auth-github?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-github) [![npm](https://img.shields.io/npm/dt/@svelte-dev/auth-github?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-github) | [Changelog](packages/auth-github/CHANGELOG.md) |
+| [@svelte-dev/auth-alipay](packages/auth-alipay/) | [![npm](https://img.shields.io/npm/v/@svelte-dev/auth-alipay?style=flat-square&logo=npm)](https://npmjs.org/package/@svelte-dev/auth-alipay) [![npm](https://img.shields.io/npm/dm/@svelte-dev/auth-alipay?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-alipay) [![npm](https://img.shields.io/npm/dt/@svelte-dev/auth-alipay?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-alipay) | [Changelog](packages/auth-alipay/CHANGELOG.md) |
+| [@svelte-dev/auth-afdian](packages/auth-afdian/) | [![npm](https://img.shields.io/npm/v/@svelte-dev/auth-afdian?style=flat-square&logo=npm)](https://npmjs.org/package/@svelte-dev/auth-afdian) [![npm](https://img.shields.io/npm/dm/@svelte-dev/auth-afdian?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-afdian) [![npm](https://img.shields.io/npm/dt/@svelte-dev/auth-afdian?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-afdian) | [Changelog](packages/auth-afdian/CHANGELOG.md) |
+| [@svelte-dev/auth-sso](packages/auth-sso/) | [![npm](https://img.shields.io/npm/v/@svelte-dev/auth-sso?style=flat-square&logo=npm)](https://npmjs.org/package/@svelte-dev/auth-sso) [![npm](https://img.shields.io/npm/dm/@svelte-dev/auth-sso?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-sso) [![npm](https://img.shields.io/npm/dt/@svelte-dev/auth-sso?style=flat-square&label=down)](https://npmjs.org/package/@svelte-dev/auth-sso) | [Changelog](packages/auth-sso/CHANGELOG.md) |
+
+> Welcome to share your strategies here.
+
+## TypeDocs
+
+[API Spec](/docs/auth/)
+
+## Sponsor
+
+Owner: [Willin Wang](https://willin.wang)
+
+Donation ways:
+
+- Follow me: [@willin](https://github.com/willin) [![github](https://img.shields.io/- Github:
+- Paypal:
+- Alipay or Wechat Pay: [QRCode](https://user-images.githubusercontent.com/1890238/89126156-0f3eeb80-d516-11ea-9046-5a3a5d59b86b.png)
+
+## License
+
+Apache-2.0
diff --git a/apps/web/src/routes/en/auth/+page.server.ts b/apps/web/src/routes/en/auth/+page.server.ts
new file mode 100644
index 0000000..4d0d5cf
--- /dev/null
+++ b/apps/web/src/routes/en/auth/+page.server.ts
@@ -0,0 +1,5 @@
+import type { ServerLoad } from '@sveltejs/kit';
+
+export const load: ServerLoad = async ({ locals }) => {
+ return { user: locals.user };
+};
diff --git a/apps/web/src/routes/en/i18n/+page.md b/apps/web/src/routes/en/i18n/+page.md
new file mode 100644
index 0000000..08240a3
--- /dev/null
+++ b/apps/web/src/routes/en/i18n/+page.md
@@ -0,0 +1,6 @@
+---
+title: '@svelte-dev/i18n'
+desc: A simple and easy-to-use Svelte I18n management library
+---
+
+TBD.
diff --git a/apps/web/src/routes/en/session/+page.md b/apps/web/src/routes/en/session/+page.md
new file mode 100644
index 0000000..5405c31
--- /dev/null
+++ b/apps/web/src/routes/en/session/+page.md
@@ -0,0 +1,316 @@
+---
+title: '@svelte-dev/session'
+desc: A simple and easy-to-use Svelte Session storage management library
+---
+
+
+
+## Overview
+
+Sessions are an important part of websites that allow the server to identify requests coming from the same person, especially when it comes to server-side form validation or when JavaScript is not on the page. Sessions are a fundamental building block of many sites that let users "log in", including social, e-commerce, business, and educational websites.
+
+Svelte-Session comes with several pre-built session storage options for common scenarios, and one to create your own:
+
+- custom storage with `createCustomStrategy`
+- `CookieSessionStrategy`
+- `MemoryStrategy`
+- `CloudflareKVStrategy` (Cloudflare Workers)
+
+## Demo
+
+## Installation
+
+To use it, install it from `npm` (`yarn` or `bun`):
+
+```bash
+npm add @svelte-dev/session
+```
+
+## Demo
+
+
+
+
+
You have visited
+
{$page.data.views}
+
Refresh to check
+
+
+
+
+## Usage
+
+Init from `hooks.server.ts`:
+
+```ts
+import { handleSession } from '@svelte-dev/session';
+
+export const handle = handleSession({
+ adapter: {
+ name: 'cookie',
+ options: {
+ chunk: true
+ }
+ },
+ session: {
+ key: '__sid',
+ secrets: ['s3cr3t']
+ },
+ cookie: {
+ path: '/',
+ sameSite: 'lax',
+ secure: true,
+ httpOnly: true
+ }
+});
+```
+
+### Svelte 5
+
+Load Data from `+page.server.ts`:
+
+```ts
+import type { ServerLoad } from '@sveltejs/kit';
+
+export const load: ServerLoad = async ({ locals }) => {
+ const views = locals.session.get('views') ?? 0;
+ await locals.session.set('views', views + 1);
+ return {};
+};
+```
+
+Use in `svelte5` runes component:
+
+```svelte
+
+
+{data.session.views}
+```
+
+### Svelte 4
+
+Load Data from `+page.server.ts`:
+
+```ts
+import type { ServerLoad } from '@sveltejs/kit';
+
+export const load: ServerLoad = async ({ locals }) => {
+ const views = locals.session.get('views') ?? 0;
+ await locals.session.set('views', views + 1);
+ return { views };
+};
+```
+
+Use in `svelte4` component:
+
+```svelte
+
+
+{$page.data.views}
+```
+
+## Advanced Usage
+
+### Cloudflare KV
+
+Init from `hooks.server.ts`:
+
+```ts
+import { handleSession } from '@svelte-dev/session';
+
+export const handle = handleSession({
+ adapter: {
+ name: 'cloudflare-kv',
+ options: {
+ namespace: 'SESSION'
+ }
+ },
+ session: {
+ secrets: ['s3cr3t']
+ },
+ cookie: {
+ path: '/'
+ }
+});
+```
+
+Checkout the docs for more details:
+
+### Custom Handler
+
+```ts
+export const handle = handleSession({
+ adapter: {
+ name: 'cookie',
+ options: {
+ chunk: true
+ }
+ },
+ session: {
+ key: '__sid',
+ secrets: ['s3cr3t']
+ },
+ cookie: {
+ path: '/',
+ sameSite: 'lax',
+ secure: true,
+ httpOnly: true
+ },
+ ({ event, resolve }) => {
+ // event.locals is populated with the session `event.locals.session`
+ // Do anything you want here
+ return resolve(event);
+ }
+);
+```
+
+In case you're using [sequence()](https://kit.svelte.dev/docs/modules#sveltejs-kit-hooks-sequence), do this
+
+```ts
+const sessionHandler = handleSession({
+ adapter: {
+ name: 'cookie',
+ options: {
+ chunk: true
+ }
+ }
+});
+
+export const handle = sequence(sessionHandler, ({ resolve, event }) => {
+ // event.locals is populated with the session `event.locals.session`
+ // event.locals is also populated with all parsed cookies by handleSession, it would cause overhead to parse them again - `event.locals.cookies`.
+ // Do anything you want here
+ return resolve(event);
+});
+```
+
+### Typescript
+
+Here's a simple example, modify `app.d.ts`:
+
+```ts
+import type { FlashSessionData, SessionData, SessionStorage } from '@svelte-dev/session';
+
+declare global {
+ namespace App {
+ // interface Error {}
+ interface Locals {
+ session: SessionStorage<{ views: number }>;
+ }
+ interface PageData {
+ session: FlashSessionData;
+ }
+ interface Session extends SessionStorage {}
+ // interface Platform {}
+ }
+}
+```
+
+### Create your own stragety
+
+Interface:
+
+```ts
+export interface SessionStorageStrategy {
+ /**
+ * Creates a new record with the given data and returns the session id.
+ */
+ createData: (data: FlashSessionData, expires?: Date) => Promise;
+
+ /**
+ * Returns data for a given session id, or `null` if there isn't any.
+ */
+ readData: (id: string) => Promise | null>;
+
+ /**
+ * Updates data for the given session id.
+ */
+ updateData: (
+ id: string,
+ data: FlashSessionData,
+ expires?: Date
+ ) => Promise;
+
+ /**
+ * Deletes data for a given session id from the data store.
+ */
+ deleteData: (id: string) => Promise;
+}
+```
+
+A simple example:
+
+```ts
+import type { RequestEvent } from '@sveltejs/kit';
+import type {
+ CookieOptions,
+ FlashSessionData,
+ SessionData,
+ SessionOptions,
+ SessionStorageStrategy
+} from '@svelte-dev/session';
+
+export type YourStrageOptions = {
+ /**
+ * Example
+ */
+ key?: string;
+};
+
+export class YourStrategy
+ implements SessionStorageStrategy
+{
+ constructor(
+ event: RequestEvent,
+ options: YourStrageOptions & { cookie: CookieOptions; session: SessionOptions }
+ ) {}
+ /**
+ * Creates a new record with the given data and returns the session id.
+ */
+ async createData(data, expires?: Date): Promise {}
+
+ /**
+ * Returns data for a given session id, or `null` if there isn't any.
+ */
+ async readData(id: string): Promise | null> {}
+
+ /**
+ * Updates data for the given session id.
+ */
+ async updateData(
+ id: string,
+ data: FlashSessionData,
+ expires?: Date
+ ): Promise {}
+
+ /**
+ * Deletes data for a given session id from the data store.
+ */
+ async deleteData(id: string): Promise {}
+}
+```
+
+## TypeDocs
+
+[API Spec](/docs/session/)
+
+## Sponsor
+
+Owner: [Willin Wang](https://willin.wang)
+
+Donation ways:
+
+- Follow me:[@willin](https://github.com/willin) [![github](https://img.shields.io/github/followers/willin.svg?style=social&label=Followers)](https://github.com/willin)
+- Github:
+- Paypal:
+- Alipay or Wechat Pay: [QRCode](https://user-images.githubusercontent.com/1890238/89126156-0f3eeb80-d516-11ea-9046-5a3a5d59b86b.png)
+
+## License
+
+Apache-2.0
diff --git a/apps/web/src/routes/en/session/+page.server.ts b/apps/web/src/routes/en/session/+page.server.ts
new file mode 100644
index 0000000..82ebc53
--- /dev/null
+++ b/apps/web/src/routes/en/session/+page.server.ts
@@ -0,0 +1,7 @@
+import type { ServerLoad } from '@sveltejs/kit';
+
+export const load: ServerLoad = async ({ locals }) => {
+ const views = locals.session.get('views') ?? 0;
+ await locals.session.set('views', views + 1);
+ return { views };
+};
diff --git a/apps/web/static/ads.txt b/apps/web/static/ads.txt
new file mode 100644
index 0000000..e2a8718
--- /dev/null
+++ b/apps/web/static/ads.txt
@@ -0,0 +1 @@
+google.com, pub-5059418763237956, DIRECT, f08c47fec0942fa0
diff --git a/apps/web/svelte.config.js b/apps/web/svelte.config.js
index 2fd1699..abcc45f 100644
--- a/apps/web/svelte.config.js
+++ b/apps/web/svelte.config.js
@@ -1,24 +1,41 @@
import adapter from '@sveltejs/adapter-cloudflare';
import { vitePreprocess } from '@sveltejs/kit/vite';
+import { mdsvex } from 'mdsvex';
+import { preprocessMeltUI } from '@melt-ui/pp';
+import mdsvexConfig from './mdsvex.config.js';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
- preprocess: vitePreprocess(),
- compilerOptions: {
- runes: true
- },
+ extensions: ['.svelte', ...mdsvexConfig.extensions],
+ preprocess: [mdsvex(mdsvexConfig), vitePreprocess(), preprocessMeltUI()],
+ // compilerOptions: {
+ // runes: true
+ // },
kit: {
+ alias: {
+ $components: './src/components'
+ },
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter({
+ pages: 'build',
+ assets: 'build',
+ fallback: null,
+ precompress: true,
routes: {
include: ['/*'],
- exclude: ['', '', '/favicon.png', '/docs/*']
+ exclude: ['', '', '/favicon.png', '/ads.txt', '/images', '/docs/*']
}
})
+ },
+ onwarn: (warning, handler) => {
+ if (warning.code.startsWith('a11y-no-noninteractive-tabindex')) {
+ return;
+ }
+ handler(warning);
}
};
diff --git a/apps/web/tailwind.config.cjs b/apps/web/tailwind.config.cjs
new file mode 100644
index 0000000..358e5d6
--- /dev/null
+++ b/apps/web/tailwind.config.cjs
@@ -0,0 +1,25 @@
+/** @type {import('tailwindcss').Config} */
+
+export default {
+ content: [
+ //
+ './src/**/*.{html,svelte,js,ts,md,svx,svelte.md}'
+ ],
+ theme: {
+ extend: {
+ backgroundImage: {
+ 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
+ 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))'
+ }
+ }
+ },
+ daisyui: {
+ themes: true, // false: only light + dark | true: all themes | array: specific themes like this ["light", "dark", "cupcake"]
+ darkTheme: 'sunset', // name of one of the included themes for dark mode
+ base: true, // applies background color and foreground color for root element by default
+ styled: true, // include daisyUI colors and design decisions for all components
+ utils: true, // adds responsive and modifier utility classes
+ themeRoot: ':root' // The element that receives theme color CSS variables
+ },
+ plugins: [require('@tailwindcss/typography'), require('daisyui')]
+};
diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts
index 0131ff9..fc2afe1 100644
--- a/apps/web/vite.config.ts
+++ b/apps/web/vite.config.ts
@@ -1,8 +1,14 @@
+import path from 'node:path';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [sveltekit()],
+ resolve: {
+ alias: {
+ $components: path.resolve('/src/components')
+ }
+ },
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
}
diff --git a/bun.lockb b/bun.lockb
index 3f3bc8d..c848cd7 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/packages/auth-oauth2/vite.config.ts.timestamp-1702359796228-e895b48aa94cc.mjs b/packages/auth-oauth2/vite.config.ts.timestamp-1702359796228-e895b48aa94cc.mjs
new file mode 100644
index 0000000..fcca68a
--- /dev/null
+++ b/packages/auth-oauth2/vite.config.ts.timestamp-1702359796228-e895b48aa94cc.mjs
@@ -0,0 +1,10 @@
+// vite.config.ts
+import { sveltekit } from "file:///Users/v0/Projects/svelte-dev/svelte-turbo/node_modules/@sveltejs/kit/src/exports/vite/index.js";
+import { defineConfig } from "file:///Users/v0/Projects/svelte-dev/svelte-turbo/node_modules/vite/dist/node/index.js";
+var vite_config_default = defineConfig({
+ plugins: [sveltekit()]
+});
+export {
+ vite_config_default as default
+};
+//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvVXNlcnMvdjAvUHJvamVjdHMvc3ZlbHRlLWRldi9zdmVsdGUtdHVyYm8vcGFja2FnZXMvYXV0aC1vYXV0aDJcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9Vc2Vycy92MC9Qcm9qZWN0cy9zdmVsdGUtZGV2L3N2ZWx0ZS10dXJiby9wYWNrYWdlcy9hdXRoLW9hdXRoMi92aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vVXNlcnMvdjAvUHJvamVjdHMvc3ZlbHRlLWRldi9zdmVsdGUtdHVyYm8vcGFja2FnZXMvYXV0aC1vYXV0aDIvdml0ZS5jb25maWcudHNcIjtpbXBvcnQgeyBzdmVsdGVraXQgfSBmcm9tICdAc3ZlbHRlanMva2l0L3ZpdGUnO1xuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSc7XG5cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XG4gIHBsdWdpbnM6IFtzdmVsdGVraXQoKV1cbn0pO1xuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUErVyxTQUFTLGlCQUFpQjtBQUN6WSxTQUFTLG9CQUFvQjtBQUU3QixJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTLENBQUMsVUFBVSxDQUFDO0FBQ3ZCLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg==
diff --git a/packages/auth/README.md b/packages/auth/README.md
index acf9606..74b12ed 100644
--- a/packages/auth/README.md
+++ b/packages/auth/README.md
@@ -4,157 +4,7 @@
[![github](https://img.shields.io/github/followers/willin.svg?style=social&label=Followers)](https://github.com/willin) [![npm](https://img.shields.io/npm/v/@svelte-dev/auth.svg)](https://npmjs.org/package/@svelte-dev/auth) [![npm](https://img.shields.io/npm/dm/@svelte-dev/auth.svg)](https://npmjs.org/package/@svelte-dev/auth) [![npm](https://img.shields.io/npm/dt/@svelte-dev/auth.svg)](https://npmjs.org/package/@svelte-dev/auth)
-Simple Authentication for [Svlelte](https://svelte.dev/).
-
-## Features
-
-- Full **Server-Side** Authentication
-- Complete **TypeScript** Support
-- **Strategy**-based Authentication
-- Easily handle **success and failure**
-- Implement **custom** strategies
-- Supports persistent **sessions**
-
-## Overview
-
-Svelte Auth is a complete open-source authentication solution for Svelte applications.
-
-Heavily inspired by [Passport.js](https://passportjs.org) and [Remix-Auth](https://github.com/sergiodxa/remix-auth), but completely rewrote it from scratch to work on top of the [Web Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). Svelte Auth can be dropped in to any Svelte-based application with minimal setup.
-
-As with Passport.js, it uses the strategy pattern to support the different authentication flows. Each strategy is published individually as a separate npm package.
-
-## Installation
-
-To use it, install it from npm (yarn or bun):
-
-```bash
-npm install @svelte-dev/auth @svelte-dev/session
-```
-
-## Usage
-
-API Specification: [Documentation](https://svelte-auth.js.cool/docs/)
-
-Here's an simple Example:
-
-```ts
-// hooks.server.ts
-import { env } from '$env/dynamic/private';
-import { sequence } from '@sveltejs/kit/hooks';
-import { handleAuth } from '@svelte-dev/auth';
-import { OAuth2Strategy } from '@svelte-dev/auth-oauth2';
-
-const oauthStrategy = new OAuth2Strategy(
- {
- clientID: env.SSO_ID,
- clientSecret: env.SSO_SECRET,
- callbackURL: env.SSO_CALLBACK_URL || 'http://localhost:8788/auth/oauth2/callback'
- },
- async ({ profile }) => {
- // Get the user data from your DB or API using the tokens and profile
- return profile;
- }
-);
-
-export const handle = handleAuth({
- // Auth Options
- autoRouting: true,
- strategies: [oauthStrategy],
- sessionKey: 'user',
- sessionErrorKey: 'auth:error',
- sessionStrategyKey: 'strategy',
- successRedirect: '/',
- failureRedirect: '/',
- // Session Storage Options
- adapter: {
- name: 'cookie',
- options: {
- chunk: true
- }
- },
- session: {
- secrets: ['s3cr3t']
- },
- cookie: {
- secure: !!env.SSO_CALLBACK_URL,
- sameSite: 'lax',
- path: '/',
- httpOnly: !!env.SSO_CALLBACK_URL
- }
-});
-```
-
-That's it.
-
-## Advanced Usage
-
-If you did not set `authRouting`. You need to add a login handler `src/routes/auth/[provider]/+server.ts`:
-
-```ts
-import { redirect, type RequestEvent } from '@sveltejs/kit';
-
-export const GET = async (event: RequestEvent) => {
- const { request } = event;
- const provider = event.params.provider ?? 'github';
- return await event.locals.auth.authenticate(event, provider, {
- successRedirect: '/dashboard',
- failureRedirect: '/error'
- });
-};
-```
-
-Then, add a callback handler `src/routes/auth/[provider]/callback/+server.ts.ts`:
-
-```ts
-// same as before...
-import type { RequestEvent } from '@sveltejs/kit';
-
-export const GET = async (event: RequestEvent) => {
- const provider = event.params.provider ?? 'github';
-
- return await event.locals.auth.authenticate(event, provider, {
- successRedirect: '/dashboard',
- failureRedirect: '/error'
- });
-};
-```
-
-### Typescript
-
-Modify `app.d.ts`, here is an example:
-
-```ts
-// See https://kit.svelte.dev/docs/types#app
-// for information about these interfaces
-declare global {
- namespace App {
- // interface Error {}
- interface Locals {
- auth: Auth;
- session: SessionStorage<{ user: any }>;
- user:
- | {
- invalid?: boolean;
- [key: string]: unknown;
- }
- | unknown;
- }
- // interface PageData {}
- interface Platform {
- env: {
- SSO_ID: string;
- SSO_SECRET: string;
- };
- context: {
- waitUntil(promise: Promise): void;
- };
- caches: CacheStorage & { default: Cache };
- }
- }
-}
-
-export {};
-```
+[中文文档](https://svelte.js.cool/auth) | [English Docs](https://svelte.js.cool/en/auth)
## 赞助 Sponsor
diff --git a/packages/auth/src/lib/auth/auth.ts b/packages/auth/src/lib/auth/auth.ts
index 6bd489c..9bcead7 100644
--- a/packages/auth/src/lib/auth/auth.ts
+++ b/packages/auth/src/lib/auth/auth.ts
@@ -90,19 +90,35 @@ export class Auth {
if (!inject || !event.url.pathname.startsWith('/auth')) {
return;
}
+ const params = event.url.pathname.split('/');
+ if (params.length !== 3 && params.length !== 4) {
+ // /auth
+ return;
+ }
+ if (![...this.#strategies.keys()].includes(params[2])) {
+ // /auth/invalid-provider
+ return;
+ }
+ if (params.length === 4 && params[3] !== 'callback') {
+ // /auth/provider/invalid-path
+ return;
+ }
+ const returnUrl = event.url?.searchParams?.get('redirect_uri');
+ if (returnUrl) {
+ await this.#session.flash('returnTo', returnUrl);
+ }
if ((event.locals as any).user) {
- throw redirect(307, this.#options.successRedirect ?? '/');
+ throw redirect(307, returnUrl || this.#options.successRedirect || '/');
}
- const params = event.url.pathname.split('/');
const idx = params.findIndex((x) => x === 'auth') + 1;
const provider = idx > 0 && idx < params.length ? params[idx] : '';
if (!provider) {
- throw redirect(307, this.#options.failureRedirect ?? '/');
+ throw redirect(307, this.#options.failureRedirect || '/');
}
await this.authenticate(event, provider, {
- successRedirect: this.#options.successRedirect ?? '/',
- failureRedirect: this.#options.failureRedirect ?? '/'
+ successRedirect: this.#options.successRedirect || '/',
+ failureRedirect: this.#options.failureRedirect || '/'
});
}
}
diff --git a/packages/i18n/README.md b/packages/i18n/README.md
index 2fd3d95..68a2308 100644
--- a/packages/i18n/README.md
+++ b/packages/i18n/README.md
@@ -1,5 +1,9 @@
# @svelte-dev/i18n
+[![github](https://img.shields.io/github/followers/willin.svg?style=social&label=Followers)](https://github.com/willin) [![npm](https://img.shields.io/npm/v/@svelte-dev/i18n.svg)](https://npmjs.org/package/@svelte-dev/i18n) [![npm](https://img.shields.io/npm/dm/@svelte-dev/i18n.svg)](https://npmjs.org/package/@svelte-dev/i18n) [![npm](https://img.shields.io/npm/dt/@svelte-dev/i18n.svg)](https://npmjs.org/package/@svelte-dev/i18n)
+
+[中文文档](https://svelte.js.cool/i18n) | [English Docs](https://svelte.js.cool/en/i18n)
+
## 赞助 Sponsor
维护者 Owner: [Willin Wang](https://willin.wang)
diff --git a/packages/i18n/src/lib/i18n/dictionary.ts b/packages/i18n/src/lib/i18n/dictionary.ts
index 0a2b1f2..f01a6cb 100644
--- a/packages/i18n/src/lib/i18n/dictionary.ts
+++ b/packages/i18n/src/lib/i18n/dictionary.ts
@@ -1,5 +1,5 @@
import deepmerge from 'deepmerge';
-import { derived, writable } from 'svelte/store';
+import { derived, writable, type Readable } from 'svelte/store';
import type { I18nDict } from './types.js';
import { getPossibleLocales } from './locale.js';
@@ -72,7 +72,9 @@ export function addMessages(locale: string, ...partials: I18nDict[]) {
});
}
-const $locales = derived([$dictionary], ([dictionary]) => Object.keys(dictionary));
+const $locales: Readable = derived([$dictionary], ([dictionary]) =>
+ Object.keys(dictionary)
+);
$dictionary.subscribe((newDictionary) => (dictionary = newDictionary));
diff --git a/packages/session/README.md b/packages/session/README.md
index f87fe88..b403fab 100644
--- a/packages/session/README.md
+++ b/packages/session/README.md
@@ -2,248 +2,7 @@
[![github](https://img.shields.io/github/followers/willin.svg?style=social&label=Followers)](https://github.com/willin) [![npm](https://img.shields.io/npm/v/@svelte-dev/session.svg)](https://npmjs.org/package/@svelte-dev/session) [![npm](https://img.shields.io/npm/dm/@svelte-dev/session.svg)](https://npmjs.org/package/@svelte-dev/session) [![npm](https://img.shields.io/npm/dt/@svelte-dev/session.svg)](https://npmjs.org/package/@svelte-dev/session)
-Simple Session Storage Management for [Svlelte](https://svelte.dev/).
-
-
-
-
-- [@svelte-dev/session](#svelte-devsession)
- - [Overview](#overview)
- - [Installation](#installation)
- - [Usage](#usage)
- - [Advanced Usage](#advanced-usage)
- - [Session API](#session-api)
- - [Cloudflare KV](#cloudflare-kv)
- - [Custom Handler](#custom-handler)
- - [Typescript](#typescript)
- - [Create your own stragety](#create-your-own-stragety)
- - [赞助 Sponsor](#赞助-sponsor)
- - [许可证 License](#许可证-license)
-
-
-
-## Overview
-
-Sessions are an important part of websites that allow the server to identify requests coming from the same person, especially when it comes to server-side form validation or when JavaScript is not on the page. Sessions are a fundamental building block of many sites that let users "log in", including social, e-commerce, business, and educational websites.
-
-Svelte-Session comes with several pre-built session storage options for common scenarios, and one to create your own:
-
-- custom storage with `createCustomStrategy`
-- `CookieSessionStrategy`
-- `MemoryStrategy`
-- `CloudflareKVStrategy` (Cloudflare Workers)
-
-## Installation
-
-To use it, install it from npm (yarn or bun):
-
-```bash
-npm install @svelte-dev/session
-```
-
-## Usage
-
-Init from `hooks.server.ts`:
-
-```ts
-import { handleSession } from '@svelte-dev/session';
-
-export const handle = handleSession({
- adapter: {
- name: 'cookie',
- options: {
- chunk: true
- }
- },
- session: {
- key: '__sid',
- secrets: ['s3cr3t']
- },
- cookie: {
- path: '/',
- sameSite: 'lax',
- secure: true,
- httpOnly: true
- }
-});
-```
-
-Load Data from `+page.server.ts`:
-
-```ts
-import type { ServerLoad } from '@sveltejs/kit';
-
-export const load: ServerLoad = async ({ locals }) => {
- const views = locals.session.get('views') ?? 0;
- await locals.session.set('views', views + 1);
- return {};
-};
-```
-
-Use in `svelte5` runes component:
-
-```svelte
-
-
-
- {JSON.stringify(data, null, 2)}
-
-```
-
-## Advanced Usage
-
-### Session API
-
-See: For more details
-
-### Cloudflare KV
-
-Init from `hooks.server.ts`:
-
-```ts
-import { handleSession } from '@svelte-dev/session';
-
-export const handle = handleSession({
- adapter: {
- name: 'cloudflare-kv',
- options: {
- namespace: 'SESSION'
- }
- },
- session: {
- secrets: ['s3cr3t']
- },
- cookie: {
- path: '/'
- }
-});
-```
-
-Checkout the docs for more details:
-
-### Custom Handler
-
-```ts
-export const handle = handleSession({
- adapter: {
- name: 'cookie',
- options: {
- chunk: true
- }
- },
- session: {
- key: '__sid',
- secrets: ['s3cr3t']
- },
- cookie: {
- path: '/',
- sameSite: 'lax',
- secure: true,
- httpOnly: true
- },
- ({ event, resolve }) => {
- // event.locals is populated with the session `event.locals.session`
- // Do anything you want here
- return resolve(event);
- }
-);
-```
-
-In case you're using [sequence()](https://kit.svelte.dev/docs/modules#sveltejs-kit-hooks-sequence), do this
-
-```ts
-const sessionHandler = handleSession({
- adapter: {
- name: 'cookie',
- options: {
- chunk: true
- }
- }
-});
-
-export const handle = sequence(sessionHandler, ({ resolve, event }) => {
- // event.locals is populated with the session `event.locals.session`
- // event.locals is also populated with all parsed cookies by handleSession, it would cause overhead to parse them again - `event.locals.cookies`.
- // Do anything you want here
- return resolve(event);
-});
-```
-
-### Typescript
-
-Here's a simple example, modify `app.d.ts`:
-
-```ts
-import type { FlashSessionData, SessionData, SessionStorage } from '@svelte-dev/session';
-
-declare global {
- namespace App {
- // interface Error {}
- interface Locals {
- session: SessionStorage<{ views: number }>;
- }
- interface PageData {
- session: FlashSessionData;
- }
- interface Session extends SessionStorage {}
- // interface Platform {}
- }
-}
-```
-
-### Create your own stragety
-
-```ts
-import type { RequestEvent } from '@sveltejs/kit';
-import type {
- CookieOptions,
- FlashSessionData,
- SessionData,
- SessionOptions,
- SessionStorageStrategy
-} from '@svelte-dev/session';
-
-export type YourStrageOptions = {
- /**
- * Example
- */
- key?: string;
-};
-
-export class YourStrategy
- implements SessionStorageStrategy
-{
- constructor(
- event: RequestEvent,
- options: YourStrageOptions & { cookie: CookieOptions; session: SessionOptions }
- ) {}
- /**
- * Creates a new record with the given data and returns the session id.
- */
- async createData(data, expires?: Date): Promise {}
-
- /**
- * Returns data for a given session id, or `null` if there isn't any.
- */
- async readData(id: string): Promise | null> {}
-
- /**
- * Updates data for the given session id.
- */
- async updateData(
- id: string,
- data: FlashSessionData,
- expires?: Date
- ): Promise {}
-
- /**
- * Deletes data for a given session id from the data store.
- */
- async deleteData(id: string): Promise {}
-}
-```
+[中文文档](https://svelte.js.cool/i18n) | [English Docs](https://svelte.js.cool/en/i18n)
## 赞助 Sponsor