Skip to content
This repository has been archived by the owner on Jan 11, 2023. It is now read-only.

Do not reference any internal types in runtime/index.d.ts #1604

Merged
merged 12 commits into from
Oct 23, 2020
82 changes: 74 additions & 8 deletions runtime/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/*
* This file declares all Sapper types that are accessible to project code.
* It is created in src/node_modules/@sapper in projects during the build.
* It must not import any internal Sapper types as it will not be possible for
* project code to reference those.
*/

declare module '@sapper/app' {
export interface Redirect {
statusCode: number
Expand All @@ -12,16 +19,64 @@ declare module '@sapper/app' {
}

declare module '@sapper/server' {
import { Handler, Req, Res } from '@sapper/internal/manifest-server';
import { IncomingMessage, ServerResponse } from 'http';
import { TLSSocket } from 'tls';

export type Ignore = string | RegExp | ((uri: string) => boolean) | Ignore[];

/**
* The request object passed to middleware and server-side routes.
* These fields are common to both Polka and Express, but you are free to
* instead use the typings that come with the server you use.
*/
export interface SapperRequest extends IncomingMessage {
url: string;
method: string;
baseUrl: string;

/**
* The originally requested URL, including parent router segments.
*/
originalUrl: string;

/**
* The path portion of the requested URL.
*/
path: string;

/**
* The values of named parameters within your route pattern
*/
params: Record<string, string>;

/**
* The un-parsed querystring
*/
search: string | null;

/**
* The parsed querystring
*/
query: Record<string, string>;

socket: TLSSocket;
}

export interface SapperResponse extends ServerResponse {
locals?: {
nonce?: string;
name?: string;
};
}

export interface MiddlewareOptions {
session?: (req: Req, res: Res) => unknown
ignore?: Ignore
session?: (req: SapperRequest, res: SapperResponse) => unknown;
ignore?: Ignore;
}

export function middleware(opts: MiddlewareOptions): Handler;
export function middleware(
opts?: MiddlewareOptions
): (req: SapperRequest, res: SapperResponse, next: () => void) => void;
}

declare module '@sapper/service-worker' {
Expand All @@ -39,15 +94,26 @@ declare module '@sapper/common' {
redirect: (statusCode: number, location: string) => void;
}

export interface Page {
export type PageParams = Record<string, string>;
export type Query = Record<string, string | string[]>;

export interface PageContext {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably rather save the nice name Page for external usage and rename the internal Page type to something like PageInfo

Copy link
Contributor Author

@ehrencrona ehrencrona Oct 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be fine with that, but I generally feel this isn't a "page". The page parameters really parametrize a route, so I guess a page is more or less the same as a route, This object is attached to a request, whereas a page feels like something more permanent, at least to me.

How about PageRequest ("a request for a page")? The request carries the parameters for the page, the PageParams. That kind of makes sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not really a PageRequest because of the error. I guess PageContext makes sense

host: string;
path: string;
params: Record<string, string>;
query: Record<string, string | string[]>;
params: PageParams;
query: Query;
/** `error` is only set when the error page is being rendered. */
error?: Error;
}

/**
* @deprecated PageContext is the preferred name. Page might be removed in the future.
*/
export { PageContext as Page };

export type PreloadResult = object | Promise<object>

export interface Preload {
(this: PreloadContext, page: Page, session: any): object | Promise<object>;
(this: PreloadContext, page: PageContext, session: any): PreloadResult;
}
}
2 changes: 1 addition & 1 deletion runtime/src/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import {
Redirect,
Branch,
Page,
PageContext,
InitialData
} from './types';
import { PageContext } from '@sapper/common';
import goto from './goto';
import { page_store } from './stores';

Expand Down
8 changes: 4 additions & 4 deletions runtime/src/app/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
ignore,
routes
} from '@sapper/internal/manifest-client';
import { Query } from '@sapper/internal/shared';
import find_anchor from './find_anchor';
import { Page, Query } from '@sapper/common';

export let uid = 1;
export function set_uid(n: number) {
Expand Down Expand Up @@ -68,7 +68,7 @@ export function init(base: string, handler: (dest: Target) => Promise<void>): vo
}

export function extract_query(search: string) {
const query = Object.create(null);
const query: Query = Object.create(null);
if (search.length > 0) {
search.slice(1).split('&').forEach(searchParam => {
const [, key, value = ''] = /([^=]*)(?:=(.*))?/.exec(decodeURIComponent(searchParam.replace(/\+/g, ' ')));
Expand Down Expand Up @@ -99,11 +99,11 @@ export function select_target(url: URL): Target {
const match = route.pattern.exec(path);

if (match) {
const query: Query = extract_query(url.search);
const query = extract_query(url.search);
const part = route.parts[route.parts.length - 1];
const params = part.params ? part.params(match) : {};

const page = { host: location.host, path, query, params };
const page: Page = { host: location.host, path, query, params };

return { href: url.href, route, match, page };
}
Expand Down
8 changes: 0 additions & 8 deletions runtime/src/app/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,3 @@ export interface Page {
params: Record<string, string>;
query: Record<string, string | string[]>;
}

/**
* Information about the current page in the `page` store.
*/
export interface PageContext extends Page {
/** `error` is only set when the error page is being rendered. */
error?: Error;
}
6 changes: 6 additions & 0 deletions runtime/src/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* This file exists to avoid errors on references to @sapper/common from inside Sapper.
* (@sapper/common is a namespace defined in index.d.ts)
*/

export default null;
3 changes: 2 additions & 1 deletion runtime/src/internal/manifest-client.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { PageParams } from '@sapper/common';
import {
Preload
} from './shared';
Expand All @@ -24,7 +25,7 @@ export interface Route {
pattern: RegExp;
parts: Array<{
i: number;
params?: (match: RegExpExecArray) => Record<string, string>;
params?: (match: RegExpExecArray) => PageParams;
}>;
}

Expand Down
26 changes: 3 additions & 23 deletions runtime/src/internal/manifest-server.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { ClientRequest, ServerResponse } from 'http';
import { TLSSocket } from 'tls';
import {
Preload
} from './shared';
Expand All @@ -9,6 +7,8 @@ export const build_dir: string;
export const dev: boolean;
export const manifest: Manifest;

export { SapperRequest, SapperResponse } from '@sapper/server';

export interface SSRComponentModule {
default: SSRComponent;
preload?: Preload;
Expand Down Expand Up @@ -42,27 +42,7 @@ export interface ManifestPagePart {
params?: (match: RegExpMatchArray | null) => Record<string, string>;
}

export type Handler = (req: Req, res: Res, next: () => void) => void;

export interface Req extends ClientRequest {
url: string;
baseUrl: string;
originalUrl: string;
method: string;
path: string;
params: Record<string, string>;
query: Record<string, string>;
headers: Record<string, string>;
socket: TLSSocket;
}

export interface Res extends ServerResponse {
write: (data: any) => boolean;
locals?: {
nonce?: string;
name?: string;
};
}
export type Handler = (req: SapperRequest, res: SapperResponse, next: () => void) => void;

export interface ServerRoute {
pattern: RegExp;
Expand Down
7 changes: 0 additions & 7 deletions runtime/src/internal/shared.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1 @@
export const CONTEXT_KEY: unknown;

export type Params = Record<string, string>;
export type Query = Record<string, string | string[]>;
export type PreloadResult = object | Promise<object>;
export interface Preload {
(this: PreloadContext, page: PreloadPage, session: any): PreloadResult;
}
28 changes: 20 additions & 8 deletions runtime/src/server/middleware/get_page_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,22 @@ import devalue from 'devalue';
import fetch from 'node-fetch';
import URL from 'url';
import { sourcemap_stacktrace } from './sourcemap_stacktrace';
import { Manifest, ManifestPage, Req, Res, build_dir, dev, src_dir } from '@sapper/internal/manifest-server';
import { PreloadResult } from '@sapper/internal/shared';
import {
Manifest,
ManifestPage,
SapperRequest,
SapperResponse,
build_dir,
dev,
src_dir
} from '@sapper/internal/manifest-server';
import App from '@sapper/internal/App.svelte';
import { PageContext } from '@sapper/app/types';
import { PageContext, PreloadResult } from '@sapper/common';
import detectClientOnlyReferences from './detect_client_only_references';

export function get_page_handler(
manifest: Manifest,
session_getter: (req: Req, res: Res) => Promise<any>
session_getter: (req: SapperRequest, res: SapperResponse) => Promise<any>
) {
const get_build_info = dev
? () => JSON.parse(fs.readFileSync(path.join(build_dir, 'build.json'), 'utf-8'))
Expand All @@ -28,7 +35,7 @@ export function get_page_handler(

const { pages, error: error_route } = manifest;

function bail(res: Res, err: Error | string) {
function bail(res: SapperResponse, err: Error | string) {
console.error(err);

const message = dev ? escape_html(typeof err === 'string' ? err : err.message) : 'Internal server error';
Expand All @@ -37,7 +44,7 @@ export function get_page_handler(
res.end(`<pre>${message}</pre>`);
}

function handle_error(req: Req, res: Res, statusCode: number, error: Error | string) {
function handle_error(req: SapperRequest, res: SapperResponse, statusCode: number, error: Error | string) {
handle_page({
pattern: null,
parts: [
Expand All @@ -46,7 +53,12 @@ export function get_page_handler(
}, req, res, statusCode, error || 'Unknown error');
}

async function handle_page(page: ManifestPage, req: Req, res: Res, status = 200, error: Error | string = null) {
async function handle_page(
page: ManifestPage,
req: SapperRequest,
res: SapperResponse,
status = 200,
error: Error | string = null) {
const is_service_worker_index = req.path === '/service-worker-index.html';
const build_info: {
bundler: 'rollup' | 'webpack',
Expand Down Expand Up @@ -382,7 +394,7 @@ export function get_page_handler(
}
}

return function find_route(req: Req, res: Res, next: () => void) {
return function find_route(req: SapperRequest, res: SapperResponse, next: () => void) {
const req_path = req.path === '/service-worker-index.html' ? '/' : req.path;

const page = pages.find(p => p.pattern.test(req_path));
Expand Down
6 changes: 3 additions & 3 deletions runtime/src/server/middleware/get_server_route_handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Req, Res, ServerRoute } from '@sapper/internal/manifest-server';
import { SapperRequest, SapperResponse, ServerRoute } from '@sapper/internal/manifest-server';

export function get_server_route_handler(routes: ServerRoute[]) {
async function handle_route(route: ServerRoute, req: Req, res: Res, next: () => void) {
async function handle_route(route: ServerRoute, req: SapperRequest, res: SapperResponse, next: () => void) {
req.params = route.params(route.pattern.exec(req.path));

const method = req.method.toLowerCase();
Expand Down Expand Up @@ -63,7 +63,7 @@ export function get_server_route_handler(routes: ServerRoute[]) {
}
}

return function find_route(req: Req, res: Res, next: () => void) {
return function find_route(req: SapperRequest, res: SapperResponse, next: () => void) {
for (const route of routes) {
if (route.pattern.test(req.path)) {
handle_route(route, req, res, next);
Expand Down
16 changes: 8 additions & 8 deletions runtime/src/server/middleware/index.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import fs from 'fs';
import path from 'path';
import mime from 'mime/lite';
import { Handler, Req, Res, build_dir, dev, manifest } from '@sapper/internal/manifest-server';
import { Handler, SapperRequest, SapperResponse, build_dir, dev, manifest } from '@sapper/internal/manifest-server';
import { get_server_route_handler } from './get_server_route_handler';
import { get_page_handler } from './get_page_handler';

type IgnoreValue = IgnoreValue[] | RegExp | ((uri: string) => boolean) | string;

export default function middleware(opts: {
session?: (req: Req, res: Res) => any,
session?: (req: SapperRequest, res: SapperResponse) => any,
ignore?: IgnoreValue
} = {}) {
const { session, ignore } = opts;

let emitted_basepath = false;

return compose_handlers(ignore, [
(req: Req, res: Res, next: () => void) => {
(req: SapperRequest, res: SapperResponse, next: () => void) => {
if (req.baseUrl === undefined) {
let originalUrl = req.originalUrl || req.url;
if (req.url === '/' && originalUrl[originalUrl.length - 1] !== '/') {
Expand Down Expand Up @@ -69,7 +69,7 @@ export default function middleware(opts: {
export function compose_handlers(ignore: IgnoreValue, handlers: Handler[]): Handler {
const total = handlers.length;

function nth_handler(n: number, req: Req, res: Res, next: () => void) {
function nth_handler(n: number, req: SapperRequest, res: SapperResponse, next: () => void) {
if (n >= total) {
return next();
}
Expand Down Expand Up @@ -101,16 +101,16 @@ export function serve({ prefix, pathname, cache_control }: {
cache_control: string
}) {
const filter = pathname
? (req: Req) => req.path === pathname
: (req: Req) => req.path.startsWith(prefix);
? (req: SapperRequest) => req.path === pathname
: (req: SapperRequest) => req.path.startsWith(prefix);

const cache: Map<string, Buffer> = new Map();

const read = dev
? (file: string) => fs.readFileSync(path.join(build_dir, file))
: (file: string) => (cache.has(file) ? cache : cache.set(file, fs.readFileSync(path.join(build_dir, file)))).get(file);

return (req: Req, res: Res, next: () => void) => {
return (req: SapperRequest, res: SapperResponse, next: () => void) => {
if (filter(req)) {
const type = mime.getType(req.path);

Expand All @@ -137,4 +137,4 @@ export function serve({ prefix, pathname, cache_control }: {
};
}

function noop() {}
async function noop() {}
Loading