;
7 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/vuetify/playground/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Nuxt module playground!
4 |
5 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/playground/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Nuxt module playground!
4 |
5 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/axios/playground/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Nuxt module playground!
4 |
5 |
6 |
7 |
11 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/vuetify/playground/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | import { defineNuxtConfig } from "nuxt";
2 | import MyModule from '..'
3 |
4 | export default defineNuxtConfig({
5 | modules: [
6 | MyModule
7 | ],
8 | vuetify: {},
9 | });
10 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/router.d.ts:
--------------------------------------------------------------------------------
1 | export interface VueComponent {
2 | options: object;
3 | _Ctor: VueComponent;
4 | }
5 |
6 | export type MatchedRoute = { components: VueComponent[] };
7 |
8 | export type Route = { matched: MatchedRoute[] };
9 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/utils.ts:
--------------------------------------------------------------------------------
1 | export type RecursivePartial = {
2 | [P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial[any] : RecursivePartial;
3 | };
4 |
5 | export type PartialExcept = RecursivePartial &Pick;
6 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/utils.d.ts:
--------------------------------------------------------------------------------
1 | export type RecursivePartial = {
2 | [P in keyof T]?: T[P] extends (infer U)[] ? RecursivePartial[any] : RecursivePartial;
3 | };
4 |
5 | export type PartialExcept = RecursivePartial &Pick;
6 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_size = 4
6 | indent_style = space
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/schemes/index.ts:
--------------------------------------------------------------------------------
1 | export * from './base';
2 | export * from './cookie';
3 | export * from './local';
4 | export * from './oauth2';
5 | export * from './openIDConnect';
6 | export * from './refresh';
7 | export * from './auth0';
8 | export * from './laravel-jwt';
9 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/playground/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Nuxt module playground!
4 |
5 |
6 |
7 |
13 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/expired-auth-session-error.ts:
--------------------------------------------------------------------------------
1 | export class ExpiredAuthSessionError extends Error {
2 | constructor() {
3 | super('Both token and refresh token have expired. Your request was aborted.');
4 | this.name = 'ExpiredAuthSessionError';
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/playground/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | import httpModule from '..'
2 | import { defineNuxtConfig } from 'nuxt/config'
3 |
4 | export default defineNuxtConfig({
5 | modules: [
6 | httpModule,
7 | ],
8 | http: {
9 | interceptorPlugin: true
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/configuration-document-request-error.ts:
--------------------------------------------------------------------------------
1 | export class ConfigurationDocumentRequestError extends Error {
2 | constructor() {
3 | super('Error loading OpenIDConnect configuration document');
4 | this.name = 'ConfigurationDocumentRequestError';
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/playground/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | import Module from '..'
2 |
3 | export default defineNuxtConfig({
4 | modules: [
5 | Module,
6 | "@nuxtjs-alt/http",
7 | "@pinia/nuxt",
8 | ],
9 | auth: {
10 | enableMiddleware: false,
11 | }
12 | });
13 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/proxy/playground/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | import ProxyModule from '..'
2 | import { defineNuxtConfig } from 'nuxt/config'
3 |
4 | export default defineNuxtConfig({
5 | modules: [
6 | ProxyModule
7 | ],
8 | proxy: {
9 | proxies: {
10 | '/api': 'http://localhost:3001'
11 | }
12 | }
13 | })
14 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/index.ts:
--------------------------------------------------------------------------------
1 | export * from './configuration-document-request-error';
2 | export * from './configuration-document';
3 | export * from './expired-auth-session-error';
4 | export * from './refresh-controller';
5 | export * from './refresh-token';
6 | export * from './request-handler';
7 | export * from './token-status';
8 | export * from './token';
9 | export * from './id-token';
10 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/schemes/laravel-jwt.ts:
--------------------------------------------------------------------------------
1 | import type { HTTPResponse } from '../../types';
2 | import { RefreshScheme } from './refresh';
3 |
4 | export class LaravelJWTScheme extends RefreshScheme {
5 | protected updateTokens(response: HTTPResponse, { isRefreshing = false, updateOnRefresh = false } = {}): void {
6 | super.updateTokens(response, { isRefreshing, updateOnRefresh });
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/axios/playground/nuxt.config.ts:
--------------------------------------------------------------------------------
1 | import { defineNuxtConfig } from "nuxt";
2 | import axiosModule from '..'
3 |
4 | export default defineNuxtConfig({
5 | modules: [
6 | axiosModule
7 | ],
8 | vite: {
9 | server: {
10 | hmr: {
11 | clientPort: 443,
12 | path: "hmr/",
13 | },
14 | },
15 | },
16 | });
17 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/vuetify/src/runtime/templates/plugin.mjs:
--------------------------------------------------------------------------------
1 | import { defineNuxtPlugin } from '#imports';
2 | import { createVuetify } from '#vuetify';
3 |
4 | const options = JSON.parse('<%= JSON.stringify(options) %>')
5 |
6 | export default defineNuxtPlugin(nuxtApp => {
7 | const vuetify = createVuetify(options)
8 | nuxtApp.vueApp.use(vuetify)
9 |
10 | return {
11 | provide: {
12 | vuetify
13 | }
14 | }
15 | })
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/providers/index.ts:
--------------------------------------------------------------------------------
1 | export * from './auth0';
2 | export * from './discord';
3 | export * from './facebook';
4 | export * from './github';
5 | export * from './google';
6 | export * from './laravel-jwt';
7 | export * from './laravel-passport';
8 | export * from './laravel-sanctum';
9 |
10 | export const ProviderAliases = {
11 | 'laravel/jwt': 'laravelJWT',
12 | 'laravel/passport': 'laravelPassport',
13 | 'laravel/sanctum': 'laravelSanctum',
14 | };
15 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/provider.d.ts:
--------------------------------------------------------------------------------
1 | import type { SchemeOptions } from "./scheme";
2 | import type { PartialExcept } from "./utils";
3 |
4 | export interface ProviderOptions {
5 | scheme: string;
6 | clientSecret: string | number;
7 | }
8 |
9 | export type ProviderOptionsKeys = Exclude;
10 |
11 | export type ProviderPartialOptions = PartialExcept;
12 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/provider.ts:
--------------------------------------------------------------------------------
1 | import type { SchemeOptions } from './scheme';
2 | import type { PartialExcept } from './utils';
3 |
4 | export interface ProviderOptions {
5 | scheme: string;
6 | clientSecret: string | number;
7 | }
8 |
9 | export type ProviderOptionsKeys = Exclude;
10 |
11 | export type ProviderPartialOptions = PartialExcept;
12 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/strategy.ts:
--------------------------------------------------------------------------------
1 | import type { SchemeOptions } from './scheme';
2 | import type { ProviderPartialOptions, ProviderOptions } from './provider';
3 |
4 | export interface Strategy extends SchemeOptions {
5 | provider?: string | ((...args: any[]) => any);
6 | scheme?: string;
7 | enabled?: boolean;
8 | [option: string]: any;
9 | }
10 |
11 | export type StrategyOptions = ProviderPartialOptions;
12 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/strategy.d.ts:
--------------------------------------------------------------------------------
1 | import type { SchemeOptions } from "./scheme";
2 | import type { ProviderPartialOptions, ProviderOptions } from "./provider";
3 |
4 | export interface Strategy extends SchemeOptions {
5 | provider?: string | ((...args: any[]) => any);
6 | scheme?: string;
7 | enabled?: boolean;
8 | [option: string]: any;
9 | }
10 |
11 | export type StrategyOptions = ProviderPartialOptions;
12 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/schemes/base.ts:
--------------------------------------------------------------------------------
1 | import type { SchemeOptions } from '../../types';
2 | import type { Auth } from '..';
3 | import { defu } from 'defu';
4 |
5 | export class BaseScheme {
6 | options: OptionsT;
7 |
8 | constructor(public $auth: Auth, ...options: OptionsT[]) {
9 | this.options = options.reduce((p, c) => defu(p, c), {}) as OptionsT;
10 | }
11 |
12 | get name(): string {
13 | return this.options.name as string;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/schemes/auth0.ts:
--------------------------------------------------------------------------------
1 | import { withQuery } from 'ufo';
2 | import { Oauth2Scheme } from '../schemes/oauth2';
3 |
4 | export class Auth0Scheme extends Oauth2Scheme {
5 | logout(): void {
6 | this.$auth.reset();
7 |
8 | const opts = {
9 | client_id: this.options.clientId as string,
10 | returnTo: this.logoutRedirectURI,
11 | };
12 |
13 | const url = withQuery(this.options.endpoints.logout as string, opts)
14 | window.location.replace(url);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/index.d.ts:
--------------------------------------------------------------------------------
1 | import type { ModuleOptions } from "./options";
2 | import * as NuxtSchema from '@nuxt/schema';
3 |
4 | export * from "./openIDConnectConfigurationDocument";
5 | export * from "./provider";
6 | export * from "./request";
7 | export * from "./router";
8 | export * from "./scheme";
9 | export * from "./strategy";
10 | export * from "./utils";
11 | export * from "./options";
12 |
13 | declare const AuthModule: NuxtSchema.NuxtModule;
14 |
15 | declare module "@nuxt/schema" {
16 | export interface NuxtConfig {
17 | ["auth"]?: Partial;
18 | }
19 | export interface NuxtOptions {
20 | ["auth"]?: ModuleOptions;
21 | }
22 | }
23 |
24 | export default AuthModule
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 3
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 5
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - pinned
8 | - security
9 | # Label to use when marking an issue as stale
10 | staleLabel: wontfix
11 | # Comment to post when marking an issue as stale. Set to `false` to disable
12 | markComment: >
13 | This issue has been automatically marked as stale because it has not had
14 | recent activity. It will be closed if no further activity occurs. Thank you
15 | for your contributions.
16 | # Comment to post when closing a stale issue. Set to `false` to disable
17 | closeComment: false
18 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/providers/google.ts:
--------------------------------------------------------------------------------
1 | import type { ProviderPartialOptions, ProviderOptions } from '../types';
2 | import type { Oauth2SchemeOptions } from '../runtime';
3 | import type { Nuxt } from '@nuxt/schema'
4 | import { assignDefaults } from '../utils/provider';
5 |
6 | export interface GoogleProviderOptions extends ProviderOptions, Oauth2SchemeOptions {}
7 |
8 | export function google(nuxt: Nuxt, strategy: ProviderPartialOptions): void {
9 | const DEFAULTS: typeof strategy = {
10 | scheme: 'oauth2',
11 | endpoints: {
12 | authorization: 'https://accounts.google.com/o/oauth2/auth',
13 | userInfo: 'https://www.googleapis.com/oauth2/v3/userinfo',
14 | },
15 | scope: ['openid', 'profile', 'email'],
16 | };
17 |
18 | assignDefaults(strategy, DEFAULTS);
19 | }
20 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/providers/facebook.ts:
--------------------------------------------------------------------------------
1 | import type { ProviderPartialOptions, ProviderOptions } from '../types';
2 | import type { Oauth2SchemeOptions } from '../runtime';
3 | import type { Nuxt } from '@nuxt/schema'
4 | import { assignDefaults } from '../utils/provider';
5 |
6 | export interface FacebookProviderOptions extends ProviderOptions, Oauth2SchemeOptions {}
7 |
8 | export function facebook(nuxt: Nuxt, strategy: ProviderPartialOptions): void {
9 | const DEFAULTS: typeof strategy = {
10 | scheme: 'oauth2',
11 | endpoints: {
12 | authorization: 'https://facebook.com/v2.12/dialog/oauth',
13 | userInfo: 'https://graph.facebook.com/v2.12/me?fields=about,name,picture{url},email',
14 | },
15 | scope: ['public_profile', 'email'],
16 | };
17 |
18 | assignDefaults(strategy, DEFAULTS);
19 | }
20 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/vuetify/src/types.ts:
--------------------------------------------------------------------------------
1 | import * as NuxtSchema from '@nuxt/schema';
2 | import type { VuetifyOptions } from 'vuetify';
3 |
4 | interface Options {
5 | autoImport?: boolean;
6 | styles?: true | 'none' | 'expose' | 'sass' | {
7 | configFile: string;
8 | };
9 | /** @internal Only for testing */
10 | stylesTimeout?: number;
11 | }
12 |
13 | export interface ModuleOptions {
14 | vuetifyOptions?: VuetifyOptions
15 | pluginOptions?: Options
16 | }
17 |
18 | declare module '#app' {
19 | interface NuxtApp {
20 | $vuetify: VuetifyOptions;
21 | }
22 | }
23 |
24 | declare module '@nuxt/schema' {
25 | interface NuxtConfig {
26 | vuetify?: ModuleOptions;
27 | }
28 | interface NuxtOptions {
29 | vuetify?: ModuleOptions
30 | }
31 | }
32 |
33 | declare const NuxtVuetify: NuxtSchema.NuxtModule
34 |
35 | export default NuxtVuetify
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/providers/github.ts:
--------------------------------------------------------------------------------
1 | import type { ProviderOptions, ProviderPartialOptions } from '../types';
2 | import type { Oauth2SchemeOptions } from '../runtime';
3 | import type { Nuxt } from '@nuxt/schema'
4 | import { assignDefaults, addAuthorize } from '../utils/provider';
5 |
6 | export interface GithubProviderOptions extends ProviderOptions, Oauth2SchemeOptions {}
7 |
8 | export function github(nuxt: Nuxt, strategy: ProviderPartialOptions): void {
9 | const DEFAULTS: typeof strategy = {
10 | scheme: 'oauth2',
11 | endpoints: {
12 | authorization: 'https://github.com/login/oauth/authorize',
13 | token: 'https://github.com/login/oauth/access_token',
14 | userInfo: 'https://api.github.com/user',
15 | },
16 | scope: ['user', 'email'],
17 | };
18 |
19 | assignDefaults(strategy, DEFAULTS);
20 |
21 | addAuthorize(nuxt, strategy);
22 | }
23 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/providers/auth0.ts:
--------------------------------------------------------------------------------
1 | import type { ProviderOptions, ProviderPartialOptions } from '../types';
2 | import type { Oauth2SchemeOptions } from '../runtime';
3 | import type { Nuxt } from '@nuxt/schema'
4 | import { assignDefaults } from '../utils/provider';
5 |
6 | export interface Auth0ProviderOptions extends ProviderOptions, Oauth2SchemeOptions {
7 | domain: string;
8 | }
9 |
10 | export function auth0(nuxt: Nuxt, strategy: ProviderPartialOptions): void {
11 | const DEFAULTS: typeof strategy = {
12 | scheme: 'auth0',
13 | endpoints: {
14 | authorization: `https://${strategy.domain}/authorize`,
15 | userInfo: `https://${strategy.domain}/userinfo`,
16 | token: `https://${strategy.domain}/oauth/token`,
17 | logout: `https://${strategy.domain}/v2/logout`,
18 | },
19 | scope: ['openid', 'profile', 'email'],
20 | };
21 |
22 | assignDefaults(strategy, DEFAULTS);
23 | }
24 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/index.ts:
--------------------------------------------------------------------------------
1 | import type { ModuleOptions } from './options';
2 | import type { Auth } from '../runtime';
3 | import * as NuxtSchema from '@nuxt/schema';
4 |
5 | export * from './openIDConnectConfigurationDocument';
6 | export * from './provider';
7 | export * from './request';
8 | export * from './router';
9 | export * from './scheme';
10 | export * from './strategy';
11 | export * from './utils';
12 | export * from './options';
13 |
14 | declare module '#app' {
15 | interface NuxtApp extends AuthPluginInjection {}
16 | }
17 |
18 | interface AuthPluginInjection {
19 | $auth: Auth;
20 | }
21 |
22 | declare module '@nuxt/schema' {
23 | export interface NuxtConfig {
24 | auth?: Partial;
25 | }
26 | export interface NuxtOptions {
27 | auth?: Partial;
28 | }
29 | export interface RuntimeConfig {
30 | auth?: Partial
31 | }
32 | }
33 |
34 | declare const NuxtAuth: NuxtSchema.NuxtModule>
35 |
36 | export default NuxtAuth
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Teranode
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/providers/discord.ts:
--------------------------------------------------------------------------------
1 | import type { ProviderOptions, ProviderPartialOptions } from '../types';
2 | import type { Oauth2SchemeOptions } from '../runtime';
3 | import type { Nuxt } from '@nuxt/schema'
4 | import { assignDefaults, addAuthorize } from '../utils/provider';
5 |
6 | export interface DiscordProviderOptions extends ProviderOptions, Oauth2SchemeOptions {}
7 |
8 | export function discord(nuxt: Nuxt, strategy: ProviderPartialOptions): void {
9 | const DEFAULTS: typeof strategy = {
10 | scheme: 'oauth2',
11 | endpoints: {
12 | authorization: 'https://discord.com/api/oauth2/authorize',
13 | token: 'https://discord.com/api/oauth2/token',
14 | userInfo: 'https://discord.com/api/users/@me',
15 | // logout: 'https://discord.com/api/oauth2/token/revoke' //TODO: add post method, because discord using the post method to logout
16 | },
17 | grantType: 'authorization_code',
18 | codeChallengeMethod: 'S256',
19 | scope: ['identify', 'email'],
20 | };
21 |
22 | assignDefaults(strategy, DEFAULTS);
23 |
24 | addAuthorize(nuxt, strategy, true);
25 | }
26 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/options.ts:
--------------------------------------------------------------------------------
1 | export const moduleDefaults = {
2 | // -- Enable Global Middleware --
3 | globalMiddleware: false,
4 |
5 | enableMiddleware: true,
6 |
7 | // -- Error handling --
8 |
9 | resetOnError: false,
10 |
11 | ignoreExceptions: false,
12 |
13 | // -- Authorization --
14 |
15 | scopeKey: 'scope',
16 |
17 | // -- Redirects --
18 |
19 | rewriteRedirects: true,
20 |
21 | fullPathRedirect: false,
22 |
23 | watchLoggedIn: true,
24 |
25 | redirect: {
26 | login: '/login',
27 | logout: '/',
28 | home: '/',
29 | callback: '/login',
30 | },
31 |
32 | // -- Pinia Store --
33 |
34 | pinia: {
35 | namespace: 'auth',
36 | },
37 |
38 | // -- Cookie Store --
39 |
40 | cookie: {
41 | prefix: 'auth.',
42 | options: {
43 | path: '/',
44 | },
45 | },
46 |
47 | // -- localStorage Store --
48 |
49 | localStorage: {
50 | prefix: 'auth.',
51 | },
52 |
53 | // -- sessionStorage Store --
54 |
55 | sessionStorage: {
56 | prefix: 'auth.',
57 | },
58 |
59 | // -- Strategies --
60 |
61 | defaultStrategy: undefined /* will be auto set at module level */,
62 |
63 | strategies: {},
64 | };
65 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/src/runtime/templates/interceptor.plugin.mjs:
--------------------------------------------------------------------------------
1 | import { defineNuxtPlugin, useRuntimeConfig } from '#imports'
2 |
3 | // Nuxt Options
4 | const proxies = {}
5 | const options = JSON.parse('<%= JSON.stringify(options) %>')
6 |
7 | function isObject(value) {
8 | return Object.prototype.toString.call(value) === '[object Object]'
9 | }
10 |
11 | function doesProxyContextMatchUrl(context, url) {
12 | return (
13 | (context.startsWith('^') && new RegExp(context).test(url)) || url.startsWith(context)
14 | )
15 | }
16 |
17 | export default defineNuxtPlugin(({ $http }) => {
18 | Object.keys(options.proxies).forEach((context) => {
19 | let opts = options.proxies[context]
20 |
21 | if (typeof opts === 'string') {
22 | opts = { target: opts }
23 | }
24 |
25 | if (isObject(opts)) {
26 | opts = { ...opts }
27 | }
28 |
29 | proxies[context] = [{ ...opts }]
30 | })
31 |
32 | if (process.client) {
33 | $http.interceptors.request.use(config => {
34 | for (const context in proxies) {
35 | const [opts] = proxies[context]
36 | if (doesProxyContextMatchUrl(context, config.url)) {
37 | config.baseURL = opts.target
38 | }
39 | }
40 |
41 | return config
42 | })
43 | }
44 | })
--------------------------------------------------------------------------------
/@nuxtjs-alt/proxy/src/runtime/fetch.interceptor.mjs:
--------------------------------------------------------------------------------
1 | import { defineNuxtPlugin } from '#imports'
2 |
3 | // Nuxt Options
4 | const proxies = {}
5 | const options = JSON.parse('<%= JSON.stringify(options) %>')
6 |
7 | function isObject(value) {
8 | return Object.prototype.toString.call(value) === '[object Object]'
9 | }
10 |
11 | function doesProxyContextMatchUrl(context, url) {
12 | return (
13 | (context.startsWith('^') && new RegExp(context).test(url)) || url.startsWith(context)
14 | )
15 | }
16 |
17 | export default defineNuxtPlugin(nuxtApp => {
18 | Object.keys(options.proxies).forEach((context) => {
19 | let opts = options.proxies[context]
20 |
21 | if (typeof opts === 'string') {
22 | opts = { target: opts }
23 | }
24 |
25 | if (isObject(opts)) {
26 | opts = { ...opts }
27 | }
28 |
29 | proxies[context] = [{ ...opts }]
30 | })
31 |
32 | if (process.client && options.fetch) {
33 | $fetch.create({
34 | async onRequest({ request, options }) {
35 | for (const context in proxies) {
36 | const [opts] = proxies[context]
37 | if (doesProxyContextMatchUrl(context, request)) {
38 | options.baseURL = opts.target
39 | }
40 | }
41 | }
42 | })
43 | }
44 | })
--------------------------------------------------------------------------------
/@nuxtjs-alt/proxy/src/runtime/interceptor.mjs:
--------------------------------------------------------------------------------
1 | import { defineNuxtPlugin, useRuntimeConfig } from '#imports'
2 |
3 | // Nuxt Options
4 | const proxies = {}
5 | const options = JSON.parse('<%= JSON.stringify(options) %>')
6 |
7 | function isObject(value) {
8 | return Object.prototype.toString.call(value) === '[object Object]'
9 | }
10 |
11 | function doesProxyContextMatchUrl(context, url) {
12 | return (
13 | (context.startsWith('^') && new RegExp(context).test(url)) || url.startsWith(context)
14 | )
15 | }
16 |
17 | export default defineNuxtPlugin(nuxtApp => {
18 | Object.keys(options.proxies).forEach((context) => {
19 | let opts = options.proxies[context]
20 |
21 | if (typeof opts === 'string') {
22 | opts = { target: opts }
23 | }
24 |
25 | if (isObject(opts)) {
26 | opts = { ...opts }
27 | }
28 |
29 | proxies[context] = [{ ...opts }]
30 | })
31 |
32 | if (process.client && options.fetch) {
33 | $fetch.create({
34 | async onRequest({ request, options }) {
35 | for (const context in proxies) {
36 | const [opts] = proxies[context]
37 | if (doesProxyContextMatchUrl(context, request)) {
38 | options.baseURL = opts.target
39 | }
40 | }
41 | }
42 | })
43 | }
44 | })
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/openIDConnectConfigurationDocument.ts:
--------------------------------------------------------------------------------
1 | export type OpenIDConnectConfigurationDocument = {
2 | issuer?: string;
3 | authorization_endpoint?: string;
4 | token_endpoint?: string;
5 | token_endpoint_auth_methods_supported?: string[];
6 | token_endpoint_auth_signing_alg_values_supported?: string[];
7 | userinfo_endpoint?: string;
8 | check_session_iframe?: string;
9 | end_session_endpoint?: string;
10 | jwks_uri?: string;
11 | registration_endpoint?: string;
12 | scopes_supported?: string[];
13 | response_types_supported?: string[];
14 | acr_values_supported?: string[];
15 | response_modes_supported?: string[];
16 | grant_types_supported?: string[];
17 | subject_types_supported?: string[];
18 | userinfo_signing_alg_values_supported?: string[];
19 | userinfo_encryption_alg_values_supported?: string[];
20 | userinfo_encryption_enc_values_supported?: string[];
21 | id_token_signing_alg_values_supported?: string[];
22 | id_token_encryption_alg_values_supported?: string[];
23 | id_token_encryption_enc_values_supported?: string[];
24 | request_object_signing_alg_values_supported?: string[];
25 | display_values_supported?: string[];
26 | claim_types_supported?: string[];
27 | claims_supported?: string[];
28 | claims_parameter_supported?: boolean;
29 | service_documentation?: string;
30 | ui_locales_supported?: string[];
31 | };
32 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/options.d.ts:
--------------------------------------------------------------------------------
1 | import type { Strategy } from "./strategy";
2 | import type { NuxtPlugin } from '@nuxt/schema'
3 |
4 | export interface ModuleOptions {
5 | globalMiddleware?: boolean;
6 | enableMiddleware?: boolean;
7 | plugins?: (NuxtPlugin | string)[];
8 | strategies?: {
9 | [strategy: string]: Strategy | false;
10 | };
11 | ignoreExceptions: boolean;
12 | resetOnError: boolean | ((...args: any[]) => boolean);
13 | defaultStrategy: string | undefined;
14 | watchLoggedIn: boolean;
15 | rewriteRedirects: boolean;
16 | fullPathRedirect: boolean;
17 | scopeKey: string;
18 | redirect: {
19 | login: string;
20 | logout: string;
21 | callback: string;
22 | home: string;
23 | };
24 | pinia: {
25 | namespace: string;
26 | };
27 | cookie:
28 | | {
29 | prefix: string;
30 | options: {
31 | path: string;
32 | expires?: number | Date;
33 | maxAge?: number;
34 | domain?: string;
35 | secure?: boolean;
36 | };
37 | }
38 | | false;
39 | localStorage: { prefix: string; } | false;
40 | sessionStorage: { prefix: string; } | false;
41 | initialState?: {
42 | user: null;
43 | loggedIn: boolean;
44 | [key: string]: any;
45 | };
46 | }
47 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/refresh-controller.ts:
--------------------------------------------------------------------------------
1 | import type { RefreshableScheme, HTTPResponse } from '../../types';
2 | import type { Auth } from '../core';
3 |
4 | export class RefreshController {
5 | $auth: Auth;
6 | #refreshPromise: Promise | null = null;
7 |
8 | constructor(public scheme: RefreshableScheme) {
9 | this.$auth = scheme.$auth;
10 | }
11 |
12 | // Multiple requests will be queued until the first has completed token refresh.
13 | handleRefresh(): Promise {
14 | // Another request has started refreshing the token, wait for it to complete
15 | if (this.#refreshPromise) {
16 | return this.#refreshPromise;
17 | }
18 |
19 | return this.#doRefresh();
20 | }
21 |
22 | // Returns a promise which is resolved when refresh is completed
23 | // Call this function when you intercept a request with an expired token.
24 |
25 | #doRefresh(): Promise {
26 | this.#refreshPromise = new Promise((resolve, reject) => {
27 | this.scheme.refreshTokens()
28 | .then((response) => {
29 | this.#refreshPromise = null;
30 | resolve(response);
31 | })
32 | .catch((error) => {
33 | this.#refreshPromise = null;
34 | reject(error);
35 | });
36 | });
37 |
38 | return this.#refreshPromise;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/token-status.ts:
--------------------------------------------------------------------------------
1 | export enum TokenStatusEnum {
2 | UNKNOWN = 'UNKNOWN',
3 | VALID = 'VALID',
4 | EXPIRED = 'EXPIRED',
5 | }
6 |
7 | export class TokenStatus {
8 | readonly #status: TokenStatusEnum;
9 |
10 | constructor(token: string | boolean, tokenExpiresAt: number | false) {
11 | this.#status = this.#calculate(token, tokenExpiresAt);
12 | }
13 |
14 | unknown(): boolean {
15 | return TokenStatusEnum.UNKNOWN === this.#status;
16 | }
17 |
18 | valid(): boolean {
19 | return TokenStatusEnum.VALID === this.#status;
20 | }
21 |
22 | expired(): boolean {
23 | return TokenStatusEnum.EXPIRED === this.#status;
24 | }
25 |
26 | #calculate(token: string | boolean, tokenExpiresAt: number | false): TokenStatusEnum {
27 | const now = Date.now();
28 |
29 | try {
30 | if (!token || !tokenExpiresAt) {
31 | return TokenStatusEnum.UNKNOWN;
32 | }
33 | } catch (error) {
34 | return TokenStatusEnum.UNKNOWN;
35 | }
36 |
37 | // Give us some slack to help the token from expiring between validation and usage
38 | const timeSlackMillis = 500;
39 | tokenExpiresAt -= timeSlackMillis;
40 |
41 | // Token is still valid
42 | if (now < tokenExpiresAt) {
43 | return TokenStatusEnum.VALID;
44 | }
45 |
46 | return TokenStatusEnum.EXPIRED;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/src/types.ts:
--------------------------------------------------------------------------------
1 | import { FetchConfig, FetchInstance } from '@refactorjs/ofetch'
2 | import * as NuxtSchema from '@nuxt/schema';
3 |
4 | export interface ModuleOptions extends Omit {
5 | baseURL?: string;
6 | browserBaseURL?: string;
7 | host?: string;
8 | prefix?: string;
9 | proxyHeaders?: boolean;
10 | proxyHeadersIgnore?: string[];
11 | serverTimeout?: number,
12 | clientTimeout?: number,
13 | port?: string | number;
14 | https?: boolean;
15 | retry?: number;
16 | credentials?: string;
17 | headers?: any;
18 | debug?: boolean;
19 | interceptorPlugin?: boolean;
20 | }
21 |
22 | declare global {
23 | var $http: FetchInstance;
24 | namespace NodeJS {
25 | interface Global {
26 | $http: FetchInstance;
27 | }
28 | }
29 | }
30 |
31 | declare module '#app' {
32 | interface NuxtApp extends HttpPluginInjection {}
33 | }
34 |
35 | interface HttpPluginInjection {
36 | $http: FetchInstance;
37 | }
38 |
39 | declare module '@nuxt/schema' {
40 | interface NuxtConfig {
41 | http?: ModuleOptions
42 | }
43 | interface NuxtOptions {
44 | http?: ModuleOptions
45 | }
46 | interface RuntimeConfig {
47 | http?: ModuleOptions;
48 | }
49 | interface PublicRuntimeConfig {
50 | http?: ModuleOptions
51 | }
52 | }
53 |
54 | declare const NuxtHttp: NuxtSchema.NuxtModule
55 |
56 | export default NuxtHttp
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/options.ts:
--------------------------------------------------------------------------------
1 | import type { Strategy } from './strategy';
2 | import type { NuxtPlugin } from '@nuxt/schema'
3 |
4 | export interface ModuleOptions {
5 | globalMiddleware?: boolean;
6 | enableMiddleware?: boolean;
7 | plugins?: (NuxtPlugin | string)[];
8 | strategies?: {
9 | [strategy: string]: Strategy | false;
10 | };
11 | ignoreExceptions: boolean;
12 | resetOnError: boolean | ((...args: any[]) => boolean);
13 | defaultStrategy: string | undefined;
14 | watchLoggedIn: boolean;
15 | rewriteRedirects: boolean;
16 | fullPathRedirect: boolean;
17 | scopeKey: string;
18 | redirect: {
19 | login: string;
20 | logout: string;
21 | callback: string;
22 | home: string;
23 | };
24 | pinia: {
25 | namespace: string;
26 | };
27 | cookie:
28 | | {
29 | prefix: string;
30 | options: {
31 | path: string;
32 | expires?: number | Date;
33 | maxAge?: number;
34 | domain?: string;
35 | secure?: boolean;
36 | };
37 | }
38 | | false;
39 | localStorage: { prefix: string; } | false;
40 | sessionStorage: { prefix: string; } | false;
41 | initialState?: {
42 | user: null;
43 | loggedIn: boolean;
44 | strategy?: string | null;
45 | busy?: boolean | null;
46 | };
47 | }
48 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/proxy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@nuxtjs-alt/proxy",
3 | "version": "2.1.0",
4 | "description": "An alternative module to @nuxtjs/proxy",
5 | "homepage": "https://github.com/Teranode/nuxt-module-alternatives",
6 | "author": "Teranode",
7 | "keywords": [
8 | "nuxt",
9 | "nuxtjs",
10 | "nuxt-module",
11 | "nuxt-plugin",
12 | "nuxt-module-alternatives",
13 | "@nuxtjs/proxy"
14 | ],
15 | "license": "MIT",
16 | "type": "module",
17 | "main": "./dist/module.cjs",
18 | "module": "./dist/module.mjs",
19 | "types": "./dist/types.d.ts",
20 | "scripts": {
21 | "dev": "nuxi dev playground",
22 | "dev:build": "nuxi build playground",
23 | "dev:prepare": "unbuild --stub && nuxi prepare playground",
24 | "prepack": "unbuild"
25 | },
26 | "files": [
27 | "dist"
28 | ],
29 | "dependencies": {
30 | "@nuxt/kit": "^3.0.0",
31 | "@refactorjs/http-proxy": "latest",
32 | "defu": "latest",
33 | "ofetch": "latest"
34 | },
35 | "devDependencies": {
36 | "unbuild": "latest",
37 | "nuxt": "^3.0.0"
38 | },
39 | "repository": {
40 | "type": "git",
41 | "url": "git+https://github.com/Teranode/nuxt-module-alternatives.git",
42 | "directory": "@nuxtjs-alt/proxy"
43 | },
44 | "bugs": {
45 | "url": "https://github.com/Teranode/nuxt-module-alternatives/issues"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/proxy/src/types.ts:
--------------------------------------------------------------------------------
1 | import type { ProxyServer, Server } from '@refactorjs/http-proxy'
2 | import type { IncomingMessage, ServerResponse } from 'node:http'
3 | import * as NuxtSchema from '@nuxt/schema';
4 |
5 | export interface ModuleOptions {
6 | enableProxy?: boolean
7 | proxies?: {
8 | [key: string]: string | ProxyOptions
9 | }
10 | fetch?: boolean
11 | }
12 |
13 | export interface ProxyOptions extends Server.ServerOptions {
14 | /**
15 | * rewrite path
16 | */
17 | rewrite?: (path: string) => string | null | undefined | false
18 |
19 | /**
20 | * configure the proxy server (e.g. listen to events)
21 | */
22 | configure?: (proxy: ProxyServer, options: ProxyOptions) => void | null | undefined | false
23 |
24 | /**
25 | * webpack-dev-server style bypass function
26 | */
27 | bypass?: (
28 | req: IncomingMessage,
29 | res: ServerResponse,
30 | options: ProxyOptions
31 | ) => void | null | undefined | false | string
32 | }
33 |
34 | declare module '@nuxt/schema' {
35 | interface NuxtConfig {
36 | proxy?: ModuleOptions
37 | }
38 | interface NuxtOptions {
39 | proxy?: ModuleOptions
40 | }
41 | interface RuntimeConfig {
42 | proxy?: ModuleOptions;
43 | }
44 | interface PublicRuntimeConfig {
45 | proxy?: ModuleOptions
46 | }
47 | }
48 |
49 | declare const NuxtProxy: NuxtSchema.NuxtModule
50 |
51 | export default NuxtProxy
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/openIDConnectConfigurationDocument.d.ts:
--------------------------------------------------------------------------------
1 | export type OpenIDConnectConfigurationDocument = {
2 | /* eslint-disable camelcase */
3 | issuer?: string;
4 | authorization_endpoint?: string;
5 | token_endpoint?: string;
6 | token_endpoint_auth_methods_supported?: string[];
7 | token_endpoint_auth_signing_alg_values_supported?: string[];
8 | userinfo_endpoint?: string;
9 | check_session_iframe?: string;
10 | end_session_endpoint?: string;
11 | jwks_uri?: string;
12 | registration_endpoint?: string;
13 | scopes_supported?: string[];
14 | response_types_supported?: string[];
15 | acr_values_supported?: string[];
16 | response_modes_supported?: string[];
17 | grant_types_supported?: string[];
18 | subject_types_supported?: string[];
19 | userinfo_signing_alg_values_supported?: string[];
20 | userinfo_encryption_alg_values_supported?: string[];
21 | userinfo_encryption_enc_values_supported?: string[];
22 | id_token_signing_alg_values_supported?: string[];
23 | id_token_encryption_alg_values_supported?: string[];
24 | id_token_encryption_enc_values_supported?: string[];
25 | request_object_signing_alg_values_supported?: string[];
26 | display_values_supported?: string[];
27 | claim_types_supported?: string[];
28 | claims_supported?: string[];
29 | claims_parameter_supported?: boolean;
30 | service_documentation?: string;
31 | ui_locales_supported?: string[];
32 | /* eslint-enable camelcase */
33 | };
34 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/vuetify/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@nuxtjs-alt/vuetify",
3 | "version": "1.0.4",
4 | "description": "A module to handle vuetify 3",
5 | "homepage": "https://github.com/Teranode/nuxt-module-alternatives",
6 | "author": "Teranode",
7 | "keywords": [
8 | "nuxt",
9 | "nuxtjs",
10 | "nuxt-module",
11 | "nuxt-plugin",
12 | "nuxt-module-alternatives",
13 | "vuetify"
14 | ],
15 | "license": "MIT",
16 | "type": "module",
17 | "main": "./dist/module.cjs",
18 | "module": "./dist/module.mjs",
19 | "types": "./dist/types.d.ts",
20 | "files": [
21 | "dist"
22 | ],
23 | "scripts": {
24 | "dev": "nuxi dev playground",
25 | "dev:build": "nuxi build playground",
26 | "prepack": "unbuild",
27 | "dev:prepare": "unbuild --stub && nuxi prepare playground"
28 | },
29 | "dependencies": {
30 | "@nuxt/kit": "^3.0.0",
31 | "sass": "^1.56.1",
32 | "sass-loader": "^13.2.0",
33 | "vite-plugin-vuetify": "^1.0.0",
34 | "vuetify": "^3.0.2"
35 | },
36 | "devDependencies": {
37 | "unbuild": "latest",
38 | "nuxt": "^3.0.0"
39 | },
40 | "repository": {
41 | "type": "git",
42 | "url": "git+https://github.com/Teranode/nuxt-module-alternatives.git",
43 | "directory": "@nuxtjs-alt/vuetify"
44 | },
45 | "bugs": {
46 | "url": "https://github.com/Teranode/nuxt-module-alternatives/issues"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/vuetify/readme.md:
--------------------------------------------------------------------------------
1 | ## This package is deprecated please use the package at: https://github.com/nuxt-alt/vuetify
2 |
3 | This module is meant to try to work with Vuetify 3. Here is the config for you to work with
4 |
5 | ```ts
6 | vuetify: {
7 | vuetifyOptions: {
8 |
9 | },
10 | pluginOptions: {
11 | autoImports: true, // default
12 | styles: true // default
13 | },
14 | }
15 | ```
16 |
17 | **vuetifyOptions**
18 |
19 | This is for the configuration of vuetify located here:
20 | https://next.vuetifyjs.com/en/features/global-configuration/
21 |
22 | Material Design Icons is used by default via cdn urls. you can use `mdi`, `md` or `fa` for cdn urls when setting `defaultSet` in vuetify options.
23 |
24 | **pluginOptions**
25 |
26 | Please refer to the Readme located here:
27 | https://www.npmjs.com/package/vite-plugin-vuetify
28 |
29 | By default the styles will be set to true and will load `vuetify/styles`.
30 |
31 | **Bugs**
32 |
33 | Please note that there is a bug with vuetify where custome scss files might not function correctly
34 |
35 | Source: https://github.com/nuxt/framework/issues/8825
36 |
37 | There's currently a bug with vueuse/head where it's potentially causing a memory leak and also not adapting changes when using the `useTheme` composable. For now I have made a workaround where the module will be running it's own `creatVuetify` instance inheriting from vueitfy and making the necissary changes to make it function. Until this is fixed thta will be used instead.
38 |
39 | Source: https://github.com/vuetifyjs/vuetify/issues/16156
40 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/providers/laravel-sanctum.ts:
--------------------------------------------------------------------------------
1 | import type { ProviderPartialOptions, HTTPRequest, ProviderOptions } from '../types';
2 | import type { CookieSchemeOptions } from '../runtime';
3 | import type { Nuxt } from '@nuxt/schema'
4 | import { assignDefaults } from '../utils/provider';
5 |
6 | export interface LaravelSanctumProviderOptions extends ProviderOptions, CookieSchemeOptions {}
7 |
8 | export function laravelSanctum(nuxt: Nuxt, strategy: ProviderPartialOptions): void {
9 | const endpointDefaults: Partial = {
10 | credentials: 'include'
11 | };
12 |
13 | const DEFAULTS: typeof strategy = {
14 | scheme: 'cookie',
15 | name: 'laravelSanctum',
16 | cookie: {
17 | name: 'XSRF-TOKEN',
18 | server: nuxt.options.ssr
19 | },
20 | endpoints: {
21 | csrf: {
22 | ...endpointDefaults,
23 | url: '/sanctum/csrf-cookie',
24 | },
25 | login: {
26 | ...endpointDefaults,
27 | url: '/login',
28 | },
29 | logout: {
30 | ...endpointDefaults,
31 | url: '/logout',
32 | },
33 | user: {
34 | ...endpointDefaults,
35 | url: '/api/user',
36 | },
37 | },
38 | user: {
39 | property: {
40 | server: false,
41 | client: false
42 | },
43 | autoFetch: true,
44 | }
45 | };
46 |
47 | assignDefaults(strategy, DEFAULTS)
48 | }
49 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@nuxtjs-alt/http",
3 | "version": "1.5.0",
4 | "description": "An extended module to ohmyfetch",
5 | "homepage": "https://github.com/Teranode/nuxt-module-alternatives",
6 | "author": "Teranode",
7 | "keywords": [
8 | "nuxt",
9 | "nuxtjs",
10 | "nuxt-module",
11 | "nuxt-plugin",
12 | "nuxt-module-alternatives",
13 | "ohmyfetch",
14 | "@nuxtjs/http"
15 | ],
16 | "license": "MIT",
17 | "type": "module",
18 | "sideEffects": false,
19 | "exports": {
20 | ".": {
21 | "import": "./dist/module.mjs",
22 | "require": "./dist/module.cjs"
23 | }
24 | },
25 | "main": "./dist/module.cjs",
26 | "module": "./dist/module.mjs",
27 | "types": "./dist/types.d.ts",
28 | "files": [
29 | "dist"
30 | ],
31 | "scripts": {
32 | "dev": "nuxi dev playground",
33 | "dev:build": "nuxi build playground",
34 | "dev:prepare": "unbuild --stub && nuxi prepare playground",
35 | "prepack": "unbuild"
36 | },
37 | "dependencies": {
38 | "@nuxt/kit": "^3.0.0",
39 | "@refactorjs/ofetch": "latest",
40 | "defu": "latest",
41 | "ufo": "latest"
42 | },
43 | "devDependencies": {
44 | "nuxt": "^3.0.0",
45 | "unbuild": "latest"
46 | },
47 | "repository": {
48 | "type": "git",
49 | "url": "git+https://github.com/Teranode/nuxt-module-alternatives.git",
50 | "directory": "@nuxtjs-alt/http"
51 | },
52 | "bugs": {
53 | "url": "https://github.com/Teranode/nuxt-module-alternatives/issues"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/providers/laravel-jwt.ts:
--------------------------------------------------------------------------------
1 | import type { ProviderPartialOptions, ProviderOptions } from '../types';
2 | import type { RefreshSchemeOptions } from '../runtime';
3 | import type { Nuxt } from '@nuxt/schema'
4 | import { assignDefaults, assignAbsoluteEndpoints } from '../utils/provider';
5 |
6 | export interface LaravelJWTProviderOptions extends ProviderOptions, RefreshSchemeOptions {
7 | url: string;
8 | }
9 |
10 | export function laravelJWT(nuxt: Nuxt, strategy: ProviderPartialOptions): void {
11 | const { url } = strategy;
12 |
13 | if (!url) {
14 | throw new Error('url is required for laravel jwt!');
15 | }
16 |
17 | const DEFAULTS: typeof strategy = {
18 | name: 'laravelJWT',
19 | scheme: 'laravelJWT',
20 | endpoints: {
21 | login: {
22 | url: url + '/api/auth/login',
23 | },
24 | refresh: {
25 | url: url + '/api/auth/refresh',
26 | },
27 | logout: {
28 | url: url + '/api/auth/logout',
29 | },
30 | user: {
31 | url: url + '/api/auth/user',
32 | },
33 | },
34 | token: {
35 | property: 'access_token',
36 | maxAge: 3600,
37 | },
38 | refreshToken: {
39 | property: false,
40 | data: false,
41 | maxAge: 1209600,
42 | required: false,
43 | tokenRequired: true,
44 | },
45 | user: {
46 | property: false,
47 | },
48 | clientId: false,
49 | grantType: false,
50 | };
51 |
52 | assignDefaults(strategy, DEFAULTS);
53 |
54 | assignAbsoluteEndpoints(strategy);
55 | }
56 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/axios/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@nuxtjs-alt/axios",
3 | "version": "1.0.19",
4 | "description": "An alternative module to @nuxtjs/axios",
5 | "homepage": "https://github.com/Teranode/nuxt-module-alternatives",
6 | "author": "Teranode",
7 | "keywords": [
8 | "nuxt",
9 | "nuxtjs",
10 | "nuxt-module",
11 | "nuxt-plugin",
12 | "nuxt-module-alternatives",
13 | "axios",
14 | "@nuxtjs/axios"
15 | ],
16 | "license": "MIT",
17 | "type": "module",
18 | "sideEffects": false,
19 | "exports": {
20 | ".": {
21 | "import": "./dist/module.mjs",
22 | "require": "./dist/module.cjs"
23 | }
24 | },
25 | "main": "./dist/module.cjs",
26 | "module": "./dist/module.mjs",
27 | "types": "./dist/module.d.ts",
28 | "files": [
29 | "dist"
30 | ],
31 | "scripts": {
32 | "dev": "nuxi dev playground",
33 | "dev:build": "nuxi build playground",
34 | "dev:prepare": "nuxt-module-build --stub && nuxi prepare playground",
35 | "prepack": "unbuild"
36 | },
37 | "dependencies": {
38 | "@nuxt/kit": "^3.0.0-rc.9",
39 | "axios": "^0.27.2",
40 | "axios-retry": "^3.3.1",
41 | "defu": "^6.1.0"
42 | },
43 | "devDependencies": {
44 | "@nuxt/module-builder": "^0.1.7",
45 | "@nuxt/schema": "3.0.0-rc.9",
46 | "@types/node": "^18.7.15",
47 | "nuxt": "^3.0.0-rc.9",
48 | "unbuild": "^0.8.10"
49 | },
50 | "repository": {
51 | "type": "git",
52 | "url": "git+https://github.com/Teranode/nuxt-module-alternatives.git",
53 | "directory": "@nuxtjs-alt/axios"
54 | },
55 | "bugs": {
56 | "url": "https://github.com/Teranode/nuxt-module-alternatives/issues"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@nuxtjs-alt/auth",
3 | "version": "2.1.5",
4 | "description": "An alternative module to @nuxtjs/auth",
5 | "homepage": "https://github.com/Teranode/nuxt-module-alternatives",
6 | "author": "Teranode",
7 | "keywords": [
8 | "nuxt",
9 | "nuxtjs",
10 | "nuxt-module",
11 | "nuxt-plugin",
12 | "nuxt-module-alternatives",
13 | "@nuxtjs/auth"
14 | ],
15 | "license": "MIT",
16 | "type": "module",
17 | "sideEffects": false,
18 | "exports": {
19 | ".": {
20 | "import": "./dist/module.mjs",
21 | "require": "./dist/module.cjs"
22 | }
23 | },
24 | "main": "./dist/module.cjs",
25 | "module": "./dist/module.mjs",
26 | "types": "./dist/types/index.d.ts",
27 | "files": [
28 | "dist"
29 | ],
30 | "scripts": {
31 | "dev": "nuxi dev playground",
32 | "dev:build": "nuxi build playground",
33 | "dev:prepare": "unbuild --stub && nuxi prepare playground",
34 | "prepack": "unbuild"
35 | },
36 | "dependencies": {
37 | "@nuxt/kit": "^3.0.0",
38 | "@nuxtjs-alt/http": "latest",
39 | "@pinia/nuxt": "latest",
40 | "body-parser": "latest",
41 | "cookie-es": "latest",
42 | "jwt-decode": "latest",
43 | "requrl": "latest",
44 | "defu": "latest",
45 | "ohash": "latest",
46 | "pathe": "latest"
47 | },
48 | "devDependencies": {
49 | "@nuxt/schema": "3.0.0",
50 | "fdir": "latest",
51 | "nuxt": "^3.0.0",
52 | "unbuild": "latest"
53 | },
54 | "repository": {
55 | "type": "git",
56 | "url": "git+https://github.com/Teranode/nuxt-module-alternatives.git",
57 | "directory": "@nuxtjs-alt/auth"
58 | },
59 | "bugs": {
60 | "url": "https://github.com/Teranode/nuxt-module-alternatives/issues"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/plugin.ts:
--------------------------------------------------------------------------------
1 | import { ImportOptions } from './resolve'
2 | import { ModuleOptions, Strategy } from './types'
3 |
4 | export const getAuthDTS = () => {
5 | return `import type { Plugin } from '#app'
6 | import { Auth } from '#auth/runtime'
7 |
8 | declare const _default: Plugin<{
9 | auth: Auth;
10 | }>;
11 |
12 | export default _default;
13 | `
14 | }
15 |
16 | export const getAuthPlugin = (options: {
17 | options: ModuleOptions
18 | schemeImports: ImportOptions[]
19 | strategies: Strategy[]
20 | strategyScheme: Record
21 | }): string => {
22 | return `import { Auth, ExpiredAuthSessionError } from '#auth/runtime'
23 | import { defineNuxtPlugin } from '#imports'
24 | // Active schemes
25 | ${options.schemeImports.map((i) => `import { ${i.name}${i.name !== i.as ? ' as ' + i.as : ''} } from '${i.from}'`).join('\n')}
26 |
27 | export default defineNuxtPlugin(nuxtApp => {
28 | // Options
29 | const options = ${JSON.stringify(options.options, null, 2)}
30 |
31 | // Create a new Auth instance
32 | const auth = new Auth(nuxtApp, options)
33 |
34 | // Register strategies
35 | ${options.strategies.map((strategy) => {
36 | const scheme = options.strategyScheme[strategy.name!]
37 | const schemeOptions = JSON.stringify(strategy, null, 2)
38 | return `auth.registerStrategy('${strategy.name}', new ${scheme.as}(auth, ${schemeOptions}));`
39 | }).join(';\n')}
40 |
41 | nuxtApp.provide('auth', auth)
42 |
43 | return auth.init().catch(error => {
44 | if (process.client) {
45 | // Don't console log expired auth session errors. This error is common, and expected to happen.
46 | // The error happens whenever the user does an ssr request (reload/initial navigation) with an expired refresh
47 | // token. We don't want to log this as an error.
48 | if (error instanceof ExpiredAuthSessionError) {
49 | return
50 | }
51 |
52 | console.error('[ERROR] [AUTH]', error)
53 | }
54 | })
55 | })`
56 | }
57 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/src/runtime/templates/http.plugin.mjs:
--------------------------------------------------------------------------------
1 | import { createInstance } from '@refactorjs/ofetch'
2 | import { defineNuxtPlugin } from '#imports'
3 |
4 | // Nuxt Options
5 | const options = JSON.parse('<%= JSON.stringify(options) %>')
6 |
7 | const httpInstance = (options) => {
8 | // Create new Fetch instance
9 | const instance = createInstance(options)
10 | '<% if (options.debug) { %>';debugInterceptor(instance);'<% } %>'
11 |
12 | return instance
13 | }
14 |
15 | '<% if (options.debug) { %>'
16 | const debugInterceptor = http => {
17 | const log = (level, ...messages) => console[level]('[http]', ...messages)
18 |
19 | // request
20 | http.onRequest(config => {
21 | log('info', 'Request:', config)
22 | return config
23 | })
24 |
25 | http.onRequestError(error => {
26 | log('error', 'Request error:', error)
27 | })
28 |
29 | // response
30 | http.onResponse(res => {
31 | log('info', 'Response:', res)
32 | return res
33 | })
34 |
35 | http.onResponseError(error => {
36 | log('error', 'Response error:', error)
37 | })
38 | }
39 | '<% } %>'
40 |
41 | export default defineNuxtPlugin(ctx => {
42 | // baseURL
43 | const baseURL = process.client ? options.browserBaseURL : options.baseURL
44 |
45 | // Defaults
46 | const defaults = {
47 | baseURL,
48 | retry: options.retry,
49 | timeout: process.server ? options.serverTimeout : options.clientTimeout,
50 | credentials: options.credentials,
51 | headers: options.headers,
52 | }
53 |
54 | if (options.proxyHeaders) {
55 | // Proxy SSR request headers
56 | if (process.server && ctx.ssrContext?.event?.req?.headers) {
57 | const reqHeaders = { ...ctx.ssrContext.event.req.headers }
58 | for (const h of options.proxyHeadersIgnore) {
59 | delete reqHeaders[h]
60 | }
61 |
62 | defaults.headers = { ...reqHeaders, ...defaults.headers }
63 | }
64 | }
65 |
66 | const http = httpInstance(defaults)
67 |
68 | if (!globalThis.$http) {
69 | globalThis.$http = http
70 | }
71 |
72 | return {
73 | provide: {
74 | http: http
75 | }
76 | }
77 | })
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: "Bug report"
2 | description: Create a report to help us improve Nuxt
3 | labels: ["pending triage"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Please use a template below to create a minimal reproduction
9 | 👉 https://stackblitz.com/github/nuxt/starter/tree/v3-stackblitz
10 | 👉 https://codesandbox.io/p/github/nuxt/starter/v3-codesandbox
11 | - type: textarea
12 | id: bug-env
13 | attributes:
14 | label: Environment
15 | description: You can use `npx nuxi info` to fill this section
16 | placeholder: Environment
17 | validations:
18 | required: true
19 | - type: textarea
20 | id: nuxt-config
21 | attributes:
22 | label: Nuxt Config
23 | description: Please provide your nuxt config in here, if you do not provide it, this issue will be ignored.
24 | placeholder: Nuxt Config
25 | validations:
26 | required: true
27 | - type: textarea
28 | id: reproduction
29 | attributes:
30 | label: Reproduction
31 | description: Please provide a link to a repo that can reproduce the problem you ran into. A [**minimal reproduction**](https://v3.nuxtjs.org/community/reporting-bugs#create-a-minimal-reproduction) is required unless you are absolutely sure that the issue is obvious and the provided information is enough to understand the problem. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "need reproduction" label. If no reproduction is provided we might close it.
32 | placeholder: Reproduction
33 | validations:
34 | required: true
35 | - type: textarea
36 | id: bug-description
37 | attributes:
38 | label: Describe the bug
39 | description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks!
40 | placeholder: Bug description
41 | validations:
42 | required: true
43 | - type: textarea
44 | id: additonal
45 | attributes:
46 | label: Additional context
47 | description: If applicable, add any other context about the problem here
48 | - type: textarea
49 | id: logs
50 | attributes:
51 | label: Logs
52 | description: |
53 | Optional if provided reproduction. Please try not to insert an image but copy paste the log text.
54 | render: shell
55 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/proxy/readme.md:
--------------------------------------------------------------------------------
1 | **Information**
2 |
3 | This serves as an alternative for @nuxtjs-alt/proxy. Please note that his is for nuxt3 only.
4 |
5 | **Other Information**
6 |
7 | This module creates a file in your `buildDir` called `nuxt-http-proxy.ts` which will handle all of the proxying you set within your nuxt config. The config is similar to what vite has except that this one creates a physical file which is needed for production.
8 |
9 | **Version 2.0+**
10 | New options have been added to the proxy module. The proxies now need to be moved into a `proxies` property (example provided below). A `fetch` property has been added so that proxying applies to the native `$fetch` in nitro and via client side. An `enableProxy` property has been added if you would like to disable the `http-proxy` creation for some reason.
11 |
12 | **Configuration**
13 |
14 | The configuration looks similar to that of vite's server proxy config, only difference is that it's passed through to nuxt server handler.
15 |
16 | ```ts
17 | import { defineNuxtConfig } from 'nuxt/config'
18 |
19 | export default defineNuxtConfig({
20 | modules: [
21 | '@nuxtjs-alt/proxy',
22 | ],
23 | proxy: {
24 | enableProxy: true,
25 | proxies: {
26 | // string shorthand
27 | '/foo': 'http://localhost:4567',
28 | // with options
29 | '/api': {
30 | target: 'http://jsonplaceholder.typicode.com',
31 | changeOrigin: true,
32 | rewrite: (path) => path.replace(/^\/api/, '')
33 | },
34 | // with RegEx
35 | '^/fallback/.*': {
36 | target: 'http://jsonplaceholder.typicode.com',
37 | changeOrigin: true,
38 | rewrite: (path) => path.replace(/^\/fallback/, '')
39 | },
40 | // Using the proxy instance
41 | '/api': {
42 | target: 'http://jsonplaceholder.typicode.com',
43 | changeOrigin: true,
44 | configure: (proxy, options) => {
45 | // proxy will be an instance of 'http-proxy'
46 | }
47 | },
48 | // Proxying websockets or socket.io
49 | '/socket.io': {
50 | target: 'ws://localhost:5173',
51 | ws: true
52 | }
53 | },
54 | fetch: true
55 | }
56 | })
57 |
58 | ```
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/core/middleware.ts:
--------------------------------------------------------------------------------
1 | import { routeMeta, getMatchedComponents, normalizePath } from '../../utils';
2 | import { useNuxtApp, defineNuxtRouteMiddleware } from '#imports';
3 |
4 | export default defineNuxtRouteMiddleware(async (to, from) => {
5 | // Disable middleware if options: { auth: false } is set on the route
6 | if (Object.prototype.hasOwnProperty.call(to.meta, 'auth') && routeMeta('auth', false)) {
7 | return;
8 | }
9 |
10 | // Disable middleware if no route was matched to allow 404/error page
11 | const matches: unknown[] = [];
12 | const Components = getMatchedComponents(matches);
13 |
14 | if (!Components.length) {
15 | return;
16 | }
17 |
18 | const ctx = useNuxtApp();
19 |
20 | const { login, callback } = ctx.$auth.options.redirect;
21 |
22 | const pageIsInGuestMode = Object.prototype.hasOwnProperty.call(to.meta, 'auth') && routeMeta('auth', 'guest');
23 |
24 | const insidePage = (page: string) => normalizePath(to.path) === normalizePath(page);
25 |
26 | if (ctx.$auth.$state.loggedIn) {
27 | // Perform scheme checks.
28 | const { tokenExpired, refreshTokenExpired, isRefreshable } = ctx.$auth.check(true);
29 |
30 | // -- Authorized --
31 | if (!login || insidePage(login) || pageIsInGuestMode) {
32 | ctx.$auth.redirect('home', to);
33 | }
34 |
35 | // Refresh token has expired. There is no way to refresh. Force reset.
36 | if (refreshTokenExpired) {
37 | ctx.$auth.reset();
38 | } else if (tokenExpired) {
39 | // Token has expired. Check if refresh token is available.
40 | if (isRefreshable) {
41 | // Refresh token is available. Attempt refresh.
42 | try {
43 | await ctx.$auth.refreshTokens();
44 | } catch (error) {
45 | // Reset when refresh was not successfull
46 | ctx.$auth.reset();
47 | }
48 | } else {
49 | // Refresh token is not available. Force reset.
50 | ctx.$auth.reset();
51 | }
52 | }
53 | }
54 |
55 | // -- Guest --
56 | // (Those passing `callback` at runtime need to mark their callback component
57 | // with `auth: false` to avoid an unnecessary redirect from callback to login)
58 | else if (!pageIsInGuestMode && (!callback || !insidePage(callback))) {
59 | ctx.$auth.redirect('login', to);
60 | }
61 | });
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nuxt-module-alternatives
2 | Alternative modules to use while waiting for Nuxt 3 Compatibility
3 |
4 | ## Migration
5 |
6 | I will be migrating most of these modules over to https://github.com/orgs/nuxt-alt/repositories. This will take me a bit to set up. The module's versions will be incremented by 1 to account for the migration. Each module will have their own separate repository.
7 |
8 | | Old Package Name | New Package Name | Link
9 | | --- | --- | --- |
10 | | @nuxtjs-alt/vuetify | @nuxt-alt/vuetify | https://github.com/nuxt-alt/vuetify
11 | | @nuxtjs-alt/auth | @nuxt-alt/auth | https://github.com/nuxt-alt/auth
12 | | @nuxtjs-alt/http | @nuxt-alt/http | https://github.com/nuxt-alt/http
13 | | @nuxtjs-alt/proxy | @nuxt-alt/proxy | https://github.com/nuxt-alt/proxy
14 |
15 | **Current Modules**
16 | - Nuxt Axios Module: [Nuxt Community Repository](https://github.com/nuxt-community/axios-module)
17 | - Nuxt Http Module: [Nuxt Community Module](https://github.com/nuxt/http)
18 | - Nuxt Proxy Module: [Nuxt Community Repository](https://github.com/nuxt-community/proxy-module)
19 | - Nuxt Auth Module: [Nuxt Community Repository](https://github.com/nuxt-community/auth-module)
20 | - Nuxt Vuetify Module: [Nuxt Community Repository](https://github.com/nuxt-community/vuetify-module)
21 |
22 | **Module Order**
23 |
24 | If you're using a combination of http/ohmyfetch, pinia and auth you need to load them in `modules` in the following order.
25 | ```
26 | modules: [
27 | '@nuxtjs-alt/auth',
28 | '@nuxtjs-alt/http',
29 | '@nuxtjs-alt/proxy', // needed if using ssr
30 | '@pinia/nuxt',
31 | ]
32 | ```
33 |
34 | **Instructions**
35 |
36 | - Add any of the modules available via npm (package list: https://www.npmjs.com/org/nuxtjs-alt)
37 |
38 | **Other Modules**
39 |
40 | _If you have a nuxt module that looks like it wont be updated, and has any usefeulness to the general nuxt community, please tell me and I'll take a look into it._
41 |
42 | Example `package.json`:
43 |
44 | package.json
45 |
46 | `yarn install`
47 |
48 | ```json
49 | {
50 | "private": true,
51 | "scripts": {
52 | "dev": "nuxi dev",
53 | "build": "nuxi build",
54 | "start": "node .output/server/index.mjs"
55 | },
56 | "devDependencies": {
57 | "nuxt": "npm:nuxt3@latest"
58 | },
59 | "dependencies": {
60 | "@nuxtjs-alt/axios": "latest",
61 | "@nuxtjs-alt/auth": "latest",
62 | "@nuxtjs-alt/http": "latest",
63 | "@nuxtjs-alt/proxy": "latest",
64 | "@nuxtjs-alt/vuetify": "latest"
65 | }
66 | }
67 | ```
68 |
69 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/axios/build.config.ts:
--------------------------------------------------------------------------------
1 | import type { NuxtModule } from '@nuxt/schema'
2 | import { defineBuildConfig } from "unbuild";
3 | import { existsSync, promises as fsp } from 'fs'
4 | import { pathToFileURL } from 'url'
5 | import { resolve } from 'path'
6 |
7 | export default defineBuildConfig({
8 | declaration: true,
9 | entries: [
10 | 'src/module',
11 | { input: 'src/runtime/', outDir: 'dist/runtime', ext: 'mjs' },
12 | ],
13 | rollup: {
14 | emitCJS: false,
15 | cjsBridge: true,
16 | },
17 | externals: [
18 | '@nuxt/schema',
19 | '@nuxt/schema-edge',
20 | '@nuxt/kit',
21 | '@nuxt/kit-edge',
22 | 'nuxt',
23 | 'nuxt-edge',
24 | 'nuxt3',
25 | 'vue'
26 | ],
27 | hooks: {
28 | async 'rollup:done' (ctx) {
29 | // Generate CommonJS stup
30 | await writeCJSStub(ctx.options.outDir)
31 |
32 | // Load module meta
33 | const moduleEntryPath = resolve(ctx.options.outDir, 'module.mjs')
34 | const moduleFn: NuxtModule = await import(
35 | pathToFileURL(moduleEntryPath).toString()
36 | ).then(r => r.default || r).catch((err) => {
37 | console.error(err)
38 | console.error('Cannot load module. Please check dist:', moduleEntryPath)
39 | return null
40 | })
41 | if (!moduleFn) {
42 | return
43 | }
44 | const moduleMeta = await moduleFn.getMeta!()
45 |
46 | // Enhance meta using package.json
47 | if (ctx.pkg) {
48 | if (!moduleMeta.name) {
49 | moduleMeta.name = ctx.pkg.name
50 | }
51 | if (!moduleMeta.version) {
52 | moduleMeta.version = ctx.pkg.version
53 | }
54 | }
55 |
56 | // Write meta
57 | const metaFile = resolve(ctx.options.outDir, 'module.json')
58 | await fsp.writeFile(metaFile, JSON.stringify(moduleMeta, null, 2), 'utf8')
59 | }
60 | }
61 | });
62 |
63 | async function writeCJSStub (distDir: string) {
64 | const cjsStubFile = resolve(distDir, 'module.cjs')
65 | if (existsSync(cjsStubFile)) {
66 | return
67 | }
68 |
69 | const cjsStub =
70 | `module.exports = function(...args) {
71 | return import('./module.mjs').then(m => m.default.call(this, ...args))
72 | }
73 | const _meta = module.exports.meta = require('./module.json')
74 | module.exports.getMeta = () => Promise.resolve(_meta)`
75 |
76 | await fsp.writeFile(cjsStubFile, cjsStub, 'utf8')
77 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/axios/src/types.ts:
--------------------------------------------------------------------------------
1 | import type { AxiosStatic, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
2 | import type { IAxiosRetryConfig } from 'axios-retry';
3 |
4 | export interface NuxtAxiosInstance extends AxiosStatic {
5 | $request(config: AxiosRequestConfig): Promise;
6 | $get(url: string, config?: AxiosRequestConfig): Promise;
7 | $delete(url: string, config?: AxiosRequestConfig): Promise;
8 | $head(url: string, config?: AxiosRequestConfig): Promise;
9 | $options(url: string, config?: AxiosRequestConfig): Promise;
10 | $post(url: string, data?: any, config?: AxiosRequestConfig): Promise;
11 | $put(url: string, data?: any, config?: AxiosRequestConfig): Promise;
12 | $patch(url: string, data?: any, config?: AxiosRequestConfig): Promise;
13 | setBaseURL(baseURL: string): void;
14 | setHeader(name: string, value?: string | false, scopes?: string | string[]): void;
15 | setToken(token: string | false, type?: string, scopes?: string | string[]): void;
16 | onRequest(callback: (config: AxiosRequestConfig) => void | AxiosRequestConfig | Promise): void;
17 | onResponse(callback: (response: AxiosResponse) => void | AxiosResponse | Promise>): void;
18 | onError(callback: (error: AxiosError) => any): void;
19 | onRequestError(callback: (error: AxiosError) => any): void;
20 | onResponseError(callback: (error: AxiosError) => any): void;
21 | create(options?: AxiosRequestConfig): NuxtAxiosInstance;
22 | }
23 |
24 | export interface ModuleOptions {
25 | baseURL: string;
26 | baseUrl?: string;
27 | browserBaseURL: string;
28 | browserBaseUrl?: string;
29 | globalName?: string;
30 | credentials?: boolean;
31 | debug?: boolean;
32 | host?: string;
33 | prefix?: string;
34 | progress?: boolean;
35 | proxyHeaders?: boolean;
36 | proxyHeadersIgnore?: string[];
37 | proxy?: boolean;
38 | port?: string | number;
39 | retry?: boolean | IAxiosRetryConfig;
40 | https?: boolean;
41 | headers?: {
42 | common?: Record;
43 | delete?: Record;
44 | get?: Record;
45 | head?: Record;
46 | post?: Record;
47 | put?: Record;
48 | patch?: Record;
49 | };
50 | }
51 |
52 | declare module "axios" {
53 | interface AxiosRequestConfig {
54 | progress?: boolean;
55 | }
56 | }
57 |
58 | declare module '@nuxt/schema' {
59 | export interface NuxtConfig {
60 | ['axios']?: Partial;
61 | }
62 | export interface NuxtOptions {
63 | ['axios']?: ModuleOptions;
64 | }
65 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/build.config.ts:
--------------------------------------------------------------------------------
1 | import type { NuxtModule } from '@nuxt/schema'
2 | import { existsSync, promises as fsp } from 'node:fs'
3 | import { defineBuildConfig } from "unbuild"
4 | import { pathToFileURL } from 'node:url'
5 | import { resolve } from 'pathe'
6 | import mri from 'mri'
7 |
8 | const args = mri(process.argv.slice(2))
9 |
10 | export default defineBuildConfig({
11 | failOnWarn: false,
12 | declaration: true,
13 | stub: args.stub,
14 | entries: [
15 | 'src/module',
16 | 'src/types',
17 | { input: 'src/runtime/', outDir: 'dist/runtime', ext: 'mjs' },
18 | ],
19 | rollup: {
20 | emitCJS: false,
21 | cjsBridge: true,
22 | },
23 | externals: [
24 | '@nuxt/schema',
25 | '@nuxt/schema-edge',
26 | '@nuxt/kit',
27 | '@nuxt/kit-edge',
28 | 'nuxt',
29 | 'nuxt-edge',
30 | 'nuxt3',
31 | 'vue',
32 | 'vue-demi'
33 | ],
34 | hooks: {
35 | async 'rollup:dts:build'(ctx) {
36 | // Types file
37 | const typesFile = resolve(ctx.options.outDir, 'types.mjs')
38 | await fsp.unlink(typesFile)
39 | },
40 | async 'rollup:done' (ctx) {
41 | // Generate CommonJS stup
42 | await writeCJSStub(ctx.options.outDir)
43 |
44 | // Load module meta
45 | const moduleEntryPath = resolve(ctx.options.outDir, 'module.mjs')
46 | const moduleFn: NuxtModule = await import(
47 | pathToFileURL(moduleEntryPath).toString()
48 | ).then(r => r.default || r).catch((err) => {
49 | console.error(err)
50 | console.error('Cannot load module. Please check dist:', moduleEntryPath)
51 | return null
52 | })
53 | if (!moduleFn) {
54 | return
55 | }
56 | const moduleMeta = await moduleFn.getMeta!()
57 |
58 | // Enhance meta using package.json
59 | if (ctx.pkg) {
60 | if (!moduleMeta.name) {
61 | moduleMeta.name = ctx.pkg.name
62 | }
63 | if (!moduleMeta.version) {
64 | moduleMeta.version = ctx.pkg.version
65 | }
66 | }
67 |
68 | // Write meta
69 | const metaFile = resolve(ctx.options.outDir, 'module.json')
70 | await fsp.writeFile(metaFile, JSON.stringify(moduleMeta, null, 2), 'utf8')
71 | }
72 | }
73 | });
74 |
75 | async function writeCJSStub (distDir: string) {
76 | const cjsStubFile = resolve(distDir, 'module.cjs')
77 | if (existsSync(cjsStubFile)) {
78 | return
79 | }
80 |
81 | const cjsStub =
82 | `module.exports = function(...args) {
83 | return import('./module.mjs').then(m => m.default.call(this, ...args))
84 | }
85 | const _meta = module.exports.meta = require('./module.json')
86 | module.exports.getMeta = () => Promise.resolve(_meta)`
87 |
88 | await fsp.writeFile(cjsStubFile, cjsStub, 'utf8')
89 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/proxy/build.config.ts:
--------------------------------------------------------------------------------
1 | import type { NuxtModule } from '@nuxt/schema'
2 | import { existsSync, promises as fsp } from 'node:fs'
3 | import { defineBuildConfig } from "unbuild"
4 | import { pathToFileURL } from 'node:url'
5 | import { resolve } from 'pathe'
6 | import mri from 'mri'
7 |
8 | const args = mri(process.argv.slice(2))
9 |
10 | export default defineBuildConfig({
11 | failOnWarn: false,
12 | declaration: true,
13 | stub: args.stub,
14 | entries: [
15 | 'src/module',
16 | 'src/types',
17 | { input: 'src/runtime/', outDir: 'dist/runtime', ext: 'mjs' },
18 | ],
19 | rollup: {
20 | emitCJS: false,
21 | cjsBridge: true,
22 | },
23 | externals: [
24 | '@nuxt/schema',
25 | '@nuxt/schema-edge',
26 | '@nuxt/kit',
27 | '@nuxt/kit-edge',
28 | 'nuxt',
29 | 'nuxt-edge',
30 | 'nuxt3',
31 | 'vue',
32 | 'vue-demi'
33 | ],
34 | hooks: {
35 | async 'rollup:dts:build'(ctx) {
36 | // Types file
37 | const typesFile = resolve(ctx.options.outDir, 'types.mjs')
38 | await fsp.unlink(typesFile)
39 | },
40 | async 'rollup:done' (ctx) {
41 | // Generate CommonJS stup
42 | await writeCJSStub(ctx.options.outDir)
43 |
44 | // Load module meta
45 | const moduleEntryPath = resolve(ctx.options.outDir, 'module.mjs')
46 | const moduleFn: NuxtModule = await import(
47 | pathToFileURL(moduleEntryPath).toString()
48 | ).then(r => r.default || r).catch((err) => {
49 | console.error(err)
50 | console.error('Cannot load module. Please check dist:', moduleEntryPath)
51 | return null
52 | })
53 | if (!moduleFn) {
54 | return
55 | }
56 | const moduleMeta = await moduleFn.getMeta!()
57 |
58 | // Enhance meta using package.json
59 | if (ctx.pkg) {
60 | if (!moduleMeta.name) {
61 | moduleMeta.name = ctx.pkg.name
62 | }
63 | if (!moduleMeta.version) {
64 | moduleMeta.version = ctx.pkg.version
65 | }
66 | }
67 |
68 | // Write meta
69 | const metaFile = resolve(ctx.options.outDir, 'module.json')
70 | await fsp.writeFile(metaFile, JSON.stringify(moduleMeta, null, 2), 'utf8')
71 | }
72 | }
73 | });
74 |
75 | async function writeCJSStub (distDir: string) {
76 | const cjsStubFile = resolve(distDir, 'module.cjs')
77 | if (existsSync(cjsStubFile)) {
78 | return
79 | }
80 |
81 | const cjsStub =
82 | `module.exports = function(...args) {
83 | return import('./module.mjs').then(m => m.default.call(this, ...args))
84 | }
85 | const _meta = module.exports.meta = require('./module.json')
86 | module.exports.getMeta = () => Promise.resolve(_meta)`
87 |
88 | await fsp.writeFile(cjsStubFile, cjsStub, 'utf8')
89 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/vuetify/build.config.ts:
--------------------------------------------------------------------------------
1 | import type { NuxtModule } from '@nuxt/schema'
2 | import { existsSync, promises as fsp } from 'node:fs'
3 | import { defineBuildConfig } from "unbuild"
4 | import { pathToFileURL } from 'node:url'
5 | import { resolve } from 'pathe'
6 | import mri from 'mri'
7 |
8 | const args = mri(process.argv.slice(2))
9 |
10 | export default defineBuildConfig({
11 | declaration: true,
12 | stub: args.stub,
13 | externals: [
14 | '@nuxt/schema',
15 | '@nuxt/schema-edge',
16 | '@nuxt/kit',
17 | '@nuxt/kit-edge',
18 | 'nuxt',
19 | 'nuxt-edge',
20 | 'nuxt3',
21 | 'vue',
22 | 'vue-demi',
23 | 'vuetify',
24 | 'defu'
25 | ],
26 | entries: [
27 | 'src/module',
28 | 'src/types',
29 | { input: 'src/runtime/', outDir: 'dist/runtime', ext: 'mjs' },
30 | ],
31 | rollup: {
32 | emitCJS: false,
33 | cjsBridge: true,
34 | },
35 | hooks: {
36 | async 'rollup:dts:build'(ctx) {
37 | // Types file
38 | const typesFile = resolve(ctx.options.outDir, 'types.mjs')
39 | await fsp.unlink(typesFile)
40 | },
41 | async 'rollup:done' (ctx) {
42 | // Generate CommonJS stup
43 | await writeCJSStub(ctx.options.outDir)
44 |
45 | // Load module meta
46 | const moduleEntryPath = resolve(ctx.options.outDir, 'module.mjs')
47 | const moduleFn: NuxtModule = await import(
48 | pathToFileURL(moduleEntryPath).toString()
49 | ).then(r => r.default || r).catch((err) => {
50 | console.error(err)
51 | console.error('Cannot load module. Please check dist:', moduleEntryPath)
52 | return null
53 | })
54 | if (!moduleFn) {
55 | return
56 | }
57 | const moduleMeta = await moduleFn.getMeta!()
58 |
59 | // Enhance meta using package.json
60 | if (ctx.pkg) {
61 | if (!moduleMeta.name) {
62 | moduleMeta.name = ctx.pkg.name
63 | }
64 | if (!moduleMeta.version) {
65 | moduleMeta.version = ctx.pkg.version
66 | }
67 | }
68 |
69 | // Write meta
70 | const metaFile = resolve(ctx.options.outDir, 'module.json')
71 | await fsp.writeFile(metaFile, JSON.stringify(moduleMeta, null, 2), 'utf8')
72 | }
73 | }
74 | });
75 |
76 | async function writeCJSStub (distDir: string) {
77 | const cjsStubFile = resolve(distDir, 'module.cjs')
78 | if (existsSync(cjsStubFile)) {
79 | return
80 | }
81 |
82 | const cjsStub =
83 | `module.exports = function(...args) {
84 | return import('./module.mjs').then(m => m.default.call(this, ...args))
85 | }
86 | const _meta = module.exports.meta = require('./module.json')
87 | module.exports.getMeta = () => Promise.resolve(_meta)`
88 |
89 | await fsp.writeFile(cjsStubFile, cjsStub, 'utf8')
90 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/axios/src/module.d.ts:
--------------------------------------------------------------------------------
1 | import * as NuxtSchema from '@nuxt/schema';
2 | import { AxiosStatic, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
3 | import { IAxiosRetryConfig } from 'axios-retry';
4 |
5 | interface NuxtAxiosInstance extends AxiosStatic {
6 | $request(config: AxiosRequestConfig): Promise;
7 | $get(url: string, config?: AxiosRequestConfig): Promise;
8 | $delete(url: string, config?: AxiosRequestConfig): Promise;
9 | $head(url: string, config?: AxiosRequestConfig): Promise;
10 | $options(url: string, config?: AxiosRequestConfig): Promise;
11 | $post(url: string, data?: any, config?: AxiosRequestConfig): Promise;
12 | $put(url: string, data?: any, config?: AxiosRequestConfig): Promise;
13 | $patch(url: string, data?: any, config?: AxiosRequestConfig): Promise;
14 | setBaseURL(baseURL: string): void;
15 | setHeader(name: string, value?: string | false, scopes?: string | string[]): void;
16 | setToken(token: string | false, type?: string, scopes?: string | string[]): void;
17 | onRequest(callback: (config: AxiosRequestConfig) => void | AxiosRequestConfig | Promise): void;
18 | onResponse(callback: (response: AxiosResponse) => void | AxiosResponse | Promise>): void;
19 | onError(callback: (error: AxiosError) => any): void;
20 | onRequestError(callback: (error: AxiosError) => any): void;
21 | onResponseError(callback: (error: AxiosError) => any): void;
22 | create(options?: AxiosRequestConfig): NuxtAxiosInstance;
23 | }
24 |
25 | interface ModuleOptions {
26 | baseURL?: string;
27 | baseUrl?: string;
28 | browserBaseURL?: string;
29 | browserBaseUrl?: string;
30 | globalName?: string;
31 | credentials?: boolean;
32 | debug?: boolean;
33 | host?: string;
34 | prefix?: string;
35 | progress?: boolean;
36 | proxyHeaders?: boolean;
37 | proxyHeadersIgnore?: string[];
38 | proxy?: boolean;
39 | port?: string | number;
40 | retry?: boolean | IAxiosRetryConfig;
41 | https?: boolean;
42 | headers?: {
43 | common?: Record;
44 | delete?: Record;
45 | get?: Record;
46 | head?: Record;
47 | post?: Record;
48 | put?: Record;
49 | patch?: Record;
50 | };
51 | }
52 |
53 | declare module "axios" {
54 | interface AxiosRequestConfig {
55 | progress?: boolean;
56 | }
57 | }
58 |
59 | declare module '@nuxt/schema' {
60 | interface NuxtConfig {
61 | ['axios']?: Partial;
62 | }
63 | interface NuxtOptions {
64 | ['axios']?: ModuleOptions;
65 | }
66 | }
67 |
68 | declare const module: NuxtSchema.NuxtModule;
69 |
70 | declare module "#app" {
71 | interface NuxtApp {
72 | $axios: NuxtAxiosInstance;
73 | }
74 | interface NuxtOptions {
75 | axios: ModuleOptions;
76 | }
77 | }
78 |
79 | export { module as default, ModuleOptions, NuxtAxiosInstance };
80 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/axios/src/options.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AxiosError,
3 | AxiosRequestConfig,
4 | AxiosResponse,
5 | AxiosStatic,
6 | } from "axios";
7 |
8 | import { IAxiosRetryConfig } from "axios-retry";
9 |
10 | export interface NuxtAxiosInstance extends AxiosStatic {
11 | $request(config: AxiosRequestConfig): Promise;
12 | $get(url: string, config?: AxiosRequestConfig): Promise;
13 | $delete(url: string, config?: AxiosRequestConfig): Promise;
14 | $head(url: string, config?: AxiosRequestConfig): Promise;
15 | $options(url: string, config?: AxiosRequestConfig): Promise;
16 | $post(
17 | url: string,
18 | data?: any,
19 | config?: AxiosRequestConfig
20 | ): Promise;
21 | $put(
22 | url: string,
23 | data?: any,
24 | config?: AxiosRequestConfig
25 | ): Promise;
26 | $patch(
27 | url: string,
28 | data?: any,
29 | config?: AxiosRequestConfig
30 | ): Promise;
31 |
32 | setBaseURL(baseURL: string): void;
33 | setHeader(
34 | name: string,
35 | value?: string | false,
36 | scopes?: string | string[]
37 | ): void;
38 | setToken(
39 | token: string | false,
40 | type?: string,
41 | scopes?: string | string[]
42 | ): void;
43 |
44 | onRequest(
45 | callback: (
46 | config: AxiosRequestConfig
47 | ) => void | AxiosRequestConfig | Promise
48 | ): void;
49 | onResponse(
50 | callback: (
51 | response: AxiosResponse
52 | ) => void | AxiosResponse | Promise>
53 | ): void;
54 | onError(callback: (error: AxiosError) => any): void;
55 | onRequestError(callback: (error: AxiosError) => any): void;
56 | onResponseError(callback: (error: AxiosError) => any): void;
57 |
58 | create(options?: AxiosRequestConfig): NuxtAxiosInstance;
59 | }
60 |
61 | export interface ModuleOptions {
62 | baseURL?: string;
63 | baseUrl?: string;
64 | browserBaseURL?: string;
65 | browserBaseUrl?: string;
66 | globalName?: string;
67 | credentials?: boolean;
68 | debug?: boolean;
69 | host?: string;
70 | prefix?: string;
71 | progress?: boolean;
72 | proxyHeaders?: boolean;
73 | proxyHeadersIgnore?: string[];
74 | proxy?: boolean;
75 | port?: string | number;
76 | retry?: boolean | IAxiosRetryConfig;
77 | https?: boolean;
78 | headers?: {
79 | common?: Record;
80 | delete?: Record;
81 | get?: Record;
82 | head?: Record;
83 | post?: Record;
84 | put?: Record;
85 | patch?: Record;
86 | };
87 | }
88 |
89 | declare module "axios" {
90 | export interface AxiosRequestConfig {
91 | progress?: boolean;
92 | }
93 | }
94 |
95 | declare module '@nuxt/schema' {
96 | export interface NuxtConfig {
97 | ['axios']?: Partial
98 | }
99 | export interface NuxtOptions {
100 | ['axios']?: ModuleOptions
101 | }
102 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/providers/laravel-passport.ts:
--------------------------------------------------------------------------------
1 | import type { RefreshTokenOptions, TokenOptions, UserOptions, RecursivePartial, ProviderPartialOptions, ProviderOptions } from '../types';
2 | import type { Oauth2SchemeOptions, RefreshSchemeOptions } from '../runtime';
3 | import type { Nuxt } from '@nuxt/schema'
4 | import { assignDefaults, addAuthorize, initializePasswordGrantFlow, assignAbsoluteEndpoints } from '../utils/provider';
5 |
6 | export interface LaravelPassportProviderOptions extends ProviderOptions, Oauth2SchemeOptions {
7 | url: string;
8 | }
9 |
10 | export interface LaravelPassportPasswordProviderOptions extends ProviderOptions, RefreshSchemeOptions {
11 | url: string;
12 | }
13 |
14 | export type PartialPassportOptions = ProviderPartialOptions;
15 | export type PartialPassportPasswordOptions = ProviderPartialOptions;
16 |
17 | function isPasswordGrant(strategy: PartialPassportOptions | PartialPassportPasswordOptions): strategy is PartialPassportPasswordOptions {
18 | return strategy.grantType === 'password';
19 | }
20 |
21 | export function laravelPassport(nuxt: Nuxt, strategy: PartialPassportOptions | PartialPassportPasswordOptions): void {
22 | const { url } = strategy;
23 |
24 | if (!url) {
25 | throw new Error('url is required is laravel passport!');
26 | }
27 |
28 | const defaults: RecursivePartial<{
29 | name: string;
30 | token: TokenOptions;
31 | refreshToken: RefreshTokenOptions;
32 | user: UserOptions;
33 | }> = {
34 | name: 'laravelPassport',
35 | token: {
36 | property: 'access_token',
37 | type: 'Bearer',
38 | name: 'Authorization',
39 | maxAge: 60 * 60 * 24 * 365,
40 | },
41 | refreshToken: {
42 | property: 'refresh_token',
43 | data: 'refresh_token',
44 | maxAge: 60 * 60 * 24 * 30,
45 | },
46 | user: {
47 | property: false,
48 | },
49 | };
50 |
51 | let DEFAULTS: typeof strategy
52 |
53 | if (isPasswordGrant(strategy)) {
54 | DEFAULTS = {
55 | ...defaults,
56 | scheme: 'refresh',
57 | endpoints: {
58 | token: url + '/oauth/token',
59 | login: {
60 | baseURL: '',
61 | },
62 | refresh: {
63 | baseURL: '',
64 | },
65 | logout: false,
66 | user: {
67 | url: url + '/api/auth/user',
68 | },
69 | },
70 | grantType: 'password',
71 | };
72 |
73 | assignDefaults(strategy, DEFAULTS);
74 |
75 | assignAbsoluteEndpoints(strategy);
76 | initializePasswordGrantFlow(nuxt, strategy);
77 | } else {
78 | DEFAULTS = {
79 | ...defaults,
80 | scheme: 'oauth2',
81 | endpoints: {
82 | authorization: url + '/oauth/authorize',
83 | token: url + '/oauth/token',
84 | userInfo: url + '/api/auth/user',
85 | logout: false,
86 | },
87 | responseType: 'code',
88 | grantType: 'authorization_code',
89 | scope: '*',
90 | };
91 |
92 | assignDefaults(strategy, DEFAULTS);
93 |
94 | assignAbsoluteEndpoints(strategy);
95 | addAuthorize(nuxt, strategy);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/build.config.ts:
--------------------------------------------------------------------------------
1 | import type { NuxtModule } from '@nuxt/schema'
2 | import { existsSync, promises as fsp } from 'node:fs'
3 | import { defineBuildConfig } from 'unbuild'
4 | import { pathToFileURL } from 'url'
5 | import { resolve } from 'path'
6 | import { fdir } from 'fdir'
7 | import mri from 'mri'
8 |
9 | const args = mri(process.argv.slice(2))
10 |
11 | export default defineBuildConfig({
12 | declaration: true,
13 | stub: args.stub,
14 | entries: [
15 | 'src/module',
16 | { input: 'src/types/', outDir: 'dist/types', ext: 'mjs' },
17 | { input: 'src/runtime/', outDir: 'dist/runtime', ext: 'mjs' },
18 | { input: 'src/utils/', outDir: 'dist/utils', ext: 'mjs' },
19 | { input: 'src/providers/', outDir: 'dist/providers', ext: 'mjs' },
20 | ],
21 | rollup: {
22 | emitCJS: false,
23 | cjsBridge: true,
24 | },
25 | externals: [
26 | '@nuxt/schema',
27 | '@nuxt/schema-edge',
28 | '@nuxt/kit',
29 | '@nuxt/kit-edge',
30 | 'nuxt',
31 | 'nuxt-edge',
32 | 'nuxt3',
33 | 'vue',
34 | 'vue-demi'
35 | ],
36 | hooks: {
37 | async 'rollup:dts:build'(ctx) {
38 | const api = new fdir().withFullPaths().glob('./**/*.mjs').crawl(ctx.options.outDir + '/types').withPromise();
39 |
40 | api.then((files) => {
41 | // @ts-ignore
42 | files.forEach(async (file: any) => {
43 | await fsp.unlink(file)
44 | });
45 | });
46 | },
47 | async 'rollup:done'(ctx) {
48 | // Generate CommonJS stup
49 | await writeCJSStub(ctx.options.outDir)
50 |
51 | // Load module meta
52 | const moduleEntryPath = resolve(ctx.options.outDir, 'module.mjs')
53 | const moduleFn: NuxtModule = await import(
54 | pathToFileURL(moduleEntryPath).toString()
55 | ).then(r => r.default || r).catch((err) => {
56 | console.error(err)
57 | console.error('Cannot load module. Please check dist:', moduleEntryPath)
58 | return null
59 | })
60 | if (!moduleFn) {
61 | return
62 | }
63 | const moduleMeta = await moduleFn.getMeta!()
64 |
65 | // Enhance meta using package.json
66 | if (ctx.pkg) {
67 | if (!moduleMeta.name) {
68 | moduleMeta.name = ctx.pkg.name
69 | }
70 | if (!moduleMeta.version) {
71 | moduleMeta.version = ctx.pkg.version
72 | }
73 | }
74 |
75 | // Write meta
76 | const metaFile = resolve(ctx.options.outDir, 'module.json')
77 | await fsp.writeFile(metaFile, JSON.stringify(moduleMeta, null, 2), 'utf8')
78 | }
79 | }
80 | });
81 |
82 | async function writeCJSStub(distDir: string) {
83 | const cjsStubFile = resolve(distDir, 'module.cjs')
84 | if (existsSync(cjsStubFile)) {
85 | return
86 | }
87 |
88 | const cjsStub =
89 | `module.exports = function(...args) {
90 | return import('./module.mjs').then(m => m.default.call(this, ...args))
91 | }
92 |
93 | const _meta = module.exports.meta = require('./module.json')
94 | module.exports.getMeta = () => Promise.resolve(_meta)`
95 |
96 | await fsp.writeFile(cjsStubFile, cjsStub, 'utf8')
97 | }
98 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/scheme.ts:
--------------------------------------------------------------------------------
1 | import type { HTTPRequest, HTTPResponse } from '.';
2 | import type { Auth } from '../runtime/core';
3 | import type { Token, IdToken, RefreshToken, RefreshController, RequestHandler,} from '../runtime/inc';
4 | import type { PartialExcept } from './utils';
5 |
6 | export interface UserOptions {
7 | property: string | false;
8 | autoFetch: boolean;
9 | }
10 |
11 | export interface CookieUserOptions {
12 | property: {
13 | client: string | false;
14 | server: string | false;
15 | };
16 | autoFetch: boolean;
17 | }
18 |
19 | export interface EndpointsOption {
20 | [endpoint: string]: string | HTTPRequest | false;
21 | }
22 |
23 | // Scheme
24 |
25 | export interface SchemeOptions {
26 | name?: string;
27 | }
28 |
29 | export type SchemePartialOptions = PartialExcept;
30 |
31 | export interface SchemeCheck {
32 | valid: boolean;
33 | tokenExpired?: boolean;
34 | refreshTokenExpired?: boolean;
35 | idTokenExpired?: boolean;
36 | isRefreshable?: boolean;
37 | }
38 |
39 | export interface Scheme {
40 | options: OptionsT;
41 | name?: string;
42 | $auth: Auth;
43 | mounted?(...args: any[]): Promise;
44 | check?(checkStatus: boolean): SchemeCheck;
45 | login(...args: any[]): Promise;
46 | fetchUser(endpoint?: HTTPRequest): Promise;
47 | setUserToken?(
48 | token: string | boolean,
49 | refreshToken?: string | boolean
50 | ): Promise;
51 | logout?(endpoint?: HTTPRequest): Promise | void;
52 | reset?(options?: { resetInterceptor: boolean }): void;
53 | }
54 |
55 | // Token
56 |
57 | export interface TokenOptions {
58 | property: string;
59 | type: string | false;
60 | name: string;
61 | maxAge: number | false;
62 | global: boolean;
63 | required: boolean;
64 | prefix: string;
65 | expirationPrefix: string;
66 | }
67 |
68 | export interface TokenableSchemeOptions extends SchemeOptions {
69 | token?: TokenOptions;
70 | endpoints: EndpointsOption;
71 | }
72 |
73 | export interface TokenableScheme extends Scheme {
74 | token?: Token;
75 | requestHandler: RequestHandler;
76 | }
77 |
78 | // ID Token
79 |
80 | export interface IdTokenableSchemeOptions extends SchemeOptions {
81 | idToken: TokenOptions;
82 | }
83 |
84 | export interface IdTokenableScheme extends Scheme {
85 | idToken: IdToken;
86 | requestHandler: RequestHandler;
87 | }
88 |
89 | // Refrash
90 |
91 | export interface RefreshTokenOptions {
92 | property: string | false;
93 | type: string | false;
94 | data: string | false;
95 | maxAge: number | false;
96 | required: boolean;
97 | tokenRequired: boolean;
98 | prefix: string;
99 | expirationPrefix: string;
100 | }
101 |
102 | export interface RefreshableSchemeOptions extends TokenableSchemeOptions {
103 | refreshToken: RefreshTokenOptions;
104 | }
105 |
106 | export interface RefreshableScheme extends TokenableScheme {
107 | refreshToken: RefreshToken;
108 | refreshController: RefreshController;
109 | refreshTokens(): Promise;
110 | }
111 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/types/scheme.d.ts:
--------------------------------------------------------------------------------
1 | import type { HTTPRequest, HTTPResponse } from "../types";
2 | import type { Auth } from "../runtime/core";
3 | import type { Token, IdToken, RefreshToken, RefreshController, RequestHandler,} from "../runtime/inc";
4 | import type { PartialExcept } from "./utils";
5 |
6 | export interface UserOptions {
7 | property: string | false;
8 | autoFetch: boolean;
9 | }
10 |
11 | export interface CookieUserOptions {
12 | property: {
13 | client: string | false;
14 | server: string | false;
15 | };
16 | autoFetch: boolean;
17 | }
18 |
19 | export interface EndpointsOption {
20 | [endpoint: string]: string | HTTPRequest | false;
21 | }
22 |
23 | // Scheme
24 |
25 | export interface SchemeOptions {
26 | name?: string;
27 | }
28 |
29 | export type SchemePartialOptions = PartialExcept;
30 |
31 | export interface SchemeCheck {
32 | valid: boolean;
33 | tokenExpired?: boolean;
34 | refreshTokenExpired?: boolean;
35 | idTokenExpired?: boolean;
36 | isRefreshable?: boolean;
37 | }
38 |
39 | export interface Scheme {
40 | options: OptionsT;
41 | name?: string;
42 | $auth: Auth;
43 | mounted?(...args: any[]): Promise;
44 | check?(checkStatus: boolean): SchemeCheck;
45 | login(...args: any[]): Promise;
46 | fetchUser(endpoint?: HTTPRequest): Promise;
47 | setUserToken?(
48 | token: string | boolean,
49 | refreshToken?: string | boolean
50 | ): Promise;
51 | logout?(endpoint?: HTTPRequest): Promise | void;
52 | reset?(options?: { resetInterceptor: boolean }): void;
53 | }
54 |
55 | // Token
56 |
57 | export interface TokenOptions {
58 | property: string;
59 | type: string | false;
60 | name: string;
61 | maxAge: number | false;
62 | global: boolean;
63 | required: boolean;
64 | prefix: string;
65 | expirationPrefix: string;
66 | }
67 |
68 | export interface TokenableSchemeOptions extends SchemeOptions {
69 | token?: TokenOptions;
70 | endpoints: EndpointsOption;
71 | }
72 |
73 | export interface TokenableScheme extends Scheme {
74 | token?: Token;
75 | requestHandler: RequestHandler;
76 | }
77 |
78 | // ID Token
79 |
80 | export interface IdTokenableSchemeOptions extends SchemeOptions {
81 | idToken: TokenOptions;
82 | }
83 |
84 | export interface IdTokenableScheme extends Scheme {
85 | idToken: IdToken;
86 | requestHandler: RequestHandler;
87 | }
88 |
89 | // Refrash
90 |
91 | export interface RefreshTokenOptions {
92 | property: string | false;
93 | type: string | false;
94 | data: string | false;
95 | maxAge: number | false;
96 | required: boolean;
97 | tokenRequired: boolean;
98 | prefix: string;
99 | expirationPrefix: string;
100 | }
101 |
102 | export interface RefreshableSchemeOptions extends TokenableSchemeOptions {
103 | refreshToken: RefreshTokenOptions;
104 | }
105 |
106 | export interface RefreshableScheme extends TokenableScheme {
107 | refreshToken: RefreshToken;
108 | refreshController: RefreshController;
109 | refreshTokens(): Promise;
110 | }
111 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/refresh-token.ts:
--------------------------------------------------------------------------------
1 | import type { RefreshableScheme } from '../../types';
2 | import type { Storage } from '../core';
3 | import { addTokenPrefix } from '../../utils';
4 | import { TokenStatus } from './token-status';
5 | import jwtDecode, { JwtPayload } from 'jwt-decode';
6 |
7 | export class RefreshToken {
8 | scheme: RefreshableScheme;
9 | $storage: Storage;
10 |
11 | constructor(scheme: RefreshableScheme, storage: Storage) {
12 | this.scheme = scheme;
13 | this.$storage = storage;
14 | }
15 |
16 | get(): string | boolean {
17 | const key = this.scheme.options.refreshToken.prefix + this.scheme.name;
18 |
19 | return this.$storage.getUniversal(key) as string | boolean;
20 | }
21 |
22 | set(tokenValue: string | boolean): string | boolean {
23 | const refreshToken = addTokenPrefix(tokenValue, this.scheme.options.refreshToken.type);
24 |
25 | this.#setToken(refreshToken);
26 | this.#updateExpiration(refreshToken);
27 |
28 | return refreshToken;
29 | }
30 |
31 | sync(): string | boolean {
32 | const refreshToken = this.#syncToken();
33 | this.#syncExpiration();
34 |
35 | return refreshToken;
36 | }
37 |
38 | reset(): void {
39 | this.#setToken(false);
40 | this.#setExpiration(false);
41 | }
42 |
43 | status(): TokenStatus {
44 | return new TokenStatus(this.get(), this.#getExpiration());
45 | }
46 |
47 | #getExpiration(): number | false {
48 | const key = this.scheme.options.refreshToken.expirationPrefix + this.scheme.name;
49 |
50 | return this.$storage.getUniversal(key) as number | false;
51 | }
52 |
53 | #setExpiration(expiration: number | false): number | false {
54 | const key = this.scheme.options.refreshToken.expirationPrefix + this.scheme.name;
55 |
56 | return this.$storage.setUniversal(key, expiration) as number | false;
57 | }
58 |
59 | #syncExpiration(): number | false {
60 | const key = this.scheme.options.refreshToken.expirationPrefix + this.scheme.name;
61 |
62 | return this.$storage.syncUniversal(key) as number | false;
63 | }
64 |
65 | #updateExpiration(refreshToken: string | boolean): number | false | void {
66 | let refreshTokenExpiration: number;
67 | const tokenIssuedAtMillis = Date.now();
68 | const tokenTTLMillis = Number(this.scheme.options.refreshToken.maxAge) * 1000;
69 | const tokenExpiresAtMillis = tokenTTLMillis ? tokenIssuedAtMillis + tokenTTLMillis : 0;
70 |
71 | try {
72 | refreshTokenExpiration = jwtDecode(refreshToken as string).exp! * 1000 || tokenExpiresAtMillis;
73 | } catch (error: any) {
74 | // If the token is not jwt, we can't decode and refresh it, use tokenExpiresAt value
75 | refreshTokenExpiration = tokenExpiresAtMillis;
76 |
77 | if (!((error && error.name === 'InvalidTokenError'))) {
78 | throw error;
79 | }
80 | }
81 |
82 | // Set token expiration
83 | return this.#setExpiration(refreshTokenExpiration || false);
84 | }
85 |
86 | #setToken(refreshToken: string | boolean): string | boolean {
87 | const key = this.scheme.options.refreshToken.prefix + this.scheme.name;
88 |
89 | return this.$storage.setUniversal(key, refreshToken) as string | boolean;
90 | }
91 |
92 | #syncToken(): string | boolean {
93 | const key = this.scheme.options.refreshToken.prefix + this.scheme.name;
94 |
95 | return this.$storage.syncUniversal(key) as string | boolean;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/module.ts:
--------------------------------------------------------------------------------
1 | import type { ModuleOptions } from './types';
2 | import { addImports, addPluginTemplate, addTemplate, createResolver, defineNuxtModule, installModule } from '@nuxt/kit';
3 | import { name, version } from '../package.json';
4 | import { resolveStrategies } from './resolve';
5 | import { moduleDefaults } from './options';
6 | import { getAuthDTS, getAuthPlugin } from './plugin';
7 | import { defu } from 'defu';
8 |
9 | const CONFIG_KEY = 'auth';
10 |
11 | export default defineNuxtModule({
12 | meta: {
13 | name,
14 | version,
15 | configKey: CONFIG_KEY,
16 | compatibility: {
17 | nuxt: '^3.0.0',
18 | },
19 | },
20 | defaults: moduleDefaults,
21 | async setup(moduleOptions, nuxt) {
22 | // Merge all option sources
23 | const options: ModuleOptions = defu({ ...moduleOptions, ...nuxt.options.runtimeConfig[CONFIG_KEY] }, moduleDefaults)
24 |
25 | // Resolver
26 | const resolver = createResolver(import.meta.url);
27 |
28 | // Resolve strategies
29 | const { strategies, strategyScheme } = await resolveStrategies(nuxt, options);
30 | delete options.strategies;
31 |
32 | // Resolve required imports
33 | const uniqueImports = new Set();
34 | const schemeImports = Object.values(strategyScheme).filter((i) => {
35 | if (uniqueImports.has(i.as)) {
36 | return false;
37 | }
38 |
39 | uniqueImports.add(i.as);
40 | return true;
41 | });
42 |
43 | // Set defaultStrategy
44 | options.defaultStrategy = options.defaultStrategy || strategies.length ? strategies[0].name : '';
45 |
46 | // Install http module if not in modules
47 | if (!nuxt.options.modules.includes('@nuxtjs-alt/http')) {
48 | installModule('@nuxtjs-alt/http')
49 | }
50 |
51 | // Add auth plugin
52 | addPluginTemplate({
53 | getContents: () => getAuthPlugin({ options, strategies, strategyScheme, schemeImports }),
54 | filename: 'auth.plugin.mjs',
55 | });
56 |
57 | addTemplate({
58 | getContents: () => getAuthDTS(),
59 | filename: 'auth.plugin.d.ts',
60 | write: true
61 | })
62 |
63 | // Add auto imports
64 | addImports([
65 | { from: resolver.resolve('runtime/composables'), name: 'useAuth' },
66 | ])
67 |
68 | // Runtime
69 | const runtime = resolver.resolve('runtime');
70 | nuxt.options.alias['#auth/runtime'] = runtime;
71 |
72 | // Utils
73 | const utils = resolver.resolve('utils');
74 | nuxt.options.alias['#auth/utils'] = utils;
75 |
76 | // Providers
77 | const providers = resolver.resolve('providers');
78 | nuxt.options.alias['#auth/providers'] = providers;
79 |
80 | // Transpile
81 | nuxt.options.build.transpile.push(runtime, providers, utils)
82 |
83 | // Middleware
84 | if (options.enableMiddleware) {
85 | nuxt.hook('app:resolve', (app) => {
86 | app.middleware.push({
87 | name: 'auth',
88 | path: resolver.resolve('runtime/core/middleware'),
89 | global: options.globalMiddleware,
90 | });
91 | });
92 | }
93 |
94 | // Extend auth with plugins
95 | if (options.plugins) {
96 | options.plugins.forEach((p) => nuxt.options.plugins.push(p))
97 | delete options.plugins
98 | }
99 | }
100 | });
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/id-token.ts:
--------------------------------------------------------------------------------
1 | import decode, { JwtPayload } from 'jwt-decode';
2 | import { addTokenPrefix } from '../../utils';
3 | import type { IdTokenableScheme } from '../../types';
4 | import type { Storage } from '../core';
5 | import { TokenStatus } from './token-status';
6 |
7 | export class IdToken {
8 | scheme: IdTokenableScheme;
9 | $storage: Storage;
10 |
11 | constructor(scheme: IdTokenableScheme, storage: Storage) {
12 | this.scheme = scheme;
13 | this.$storage = storage;
14 | }
15 |
16 | get(): string | boolean {
17 | const key = this.scheme.options.idToken.prefix + this.scheme.name;
18 |
19 | return this.$storage.getUniversal(key) as string | boolean;
20 | }
21 |
22 | set(tokenValue: string | boolean): string | boolean {
23 | const idToken = addTokenPrefix(tokenValue, this.scheme.options.idToken.type);
24 |
25 | this.#setToken(idToken);
26 | this.#updateExpiration(idToken);
27 |
28 | return idToken;
29 | }
30 |
31 | sync(): string | boolean {
32 | const idToken = this.#syncToken();
33 | this.#syncExpiration();
34 |
35 | return idToken;
36 | }
37 |
38 | reset() {
39 | this.#setToken(false);
40 | this.#setExpiration(false);
41 | }
42 |
43 | status(): TokenStatus {
44 | return new TokenStatus(this.get(), this.#getExpiration());
45 | }
46 |
47 | #getExpiration(): number | false {
48 | const key = this.scheme.options.idToken.expirationPrefix + this.scheme.name;
49 |
50 | return this.$storage.getUniversal(key) as number | false;
51 | }
52 |
53 | #setExpiration(expiration: number | false): number | false {
54 | const key = this.scheme.options.idToken.expirationPrefix + this.scheme.name;
55 |
56 | return this.$storage.setUniversal(key, expiration) as number | false;
57 | }
58 |
59 | #syncExpiration(): number | false {
60 | const key =
61 | this.scheme.options.idToken.expirationPrefix + this.scheme.name;
62 |
63 | return this.$storage.syncUniversal(key) as number | false;
64 | }
65 |
66 | #updateExpiration(idToken: string | boolean): number | false | void {
67 | let idTokenExpiration: number;
68 | const tokenIssuedAtMillis = Date.now();
69 | const tokenTTLMillis = Number(this.scheme.options.idToken.maxAge) * 1000;
70 | const tokenExpiresAtMillis = tokenTTLMillis ? tokenIssuedAtMillis + tokenTTLMillis : 0;
71 |
72 | try {
73 | idTokenExpiration = decode(idToken as string).exp! * 1000 || tokenExpiresAtMillis;
74 | }
75 | catch (error: any) {
76 | // If the token is not jwt, we can't decode and refresh it, use tokenExpiresAt value
77 | idTokenExpiration = tokenExpiresAtMillis;
78 |
79 | if (!(error && error.name === 'InvalidTokenError')) {
80 | throw error;
81 | }
82 | }
83 |
84 | // Set token expiration
85 | return this.#setExpiration(idTokenExpiration || false);
86 | }
87 |
88 | #setToken(idToken: string | boolean): string | boolean {
89 | const key = this.scheme.options.idToken.prefix + this.scheme.name;
90 |
91 | return this.$storage.setUniversal(key, idToken) as string | boolean;
92 | }
93 |
94 | #syncToken(): string | boolean {
95 | const key = this.scheme.options.idToken.prefix + this.scheme.name;
96 |
97 | return this.$storage.syncUniversal(key) as string | boolean;
98 | }
99 |
100 | userInfo() {
101 | const idToken = this.get();
102 | if (typeof idToken === 'string') {
103 | return decode(idToken);
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/readme.md:
--------------------------------------------------------------------------------
1 | **Information**
2 |
3 | This serves as an extension to ohmyfetch for nuxt. Please note this is only for nuxt3.
4 | This works similar to nuxt/http and nuxtjs-alt/axios except it utilizes ohmyfetch. All property options will be under `http`.
5 | This module is required in order for `@nuxtjs-alt/auth` to function.
6 |
7 | Remember this is a mix of `ofetch` and `nuxt/http` so to use methods you would use as an example:
8 |
9 | ```ts
10 | // Available methods: 'get', 'head', 'delete', 'post', 'put', 'patch', 'options'
11 |
12 | // $http.$get('/api', options) and $http.$get({ url: '/api' }) is the same as $fetch('/api', { method: 'get' })
13 | await $http.$get('/api', options)
14 | await $http.$get({ url: '/api', ...options })
15 |
16 | // Access Raw Response
17 | // $http.get('/api', options) and $http.get({ url: '/api' }) is the same as $fetch.raw('/api', { method: 'get' })
18 | await $http.get('/api', options)
19 | await $http.get({ url: '/api', ...options })
20 |
21 | // $http.request('/api', options) and $http.request({ url: '/api' }) is the same as $fetch('/api', options)
22 | await $http.request({ url: '/api', ...options })
23 | await $http.request('/api', options)
24 |
25 | // Access Raw Response
26 | // $http.raw('/api', options) and $http.raw({ url: '/api' }) is the same as $fetch.raw('/api', options)
27 | await $http.raw({ url: '/api', ...options })
28 | await $http.raw('/api', options)
29 |
30 | // Access Fetch Native Response
31 | // $http.natvie('/api', options) and $http.native({ url: '/api' }) is the same as $fetch.native('/api', options) or fetch('/api', options)
32 | await $http.native({ url: '/api', ...options })
33 | await $http.native('/api', options)
34 | ```
35 |
36 | A `useHttp` composable is avaialble, it works like `useFetch` except uses this module under the hood
37 |
38 | **Interceptors**
39 |
40 | The interceptors should work exactly like how axios has it so to access them you would use:
41 |
42 | ```ts
43 | $http.interceptors.request.use(config)
44 | $http.interceptors.response.use(response)
45 |
46 | ```
47 |
48 | A `interceptorPlugin` property has been added. This relies on the proxy module being present and will proxy urls based on the target for the client.
49 |
50 | @nuxtjs-axios based functions have also been added:
51 |
52 | ```ts
53 | $http.onRequest(config)
54 | $http.onResponse(response)
55 | $http.onRequestError(err)
56 | $http.onResponseError(err)
57 | $http.onError(err)
58 | ```
59 |
60 | **Config Options**
61 |
62 | ```ts
63 | import { defineNuxtConfig } from 'nuxt/config'
64 |
65 | export default defineNuxtConfig({
66 | modules: [
67 | '@nuxtjs-alt/http',
68 | ],
69 | http: {
70 | baseURL: 'localhost:3000', // default is localhost:3000, otherwise it is the HOST/NITRO_HOST and PORT/NITRO_PORT enviromental values
71 | browserBaseURL: undefined, // default is nuxt app baseURL, otherwise if interceptorPlugin is enabled it's based on the proxy urls
72 | proxyHeaders: true,
73 | proxyHeadersIgnore: [
74 | 'accept',
75 | 'connection',
76 | 'cf-connecting-ip',
77 | 'cf-ray',
78 | 'content-length',
79 | 'content-md5',
80 | 'content-type',
81 | 'host',
82 | 'if-modified-since',
83 | 'if-none-match',
84 | 'x-forwarded-host',
85 | 'x-forwarded-port',
86 | 'x-forwarded-proto'
87 | ],
88 | serverTimeout: 10000,
89 | clientTimeout: 25000,
90 | https: false,
91 | retry: 1,
92 | headers: {
93 | accept: 'application/json, text/plain, */*'
94 | },
95 | credentials: 'omit',
96 | debug: false,
97 | interceptorPlugin: false
98 | }
99 | })
100 | ```
101 |
102 | Please do tell me if you encounter any bugs.
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/token.ts:
--------------------------------------------------------------------------------
1 | import type { JwtPayload } from 'jwt-decode';
2 | import type { TokenableScheme } from '../../types';
3 | import type { Storage } from '../core';
4 | import { addTokenPrefix } from '../../utils';
5 | import { TokenStatus } from './token-status';
6 | import decode from 'jwt-decode';
7 |
8 | export class Token {
9 | scheme: TokenableScheme;
10 | $storage: Storage;
11 |
12 | constructor(scheme: TokenableScheme, storage: Storage) {
13 | this.scheme = scheme;
14 | this.$storage = storage;
15 | }
16 |
17 | get(): string | boolean {
18 | const key = this.scheme.options.token!.prefix + this.scheme.name;
19 |
20 | return this.$storage.getUniversal(key) as string | boolean;
21 | }
22 |
23 | set(tokenValue: string | boolean, expiresIn: number | boolean = false): string | boolean {
24 | const token = addTokenPrefix(tokenValue, this.scheme.options.token!.type);
25 |
26 | this.#setToken(token);
27 | this.#updateExpiration(token, expiresIn);
28 |
29 | if (typeof token === 'string') {
30 | this.scheme.requestHandler.setHeader(token);
31 | }
32 |
33 | return token;
34 | }
35 |
36 | sync(): string | boolean {
37 | const token = this.#syncToken();
38 | this.#syncExpiration();
39 |
40 | if (typeof token === 'string') {
41 | this.scheme.requestHandler.setHeader(token);
42 | }
43 |
44 | return token;
45 | }
46 |
47 | reset(): void {
48 | this.scheme.requestHandler.clearHeader();
49 | this.#setToken(false);
50 | this.#setExpiration(false);
51 | }
52 |
53 | status(): TokenStatus {
54 | return new TokenStatus(this.get(), this.#getExpiration());
55 | }
56 |
57 | #getExpiration(): number | false {
58 | const key = this.scheme.options.token!.expirationPrefix + this.scheme.name;
59 |
60 | return this.$storage.getUniversal(key) as number | false;
61 | }
62 |
63 | #setExpiration(expiration: number | false): number | false {
64 | const key = this.scheme.options.token!.expirationPrefix + this.scheme.name;
65 |
66 | return this.$storage.setUniversal(key, expiration) as number | false;
67 | }
68 |
69 | #syncExpiration(): number | false {
70 | const key = this.scheme.options.token!.expirationPrefix + this.scheme.name;
71 |
72 | return this.$storage.syncUniversal(key) as number | false;
73 | }
74 |
75 | #updateExpiration(token: string | boolean, expiresIn: number | boolean): number | false | void {
76 | let tokenExpiration: number;
77 | const tokenIssuedAtMillis = Date.now();
78 | const maxAge = expiresIn ? expiresIn : this.scheme.options.token!.maxAge
79 | const tokenTTLMillis = Number(maxAge) * 1000
80 | const tokenExpiresAtMillis = tokenTTLMillis ? tokenIssuedAtMillis + tokenTTLMillis : 0;
81 |
82 | try {
83 | tokenExpiration = decode(token as string).exp! * 1000 || tokenExpiresAtMillis;
84 | }
85 | catch (error: any) {
86 | // If the token is not jwt, we can't decode and refresh it, use tokenExpiresAt value
87 | tokenExpiration = tokenExpiresAtMillis;
88 |
89 | if (!(error && error.name === 'InvalidTokenError')) {
90 | throw error;
91 | }
92 | }
93 |
94 | // Set token expiration
95 | return this.#setExpiration(tokenExpiration || false);
96 | }
97 |
98 | #setToken(token: string | boolean): string | boolean {
99 | const key = this.scheme.options.token!.prefix + this.scheme.name;
100 |
101 | return this.$storage.setUniversal(key, token) as string | boolean;
102 | }
103 |
104 | #syncToken(): string | boolean {
105 | const key = this.scheme.options.token!.prefix + this.scheme.name;
106 |
107 | return this.$storage.syncUniversal(key) as string | boolean;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/vuetify/src/runtime/vuetify.ts:
--------------------------------------------------------------------------------
1 | // Composables
2 | import { createDefaults, DefaultsSymbol } from 'vuetify/lib/composables/defaults.mjs'
3 | import { createDisplay, DisplaySymbol } from 'vuetify/lib/composables/display.mjs'
4 | import { createIcons, IconSymbol } from 'vuetify/lib/composables/icons.mjs'
5 | import { createLocale, LocaleSymbol } from 'vuetify/lib/composables/locale.mjs'
6 | import { createTheme, ThemeSymbol } from './theme'
7 |
8 | // Utilities
9 | import { defineComponent, getUid, IN_BROWSER, mergeDeep } from 'vuetify/lib/util/index.mjs'
10 | import { version } from 'vuetify/package.json'
11 | import { nextTick, reactive } from 'vue'
12 |
13 | // Types
14 | import type { App, ComponentPublicInstance, InjectionKey } from 'vue'
15 | import type { VuetifyOptions } from 'vuetify'
16 | import type { NuxtApp } from 'nuxt/app'
17 |
18 | export interface Blueprint extends Omit { }
19 |
20 | interface VueApp extends App {
21 | $nuxt: NuxtApp
22 | }
23 |
24 | export function createVuetify(vuetify: VuetifyOptions = {}) {
25 | const { blueprint, ...rest } = vuetify
26 | const options = mergeDeep(blueprint, rest)
27 | const {
28 | aliases = {},
29 | components = {},
30 | directives = {},
31 | } = options
32 |
33 | const defaults = createDefaults(options.defaults)
34 | const display = createDisplay(options.display, options.ssr)
35 | const theme = createTheme(options.theme)
36 | const icons = createIcons(options.icons)
37 | const locale = createLocale(options.locale)
38 |
39 | const install = (app: VueApp) => {
40 | for (const key in directives) {
41 | app.directive(key, directives[key])
42 | }
43 |
44 | for (const key in components) {
45 | app.component(key, components[key])
46 | }
47 |
48 | for (const key in aliases) {
49 | app.component(key, defineComponent({
50 | ...aliases[key],
51 | name: key,
52 | aliasName: aliases[key].name,
53 | }))
54 | }
55 |
56 | theme.install(app)
57 |
58 | app.provide(DefaultsSymbol, defaults)
59 | app.provide(DisplaySymbol, display)
60 | app.provide(ThemeSymbol, theme)
61 | app.provide(IconSymbol, icons)
62 | app.provide(LocaleSymbol, locale)
63 |
64 | if (IN_BROWSER && options.ssr) {
65 | if (app.$nuxt) {
66 | app.$nuxt.hook('app:suspense:resolve', () => {
67 | display.update()
68 | })
69 | } else {
70 | const { mount } = app
71 | app.mount = (...args) => {
72 | const vm = mount(...args)
73 | nextTick(() => display.update())
74 | app.mount = mount
75 | return vm
76 | }
77 | }
78 | }
79 |
80 | getUid.reset()
81 |
82 | app.mixin({
83 | computed: {
84 | $vuetify() {
85 | return reactive({
86 | defaults: inject.call(this, DefaultsSymbol),
87 | display: inject.call(this, DisplaySymbol),
88 | theme: inject.call(this, ThemeSymbol),
89 | icons: inject.call(this, IconSymbol),
90 | locale: inject.call(this, LocaleSymbol),
91 | })
92 | },
93 | },
94 | })
95 | }
96 |
97 | return {
98 | install,
99 | defaults,
100 | display,
101 | theme,
102 | icons,
103 | locale,
104 | }
105 | }
106 |
107 | createVuetify.version = version
108 |
109 | // Vue's inject() can only be used in setup
110 | function inject(this: ComponentPublicInstance, key: InjectionKey | string) {
111 | const vm = this.$
112 |
113 | // @ts-ignore
114 | const provides = vm.parent?.provides ?? vm.vnode.appContext?.provides
115 |
116 | if (provides && (key as any) in provides) {
117 | return provides[(key as string)]
118 | }
119 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/resolve.ts:
--------------------------------------------------------------------------------
1 | import type { Strategy, ModuleOptions } from './types';
2 | import type { Nuxt, NuxtModule } from '@nuxt/schema'
3 | import { resolvePath, requireModule } from '@nuxt/kit';
4 | import { ProviderAliases } from './providers';
5 | import * as AUTH_PROVIDERS from './providers';
6 | import { existsSync } from 'fs';
7 | import { hash } from 'ohash'
8 |
9 | const BuiltinSchemes = {
10 | local: 'LocalScheme',
11 | cookie: 'CookieScheme',
12 | oauth2: 'Oauth2Scheme',
13 | openIDConnect: 'OpenIDConnectScheme',
14 | refresh: 'RefreshScheme',
15 | laravelJWT: 'LaravelJWTScheme',
16 | auth0: 'Auth0Scheme',
17 | };
18 |
19 | export interface ImportOptions {
20 | name: string;
21 | as: string;
22 | from: string;
23 | }
24 |
25 | export async function resolveStrategies(nuxt: Nuxt, options: ModuleOptions): Promise<{ strategies: Strategy[]; strategyScheme: Record; }> {
26 | const strategies: Strategy[] = [];
27 | const strategyScheme = {} as Record;
28 |
29 | for (const name of Object.keys(options.strategies!)) {
30 | if (!options.strategies![name] || (options.strategies as Strategy)[name].enabled === false) {
31 | continue;
32 | }
33 |
34 | // Clone strategy
35 | const strategy = Object.assign({}, options.strategies![name]) as Strategy;
36 |
37 | // Default name
38 | if (!strategy.name) {
39 | strategy.name = name;
40 | }
41 |
42 | // Default provider (same as name)
43 | if (!strategy.provider) {
44 | strategy.provider = strategy.name;
45 | }
46 |
47 | // Try to resolve provider
48 | const provider: (...args: any) => any = resolveProvider(strategy.provider);
49 |
50 | delete strategy.provider;
51 |
52 | if (typeof provider === 'function' && !(provider as NuxtModule).getOptions) {
53 | provider(nuxt, strategy);
54 | }
55 |
56 | // Default scheme (same as name)
57 | if (!strategy.scheme) {
58 | strategy.scheme = strategy.name;
59 | }
60 |
61 | try {
62 | // Resolve and keep scheme needed for strategy
63 | const schemeImport = await resolveScheme(strategy.scheme);
64 | delete strategy.scheme;
65 | strategyScheme[strategy.name] = schemeImport as ImportOptions;
66 |
67 | // Add strategy to array
68 | strategies.push(strategy);
69 | } catch (e) {
70 | console.error(`[auth] Error resolving strategy ${strategy.name}: ${e}`);
71 | }
72 | }
73 |
74 | return {
75 | strategies,
76 | strategyScheme,
77 | };
78 | }
79 |
80 | export async function resolveScheme(scheme: string): Promise {
81 | if (typeof scheme !== 'string') {
82 | return;
83 | }
84 |
85 | if (BuiltinSchemes[scheme as keyof typeof BuiltinSchemes]) {
86 | return {
87 | name: BuiltinSchemes[scheme as keyof typeof BuiltinSchemes],
88 | as: BuiltinSchemes[scheme as keyof typeof BuiltinSchemes],
89 | from: '#auth/runtime',
90 | };
91 | }
92 |
93 | const path = await resolvePath(scheme);
94 |
95 | if (existsSync(path)) {
96 | const _path = path.replace(/\\/g, '/');
97 | return {
98 | name: 'default',
99 | as: 'Scheme$' + hash({ path: _path }),
100 | from: _path,
101 | };
102 | }
103 | }
104 |
105 | export function resolveProvider(provider: string | ((...args: any[]) => any)) {
106 | if (typeof provider === 'function') {
107 | return provider;
108 | }
109 |
110 | if (typeof provider !== 'string') {
111 | return;
112 | }
113 |
114 | provider = (ProviderAliases[provider as keyof typeof ProviderAliases] || provider);
115 |
116 | if (AUTH_PROVIDERS[provider as keyof typeof AUTH_PROVIDERS]) {
117 | return AUTH_PROVIDERS[provider as keyof typeof AUTH_PROVIDERS];
118 | }
119 |
120 | try {
121 | const m = requireModule(provider);
122 | return m.default || m;
123 | } catch (e) {
124 | return;
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/vuetify/src/module.ts:
--------------------------------------------------------------------------------
1 | import type { ModuleOptions } from './types';
2 | import type { Nuxt } from '@nuxt/schema'
3 | import { name, version } from "../package.json";
4 | import { defineNuxtModule, addPluginTemplate, createResolver, addImports, addTemplate } from '@nuxt/kit';
5 | import vuetify from 'vite-plugin-vuetify'
6 | import { defu } from 'defu'
7 |
8 | const CONFIG_KEY = 'vuetify'
9 |
10 | export default defineNuxtModule({
11 | meta: {
12 | name,
13 | version,
14 | configKey: CONFIG_KEY,
15 | compatibility: {
16 | nuxt: '^3.0.0'
17 | }
18 | },
19 | defaults: {
20 | vuetifyOptions: {},
21 | pluginOptions: {},
22 | } as ModuleOptions,
23 | async setup(moduleOptions, nuxt) {
24 | const options: ModuleOptions = moduleOptions
25 |
26 | const { resolve } = createResolver(import.meta.url)
27 |
28 | options.pluginOptions!.styles = options.pluginOptions?.styles ?? true
29 |
30 | if (typeof options.pluginOptions?.styles === 'string' && ['sass', 'expose'].includes(options.pluginOptions.styles)) {
31 | nuxt.options.css.unshift('vuetify/styles/main.sass')
32 | }
33 | else if (options.pluginOptions?.styles === true) {
34 | nuxt.options.css.unshift('vuetify/styles')
35 | }
36 |
37 | // Transpile Vuetify
38 | nuxt.options.build.transpile.push(CONFIG_KEY)
39 |
40 | nuxt.hook('vite:extendConfig', (config) => {
41 | config.optimizeDeps = defu(config.optimizeDeps, {
42 | exclude: ['vuetify']
43 | })
44 |
45 | // Vuetify plugin configuration
46 | config.plugins = [
47 | ...(config.plugins || []),
48 | vuetify(options.pluginOptions),
49 | ]
50 |
51 | config.define = {
52 | ...(config.define || {}),
53 | 'process.env.DEBUG': false,
54 | }
55 |
56 | // @ts-ignore: name property is there but not in the typing
57 | const vueIndex = config.plugins.findIndex((plugin) => plugin.name === 'vite:vue')
58 | if (vueIndex !== -1) {
59 | const vuePlugin = config.plugins.splice(vueIndex, 1)[0]
60 | config.plugins.unshift(vuePlugin)
61 | }
62 |
63 | config.ssr = config.ssr || {}
64 | config.ssr.noExternal = Array.isArray(config.ssr!.noExternal) ? config.ssr.noExternal : []
65 | config.ssr.noExternal.push(CONFIG_KEY)
66 | })
67 |
68 | const selectedIcon = options.vuetifyOptions?.icons?.defaultSet ?? 'mdi'
69 |
70 | if (Object.hasOwn(cdnPresets, selectedIcon)) {
71 | setupIcons(nuxt, selectedIcon as IconPreset)
72 | }
73 |
74 | addPluginTemplate({
75 | src: resolve('./runtime/templates/plugin.mjs'),
76 | filename: 'vuetify.plugin.mjs',
77 | options: {
78 | options: options.vuetifyOptions
79 | }
80 | })
81 |
82 | // Runtime
83 | const runtime = resolve('./runtime/vuetify');
84 | nuxt.options.alias['#vuetify'] = runtime;
85 |
86 | // vuetify-specific composables
87 | addImports([
88 | { from: resolve('./runtime/theme'), name: 'useTheme' },
89 | { from: CONFIG_KEY, name: 'useDisplay' },
90 | { from: CONFIG_KEY, name: 'useRtl' },
91 | { from: CONFIG_KEY, name: 'useLocale' },
92 | { from: CONFIG_KEY, name: 'useLayout' }
93 | ])
94 | }
95 | })
96 |
97 | type IconPreset = keyof typeof cdnPresets
98 |
99 | const cdnPresets = {
100 | mdi: 'https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css',
101 | md: 'https://fonts.googleapis.com/css?family=Material+Icons',
102 | fa: 'https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@latest/css/all.min.css'
103 | }
104 |
105 | function setupIcons(nuxt: Nuxt, preset: IconPreset) {
106 | if (cdnPresets[preset]) {
107 | nuxt.options.app.head.link = nuxt.options.app.head.link || []
108 | nuxt.options.app.head.link.push({
109 | rel: 'stylesheet',
110 | type: 'text/css',
111 | href: cdnPresets[preset]
112 | })
113 | }
114 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import type { RouteComponent } from 'vue-router';
2 | import type { RecursivePartial } from '../types';
3 | import { useRuntimeConfig, useRoute } from '#imports';
4 |
5 | export const isUnset = (o: any): boolean => typeof o === 'undefined' || o === null;
6 |
7 | export const isSet = (o: any): boolean => !isUnset(o);
8 |
9 | export function isRelativeURL(u: string) {
10 | return (u && u.length && new RegExp(['^\\/([a-zA-Z0-9@\\-%_~.:]', '[/a-zA-Z0-9@\\-%_~.:]*)?', '([?][^#]*)?(#[^#]*)?$'].join('')).test(u));
11 | }
12 |
13 | export function routeMeta(key: string, value: string | boolean): boolean {
14 | return useRoute().meta[key] === value
15 | }
16 |
17 | export function getMatchedComponents(matches: unknown[] = []): RouteComponent[][] {
18 | return [
19 | ...useRoute().matched.map(function (m, index: number) {
20 | return Object.keys(m.components!).map(function (key) {
21 | matches.push(index);
22 | return m.components![key];
23 | });
24 | })
25 | ]
26 | }
27 |
28 | export function normalizePath(path: string = ''): string {
29 | // Remove query string
30 | const config = useRuntimeConfig()
31 | let result = path.split('?')[0];
32 |
33 | // Remove base path
34 | if (config.app.baseURL) {
35 | result = result.replace(config.app.baseURL, '/');
36 | }
37 |
38 | // Remove redundant / from the end of path
39 | if (result.charAt(result.length - 1) === '/') {
40 | result = result.slice(0, -1);
41 | }
42 |
43 | // Remove duplicate slashes
44 | result = result.replace(/\/+/g, '/');
45 |
46 | return result;
47 | }
48 |
49 | export function encodeValue(val: any): string {
50 | if (typeof val === 'string') {
51 | return val;
52 | }
53 | return JSON.stringify(val);
54 | }
55 |
56 | export function decodeValue(val: any): any {
57 | // Try to parse as json
58 | if (typeof val === 'string') {
59 | try {
60 | return JSON.parse(val);
61 | } catch (_) {}
62 | }
63 |
64 | // Return as is
65 | return val;
66 | }
67 |
68 | /**
69 | * Get property defined by dot notation in string.
70 | * Based on https://github.com/dy/dotprop (MIT)
71 | *
72 | * @param { Object } holder Target object where to look property up
73 | * @param { string } propName Dot notation, like 'this.a.b.c'
74 | * @return { * } A property value
75 | */
76 | export function getProp(holder: any, propName: string | false): any {
77 | if (!propName || !holder || typeof holder !== 'object') {
78 | return holder;
79 | }
80 |
81 | if (propName in holder) {
82 | return holder[propName];
83 | }
84 |
85 | const propParts = Array.isArray(propName) ? propName : (propName as string).split('.');
86 |
87 | let result = holder;
88 | while (propParts.length && result) {
89 | result = result[propParts.shift()];
90 | }
91 |
92 | return result;
93 | }
94 |
95 | // Ie 'Bearer ' + token
96 | export function addTokenPrefix(token: string | boolean, tokenType: string | false): string | boolean {
97 | if (!token || !tokenType || typeof token !== 'string' || token.startsWith(tokenType)) {
98 | return token;
99 | }
100 |
101 | return tokenType + ' ' + token;
102 | }
103 |
104 | export function removeTokenPrefix(token: string | boolean, tokenType: string | false): string | boolean {
105 | if (!token || !tokenType || typeof token !== 'string') {
106 | return token;
107 | }
108 |
109 | return token.replace(tokenType + ' ', '');
110 | }
111 |
112 | export function cleanObj>(obj: T): RecursivePartial {
113 | for (const key in obj) {
114 | if (obj[key] === undefined) {
115 | delete obj[key];
116 | }
117 | }
118 |
119 | return obj as RecursivePartial;
120 | }
121 |
122 | export function randomString(length: number) {
123 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
124 | let result = '';
125 | const charactersLength = characters.length;
126 |
127 | for (let i = 0; i < length; i++) {
128 | result += characters.charAt(Math.floor(Math.random() * charactersLength));
129 | }
130 |
131 | return result;
132 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/axios/src/module.ts:
--------------------------------------------------------------------------------
1 | import type { ModuleOptions } from './types'
2 | import type { Nuxt } from '@nuxt/schema'
3 | import { defineNuxtModule, addPluginTemplate, createResolver } from '@nuxt/kit'
4 | import { name, version } from '../package.json'
5 | import { defu } from 'defu'
6 |
7 | const CONFIG_KEY = 'axios'
8 |
9 | export * from './types'
10 |
11 | export default defineNuxtModule({
12 | meta: {
13 | name,
14 | version,
15 | configKey: CONFIG_KEY,
16 | compatibility: {
17 | nuxt: '^3.0.0-rc.9'
18 | },
19 | },
20 | defaults: {} as ModuleOptions,
21 | setup(opts: ModuleOptions, nuxt: Nuxt) {
22 | // Combine options with runtime config
23 | const moduleOptions: ModuleOptions = defu(nuxt.options.runtimeConfig?.public[CONFIG_KEY], opts)
24 |
25 | // Default port
26 | const defaultPort = process.env.API_PORT || moduleOptions.port || process.env.PORT || process.env.npm_package_config_nuxt_port || 3000
27 |
28 | // Default host
29 | let defaultHost = process.env.API_HOST || moduleOptions.host || process.env.HOST || process.env.npm_package_config_nuxt_host || 'localhost'
30 |
31 | if (defaultHost === '0.0.0.0') {
32 | defaultHost = 'localhost'
33 | }
34 |
35 | // Default prefix
36 | const prefix = process.env.API_PREFIX || moduleOptions.prefix || '/'
37 |
38 | // Support baseUrl alternative
39 | if (moduleOptions.baseUrl) {
40 | moduleOptions.baseURL = moduleOptions.baseUrl
41 | delete moduleOptions.baseUrl
42 | }
43 |
44 | if (moduleOptions.browserBaseUrl) {
45 | moduleOptions.browserBaseURL = moduleOptions.browserBaseUrl
46 | delete moduleOptions.browserBaseUrl
47 | }
48 |
49 | // Apply defaults
50 | const options: ModuleOptions = defu(moduleOptions, {
51 | baseURL: `http://${defaultHost}:${defaultPort}${prefix}`,
52 | browserBaseURL: undefined,
53 | credentials: false,
54 | debug: false,
55 | progress: true,
56 | proxyHeaders: true,
57 | proxyHeadersIgnore: [
58 | 'accept',
59 | 'cf-connecting-ip',
60 | 'cf-ray',
61 | 'content-length',
62 | 'content-md5',
63 | 'content-type',
64 | 'host',
65 | 'if-modified-since',
66 | 'if-none-match',
67 | 'x-forwarded-host',
68 | 'x-forwarded-port',
69 | 'x-forwarded-proto'
70 | ],
71 | proxy: false,
72 | retry: false,
73 | https: false,
74 | headers: {
75 | common: {
76 | accept: 'application/json, text/plain, */*'
77 | },
78 | delete: {},
79 | get: {},
80 | head: {},
81 | post: {},
82 | put: {},
83 | patch: {}
84 | },
85 | })
86 |
87 | if (process.env.API_URL) {
88 | options.baseURL = process.env.API_URL
89 | }
90 |
91 | if (process.env.API_URL_BROWSER) {
92 | options.browserBaseURL = process.env.API_URL_BROWSER
93 | }
94 |
95 | if (typeof options.browserBaseURL === 'undefined') {
96 | options.browserBaseURL = options.baseURL
97 | }
98 |
99 | // Normalize options
100 | if (options.retry === true) {
101 | options.retry = {}
102 | }
103 |
104 | // Convert http:// to https:// if https option is on
105 | if (options.https === true) {
106 | const https = (s: string) => s.replace('http://', 'https://')
107 | options.baseURL = https(options.baseURL)
108 | options.browserBaseURL = https(options.browserBaseURL)
109 | }
110 |
111 | // globalName
112 | options.globalName = nuxt.options.globalName || 'nuxt'
113 |
114 | // Set _AXIOS_BASE_URL_ for dynamic SSR baseURL
115 | process.env._AXIOS_BASE_URL_ = options.baseURL
116 |
117 | // resolver
118 | const resolver = createResolver(import.meta.url)
119 |
120 | // Register plugin
121 | addPluginTemplate({
122 | src: resolver.resolve('runtime/templates/axios.plugin.mjs'),
123 | options: options
124 | })
125 |
126 | console.debug(`baseURL: ${options.baseURL}`)
127 | console.debug(`browserBaseURL: ${options.browserBaseURL}`)
128 | }
129 | })
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/request-handler.ts:
--------------------------------------------------------------------------------
1 | import type { TokenableScheme, RefreshableScheme } from '../../types';
2 | import { ExpiredAuthSessionError } from './expired-auth-session-error';
3 | import { FetchInstance, FetchConfig } from '@refactorjs/ofetch'
4 |
5 | export class RequestHandler {
6 | scheme: TokenableScheme | RefreshableScheme;
7 | http: FetchInstance;
8 | interceptor: number | undefined | null;
9 |
10 | constructor(scheme: TokenableScheme | RefreshableScheme, http: FetchInstance) {
11 | this.scheme = scheme;
12 | this.http = http;
13 | this.interceptor = null;
14 | }
15 |
16 | setHeader(token: string): void {
17 | if (this.scheme.options.token && this.scheme.options.token.global) {
18 | // Set Authorization token for all fetch requests
19 | this.http.setHeader(this.scheme.options.token.name, token);
20 | }
21 | }
22 |
23 | clearHeader(): void {
24 | if (this.scheme.options.token && this.scheme.options.token.global) {
25 | // Clear Authorization token for all fetch requests
26 | this.http.setHeader(this.scheme.options.token.name, null);
27 | }
28 | }
29 |
30 | initializeRequestInterceptor(refreshEndpoint?: string | Request): void {
31 | this.interceptor = this.http.interceptors.request.use(
32 | async (config: FetchConfig) => {
33 | // Don't intercept refresh token requests
34 | if ((this.scheme.options.token && !this.#needToken(config)) || config.url === refreshEndpoint) {
35 | return config;
36 | }
37 |
38 | // Perform scheme checks.
39 | const { valid, tokenExpired, refreshTokenExpired, isRefreshable } = this.scheme.check!(true);
40 | let isValid = valid;
41 |
42 | // Refresh token has expired. There is no way to refresh. Force reset.
43 | if (refreshTokenExpired) {
44 | this.scheme.reset!();
45 | throw new ExpiredAuthSessionError();
46 | }
47 |
48 | // Token has expired.
49 | if (tokenExpired) {
50 | // Refresh token is not available. Force reset.
51 | if (!isRefreshable) {
52 | this.scheme.reset!();
53 | throw new ExpiredAuthSessionError();
54 | }
55 |
56 | // Refresh token is available. Attempt refresh.
57 | isValid = await (this.scheme as RefreshableScheme).refreshController
58 | .handleRefresh()
59 | .then(() => true)
60 | .catch(() => {
61 | // Tokens couldn't be refreshed. Force reset.
62 | this.scheme.reset!();
63 | throw new ExpiredAuthSessionError();
64 | });
65 | }
66 |
67 | // Sync token
68 | const token = this.scheme.token;
69 |
70 | // Scheme checks were performed, but returned that is not valid.
71 | if (!isValid) {
72 | // The authorization header in the current request is expired.
73 | // Token was deleted right before this request
74 | if (token && !token.get() && this.#requestHasAuthorizationHeader(config)) {
75 | throw new ExpiredAuthSessionError();
76 | }
77 |
78 | return config;
79 | }
80 |
81 | // Token is valid, let the request pass
82 | // Fetch updated token and add to current request
83 | return this.#getUpdatedRequestConfig(config, token ? token.get() : false);
84 | }
85 | );
86 | }
87 |
88 | reset(): void {
89 | // Eject request interceptor
90 | this.http.interceptors.request.eject(this.interceptor as number);
91 | this.interceptor = null;
92 | }
93 |
94 | #needToken(config: FetchConfig): boolean {
95 | const options = this.scheme.options;
96 |
97 | return (options.token!.global || Object.values(options.endpoints).some((endpoint) => typeof endpoint === 'object' ? endpoint.url === config.url : endpoint === config.url));
98 | }
99 |
100 | // ---------------------------------------------------------------
101 | // Watch requests for token expiration
102 | // Refresh tokens if token has expired
103 |
104 | #getUpdatedRequestConfig(config: FetchConfig, token: string | boolean) {
105 | if (typeof token === 'string') {
106 | config.headers![this.scheme.options.token!.name] = token;
107 | }
108 |
109 | return config;
110 | }
111 |
112 | #requestHasAuthorizationHeader(config: FetchConfig): boolean {
113 | return !!config.headers![this.scheme.options.token!.name];
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/src/runtime/composables.ts:
--------------------------------------------------------------------------------
1 | import type { FetchConfig } from '@refactorjs/ofetch'
2 | import type { TypedInternalResponse, NitroFetchRequest } from 'nitropack'
3 | //@ts-ignore
4 | import type { AsyncDataOptions, _Transform, KeyOfRes, AsyncData, PickFrom } from '#app'
5 | import { computed, isRef, Ref } from 'vue'
6 | import { useAsyncData, useNuxtApp } from '#imports'
7 | import { hash } from 'ohash'
8 |
9 | export type FetchResult = TypedInternalResponse
10 |
11 | type ComputedOptions> = {
12 | [K in keyof T]: T[K] extends Function ? T[K] : T[K] extends Record ? ComputedOptions | Ref | T[K] : Ref | T[K]
13 | }
14 |
15 | type ComputedFetchOptions = ComputedOptions
16 |
17 | export interface UseHttpOptions<
18 | DataT,
19 | Transform extends _Transform = _Transform,
20 | PickKeys extends KeyOfRes = KeyOfRes
21 | > extends AsyncDataOptions, ComputedFetchOptions {
22 | key?: string
23 | }
24 |
25 | export function useHttp<
26 | ResT = void,
27 | ErrorT = Error,
28 | ReqT extends NitroFetchRequest = NitroFetchRequest,
29 | _ResT = ResT extends void ? FetchResult : ResT,
30 | Transform extends (res: _ResT) => any = (res: _ResT) => _ResT,
31 | PickKeys extends KeyOfRes = KeyOfRes
32 | >(
33 | request: Ref | ReqT | (() => ReqT),
34 | opts?: UseHttpOptions<_ResT, Transform, PickKeys>
35 | ): AsyncData, PickKeys>, ErrorT | null | true>
36 | export function useHttp<
37 | ResT = void,
38 | ErrorT = Error,
39 | ReqT extends NitroFetchRequest = NitroFetchRequest,
40 | _ResT = ResT extends void ? FetchResult : ResT,
41 | Transform extends (res: _ResT) => any = (res: _ResT) => _ResT,
42 | PickKeys extends KeyOfRes = KeyOfRes
43 | >(
44 | request: Ref | ReqT | (() => ReqT),
45 | opts: UseHttpOptions<_ResT, Transform, PickKeys> = {}
46 | ) {
47 | if (!request) {
48 | throw new Error('[nuxt] [useHttp] request is missing.')
49 | }
50 |
51 | const key = (opts.key || '$h' + hash([request, { ...opts, transform: null }]))
52 |
53 | const _request = computed(() => {
54 | let r = request
55 | if (typeof r === 'function') {
56 | r = r()
57 | }
58 | return (isRef(r) ? r.value : r)
59 | })
60 |
61 | const {
62 | server,
63 | lazy,
64 | default: defaultFn,
65 | transform,
66 | pick,
67 | watch,
68 | initialCache,
69 | immediate,
70 | ...fetchOptions
71 | } = opts
72 |
73 | const _fetchOptions = reactive({
74 | ...fetchOptions,
75 | cache: typeof opts.cache === 'boolean' ? undefined : opts.cache
76 | })
77 |
78 | const _asyncDataOptions: AsyncDataOptions<_ResT, Transform, PickKeys> = {
79 | server,
80 | lazy,
81 | default: defaultFn,
82 | transform,
83 | pick,
84 | initialCache,
85 | immediate,
86 | watch: [
87 | _fetchOptions,
88 | _request,
89 | ...(watch || [])
90 | ]
91 | }
92 |
93 | const { $http } = useNuxtApp()
94 |
95 | const asyncData = useAsyncData<_ResT, ErrorT, Transform, PickKeys>(key, () => {
96 | //@ts-ignore: Ref does not contain toLowerCase() but will be converted
97 | const method = opts && opts.method && ['get', 'head', 'delete', 'post', 'put', 'patch'].includes(opts.method.toLowerCase()) ? opts.method.toLowerCase() : 'get'
98 | return $http['$' + method](_request.value, _fetchOptions) as Promise<_ResT>
99 | }, _asyncDataOptions)
100 |
101 | return asyncData
102 | }
103 |
104 | export function useLazyHttp<
105 | ResT = void,
106 | ErrorT = Error,
107 | ReqT extends NitroFetchRequest = NitroFetchRequest,
108 | _ResT = ResT extends void ? FetchResult : ResT,
109 | Transform extends (res: _ResT) => any = (res: _ResT) => _ResT,
110 | PickKeys extends KeyOfRes = KeyOfRes
111 | >(
112 | request: Ref | ReqT | (() => ReqT),
113 | opts?: Omit, 'lazy'>
114 | ): AsyncData, PickKeys>, ErrorT | null | true>
115 | export function useLazyHttp<
116 | ResT = void,
117 | ErrorT = Error,
118 | ReqT extends NitroFetchRequest = NitroFetchRequest,
119 | _ResT = ResT extends void ? FetchResult : ResT,
120 | Transform extends (res: _ResT) => any = (res: _ResT) => _ResT,
121 | PickKeys extends KeyOfRes = KeyOfRes
122 | >(
123 | request: Ref | ReqT | (() => ReqT),
124 | opts: Omit, 'lazy'> = {},
125 | ) {
126 |
127 | return useHttp(request, {
128 | ...opts,
129 | lazy: true
130 | })
131 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/http/src/module.ts:
--------------------------------------------------------------------------------
1 | import type { ModuleOptions } from './types'
2 | import type { Nuxt } from '@nuxt/schema'
3 | import { addTemplate, defineNuxtModule, addPluginTemplate, createResolver, addImports } from '@nuxt/kit'
4 | import { name, version } from '../package.json'
5 | import { withHttps } from 'ufo'
6 | import { defu } from 'defu'
7 |
8 | const CONFIG_KEY = 'http'
9 |
10 | export default defineNuxtModule({
11 | meta: {
12 | name,
13 | version,
14 | configKey: CONFIG_KEY,
15 | compatibility: {
16 | nuxt: '^3.0.0'
17 | },
18 | },
19 | defaults: {} as ModuleOptions,
20 | setup(opts: ModuleOptions, nuxt: Nuxt) {
21 | // Combine options with runtime config
22 | const moduleOptions: ModuleOptions = defu(nuxt.options.runtimeConfig?.public?.http, opts)
23 |
24 | // Default host
25 | const defaultHost = moduleOptions.host || process.env.NITRO_HOST || process.env.HOST || 'localhost'
26 |
27 | // Default port
28 | const defaultPort = moduleOptions.port || process.env.NITRO_PORT || process.env.PORT || 3000
29 |
30 | // Default prefix
31 | const prefix = moduleOptions.prefix || process.env.PREFIX || '/'
32 |
33 | // Apply defaults
34 | const options: ModuleOptions = defu(moduleOptions, {
35 | baseURL: `http://${defaultHost}:${defaultPort}${prefix}`,
36 | browserBaseURL: undefined,
37 | proxyHeaders: true,
38 | proxyHeadersIgnore: [
39 | 'accept',
40 | 'connection',
41 | 'cf-connecting-ip',
42 | 'cf-ray',
43 | 'content-length',
44 | 'content-md5',
45 | 'content-type',
46 | 'host',
47 | 'if-modified-since',
48 | 'if-none-match',
49 | 'x-forwarded-host',
50 | 'x-forwarded-port',
51 | 'x-forwarded-proto'
52 | ],
53 | serverTimeout: 10000,
54 | clientTimeout: 25000,
55 | https: false,
56 | retry: 1,
57 | headers: {
58 | accept: 'application/json, text/plain, */*'
59 | },
60 | credentials: 'omit',
61 | debug: false,
62 | interceptorPlugin: false
63 | })
64 |
65 | if (typeof options.browserBaseURL === 'undefined') {
66 | options.browserBaseURL = nuxt.options.app.baseURL
67 | }
68 |
69 | // Convert http:// to https:// if https option is on
70 | if (options.https === true) {
71 | options.baseURL = withHttps(options.baseURL as string)
72 | options.browserBaseURL = withHttps(options.browserBaseURL)
73 | }
74 |
75 | // resolver
76 | const resolver = createResolver(import.meta.url)
77 |
78 | // Requires proxy module
79 | if (Object.hasOwn(nuxt.options, 'proxy') && moduleOptions.interceptorPlugin) {
80 | addPluginTemplate({
81 | src: resolver.resolve('runtime/templates/interceptor.plugin.mjs'),
82 | filename: 'proxy.plugin.mjs',
83 | // @ts-ignore
84 | options: nuxt.options.proxy,
85 | })
86 | }
87 |
88 | // Register plugin
89 | addPluginTemplate({
90 | src: resolver.resolve('runtime/templates/http.plugin.mjs'),
91 | filename: 'http.plugin.mjs',
92 | options: options
93 | })
94 |
95 | addTemplate({
96 | getContents: () => getHttpDTS(),
97 | filename: 'http.plugin.d.ts',
98 | write: true,
99 | })
100 |
101 | // Add auto imports
102 | const composables = resolver.resolve('runtime/composables')
103 |
104 | addImports([
105 | { from: composables, name: 'useHttp' },
106 | { from: composables, name: 'useLazyHttp' }
107 | ])
108 |
109 | // Unsure if it works on windows still.
110 | if (process.platform !== "win32") {
111 | // create nitro plugin
112 | addTemplate({
113 | getContents: () => nitroHttp(),
114 | filename: `nitro-http.mjs`,
115 | write: true
116 | })
117 |
118 | nuxt.hook('nitro:config', (nitro) => {
119 | nitro.plugins = nitro.plugins || []
120 | nitro.plugins.push(resolver.resolve(nuxt.options.buildDir, `nitro-http.mjs`))
121 | })
122 | }
123 | }
124 | })
125 |
126 | function nitroHttp() {
127 | return `import { createInstance } from '@refactorjs/ofetch'
128 |
129 | export default function (nitroApp) {
130 | // should inherit defaults from $fetch
131 | globalThis.$http = createInstance({}, $fetch)
132 | }
133 | `
134 | }
135 |
136 | function getHttpDTS() {
137 | return `import type { Plugin } from '#app'
138 | import { FetchInstance } from '@refactorjs/ofetch'
139 |
140 | declare const _default: Plugin<{
141 | http: FetchInstance;
142 | }>;
143 |
144 | export default _default;
145 | `
146 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/readme.md:
--------------------------------------------------------------------------------
1 | **Information**
2 |
3 | This module is meant as an alternative to @nuxtjs/auth, except this is for nuxt3 only with no backwards compatibility support. This will only work with pinia, I had originally had it work with vuex, but since that is in maintenece mode, I decided to switch to pinia. If you find any bugs please do tell me, I'm still working on this.
4 |
5 | **Typescript**
6 |
7 | Please note, any issues regarding typescript is not a priorty for me. If you're having issues with it it'll be noted but not a priority, I normally have typescript disabled to focus on the functionality of the module.
8 |
9 | **Refactored (Version 2.0.0+)**
10 |
11 | The module now requires '@nuxtjs-alt/http' to function in version 2.0.0 and up, that module extends ohmyfetch. Please note that if you were using `data` to post data, you now need to use `body` since this is what `ohmyfetch` uses.
12 | Please tell me if you encounter any issues with these changes.
13 |
14 | **Composable**
15 |
16 | A `useAuth()` composable is available to utitlize if `$auth` from `useNuxtApp()` isnt working out for you in terms of type hinting.
17 |
18 | **Options/Extra Features**
19 |
20 | Besides what nuxt auth normally offers, here are some other options/changes
21 |
22 | - `globalMiddleware`: `boolean` (Default: false) - Enables/disables the middleware to be used globally
23 | - `enableMiddleware`: `boolean` (Default: true) - Enables/disables the built-in middleware
24 | - `pinia.namespace`: `string` (Default: 'auth') - Changed from vuex to pinia, this is the namespace to use for the pinia store
25 | - `sessionStorage`: `string|false` (Default: 'auth.') - Similar to the localstorage option, there is a session storage options available for you to use.
26 |
27 | **Cookie-based auth**
28 |
29 | If you have any specific changes that need to be made to accomodate cookie based-auth please tell me, at this moment the way I configured it is that it pretty much does the same thing as the official auth module cookie, but in cases where the server autmaitcally attaches the server cookie to all requests it will function conrrently (in this case setting a cookie on all requests via laravel).
30 |
31 | the config would look like this
32 |
33 | ```ts
34 | auth: {
35 | strategies: {
36 | localStorage: false,
37 | cookie: {
38 | cookie: {
39 | server: true, // by default this is set based on if nuxt ssr is enabled
40 | name: 'token',
41 | },
42 | endpoints: {
43 | csrf: false,
44 | login: {
45 | url: '/api/user/login',
46 | method: 'post'
47 | },
48 | user: {
49 | url: '/api/user/me',
50 | method: 'get'
51 | }
52 | },
53 | user: {
54 | property: {
55 | client: false,
56 | server: false
57 | },
58 | autoFetch: true
59 | }
60 | },
61 | }
62 | }
63 | ```
64 |
65 | notice the `cookie.server` property, this indicates that the cookie we will be looking for will be set upon login otherwise we will be looking at a client/browser cookie.
66 | the cookie scheme has been moved to its own scheme so the user property takes place within the cookie strategy and doesnt extend the token scheme from the local scheme. There has also been 2 user properties one for the client/browser and one for the server.
67 |
68 | **Laravel Sanctum**
69 |
70 | Laravel Sanctum wokrs a tiny bit differently, It inherits the same config as the Cookie scheme (see above) here's what the config would look like:
71 |
72 | ```ts
73 | auth: {
74 | strategies: {
75 | laravelSanctum: {
76 | provider: 'laravel/sanctum',
77 | cookie: {
78 | server: true, // by default this is set based on if nuxt ssr is enabled
79 | name: 'XSRF-TOKEN',
80 | },
81 | endpoints: {
82 | csrf: {
83 | url: '/sanctum/csrf-cookie'
84 | },
85 | login: {
86 | url: '/login'
87 | },
88 | logout: {
89 | url: '/logout'
90 | },
91 | user: {
92 | url: '/api/user'
93 | }
94 | },
95 | user: {
96 | property: {
97 | client: false,
98 | server: false
99 | },
100 | autoFetch: true
101 | }
102 | },
103 | }
104 | }
105 | ```
106 |
107 | **Oauth2**
108 |
109 | Oauth2 now has client window authentication thanks to this pull request: https://github.com/nuxt-community/auth-module/pull/1746
110 | properties have been changed to:
111 | - `clientWindow`: `boolean`
112 | - `clientWindowWidth`: `number`
113 | - `clientWindowHeight`: `number`
114 |
115 | **Aliases**
116 |
117 | Available Aliases:
118 | - `#auth/runtime`
119 | - `#auth/utils`
120 | - `#auth/providers`
121 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/inc/configuration-document.ts:
--------------------------------------------------------------------------------
1 | import { ConfigurationDocumentRequestError } from './configuration-document-request-error';
2 | import { OpenIDConnectScheme, OpenIDConnectSchemeEndpoints } from '../schemes';
3 | import { OpenIDConnectConfigurationDocument } from '../../types';
4 | import { Storage } from '../core/storage';
5 | import { defu } from 'defu';
6 |
7 | // eslint-disable-next-line no-console
8 | const ConfigurationDocumentWarning = (message: string) =>
9 | console.warn(`[AUTH] [OPENID CONNECT] Invalid configuration. ${message}`);
10 |
11 | /**
12 | * A metadata document that contains most of the OpenID Provider's information,
13 | * such as the URLs to use and the location of the service's public signing keys.
14 | * You can find this document by appending the discovery document path
15 | * (/.well-known/openid-configuration) to the authority URL(https://example.com)
16 | * Eg. https://example.com/.well-known/openid-configuration
17 | *
18 | * More info: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig
19 | */
20 | export class ConfigurationDocument {
21 | scheme: OpenIDConnectScheme;
22 | $storage: Storage;
23 | key: string;
24 |
25 | constructor(scheme: OpenIDConnectScheme, storage: Storage) {
26 | this.scheme = scheme;
27 | this.$storage = storage;
28 | this.key = '_configuration_document.' + this.scheme.name;
29 | }
30 |
31 | #set(value: OpenIDConnectConfigurationDocument | boolean) {
32 | return this.$storage.setState(this.key, value);
33 | }
34 |
35 | get(): OpenIDConnectConfigurationDocument {
36 | return this.$storage.getState(this.key);
37 | }
38 |
39 | set(value: OpenIDConnectConfigurationDocument | boolean) {
40 | this.#set(value);
41 |
42 | return value;
43 | }
44 |
45 | async request() {
46 | // Get Configuration document from state hydration
47 | // @ts-ignore
48 | const serverDoc: OpenIDConnectConfigurationDocument = this.scheme.$auth.ctx.payload!.data.$auth?.openIDConnect?.configurationDocument;
49 |
50 | if (process.client && serverDoc) {
51 | this.set(serverDoc);
52 | }
53 |
54 | if (!this.get()) {
55 | const configurationDocument = await this.scheme.requestHandler.http.$get(this.scheme.options.endpoints.configuration).catch((e: any) => Promise.reject(e));
56 |
57 | // Push Configuration document to state hydration
58 | if (process.server) {
59 | this.scheme.$auth.ctx.payload!.data = {
60 | ...this.scheme.$auth.ctx.payload!.data,
61 | $auth: {
62 | /* use `openIDConnect` instead of `oidc` because it could not be picked up by `serverDoc` */
63 | openIDConnect: {
64 | configurationDocument
65 | }
66 | }
67 | }
68 | }
69 |
70 | this.set(configurationDocument);
71 | }
72 | }
73 |
74 | validate() {
75 | const mapping = {
76 | responseType: 'response_types_supported',
77 | scope: 'scopes_supported',
78 | grantType: 'grant_types_supported',
79 | acrValues: 'acr_values_supported',
80 | };
81 |
82 | Object.keys(mapping).forEach((optionsKey) => {
83 | const configDocument: OpenIDConnectConfigurationDocument = this.get();
84 | const configDocumentKey = mapping[optionsKey as keyof typeof mapping];
85 | const configDocumentValues = configDocument[configDocumentKey as keyof typeof configDocument];
86 | const optionsValues = this.scheme.options[optionsKey as keyof typeof this.scheme.options];
87 |
88 | if (typeof configDocumentValues !== 'undefined') {
89 | if (Array.isArray(optionsValues) && Array.isArray(configDocumentValues)) {
90 | optionsValues.forEach((optionsValue) => {
91 | if (!configDocumentValues.includes(optionsValue)) {
92 | ConfigurationDocumentWarning(
93 | `A value of scheme options ${optionsKey} is not supported by ${configDocumentKey} of by Authorization Server.`
94 | );
95 | }
96 | });
97 | }
98 |
99 | if (!Array.isArray(optionsValues) && Array.isArray(configDocumentValues) && !configDocumentValues.includes(optionsValues as string)) {
100 | ConfigurationDocumentWarning(`Value of scheme option ${optionsKey} is not supported by ${configDocumentKey} of by Authorization Server.`);
101 | }
102 |
103 | if (!Array.isArray(optionsValues) && !Array.isArray(configDocumentValues) && configDocumentValues !== optionsValues) {
104 | ConfigurationDocumentWarning(`Value of scheme option ${optionsKey} is not supported by ${configDocumentKey} of by Authorization Server.`);
105 | }
106 | }
107 | });
108 | }
109 |
110 | async init() {
111 | await this.request().catch(() => {
112 | throw new ConfigurationDocumentRequestError();
113 | });
114 | this.validate();
115 | this.setSchemeEndpoints();
116 | }
117 |
118 | setSchemeEndpoints() {
119 | const configurationDocument = this.get();
120 |
121 | this.scheme.options.endpoints = defu(this.scheme.options.endpoints, {
122 | authorization: configurationDocument.authorization_endpoint,
123 | token: configurationDocument.token_endpoint,
124 | userInfo: configurationDocument.userinfo_endpoint,
125 | logout: configurationDocument.end_session_endpoint,
126 | }) as OpenIDConnectSchemeEndpoints;
127 | }
128 |
129 | reset() {
130 | this.#set(false);
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/schemes/cookie.ts:
--------------------------------------------------------------------------------
1 | import type { EndpointsOption, SchemePartialOptions, SchemeCheck, CookieUserOptions, HTTPRequest, HTTPResponse } from '../../types';
2 | import type { Auth } from '..';
3 | import { BaseScheme } from './base';
4 | import { getProp } from '../../utils';
5 | import { RequestHandler } from '../inc';
6 |
7 | export interface CookieSchemeEndpoints extends EndpointsOption {
8 | login: HTTPRequest;
9 | logout: HTTPRequest | false;
10 | user: HTTPRequest | false;
11 | csrf: HTTPRequest | false;
12 | }
13 |
14 | export interface CookieSchemeCookie {
15 | name: string;
16 | server: boolean;
17 | }
18 |
19 | export interface CookieSchemeOptions {
20 | name: string;
21 | endpoints: CookieSchemeEndpoints;
22 | user: CookieUserOptions;
23 | cookie: CookieSchemeCookie;
24 | }
25 |
26 | const DEFAULTS: SchemePartialOptions = {
27 | name: 'cookie',
28 | cookie: {
29 | name: undefined,
30 | server: false,
31 | },
32 | endpoints: {
33 | csrf: false,
34 | login: {
35 | url: '/api/auth/login',
36 | method: 'post',
37 | },
38 | logout: {
39 | url: '/api/auth/logout',
40 | method: 'post',
41 | },
42 | user: {
43 | url: '/api/auth/user',
44 | method: 'get',
45 | },
46 | },
47 | user: {
48 | property: {
49 | client: false,
50 | server: false,
51 | },
52 | autoFetch: true,
53 | },
54 | };
55 |
56 | export class CookieScheme extends BaseScheme {
57 | requestHandler: RequestHandler;
58 |
59 | constructor($auth: Auth, options: SchemePartialOptions, ...defaults: SchemePartialOptions[]) {
60 | super($auth, options as OptionsT, ...(defaults as OptionsT[]), DEFAULTS as OptionsT);
61 |
62 | // Initialize Request Interceptor
63 | this.requestHandler = new RequestHandler(this, this.$auth.ctx.$http);
64 | }
65 |
66 | async mounted(): Promise {
67 | if (process.server) {
68 | this.$auth.ctx.$http.setHeader('referer', this.$auth.ctx.ssrContext?.event.req.headers.host);
69 | }
70 |
71 | // Initialize request interceptor
72 | this.initializeRequestInterceptor();
73 |
74 | if (this.isServerCookie() || this.isClientCookie()) {
75 | // Fetch user once
76 | return this.$auth.fetchUserOnce();
77 | }
78 | }
79 |
80 | check(): SchemeCheck {
81 | const response = { valid: false };
82 |
83 | if (this.options.cookie.name) {
84 | const cookies = this.$auth.$storage.getCookies();
85 |
86 | if (this.isServerCookie() || this.isClientCookie()) {
87 | response.valid = Boolean(cookies![this.options.cookie.name]);
88 | } else {
89 | response.valid = true;
90 | }
91 |
92 | return response;
93 | }
94 |
95 | response.valid = true;
96 | return response;
97 | }
98 |
99 | async login(endpoint: HTTPRequest): Promise {
100 | // Ditch any leftover local tokens before attempting to log in
101 | this.$auth.reset();
102 |
103 | // Make CSRF request if required
104 | if (this.options.endpoints.csrf) {
105 | await this.$auth.request(this.options.endpoints.csrf);
106 | }
107 |
108 | if (!this.options.endpoints.login) {
109 | return;
110 | }
111 |
112 | // Make login request
113 | const response = await this.$auth.request(endpoint, this.options.endpoints.login);
114 |
115 | // Initialize request interceptor if not initialized
116 | if (!this.requestHandler.interceptor) {
117 | this.initializeRequestInterceptor();
118 | }
119 |
120 | // Fetch user if `autoFetch` is enabled
121 | if (this.options.user.autoFetch) {
122 | await this.fetchUser();
123 | }
124 |
125 | return response;
126 | }
127 |
128 | async fetchUser(endpoint?: HTTPRequest): Promise {
129 | if (this.isServerCookie() || this.isClientCookie()) {
130 | if (!this.check().valid) {
131 | return Promise.resolve();
132 | }
133 | }
134 |
135 | // User endpoint is disabled
136 | if (!this.options.endpoints.user) {
137 | this.$auth.setUser({});
138 | return Promise.resolve();
139 | }
140 |
141 | // Try to fetch user and then set
142 | return this.$auth
143 | .requestWith(endpoint, this.options.endpoints.user)
144 | .then((response) => {
145 | let userData: any;
146 |
147 | if (process.client) {
148 | userData = getProp(response, this.options.user.property.client);
149 | }
150 | else {
151 | userData = getProp(response, this.options.user.property.server);
152 | }
153 |
154 | if (!userData) {
155 | const error = new Error(`User Data response does not contain field ${this.options.user.property}`);
156 |
157 | return Promise.reject(error);
158 | }
159 |
160 | this.$auth.setUser(userData);
161 |
162 | return response;
163 | })
164 | .catch((error) => {
165 | this.$auth.callOnError(error, { method: 'fetchUser' });
166 | return Promise.reject(error);
167 | });
168 | }
169 |
170 | async logout(endpoint: HTTPRequest = {}): Promise {
171 | // Only connect to logout endpoint if it's configured
172 | if (this.options.endpoints.logout) {
173 | await this.$auth.requestWith(endpoint, this.options.endpoints.logout).catch((err: any) => console.error(err));
174 | }
175 |
176 | // But reset regardless
177 | this.$auth.redirect('logout');
178 | return this.$auth.reset();
179 | }
180 |
181 | reset({ resetInterceptor = true } = {}): void {
182 | if (this.options.cookie.name) {
183 | this.$auth.$storage.setCookie(this.options.cookie.name, null, {
184 | prefix: '',
185 | });
186 | }
187 |
188 | this.$auth.setUser(false);
189 |
190 | if (resetInterceptor) {
191 | this.requestHandler.reset();
192 | }
193 | }
194 |
195 | isServerCookie(): boolean {
196 | return this.options.cookie.server && process.server;
197 | }
198 |
199 | isClientCookie(): boolean {
200 | return !this.options.cookie.server && process.client;
201 | }
202 |
203 | initializeRequestInterceptor(): void {
204 | this.requestHandler.initializeRequestInterceptor();
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/schemes/refresh.ts:
--------------------------------------------------------------------------------
1 | import type { HTTPRequest, HTTPResponse, RefreshableScheme, RefreshableSchemeOptions, SchemeCheck, SchemePartialOptions } from '../../types';
2 | import type { Auth } from '..';
3 | import { cleanObj, getProp } from '../../utils';
4 | import { RefreshController, RefreshToken, ExpiredAuthSessionError } from '../inc';
5 | import { LocalScheme, LocalSchemeEndpoints, LocalSchemeOptions } from './local';
6 |
7 | export interface RefreshSchemeEndpoints extends LocalSchemeEndpoints {
8 | refresh: HTTPRequest;
9 | }
10 |
11 | export interface RefreshSchemeOptions extends LocalSchemeOptions, RefreshableSchemeOptions {
12 | endpoints: RefreshSchemeEndpoints;
13 | autoLogout: boolean;
14 | }
15 |
16 | const DEFAULTS: SchemePartialOptions = {
17 | name: 'refresh',
18 | endpoints: {
19 | refresh: {
20 | url: '/api/auth/refresh',
21 | method: 'post',
22 | },
23 | },
24 | refreshToken: {
25 | property: 'refresh_token',
26 | data: 'refresh_token',
27 | maxAge: 60 * 60 * 24 * 30,
28 | required: true,
29 | tokenRequired: false,
30 | prefix: '_refresh_token.',
31 | expirationPrefix: '_refresh_token_expiration.',
32 | },
33 | autoLogout: false,
34 | };
35 |
36 | export class RefreshScheme extends LocalScheme implements RefreshableScheme
37 | {
38 | refreshToken: RefreshToken;
39 | refreshController: RefreshController;
40 |
41 | constructor($auth: Auth, options: SchemePartialOptions) {
42 | super($auth, options, DEFAULTS);
43 |
44 | // Initialize Refresh Token instance
45 | this.refreshToken = new RefreshToken(this, this.$auth.$storage);
46 |
47 | // Initialize Refresh Controller
48 | this.refreshController = new RefreshController(this);
49 | }
50 |
51 | check(checkStatus = false): SchemeCheck {
52 | const response = {
53 | valid: false,
54 | tokenExpired: false,
55 | refreshTokenExpired: false,
56 | isRefreshable: true,
57 | };
58 |
59 | // Sync tokens
60 | const token = this.token.sync();
61 | const refreshToken = this.refreshToken.sync();
62 |
63 | // Token and refresh token are required but not available
64 | if (!token || !refreshToken) {
65 | return response;
66 | }
67 |
68 | // Check status wasn't enabled, let it pass
69 | if (!checkStatus) {
70 | response.valid = true;
71 | return response;
72 | }
73 |
74 | // Get status
75 | const tokenStatus = this.token.status();
76 | const refreshTokenStatus = this.refreshToken.status();
77 |
78 | // Refresh token has expired. There is no way to refresh. Force reset.
79 | if (refreshTokenStatus.expired()) {
80 | response.refreshTokenExpired = true;
81 | return response;
82 | }
83 |
84 | // Token has expired, Force reset.
85 | if (tokenStatus.expired()) {
86 | response.tokenExpired = true;
87 | return response;
88 | }
89 |
90 | response.valid = true;
91 | return response;
92 | }
93 |
94 | mounted(): Promise {
95 | return super.mounted({
96 | tokenCallback: () => {
97 | if (this.options.autoLogout) {
98 | this.$auth.reset();
99 | }
100 | },
101 | // @ts-ignore
102 | refreshTokenCallback: () => {
103 | this.$auth.reset();
104 | },
105 | });
106 | }
107 |
108 | async refreshTokens(): Promise {
109 | // Refresh endpoint is disabled
110 | if (!this.options.endpoints.refresh) {
111 | return Promise.resolve();
112 | }
113 |
114 | // Token and refresh token are required but not available
115 | if (!this.check().valid) {
116 | return Promise.resolve();
117 | }
118 |
119 | // Get refresh token status
120 | const refreshTokenStatus = this.refreshToken.status();
121 |
122 | // Refresh token is expired. There is no way to refresh. Force reset.
123 | if (refreshTokenStatus.expired()) {
124 | this.$auth.reset();
125 |
126 | throw new ExpiredAuthSessionError();
127 | }
128 |
129 | // Delete current token from the request header before refreshing, if `tokenRequired` is disabled
130 | if (!this.options.refreshToken.tokenRequired) {
131 | this.requestHandler.clearHeader();
132 | }
133 |
134 | const endpoint: {
135 | body: {
136 | [key: string]: string | boolean | undefined
137 | client_id: string | undefined,
138 | grant_type: string | undefined,
139 | },
140 | } = {
141 | body: {
142 | client_id: undefined,
143 | grant_type: undefined,
144 | },
145 | };
146 |
147 | // Add refresh token to payload if required
148 | if (this.options.refreshToken.required && this.options.refreshToken.data) {
149 | endpoint.body[this.options.refreshToken.data] = this.refreshToken.get();
150 | }
151 |
152 | // Add client id to payload if defined
153 | if (this.options.clientId) {
154 | endpoint.body.client_id = this.options.clientId;
155 | }
156 |
157 | // Add grant type to payload if defined
158 | if (this.options.grantType) {
159 | endpoint.body.grant_type = 'refresh_token';
160 | }
161 |
162 | cleanObj(endpoint.body);
163 |
164 | // Make refresh request
165 | try {
166 | const response = await this.$auth.request(endpoint, this.options.endpoints.refresh);
167 | // Update tokens
168 | this.updateTokens(response, { isRefreshing: true });
169 | return await response;
170 | } catch (error: any) {
171 | this.$auth.callOnError(error, { method: 'refreshToken' });
172 | return await Promise.reject(error);
173 | }
174 | }
175 |
176 | setUserToken(token: string | boolean, refreshToken?: string | boolean): Promise {
177 | this.token.set(token);
178 |
179 | if (refreshToken) {
180 | this.refreshToken.set(refreshToken);
181 | }
182 |
183 | // Fetch user
184 | return this.fetchUser();
185 | }
186 |
187 | reset({ resetInterceptor = true } = {}): void {
188 | this.$auth.setUser(false);
189 | this.token.reset();
190 | this.refreshToken.reset();
191 |
192 | if (resetInterceptor) {
193 | this.requestHandler.reset();
194 | }
195 | }
196 |
197 | protected updateTokens(response: HTTPResponse, { isRefreshing = false, updateOnRefresh = true } = {}): void {
198 | const token = this.options.token?.required ? (getProp(response, this.options.token.property) as string) : true;
199 | const refreshToken = this.options.refreshToken.required ? (getProp(response, this.options.refreshToken.property) as string) : true;
200 |
201 | this.token.set(token);
202 |
203 | // Update refresh token if defined and if `isRefreshing` is `false`
204 | // If `isRefreshing` is `true`, then only update if `updateOnRefresh` is also `true`
205 | if (refreshToken && (!isRefreshing || (isRefreshing && updateOnRefresh))) {
206 | this.refreshToken.set(refreshToken);
207 | }
208 | }
209 |
210 | protected initializeRequestInterceptor(): void {
211 | this.requestHandler.initializeRequestInterceptor(
212 | this.options.endpoints.refresh.url
213 | );
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/schemes/local.ts:
--------------------------------------------------------------------------------
1 | import type { EndpointsOption, SchemePartialOptions, TokenableSchemeOptions, TokenableScheme, UserOptions, HTTPRequest, HTTPResponse, SchemeCheck } from '../../types';
2 | import type { Auth } from '..';
3 | import { getProp } from '../../utils';
4 | import { Token, RequestHandler } from '../inc';
5 | import { BaseScheme } from './base';
6 |
7 | export interface LocalSchemeEndpoints extends EndpointsOption {
8 | login: HTTPRequest;
9 | logout: HTTPRequest | false;
10 | user: HTTPRequest | false;
11 | }
12 |
13 | export interface LocalSchemeOptions extends TokenableSchemeOptions {
14 | endpoints: LocalSchemeEndpoints;
15 | user: UserOptions;
16 | clientId: string | false;
17 | grantType: string | false;
18 | scope: string[] | false;
19 | }
20 |
21 | const DEFAULTS: SchemePartialOptions = {
22 | name: 'local',
23 | endpoints: {
24 | login: {
25 | url: '/api/auth/login',
26 | method: 'post',
27 | },
28 | logout: {
29 | url: '/api/auth/logout',
30 | method: 'post',
31 | },
32 | user: {
33 | url: '/api/auth/user',
34 | method: 'get',
35 | },
36 | },
37 | token: {
38 | property: 'token',
39 | type: 'Bearer',
40 | name: 'Authorization',
41 | maxAge: 1800,
42 | global: true,
43 | required: true,
44 | prefix: '_token.',
45 | expirationPrefix: '_token_expiration.',
46 | },
47 | user: {
48 | property: 'user',
49 | autoFetch: true,
50 | },
51 | clientId: false,
52 | grantType: false,
53 | scope: false,
54 | };
55 |
56 | export class LocalScheme extends BaseScheme implements TokenableScheme
57 | {
58 | token: Token;
59 | requestHandler: RequestHandler;
60 |
61 | constructor($auth: Auth, options: SchemePartialOptions, ...defaults: SchemePartialOptions[]) {
62 | super($auth, options as OptionsT, ...(defaults as OptionsT[]), DEFAULTS as OptionsT);
63 |
64 | // Initialize Token instance
65 | this.token = new Token(this, this.$auth.$storage);
66 |
67 | // Initialize Request Interceptor
68 | this.requestHandler = new RequestHandler(this, this.$auth.ctx.$http);
69 | }
70 |
71 | check(checkStatus = false): SchemeCheck {
72 | const response = {
73 | valid: false,
74 | tokenExpired: false,
75 | };
76 |
77 | // Sync token
78 | const token = this.token.sync();
79 |
80 | // Token is required but not available
81 | if (!token) {
82 | return response;
83 | }
84 |
85 | // Check status wasn't enabled, let it pass
86 | if (!checkStatus) {
87 | response.valid = true;
88 | return response;
89 | }
90 |
91 | // Get status
92 | const tokenStatus = this.token.status();
93 |
94 | // Token has expired. Attempt `tokenCallback`
95 | if (tokenStatus.expired()) {
96 | response.tokenExpired = true;
97 | return response;
98 | }
99 |
100 | response.valid = true;
101 | return response;
102 | }
103 |
104 | mounted({ tokenCallback = () => this.$auth.reset(), refreshTokenCallback = undefined } = {}): Promise {
105 | const { tokenExpired, refreshTokenExpired } = this.check(true);
106 |
107 | if (refreshTokenExpired && typeof refreshTokenCallback === 'function') {
108 | //@ts-ignore
109 | refreshTokenCallback();
110 | } else if (tokenExpired && typeof tokenCallback === 'function') {
111 | tokenCallback();
112 | }
113 |
114 | // Initialize request interceptor
115 | this.initializeRequestInterceptor();
116 |
117 | // Fetch user once
118 | return this.$auth.fetchUserOnce();
119 | }
120 |
121 | async login(endpoint: HTTPRequest, { reset = true } = {}): Promise {
122 | if (!this.options.endpoints.login) {
123 | return;
124 | }
125 |
126 | // Ditch any leftover local tokens before attempting to log in
127 | if (reset) {
128 | this.$auth.reset({ resetInterceptor: false });
129 | }
130 |
131 | // Add client id to payload if defined
132 | if (this.options.clientId) {
133 | endpoint.body!['client_id' as keyof BodyInit] = this.options.clientId as keyof BodyInit;
134 | }
135 |
136 | // Add grant type to payload if defined
137 | if (this.options.grantType) {
138 | endpoint.body!['grant_type' as keyof BodyInit] = this.options.grantType as keyof BodyInit;
139 | }
140 |
141 | // Add scope to payload if defined
142 | if (this.options.scope) {
143 | endpoint.body!['scope' as keyof BodyInit] = this.options.scope as keyof BodyInit;
144 | }
145 |
146 | // Make login request
147 | const response = await this.$auth.request(endpoint, this.options.endpoints.login);
148 |
149 | // Update tokens
150 | this.updateTokens(response);
151 |
152 | // Initialize request interceptor if not initialized
153 | if (!this.requestHandler.interceptor) {
154 | this.initializeRequestInterceptor();
155 | }
156 |
157 | // Fetch user if `autoFetch` is enabled
158 | if (this.options.user.autoFetch) {
159 | await this.fetchUser();
160 | }
161 |
162 | return response;
163 | }
164 |
165 | setUserToken(token: string): Promise {
166 | this.token.set(token);
167 |
168 | // Fetch user
169 | return this.fetchUser();
170 | }
171 |
172 | async fetchUser(endpoint?: HTTPRequest): Promise {
173 | // Token is required but not available
174 | if (!this.check().valid) {
175 | return Promise.resolve();
176 | }
177 |
178 | // User endpoint is disabled
179 | if (!this.options.endpoints.user) {
180 | this.$auth.setUser({});
181 | return Promise.resolve();
182 | }
183 |
184 | // Try to fetch user and then set
185 | return this.$auth
186 | .requestWith(endpoint, this.options.endpoints.user)
187 | .then((response) => {
188 | const userData = getProp(response, this.options.user.property!);
189 |
190 | if (!userData) {
191 | const error = new Error(`User Data response does not contain field ${this.options.user.property}`);
192 | return Promise.reject(error);
193 | }
194 |
195 | this.$auth.setUser(userData);
196 | return response;
197 | })
198 | .catch((error) => {
199 | this.$auth.callOnError(error, { method: 'fetchUser' });
200 | return Promise.reject(error);
201 | });
202 | }
203 |
204 | async logout(endpoint: HTTPRequest = {}): Promise {
205 | // Only connect to logout endpoint if it's configured
206 | if (this.options.endpoints.logout) {
207 | await this.$auth.requestWith(endpoint, this.options.endpoints.logout).catch((err: any) => console.error(err));
208 | }
209 |
210 | // But reset regardless
211 | this.$auth.redirect('logout');
212 | return this.$auth.reset();
213 | }
214 |
215 | reset({ resetInterceptor = true } = {}): void {
216 | this.$auth.setUser(false);
217 | this.token.reset();
218 |
219 | if (resetInterceptor) {
220 | this.requestHandler.reset();
221 | }
222 | }
223 |
224 | protected updateTokens(response: HTTPResponse): void {
225 | const token = this.options.token?.required ? (getProp(response, this.options.token.property) as string) : true;
226 |
227 | this.token.set(token);
228 | }
229 |
230 | protected initializeRequestInterceptor(): void {
231 | this.requestHandler.initializeRequestInterceptor();
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/@nuxtjs-alt/axios/src/runtime/templates/axios.plugin.mjs:
--------------------------------------------------------------------------------
1 | import { defineNuxtPlugin } from '#imports'
2 | import Axios from 'axios'
3 | '<% if (options.retry) { %>'
4 | import axiosRetry from 'axios-retry'
5 | '<% } %>'
6 |
7 | // Axios.prototype cannot be modified
8 | const axiosExtra = {
9 | setBaseURL(baseURL) {
10 | this.defaults.baseURL = baseURL
11 | },
12 | setHeader(name, value, scopes = 'common') {
13 | for (const scope of Array.isArray(scopes) ? scopes : [scopes]) {
14 | if (!value) {
15 | delete this.defaults.headers[scope][name];
16 | continue
17 | }
18 | this.defaults.headers[scope][name] = value
19 | }
20 | },
21 | setToken(token, type, scopes = 'common') {
22 | const value = !token ? null : (type ? type + ' ' : '') + token
23 | this.setHeader('Authorization', value, scopes)
24 | },
25 | onRequest(fn) {
26 | this.interceptors.request.use(config => fn(config) || config)
27 | },
28 | onResponse(fn) {
29 | this.interceptors.response.use(response => fn(response) || response)
30 | },
31 | onRequestError(fn) {
32 | this.interceptors.request.use(undefined, error => fn(error) || Promise.reject(error))
33 | },
34 | onResponseError(fn) {
35 | this.interceptors.response.use(undefined, error => fn(error) || Promise.reject(error))
36 | },
37 | onError(fn) {
38 | this.onRequestError(fn)
39 | this.onResponseError(fn)
40 | },
41 | create(options) {
42 | return createAxiosInstance({ ...this.defaults, ...options })
43 | }
44 | }
45 |
46 | // Request helpers ($get, $post, ...)
47 | for (const method of ['request', 'delete', 'get', 'head', 'options', 'post', 'put', 'patch']) {
48 | axiosExtra['$' + method] = function () { return this[method].apply(this, arguments).then(res => res && res.data) }
49 | }
50 |
51 | const extendAxiosInstance = axios => {
52 | for (const key in axiosExtra) {
53 | axios[key] = axiosExtra[key].bind(axios)
54 | }
55 | }
56 |
57 | const createAxiosInstance = axiosOptions => {
58 | // Create new axios instance
59 | const axios = Axios.create(axiosOptions)
60 | axios.CancelToken = Axios.CancelToken
61 | axios.isCancel = Axios.isCancel
62 | axios.isAxiosError = Axios.isAxiosError
63 |
64 | // Extend axios proto
65 | extendAxiosInstance(axios)
66 |
67 | // Intercept to apply default headers
68 | axios.onRequest((config) => {
69 | config.headers = { ...axios.defaults.headers.common, ...config.headers }
70 | })
71 |
72 | // Setup interceptors
73 | '<% if (options.debug) { %>'; setupDebugInterceptor(axios); '<% } %>'
74 | '<% if (options.credentials) { %>'; setupCredentialsInterceptor(axios); '<% } %>'
75 | '<% if (options.progress) { %>'; setupProgress(axios); '<% } %>'
76 | '<% if (options.retry) { %>'; axiosRetry(axios, JSON.parse('<%= JSON.stringify(options.retry) %>')); '<% } %>'
77 |
78 | return axios
79 | }
80 |
81 | '<% if (options.debug) { %>'
82 | const log = (level, ...messages) => console[level]('[Axios]', ...messages)
83 |
84 | const setupDebugInterceptor = axios => {
85 | // request
86 | axios.onRequestError(error => {
87 | log('error', 'Request error:', error)
88 | })
89 |
90 | // response
91 | axios.onResponseError(error => {
92 | log('error', 'Response error:', error)
93 | })
94 | axios.onResponse(res => {
95 | log(
96 | 'info',
97 | '[' + (res.status + ' ' + res.statusText) + ']',
98 | '[' + res.config.method.toUpperCase() + ']',
99 | res.config.url)
100 |
101 | if (process.client) {
102 | console.log(res)
103 | } else {
104 | console.log(JSON.stringify(res.data, undefined, 2))
105 | }
106 |
107 | return res
108 | })
109 | }
110 | '<% } %>'
111 |
112 | '<% if (options.credentials) { %>'
113 | const setupCredentialsInterceptor = axios => {
114 | // Send credentials only to relative and API Backend requests
115 | axios.onRequest(config => {
116 | if (config.withCredentials === undefined) {
117 | if (!/^https?:\/\//i.test(config.url) || config.url.indexOf(config.baseURL) === 0) {
118 | config.withCredentials = true
119 | }
120 | }
121 | })
122 | }
123 | '<% } %>'
124 |
125 | '<% if (options.progress) { %>'
126 | const setupProgress = (axios) => {
127 | if (process.server) {
128 | return
129 | }
130 |
131 | // A noop loading inteterface for when $nuxt is not yet ready
132 | const noopLoading = {
133 | finish: () => { },
134 | start: () => { },
135 | fail: () => { },
136 | set: () => { }
137 | }
138 |
139 | const $loading = () => {
140 | const $nuxt = typeof window !== 'undefined' && window['$<%= options.globalName %>']
141 | return ($nuxt && $nuxt.$loading && $nuxt.$loading.set) ? $nuxt.$loading : noopLoading
142 | }
143 |
144 | let currentRequests = 0
145 |
146 | axios.onRequest(config => {
147 | if (config && config.progress === false) {
148 | return
149 | }
150 |
151 | currentRequests++
152 | })
153 |
154 | axios.onResponse(response => {
155 | if (response && response.config && response.config.progress === false) {
156 | return
157 | }
158 |
159 | currentRequests--
160 | if (currentRequests <= 0) {
161 | currentRequests = 0
162 | $loading().finish()
163 | }
164 | })
165 |
166 | axios.onError(error => {
167 | if (error && error.config && error.config.progress === false) {
168 | return
169 | }
170 |
171 | currentRequests--
172 |
173 | if (Axios.isCancel(error)) {
174 | if (currentRequests <= 0) {
175 | currentRequests = 0
176 | $loading().finish()
177 | }
178 | return
179 | }
180 |
181 | $loading().fail()
182 | $loading().finish()
183 | })
184 |
185 | const onProgress = e => {
186 | if (!currentRequests || !e.total) {
187 | return
188 | }
189 | const progress = ((e.loaded * 100) / (e.total * currentRequests))
190 | $loading().set(Math.min(100, progress))
191 | }
192 |
193 | axios.defaults.onUploadProgress = onProgress
194 | axios.defaults.onDownloadProgress = onProgress
195 | }
196 | '<% } %>'
197 |
198 | export default defineNuxtPlugin(ctx => {
199 | // runtimeConfig
200 | const runtimeConfig = ctx.$config && ctx.$config.public.axios || {}
201 |
202 | // Nuxt Options
203 | const nuxtOptions = JSON.parse('<%= JSON.stringify(options) %>')
204 |
205 | // baseURL
206 | const baseURL = process.client ? (runtimeConfig.browserBaseURL || runtimeConfig.browserBaseUrl || runtimeConfig.baseURL || runtimeConfig.baseUrl || nuxtOptions.browserBaseURL || '') : (runtimeConfig.baseURL || runtimeConfig.baseUrl || process.env._AXIOS_BASE_URL_ || nuxtOptions.baseURL || '')
207 |
208 | const axiosOptions = {
209 | baseURL,
210 | headers: nuxtOptions.headers,
211 | }
212 |
213 | if (nuxtOptions.proxyHeaders) {
214 | // Proxy SSR request headers
215 | if (process.server && ctx.ssrContext?.event.req && ctx.ssrContext?.event.req.headers) {
216 | const reqHeaders = { ...ctx.ssrContext?.event.req.headers }
217 | for (const h of nuxtOptions.proxyHeadersIgnore) {
218 | delete reqHeaders[h]
219 | }
220 |
221 | axiosOptions.headers.common = { ...reqHeaders, ...axiosOptions.headers.common }
222 | }
223 | }
224 |
225 | if (process.server) {
226 | // Don't accept brotli encoding because Node can't parse it
227 | axiosOptions.headers.common['accept-encoding'] = 'gzip, deflate'
228 | }
229 |
230 | const axios = createAxiosInstance(axiosOptions)
231 |
232 | globalThis['$axios'] = axios
233 | ctx.provide('axios', axios);
234 | })
--------------------------------------------------------------------------------
/@nuxtjs-alt/proxy/src/module.ts:
--------------------------------------------------------------------------------
1 | import { addServerHandler, addTemplate, addPluginTemplate, createResolver, defineNuxtModule } from '@nuxt/kit'
2 | import { name, version } from '../package.json'
3 | import { ModuleOptions, ProxyOptions } from './types'
4 | import { defu } from 'defu'
5 |
6 | const CONFIG_KEY = 'proxy'
7 |
8 | export default defineNuxtModule({
9 | meta: {
10 | name,
11 | version,
12 | configKey: CONFIG_KEY,
13 | compatibility: {
14 | nuxt: '^3.0.0'
15 | }
16 | },
17 | defaults: {
18 | enableProxy: true,
19 | fetch: false
20 | },
21 | setup(options, nuxt) {
22 | const config = (nuxt.options.runtimeConfig.proxy = defu(nuxt.options.runtimeConfig.proxy, options)) as ModuleOptions
23 | const resolver = createResolver(import.meta.url)
24 | const defaultHost = process.env.NITRO_HOST || process.env.HOST || 'localhost'
25 | const defaultPort = process.env.NITRO_PORT || process.env.PORT || 3000
26 |
27 | if (config.enableProxy) {
28 | // Create Proxy
29 | addTemplate({
30 | filename: 'nuxt-proxy.ts',
31 | write: true,
32 | getContents: () => proxyMiddlewareContent(config.proxies ?? {})
33 | })
34 |
35 | addServerHandler({
36 | handler: resolver.resolve(nuxt.options.buildDir, 'nuxt-proxy.ts'),
37 | middleware: true
38 | })
39 | }
40 |
41 | if (config.fetch) {
42 | // Create Interceptor
43 | addPluginTemplate({
44 | src: resolver.resolve('runtime/fetch.interceptor.mjs'),
45 | filename: 'fetch.interceptor.mjs',
46 | options: config
47 | })
48 |
49 | nuxt.options.build.transpile.push(resolver.resolve('runtime'))
50 | }
51 |
52 | // Don't know if it runs on windows still.
53 | if (config.fetch && process.platform !== "win32") {
54 | // create nitro plugin
55 | addTemplate({
56 | getContents: () => nitroFetchProxy(defaultHost, defaultPort),
57 | filename: 'nitro-fetch.mjs',
58 | write: true
59 | })
60 |
61 | nuxt.hook('nitro:config', (nitro) => {
62 | nitro.plugins = nitro.plugins || []
63 | nitro.plugins.push(resolver.resolve(nuxt.options.buildDir, 'nitro-fetch.mjs'))
64 | })
65 | }
66 | }
67 | })
68 |
69 | function nitroFetchProxy(host: string, port: number | string): string {
70 | return `import { createFetch, Headers } from 'ofetch'
71 |
72 | export default function (nitroApp) {
73 | // the proxy module needs the host and port of the nitro server in order for it to proxy it properly.
74 | // By default only a path is being submitted so this will chnage it to the host and port
75 | globalThis.$fetch = createFetch({ fetch: nitroApp.localFetch, Headers, defaults: { baseURL: 'http://${host}:${port}' } })
76 | }
77 | `
78 | }
79 |
80 | function converter(key: string, val: any) {
81 | if (typeof val === 'function' || val && val.constructor === RegExp) {
82 | return String(val)
83 | }
84 | return val
85 | }
86 |
87 | function proxyMiddlewareContent(options: ProxyOptions): string {
88 | return `import * as http from 'node:http'
89 | import * as net from 'node:net'
90 | import { createProxyServer, ProxyServer, Server } from '@refactorjs/http-proxy'
91 | import { defineEventHandler } from 'h3'
92 |
93 | interface ProxyOptions extends Server.ServerOptions {
94 | /**
95 | * rewrite path
96 | */
97 | rewrite?: (path: string) => string | null | undefined | false
98 |
99 | /**
100 | * configure the proxy server (e.g. listen to events)
101 | */
102 | configure?: (proxy: ProxyServer, options: ProxyOptions) => void | null | undefined | false
103 |
104 | /**
105 | * webpack-dev-server style bypass function
106 | */
107 | bypass?: (
108 | req: http.IncomingMessage,
109 | res: http.ServerResponse,
110 | options: ProxyOptions
111 | ) => void | null | undefined | false | string
112 | }
113 |
114 | // lazy require only when proxy is used
115 | const proxies: Record = {}
116 | const options: { [key: string]: string | ProxyOptions } | undefined = ${JSON.stringify(options, converter)};
117 |
118 | Object.keys(options!).forEach((context) => {
119 | let opts = options![context]
120 |
121 | if (!opts) return
122 |
123 | if (typeof opts === 'string') {
124 | opts = { target: opts, changeOrigin: true } as ProxyOptions
125 | }
126 |
127 | if (isObject(opts)) {
128 | opts = { changeOrigin: true, ...opts } as ProxyOptions
129 | opts.rewrite = opts.rewrite ? new Function("return (" + opts.rewrite + ")")() : false
130 | opts.configure = opts.configure ? new Function("return (" + opts.configure + ")")() : false
131 | opts.bypass = opts.bypass ? new Function("return (" + opts.bypass + ")")() : false
132 | }
133 |
134 | const proxy = createProxyServer(opts)
135 |
136 | proxy.on('error', (err, req, originalRes) => {
137 | // When it is ws proxy, res is net.Socket
138 | const res = originalRes as http.ServerResponse | net.Socket
139 | if ('req' in res) {
140 | console.error('http proxy error:' + err.stack, {
141 | timestamp: true,
142 | error: err
143 | })
144 | if (!res.headersSent && !res.writableEnded) {
145 | res.writeHead(500, {
146 | 'Content-Type': 'text/plain'
147 | })
148 | .end()
149 | }
150 | } else {
151 | console.error('ws proxy error:' + err.stack, {
152 | timestamp: true,
153 | error: err
154 | })
155 | res.end()
156 | }
157 | })
158 |
159 | if (opts.configure) {
160 | opts.configure(proxy, opts)
161 | }
162 |
163 | // clone before saving because http-proxy mutates the options
164 | proxies[context] = [proxy, { ...opts }]
165 | })
166 |
167 | export default defineEventHandler(async (event) => {
168 | await new Promise((resolve, reject) => {
169 | const next = (err?: unknown) => {
170 | if (err) {
171 | reject(err)
172 | } else {
173 | resolve()
174 | }
175 | }
176 |
177 | const url = event.req.url!
178 |
179 | for (const context in proxies) {
180 | if (doesProxyContextMatchUrl(context, url)) {
181 | const [proxy, opts] = proxies[context]
182 | const options: Server.ServerOptions = {}
183 |
184 | if (opts.bypass) {
185 | const bypassResult = opts.bypass(event.req, event.res, opts)
186 | if (typeof bypassResult === 'string') {
187 | event.req.url = bypassResult
188 | console.debug('bypass: ' + event.req.url + ' -> ' + bypassResult)
189 | return next()
190 | } else if (isObject(bypassResult)) {
191 | Object.assign(options, bypassResult)
192 | console.debug('bypass: ' + event.req.url + ' use modified options: %O', options)
193 | return next()
194 | } else if (bypassResult === false) {
195 | console.debug('bypass: ' + event.req.url + ' -> 404')
196 | return event.res.end(404)
197 | }
198 | }
199 |
200 | console.debug(event.req.url + ' -> ' + opts.target || opts.forward)
201 |
202 | if (opts.rewrite) {
203 | event.req.url = opts.rewrite(event.req.url!) as string
204 | }
205 |
206 | proxy.web(event.req, event.res, options)
207 | return
208 | }
209 | }
210 | next()
211 | })
212 | })
213 |
214 | function isObject(value: unknown): value is Record {
215 | return Object.prototype.toString.call(value) === '[object Object]'
216 | }
217 |
218 | function doesProxyContextMatchUrl(context: string, url: string): boolean {
219 | return (
220 | (context.startsWith('^') && new RegExp(context).test(url)) || url.startsWith(context)
221 | )
222 | }
223 | `
224 | }
--------------------------------------------------------------------------------
/@nuxtjs-alt/auth/src/runtime/schemes/openIDConnect.ts:
--------------------------------------------------------------------------------
1 | import type { HTTPResponse, SchemeCheck, SchemePartialOptions } from '../../types';
2 | import type { Auth } from '..';
3 | import { Oauth2Scheme, Oauth2SchemeEndpoints, Oauth2SchemeOptions } from './oauth2';
4 | import { normalizePath, getProp } from '../../utils';
5 | import { IdToken, ConfigurationDocument } from '../inc';
6 | import { IdTokenableSchemeOptions } from '../../types';
7 | import { useRoute } from '#imports';
8 | import { getQuery, withQuery, QueryObject, QueryValue } from 'ufo'
9 |
10 | export interface OpenIDConnectSchemeEndpoints extends Oauth2SchemeEndpoints {
11 | configuration: string;
12 | }
13 |
14 | export interface OpenIDConnectSchemeOptions extends Oauth2SchemeOptions, IdTokenableSchemeOptions {
15 | endpoints: OpenIDConnectSchemeEndpoints;
16 | }
17 |
18 | const DEFAULTS: SchemePartialOptions = {
19 | name: 'openIDConnect',
20 | responseType: 'code',
21 | grantType: 'authorization_code',
22 | scope: ['openid', 'profile', 'offline_access'],
23 | idToken: {
24 | property: 'id_token',
25 | maxAge: 1800,
26 | prefix: '_id_token.',
27 | expirationPrefix: '_id_token_expiration.',
28 | },
29 | codeChallengeMethod: 'S256',
30 | };
31 |
32 | export class OpenIDConnectScheme extends Oauth2Scheme {
33 | idToken: IdToken;
34 | configurationDocument: ConfigurationDocument;
35 |
36 | constructor($auth: Auth, options: SchemePartialOptions, ...defaults: SchemePartialOptions[]) {
37 | super($auth, options as OptionsT, ...(defaults as OptionsT[]), DEFAULTS as OptionsT);
38 |
39 | // Initialize ID Token instance
40 | this.idToken = new IdToken(this, this.$auth.$storage);
41 |
42 | // Initialize ConfigurationDocument
43 | this.configurationDocument = new ConfigurationDocument(this, this.$auth.$storage);
44 | }
45 |
46 | protected updateTokens(response: HTTPResponse): void {
47 | super.updateTokens(response);
48 | const idToken = getProp(response, this.options.idToken.property) as string;
49 |
50 | if (idToken) {
51 | this.idToken.set(idToken);
52 | }
53 | }
54 |
55 | check(checkStatus = false): SchemeCheck {
56 | const response: SchemeCheck = {
57 | valid: false,
58 | tokenExpired: false,
59 | refreshTokenExpired: false,
60 | idTokenExpired: false,
61 | isRefreshable: true,
62 | };
63 |
64 | // Sync tokens
65 | const token = this.token.sync();
66 | this.refreshToken.sync();
67 | this.idToken.sync();
68 |
69 | // Token is required but not available
70 | if (!token) {
71 | return response;
72 | }
73 |
74 | // Check status wasn't enabled, let it pass
75 | if (!checkStatus) {
76 | response.valid = true;
77 | return response;
78 | }
79 |
80 | // Get status
81 | const tokenStatus = this.token.status();
82 | const refreshTokenStatus = this.refreshToken.status();
83 | const idTokenStatus = this.idToken.status();
84 |
85 | // Refresh token has expired. There is no way to refresh. Force reset.
86 | if (refreshTokenStatus.expired()) {
87 | response.refreshTokenExpired = true;
88 | return response;
89 | }
90 |
91 | // Token has expired, Force reset.
92 | if (tokenStatus.expired()) {
93 | response.tokenExpired = true;
94 | return response;
95 | }
96 |
97 | // Id token has expired. Force reset.
98 | if (idTokenStatus.expired()) {
99 | response.idTokenExpired = true;
100 | return response;
101 | }
102 |
103 | response.valid = true;
104 | return response;
105 | }
106 |
107 | async mounted() {
108 | // Get and validate configuration based upon OpenIDConnect Configuration document
109 | // https://openid.net/specs/openid-connect-configuration-1_0.html
110 | await this.configurationDocument.init();
111 |
112 | const { tokenExpired, refreshTokenExpired } = this.check(true);
113 |
114 | // Force reset if refresh token has expired
115 | // Or if `autoLogout` is enabled and token has expired
116 | if (refreshTokenExpired || (tokenExpired && this.options.autoLogout)) {
117 | this.$auth.reset();
118 | }
119 |
120 | // Initialize request interceptor
121 | this.requestHandler.initializeRequestInterceptor(this.options.endpoints.token);
122 |
123 | // Handle callbacks on page load
124 | const redirected = await this.#handleCallback();
125 |
126 | if (!redirected) {
127 | return this.$auth.fetchUserOnce();
128 | }
129 | }
130 |
131 | reset() {
132 | this.$auth.setUser(false);
133 | this.token.reset();
134 | this.idToken.reset();
135 | this.refreshToken.reset();
136 | this.requestHandler.reset();
137 | this.configurationDocument.reset();
138 | }
139 |
140 | logout() {
141 | if (this.options.endpoints.logout) {
142 | const opts: QueryObject = {
143 | id_token_hint: this.idToken.get() as QueryValue,
144 | post_logout_redirect_uri: this.logoutRedirectURI,
145 | };
146 | const url = withQuery(this.options.endpoints.logout, opts);
147 | window.location.replace(url);
148 | }
149 | return this.$auth.reset();
150 | }
151 |
152 | async fetchUser() {
153 | if (!this.check().valid) {
154 | return;
155 | }
156 |
157 | if (this.idToken.get()) {
158 | const data = this.idToken.userInfo();
159 | this.$auth.setUser(data);
160 | return;
161 | }
162 |
163 | if (!this.options.endpoints.userInfo) {
164 | this.$auth.setUser({});
165 | return;
166 | }
167 |
168 | const data = await this.$auth.requestWith({
169 | url: this.options.endpoints.userInfo,
170 | });
171 |
172 | this.$auth.setUser(data);
173 | }
174 |
175 | async #handleCallback() {
176 | const route = useRoute();
177 | // Handle callback only for specified route
178 | if (this.$auth.options.redirect && normalizePath(route.path) !== normalizePath(this.$auth.options.redirect.callback)) {
179 | return;
180 | }
181 |
182 | // Callback flow is not supported in server side
183 | if (process.server) {
184 | return;
185 | }
186 |
187 | const hash = getQuery(route.hash.slice(1));
188 | const parsedQuery = Object.assign({}, route.query, hash);
189 |
190 | // accessToken/idToken
191 | let token: string = parsedQuery[this.options.token!.property] as string;
192 |
193 | // refresh token
194 | let refreshToken: string;
195 | if (this.options.refreshToken.property) {
196 | refreshToken = parsedQuery[this.options.refreshToken.property] as string;
197 | }
198 |
199 | // id token
200 | let idToken = parsedQuery[this.options.idToken.property] as string;
201 |
202 | // Validate state
203 | const state = this.$auth.$storage.getUniversal(this.name + '.state');
204 | this.$auth.$storage.setUniversal(this.name + '.state', null);
205 | if (state && parsedQuery.state !== state) {
206 | return;
207 | }
208 |
209 | // -- Authorization Code Grant --
210 | if (this.options.responseType === 'code' && parsedQuery.code) {
211 | let codeVerifier: any;
212 |
213 | // Retrieve code verifier and remove it from storage
214 | if (this.options.codeChallengeMethod && this.options.codeChallengeMethod !== 'implicit') {
215 | codeVerifier = this.$auth.$storage.getUniversal(this.name + '.pkce_code_verifier');
216 | this.$auth.$storage.setUniversal(this.name + '.pkce_code_verifier', null);
217 | }
218 |
219 | const response = await this.$auth.request({
220 | method: 'post',
221 | url: this.options.endpoints.token,
222 | baseURL: '',
223 | headers: {
224 | 'Content-Type': 'application/x-www-form-urlencoded'
225 | },
226 | body: new URLSearchParams({
227 | code: parsedQuery.code as string,
228 | client_id: this.options.clientId,
229 | redirect_uri: this.redirectURI,
230 | response_type: this.options.responseType,
231 | audience: this.options.audience,
232 | grant_type: this.options.grantType,
233 | code_verifier: codeVerifier,
234 | }),
235 | });
236 |
237 | token = (getProp(response, this.options.token!.property) as string) || token;
238 | refreshToken = (getProp(response, this.options.refreshToken.property!) as string) || refreshToken!;
239 | idToken = (getProp(response, this.options.idToken.property) as string) || idToken;
240 | }
241 |
242 | if (!token || !token.length) {
243 | return;
244 | }
245 |
246 | // Set token
247 | this.token.set(token);
248 |
249 | // Store refresh token
250 | if (refreshToken! && refreshToken.length) {
251 | this.refreshToken.set(refreshToken);
252 | }
253 |
254 | if (idToken && idToken.length) {
255 | this.idToken.set(idToken);
256 | }
257 |
258 | // Redirect to home
259 | this.$auth.redirect('home', false, false);
260 |
261 | return true; // True means a redirect happened
262 | }
263 | }
264 |
--------------------------------------------------------------------------------