Skip to content

Commit

Permalink
fix: add setup config decoupled from Next
Browse files Browse the repository at this point in the history
  • Loading branch information
luwes committed Oct 14, 2024
1 parent ddbb92a commit cc5a56b
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 44 deletions.
3 changes: 2 additions & 1 deletion examples/default-provider/app/api/video/route.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { GET } from 'next-video/request-handler';
//export { GET } from 'next-video/request-handler';
export { GET, POST } from '@/next-video';
11 changes: 11 additions & 0 deletions examples/default-provider/next-video.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { NextVideo } from 'next-video/process';
import { readFile } from 'fs/promises';

export const { GET, POST, handler, withNextVideo } = NextVideo({
loadAsset: async function (assetPath) {
console.warn(99, assetPath);
const file = await readFile(assetPath);
const asset = JSON.parse(file.toString());
return asset;
},
});
12 changes: 2 additions & 10 deletions examples/default-provider/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { withNextVideo } from 'next-video/process';
import { readFile } from 'node:fs/promises';
import { withNextVideo } from './next-video.mjs';

/** @type {import('next').NextConfig} */
const nextConfig = (phase, { defaultConfig }) => {
Expand All @@ -8,14 +7,7 @@ const nextConfig = (phase, { defaultConfig }) => {
};
};

export default withNextVideo(nextConfig, {
loadAsset: async function (assetPath) {
console.warn(99, assetPath);
const file = await readFile(assetPath);
const asset = JSON.parse(file.toString());
return asset;
},
});
export default withNextVideo(nextConfig);

// Amazon S3 example
// export default withNextVideo(nextConfig, {
Expand Down
2 changes: 1 addition & 1 deletion src/assets.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from 'node:path';
import { cwd } from 'node:process';
import { stat, readFile, writeFile, mkdir } from 'node:fs/promises';
import { stat } from 'node:fs/promises';
import { getVideoConfig } from './config.js';
import { deepMerge, camelCase, isRemote, toSafePath } from './utils/utils.js';
import * as transformers from './providers/transformers.js';
Expand Down
22 changes: 12 additions & 10 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { cwd } from 'node:process';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
import nextConfig from 'next/config.js';
import type { NextConfig } from 'next';
import { Asset } from './assets';
import { mkdir, readFile, writeFile } from 'node:fs/promises';

// @ts-ignore
const getConfig = nextConfig.default;

/**
* Video configurations
*/
Expand Down Expand Up @@ -98,25 +94,31 @@ export const videoConfigDefault: VideoConfigComplete = {
}
};

let videoConfigComplete: VideoConfigComplete = videoConfigDefault;

export function setVideoConfig(videoConfig?: VideoConfig): VideoConfigComplete {
videoConfigComplete = Object.assign({}, videoConfigDefault, videoConfig);
return videoConfigComplete;
}

/**
* The video config is set in `next.config.js` and passed to the `withNextVideo` function.
* The video config is then stored in `serverRuntimeConfig`.
*/
export async function getVideoConfig(): Promise<VideoConfigComplete> {
let nextConfig: NextConfig | undefined = getConfig();
if (!nextConfig?.serverRuntimeConfig?.nextVideo) {
let videoConfig: NextConfig | undefined = videoConfigComplete;
if (!videoConfig) {
try {
nextConfig = await importConfig('next.config.js');
await importConfig('next.config.js');
} catch (err) {
try {
nextConfig = await importConfig('next.config.mjs');
await importConfig('next.config.mjs');
} catch {
console.error('Failed to load next-video config.');
}
}
}

return nextConfig?.serverRuntimeConfig?.nextVideo;
return videoConfigComplete;
}

async function importConfig(file: string) {
Expand Down
3 changes: 2 additions & 1 deletion src/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { videoHandler, callHandler } from './video-handler.js';
import { uploadLocalFile } from './handlers/local-upload.js';
import { uploadRequestedFile } from './handlers/api-request.js';
import log from './utils/logger.js';
import { NextVideo } from './setup-next-video.js';
import { withNextVideo } from './with-next-video.js';

try {
Expand All @@ -17,4 +18,4 @@ try {
console.error(err);
}

export { videoHandler, withNextVideo, callHandler };
export { videoHandler, callHandler, NextVideo, withNextVideo };
46 changes: 31 additions & 15 deletions src/request-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,69 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { callHandler } from './process.js';
import { createAsset, getAsset } from './assets.js';
import { getVideoConfig } from './config.js';
import { isRemote } from './utils/utils.js';

// App Router
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const url = searchParams.get('url');
const { status, data } = await handleRequest(url);
const { status, data } = await getRequest(url);
// @ts-ignore - Response.json() is only valid from TypeScript 5.2
return Response.json(data, { status });
}

// App Router
export async function POST(request: Request) {
const { url } = await request.json();
const { status, data } = await postRequest(url);
// @ts-ignore - Response.json() is only valid from TypeScript 5.2
return Response.json(data, { status });
}

// Pages Router
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { status, data } = await handleRequest(String(req.query.url));
const { status, data } = await getRequest(String(req.query.url));
res.status(status).json(data);
}

async function handleRequest(url?: string | null) {
async function getRequest(url?: string | null) {
if (!url) {
return {
status: 400,
data: { error: 'url parameter is required' }
};
}

if (!isRemote(url)) {
// todo: handle local files via string src
let asset;
try {
asset = await getAsset(url);
} catch {
return { status: 404, data: { error: 'asset not found' } };
}

return { status: 200, data: asset };
}

async function postRequest(url?: string | null) {
if (!url) {
return {
status: 400,
data: { error: 'local files should be imported as a module' }
data: { error: 'url parameter is required' }
};
}

let asset;
try {
asset = await getAsset(url);
} catch {
// todo: does this require auth?
asset = await createAsset(url);

if (asset) {
const videoConfig = await getVideoConfig();
await callHandler('request.video.added', asset, videoConfig);
if (!asset) {
return { status: 500, data: { error: 'could not create asset' } };
}

const videoConfig = await getVideoConfig();
await callHandler('request.video.added', asset, videoConfig);

return { status: 200, data: asset };
} catch {
return { status: 500, data: { error: 'could not create asset' } };
}

return { status: 200, data: asset };
}
20 changes: 20 additions & 0 deletions src/setup-next-video.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { setVideoConfig } from './config.js';
import handler, { GET, POST } from './request-handler.js';
import { withNextVideo as withNextVideoInternal } from './with-next-video.js';
import type { VideoConfig } from './config.js';
import type { NextConfig } from 'next';

export function NextVideo(config?: VideoConfig) {
setVideoConfig(config);

const withNextVideo = (nextConfig: NextConfig) => {
return withNextVideoInternal(nextConfig, config);
};

return {
GET,
POST,
handler,
withNextVideo,
};
}
8 changes: 2 additions & 6 deletions src/with-next-video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { join, dirname } from 'node:path';
import fs from 'node:fs/promises';
import { env } from 'node:process';
import { fileURLToPath } from 'node:url';
import { videoConfigDefault } from './config.js';
import { setVideoConfig } from './config.js';
import type { VideoConfig } from './config.js';

export function withNextVideo(nextConfig: any, videoConfig?: VideoConfig) {
const videoConfigComplete = Object.assign({}, videoConfigDefault, videoConfig);
const videoConfigComplete = setVideoConfig(videoConfig);
const { path, folder, provider } = videoConfigComplete;

// env VARS have to be set before the async function return!!
Expand Down Expand Up @@ -49,10 +49,6 @@ export function withNextVideo(nextConfig: any, videoConfig?: VideoConfig) {

return Object.assign({}, nextConfig, {
experimental,
serverRuntimeConfig: {
...nextConfig.serverRuntimeConfig,
nextVideo: videoConfigComplete,
},
webpack(config: any, options: any) {
if (!options.defaultLoaders) {
throw new Error(
Expand Down

0 comments on commit cc5a56b

Please sign in to comment.