mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-09-16 17:55:32 -04:00
clean up strict types a bit more
This commit is contained in:
@@ -5,7 +5,7 @@ import Link from "../Link";
|
|||||||
import Captcha from "../Captcha";
|
import Captcha from "../Captcha";
|
||||||
import { CheckOcticon, XOcticon, MarkdownIcon } from "../Icons";
|
import { CheckOcticon, XOcticon, MarkdownIcon } from "../Icons";
|
||||||
import { styled, css } from "../../lib/styles/stitches.config";
|
import { styled, css } from "../../lib/styles/stitches.config";
|
||||||
import type { FormikHelpers } from "formik";
|
import type { FormikHelpers, FormikProps, FieldInputProps, FieldMetaProps } from "formik";
|
||||||
|
|
||||||
// CSS applied to both `<input />` and `<textarea />`
|
// CSS applied to both `<input />` and `<textarea />`
|
||||||
const InputStyles = css({
|
const InputStyles = css({
|
||||||
@@ -30,6 +30,7 @@ const InputStyles = css({
|
|||||||
true: {
|
true: {
|
||||||
borderColor: "$error",
|
borderColor: "$error",
|
||||||
},
|
},
|
||||||
|
false: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -89,6 +90,7 @@ const SubmitButton = styled("button", {
|
|||||||
true: {
|
true: {
|
||||||
display: "none",
|
display: "none",
|
||||||
},
|
},
|
||||||
|
false: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -117,6 +119,7 @@ const Result = styled("div", {
|
|||||||
true: {
|
true: {
|
||||||
display: "none",
|
display: "none",
|
||||||
},
|
},
|
||||||
|
false: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -128,7 +131,7 @@ const ResultIcon = styled("svg", {
|
|||||||
fill: "currentColor",
|
fill: "currentColor",
|
||||||
});
|
});
|
||||||
|
|
||||||
type Values = {
|
type FormValues = {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
message: string;
|
message: string;
|
||||||
@@ -145,7 +148,7 @@ const ContactForm = ({ className }: ContactFormProps) => {
|
|||||||
const [success, setSuccess] = useState(false);
|
const [success, setSuccess] = useState(false);
|
||||||
const [feedback, setFeedback] = useState("");
|
const [feedback, setFeedback] = useState("");
|
||||||
|
|
||||||
const handleSubmit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
const handleSubmit = (values: FormValues, { setSubmitting }: FormikHelpers<FormValues>) => {
|
||||||
// once a user attempts a submission, this is true and stays true whether or not the next attempt(s) are successful
|
// once a user attempts a submission, this is true and stays true whether or not the next attempt(s) are successful
|
||||||
setSubmitted(true);
|
setSubmitted(true);
|
||||||
|
|
||||||
@@ -196,8 +199,8 @@ const ContactForm = ({ className }: ContactFormProps) => {
|
|||||||
message: "",
|
message: "",
|
||||||
"h-captcha-response": "",
|
"h-captcha-response": "",
|
||||||
}}
|
}}
|
||||||
validate={(values: Values) => {
|
validate={(values: FormValues) => {
|
||||||
const errors: Partial<Record<keyof Values, boolean>> = {};
|
const errors: Partial<Record<keyof FormValues, boolean>> = {};
|
||||||
|
|
||||||
errors.name = !values.name;
|
errors.name = !values.name;
|
||||||
errors.email = !values.email; // also loosely validated that it's email-like via browser (not foolproof)
|
errors.email = !values.email; // also loosely validated that it's email-like via browser (not foolproof)
|
||||||
@@ -215,43 +218,40 @@ const ContactForm = ({ className }: ContactFormProps) => {
|
|||||||
return errors;
|
return errors;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ setFieldValue, isSubmitting }) => (
|
{({ setFieldValue, isSubmitting }: FormikProps<FormValues>) => (
|
||||||
<Form className={className} name="contact">
|
<Form className={className} name="contact">
|
||||||
<Field name="name">
|
<Field name="name">
|
||||||
{/* @ts-ignore */}
|
{({ field, meta }: { field: FieldInputProps<string>; meta: FieldMetaProps<string> }) => (
|
||||||
{({ field, meta }) => (
|
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Name"
|
placeholder="Name"
|
||||||
disabled={success}
|
disabled={success}
|
||||||
missing={meta.error && meta.touched}
|
missing={!!(meta.error && meta.touched)}
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field name="email">
|
<Field name="email">
|
||||||
{/* @ts-ignore */}
|
{({ field, meta }: { field: FieldInputProps<string>; meta: FieldMetaProps<string> }) => (
|
||||||
{({ field, meta }) => (
|
|
||||||
<Input
|
<Input
|
||||||
type="email"
|
type="email"
|
||||||
inputMode="email"
|
inputMode="email"
|
||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
disabled={success}
|
disabled={success}
|
||||||
missing={meta.error && meta.touched}
|
missing={!!(meta.error && meta.touched)}
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field name="message">
|
<Field name="message">
|
||||||
{/* @ts-ignore */}
|
{({ field, meta }: { field: FieldInputProps<string>; meta: FieldMetaProps<string> }) => (
|
||||||
{({ field, meta }) => (
|
|
||||||
<TextArea
|
<TextArea
|
||||||
placeholder="Write something..."
|
placeholder="Write something..."
|
||||||
minRows={5}
|
minRows={5}
|
||||||
disabled={success}
|
disabled={success}
|
||||||
missing={meta.error && meta.touched}
|
missing={!!(meta.error && meta.touched)}
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@@ -64,8 +64,7 @@ const Image = ({
|
|||||||
throw new TypeError("'src' should be a string or a valid StaticImageData object.");
|
throw new TypeError("'src' should be a string or a valid StaticImageData object.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
const img = <RoundedImage {...(imageProps as NextImageProps)} />;
|
||||||
const img = <RoundedImage {...imageProps} />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
|
@@ -55,13 +55,15 @@ const PostDate = styled(Time, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export type NotesListProps = {
|
export type NotesListProps = {
|
||||||
notesByYear: { [key: string]: NoteFrontMatter[] };
|
notesByYear: {
|
||||||
|
[year: string]: NoteFrontMatter[];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const NotesList = ({ notesByYear }: NotesListProps) => {
|
const NotesList = ({ notesByYear }: NotesListProps) => {
|
||||||
const sections: ReactElement[] = [];
|
const sections: ReactElement[] = [];
|
||||||
|
|
||||||
Object.entries(notesByYear).forEach(([year, notes]: [string, NoteFrontMatter[]]) => {
|
Object.entries(notesByYear).forEach(([year, notes]) => {
|
||||||
sections.push(
|
sections.push(
|
||||||
<Section key={year}>
|
<Section key={year}>
|
||||||
<Year>{year}</Year>
|
<Year>{year}</Year>
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { useRef, useEffect, useState, memo } from "react";
|
import { useRef, useEffect, useState, memo } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
// @ts-ignore
|
|
||||||
import RFB from "@novnc/novnc/core/rfb.js";
|
import RFB from "@novnc/novnc/core/rfb.js";
|
||||||
import Terminal from "../Terminal";
|
import Terminal from "../Terminal";
|
||||||
import { styled } from "../../lib/styles/stitches.config";
|
import { styled } from "../../lib/styles/stitches.config";
|
||||||
@@ -55,8 +54,7 @@ const VNC = ({ server }: VNCProps) => {
|
|||||||
const [message, setMessage] = useState({ message: "", anyKey: false });
|
const [message, setMessage] = useState({ message: "", anyKey: false });
|
||||||
|
|
||||||
// the actual connection and virtual screen (injected by noVNC when it's ready)
|
// the actual connection and virtual screen (injected by noVNC when it's ready)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
const rfbRef = useRef<RFB | null>(null);
|
||||||
const rfbRef = useRef<any>(null);
|
|
||||||
const screenRef = useRef<HTMLDivElement>(null);
|
const screenRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// ends the session forcefully
|
// ends the session forcefully
|
||||||
@@ -93,7 +91,7 @@ const VNC = ({ server }: VNCProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/novnc/noVNC/blob/master/docs/API.md
|
// https://github.com/novnc/noVNC/blob/master/docs/API.md
|
||||||
rfbRef.current = new RFB(screenRef.current, server, {
|
rfbRef.current = new RFB(screenRef.current as Element, server, {
|
||||||
wsProtocols: ["binary", "base64"],
|
wsProtocols: ["binary", "base64"],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,7 +99,7 @@ const VNC = ({ server }: VNCProps) => {
|
|||||||
rfbRef.current.scaleViewport = true;
|
rfbRef.current.scaleViewport = true;
|
||||||
|
|
||||||
// VM connected
|
// VM connected
|
||||||
rfbRef.current.addEventListener("connect", () => {
|
rfbRef.current?.addEventListener("connect", () => {
|
||||||
console.log("successfully connected to VM socket!");
|
console.log("successfully connected to VM socket!");
|
||||||
|
|
||||||
// finally hide the terminal and show the VNC canvas
|
// finally hide the terminal and show the VNC canvas
|
||||||
@@ -111,7 +109,7 @@ const VNC = ({ server }: VNCProps) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// VM disconnected (on either end)
|
// VM disconnected (on either end)
|
||||||
rfbRef.current.addEventListener("disconnect", (detail: unknown) => {
|
rfbRef.current?.addEventListener("disconnect", (detail: unknown) => {
|
||||||
console.warn("VM ended session remotely:", detail);
|
console.warn("VM ended session remotely:", detail);
|
||||||
|
|
||||||
// hide the display and show the terminal
|
// hide the display and show the terminal
|
||||||
|
@@ -77,17 +77,7 @@ const Video = ({ src, thumbnail, subs, autoplay, className, ...rest }: VideoProp
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper className={className}>
|
<Wrapper className={className}>
|
||||||
{hasMounted && (
|
{hasMounted && <Player width="100%" height="100%" url={url} controls={!autoplay} config={config} {...rest} />}
|
||||||
<Player
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
url={url}
|
|
||||||
controls={!autoplay}
|
|
||||||
// @ts-ignore
|
|
||||||
config={config}
|
|
||||||
{...rest}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -134,7 +134,7 @@ export const articleJsonLd: Pick<ArticleJsonLdProps, "authorName" | "publisherNa
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Re-export icons to use their static image data elsewhere
|
// Re-export icons to use their static image data elsewhere
|
||||||
export const favicons: { [key: string]: StaticImageData } = {
|
export const favicons: Record<string, StaticImageData> = {
|
||||||
faviconIco,
|
faviconIco,
|
||||||
faviconPng,
|
faviconPng,
|
||||||
appleTouchIconPng,
|
appleTouchIconPng,
|
||||||
|
@@ -16,7 +16,7 @@ export type BuildFeedOptions = {
|
|||||||
export const buildFeed = async (
|
export const buildFeed = async (
|
||||||
context: GetServerSidePropsContext<ParsedUrlQuery, PreviewData>,
|
context: GetServerSidePropsContext<ParsedUrlQuery, PreviewData>,
|
||||||
options: BuildFeedOptions
|
options: BuildFeedOptions
|
||||||
): Promise<{ props: { [key: string]: unknown } }> => {
|
): Promise<{ props: Record<string, unknown> }> => {
|
||||||
const { res } = context;
|
const { res } = context;
|
||||||
|
|
||||||
// https://github.com/jpmonette/feed#example
|
// https://github.com/jpmonette/feed#example
|
||||||
|
@@ -9,10 +9,10 @@ import remarkUnwrapImages from "remark-unwrap-images";
|
|||||||
import rehypeSlug from "rehype-slug";
|
import rehypeSlug from "rehype-slug";
|
||||||
import rehypePrism from "rehype-prism-plus";
|
import rehypePrism from "rehype-prism-plus";
|
||||||
|
|
||||||
import type { Note } from "../../types";
|
import type { NoteWithSource } from "../../types";
|
||||||
|
|
||||||
// fully parses MDX into JS and returns *everything* about a note
|
// fully parses MDX into JS and returns *everything* about a note
|
||||||
export const compileNote = async (slug: string): Promise<Note> => {
|
export const compileNote = async (slug: string): Promise<NoteWithSource> => {
|
||||||
const { frontMatter, content } = await getNoteData(slug);
|
const { frontMatter, content } = await getNoteData(slug);
|
||||||
const source = await serialize(content, {
|
const source = await serialize(content, {
|
||||||
parseFrontmatter: false,
|
parseFrontmatter: false,
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import type * as Stitches from "@stitches/react";
|
import type * as Stitches from "@stitches/react";
|
||||||
|
|
||||||
const normalizeStyles: { [key: string]: Stitches.CSSProperties } = {
|
const normalizeStyles: Record<string, Stitches.CSSProperties> = {
|
||||||
"*, ::before, ::after": {
|
"*, ::before, ::after": {
|
||||||
boxSizing: "border-box",
|
boxSizing: "border-box",
|
||||||
},
|
},
|
||||||
|
@@ -61,8 +61,8 @@ const App = ({ Component, pageProps }: AppProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* all SEO config is in ../lib/config/seo.ts except for canonical URLs, which require access to next router */}
|
|
||||||
<DefaultSeo
|
<DefaultSeo
|
||||||
|
// all SEO config is in ../lib/config/seo.ts except for canonical URLs, which require access to next router
|
||||||
{...defaultSeo}
|
{...defaultSeo}
|
||||||
canonical={canonical}
|
canonical={canonical}
|
||||||
openGraph={{
|
openGraph={{
|
||||||
|
@@ -8,11 +8,11 @@ import * as mdxComponents from "../../lib/helpers/mdx-components";
|
|||||||
import { getNoteSlugs } from "../../lib/helpers/parse-notes";
|
import { getNoteSlugs } from "../../lib/helpers/parse-notes";
|
||||||
import { compileNote } from "../../lib/helpers/compile-note";
|
import { compileNote } from "../../lib/helpers/compile-note";
|
||||||
import * as config from "../../lib/config";
|
import * as config from "../../lib/config";
|
||||||
import { articleJsonLd } from "../../lib/config/seo";
|
import { articleJsonLd, favicons } from "../../lib/config/seo";
|
||||||
import type { GetStaticProps, GetStaticPaths } from "next";
|
import type { GetStaticProps, GetStaticPaths } from "next";
|
||||||
import type { Note, NoteFrontMatter } from "../../types";
|
import type { NoteWithSource, NoteFrontMatter } from "../../types";
|
||||||
|
|
||||||
const Note = ({ frontMatter, source }: Note) => {
|
const Note = ({ frontMatter, source }: NoteWithSource) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NextSeo
|
<NextSeo
|
||||||
@@ -29,10 +29,9 @@ const Note = ({ frontMatter, source }: Note) => {
|
|||||||
publishedTime: frontMatter.date,
|
publishedTime: frontMatter.date,
|
||||||
modifiedTime: frontMatter.date,
|
modifiedTime: frontMatter.date,
|
||||||
},
|
},
|
||||||
// @ts-ignore
|
images: [
|
||||||
images: frontMatter.image && [
|
|
||||||
{
|
{
|
||||||
url: `${config.baseUrl}${frontMatter.image}`,
|
url: `${config.baseUrl}${frontMatter.image || favicons.meJpg.src}`,
|
||||||
alt: frontMatter.title,
|
alt: frontMatter.title,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -47,8 +46,7 @@ const Note = ({ frontMatter, source }: Note) => {
|
|||||||
description={frontMatter.description || config.longDescription}
|
description={frontMatter.description || config.longDescription}
|
||||||
datePublished={frontMatter.date}
|
datePublished={frontMatter.date}
|
||||||
dateModified={frontMatter.date}
|
dateModified={frontMatter.date}
|
||||||
// @ts-ignore
|
images={[`${config.baseUrl}${frontMatter.image || favicons.meJpg.src}`]}
|
||||||
images={frontMatter.image && [`${config.baseUrl}${frontMatter.image}`]}
|
|
||||||
{...articleJsonLd}
|
{...articleJsonLd}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -62,7 +60,6 @@ const Note = ({ frontMatter, source }: Note) => {
|
|||||||
/>
|
/>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
||||||
{/* comments can be disabled for an individual post via `noComments: true` in its front matter */}
|
|
||||||
{!frontMatter.noComments && (
|
{!frontMatter.noComments && (
|
||||||
<InView rootMargin="140px" triggerOnce fallbackInView>
|
<InView rootMargin="140px" triggerOnce fallbackInView>
|
||||||
{({ inView, ref }) => (
|
{({ inView, ref }) => (
|
||||||
|
@@ -115,7 +115,7 @@ export const getStaticProps: GetStaticProps = async () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const results: { node: { [key: string]: any } }[] = response.user.repositories.edges;
|
const results: Array<{ node: Record<string, any> }> = response.user.repositories.edges;
|
||||||
|
|
||||||
const repos = results.map<Repository>(({ node: repo }) => ({
|
const repos = results.map<Repository>(({ node: repo }) => ({
|
||||||
name: repo.name,
|
name: repo.name,
|
||||||
|
1
types/index.d.ts
vendored
1
types/index.d.ts
vendored
@@ -1,3 +1,4 @@
|
|||||||
export * from "./note";
|
export * from "./note";
|
||||||
export * from "./repository";
|
export * from "./repository";
|
||||||
|
export * from "./rfb";
|
||||||
export * from "./webpack";
|
export * from "./webpack";
|
||||||
|
2
types/note.d.ts
vendored
2
types/note.d.ts
vendored
@@ -12,7 +12,7 @@ export type NoteFrontMatter = {
|
|||||||
noComments?: boolean;
|
noComments?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Note = {
|
export type NoteWithSource = {
|
||||||
// yaml metadata
|
// yaml metadata
|
||||||
frontMatter: NoteFrontMatter;
|
frontMatter: NoteFrontMatter;
|
||||||
|
|
||||||
|
323
types/rfb.d.ts
vendored
Normal file
323
types/rfb.d.ts
vendored
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
// thanks @ovcharik!
|
||||||
|
// https://gist.github.com/ovcharik/35979d45af808c443e844fc1e6740b87#file-rfb-d-ts
|
||||||
|
|
||||||
|
declare module "@novnc/novnc/core/rfb.js" {
|
||||||
|
/**
|
||||||
|
* An `object` specifying the credentials to provide to the server when authenticating.
|
||||||
|
*/
|
||||||
|
export interface NoVncCredentials {
|
||||||
|
/** The user that authenticates */
|
||||||
|
username: string;
|
||||||
|
/** Password for the user */
|
||||||
|
password: string;
|
||||||
|
/** Target machine or session */
|
||||||
|
target: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `object` specifying extra details about how the connection should be made.
|
||||||
|
*/
|
||||||
|
export interface NoVncOptions {
|
||||||
|
/**
|
||||||
|
* A `boolean` indicating if the remote server should be shared or if any other connected
|
||||||
|
* clients should be disconnected. Enabled by default.
|
||||||
|
*/
|
||||||
|
shared?: boolean;
|
||||||
|
/**
|
||||||
|
* An `object` specifying the credentials to provide to the server when authenticating.
|
||||||
|
*/
|
||||||
|
credentials?: NoVncCredentials;
|
||||||
|
/**
|
||||||
|
* A `string` specifying the ID to provide to any VNC repeater encountered.
|
||||||
|
*/
|
||||||
|
repeaterID?: string;
|
||||||
|
/**
|
||||||
|
* An `Array` of `string`s specifying the sub-protocols to use in the WebSocket connection.
|
||||||
|
* Empty by default.
|
||||||
|
*/
|
||||||
|
wsProtocols?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NoVncEvents {
|
||||||
|
/**
|
||||||
|
* The `connect` event is fired after all the handshaking with the server is completed and the
|
||||||
|
* connection is fully established. After this event the `NoVncClient` object is ready to
|
||||||
|
* receive graphics updates and to send input.
|
||||||
|
*/
|
||||||
|
connect: CustomEvent<Record<string, never>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `disconnect` event is fired when the connection has been terminated. The `detail`
|
||||||
|
* property is an `object` that contains the property `clean`. `clean` is a `boolean` indicating
|
||||||
|
* if the termination was clean or not. In the event of an unexpected termination or an error
|
||||||
|
* `clean` will be set to false.
|
||||||
|
*/
|
||||||
|
disconnect: CustomEvent<{ clean: boolean }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `credentialsrequired` event is fired when the server requests more credentials than were
|
||||||
|
* specified to {@link NoVncClient}. The `detail` property is an `object` containing the
|
||||||
|
* property `types` which is an `Array` of `string` listing the credentials that are required.
|
||||||
|
*/
|
||||||
|
credentialsrequired: CustomEvent<{ types: Array<keyof NoVncCredentials> }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `securityfailure` event is fired when the handshaking process with the server fails
|
||||||
|
* during the security negotiation step. The `detail` property is an `object` containing the
|
||||||
|
* following properties:
|
||||||
|
*
|
||||||
|
* | Property | Type | Description
|
||||||
|
* | -------- | ----------- | -----------
|
||||||
|
* | `status` | `number` | The failure status code
|
||||||
|
* | `reason` | `string` | The **optional** reason for the failure
|
||||||
|
*
|
||||||
|
* The property `status` corresponds to the
|
||||||
|
* [SecurityResult](https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#securityresult)
|
||||||
|
* status code in cases of failure. A status of zero will not be sent in this event since that
|
||||||
|
* indicates a successful security handshaking process. The optional property `reason` is
|
||||||
|
* provided by the server and thus the language of the string is not known. However most servers
|
||||||
|
* will probably send English strings. The server can choose to not send a reason and in these
|
||||||
|
* cases the `reason` property will be omitted.
|
||||||
|
*/
|
||||||
|
securityfailure: CustomEvent<{ status: number; reason?: string }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `clipboard` event is fired when the server has sent clipboard data. The `detail` property
|
||||||
|
* is an `object` containing the property `text` which is a `string` with the clipboard data.
|
||||||
|
*/
|
||||||
|
clipboard: CustomEvent<{ text: string }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `bell` event is fired when the server has requested an audible bell.
|
||||||
|
*/
|
||||||
|
bell: CustomEvent<Record<string, never>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `desktopname` event is fired when the name of the remote desktop changes. The `detail`
|
||||||
|
* property is an `object` with the property `name` which is a `string` specifying the new name.
|
||||||
|
*/
|
||||||
|
desktopname: CustomEvent<{ name: string }>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `capabilities` event is fired whenever an entry is added or removed from `capabilities`.
|
||||||
|
* The `detail` property is an `object` with the property `capabilities` containing the new
|
||||||
|
* value of `capabilities`.
|
||||||
|
*/
|
||||||
|
capabilities: CustomEvent<{ capabilities: NoVncClient["capabilities"] }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NoVncEventType = keyof NoVncEvents;
|
||||||
|
export type NoVncEvent = NoVncEvents[NoVncEventType];
|
||||||
|
|
||||||
|
export class NoVncEventTarget extends EventTarget {
|
||||||
|
protected _listeners: Map<NoVncEventType, (event: Event) => void>;
|
||||||
|
|
||||||
|
addEventListener<T extends NoVncEventType>(type: T, listener: (event: NoVncEvent[T]) => void): void;
|
||||||
|
addEventListener(type: string, listener: (event: CustomEvent) => void): void;
|
||||||
|
|
||||||
|
removeEventListener<T extends NoVncEventType>(type: T, listener: (event: NoVncEvent[T]) => void): void;
|
||||||
|
removeEventListener(type: string, listener: (event: CustomEvent) => void): void;
|
||||||
|
|
||||||
|
dispatchEvent<E extends NoVncEvent[NoVncEventType]>(event: E): boolean;
|
||||||
|
dispatchEvent(event: CustomEvent): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `NoVncClient` object represents a single connection to a VNC server. It communicates using
|
||||||
|
* a WebSocket that must provide a standard NoVncClient protocol stream.
|
||||||
|
*/
|
||||||
|
export default class NoVncClient extends NoVncEventTarget {
|
||||||
|
public readonly _target: Element;
|
||||||
|
public readonly _url: string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new `NoVncClient` object and initiates a new connection to a specified VNC server.
|
||||||
|
*
|
||||||
|
* @param target - A block {@link HTMLElement} that specifies where the `NoVncClient` object
|
||||||
|
* should attach itself. The existing contents of the `HTMLElement` will be untouched, but new
|
||||||
|
* elements will be added during the lifetime of the `NoVncClient` object.
|
||||||
|
* @param url - A `string` specifying the VNC server to connect to. This must be a valid
|
||||||
|
* WebSocket URL.
|
||||||
|
* @param options - An {@link NoVncOptions} specifying extra details about how the connection
|
||||||
|
* should be made.
|
||||||
|
*/
|
||||||
|
constructor(target: Element, url: string, options?: NoVncOptions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new `NoVncClient` object and initiates a new connection to a specified VNC server.
|
||||||
|
*
|
||||||
|
* @param target - A block {@link HTMLElement} that specifies where the `NoVncClient` object
|
||||||
|
* should attach itself. The existing contents of the `HTMLElement` will be untouched, but new
|
||||||
|
* elements will be added during the lifetime of the `NoVncClient` object.
|
||||||
|
* @param socket - A {@link WebSocket} specifying the VNC server to connect to. This must be a
|
||||||
|
* valid WebSocket URL.
|
||||||
|
* @param options - An {@link NoVncOptions} specifying extra details about how the connection
|
||||||
|
* should be made.
|
||||||
|
*/
|
||||||
|
constructor(target: Element, socket: WebSocket, options?: NoVncOptions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new `NoVncClient` object and initiates a new connection to a specified VNC server.
|
||||||
|
*
|
||||||
|
* @param target - A block {@link HTMLElement} that specifies where the `NoVncClient` object
|
||||||
|
* should attach itself. The existing contents of the `HTMLElement` will be untouched, but new
|
||||||
|
* elements will be added during the lifetime of the `NoVncClient` object.
|
||||||
|
* @param channel - A {@link RTCDataChannel} specifying the VNC server to connect to. This must
|
||||||
|
* be a valid WebSocket URL.
|
||||||
|
* @param options - An {@link NoVncOptions} specifying extra details about how the connection
|
||||||
|
* should be made.
|
||||||
|
*/
|
||||||
|
constructor(target: Element, channel: RTCDataChannel, options?: NoVncOptions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a `boolean` indicating if any events (e.g. key presses or mouse movement) should be
|
||||||
|
* prevented from being sent to the server. Disabled by default.
|
||||||
|
*/
|
||||||
|
public viewOnly: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a `boolean` indicating if keyboard focus should automatically be moved to the remote
|
||||||
|
* session when a `mousedown` or `touchstart` event is received. Enabled by default.
|
||||||
|
*/
|
||||||
|
public focusOnClick: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a `boolean` indicating if the remote session should be clipped to its container. When
|
||||||
|
* disabled scrollbars will be shown to handle the resulting overflow. Disabled by default.
|
||||||
|
*/
|
||||||
|
public clipViewport: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a `boolean` indicating if mouse events should control the relative position of a clipped
|
||||||
|
* remote session. Only relevant if `clipViewport` is enabled. Disabled by default.
|
||||||
|
*/
|
||||||
|
public dragViewport: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a `boolean` indicating if the remote session should be scaled locally so it fits its
|
||||||
|
* container. When disabled it will be centered if the remote session is smaller than its
|
||||||
|
* container, or handled according to `clipViewport` if it is larger. Disabled by default.
|
||||||
|
*/
|
||||||
|
public scaleViewport: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a `boolean` indicating if a request to resize the remote session should be sent whenever
|
||||||
|
* the container changes dimensions. Disabled by default.
|
||||||
|
*/
|
||||||
|
public resizeSession: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a `boolean` indicating whether a dot cursor should be shown instead of a zero-sized or
|
||||||
|
* fully-transparent cursor if the server sets such invisible cursor. Disabled by default.
|
||||||
|
*/
|
||||||
|
public showDotCursor: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a valid CSS [background](https://developer.mozilla.org/en-US/docs/Web/CSS/background)
|
||||||
|
* style value indicating which background style should be applied to the element containing the
|
||||||
|
* remote session screen. The default value is `rgb(40, 40, 40)` (solid gray color).
|
||||||
|
*/
|
||||||
|
public background: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is an `int` in range `[0-9]` controlling the desired JPEG quality. Value `0` implies low
|
||||||
|
* quality and `9` implies high quality. Default value is `6`.
|
||||||
|
*/
|
||||||
|
public qualityLevel: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is an `int` in range `[0-9]` controlling the desired compression level. Value `0` means no
|
||||||
|
* compression. Level 1 uses a minimum of CPU resources and achieves weak compression ratios,
|
||||||
|
* while level 9 offers best compression but is slow in terms of CPU consumption on the server
|
||||||
|
* side. Use high levels with very slow network connections. Default value is `2`.
|
||||||
|
*/
|
||||||
|
public compressionLevel: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is an `object` indicating which optional extensions are available on the server. Some methods
|
||||||
|
* may only be called if the corresponding capability is set. The following capabilities are
|
||||||
|
* defined:
|
||||||
|
*
|
||||||
|
* | name | type | description
|
||||||
|
* | -------- | --------- | -----------
|
||||||
|
* | `power` | `boolean` | Machine power control is available
|
||||||
|
*/
|
||||||
|
public readonly capabilities: {
|
||||||
|
/** Machine power control is available */
|
||||||
|
power: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect from the server.
|
||||||
|
*/
|
||||||
|
public disconnect(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send credentials to server. Should be called after the
|
||||||
|
* {@link NoVncEventType.credentialsrequired} event has fired.
|
||||||
|
*
|
||||||
|
* @param credentials An {@link NoVncCredentials} specifying the credentials to provide to the
|
||||||
|
* server when authenticating.
|
||||||
|
*/
|
||||||
|
public sendCredentials(credentials: NoVncCredentials): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a key event to the server.
|
||||||
|
*
|
||||||
|
* @param keysym A `number` specifying the NoVncClient keysym to send. Can be `0` if a valid
|
||||||
|
* **`code`** is specified.
|
||||||
|
* @param code A `string` specifying the physical key to send. Valid values are those that can
|
||||||
|
* be specified to {@link KeyboardEvent.code}. If the physical key cannot be determined then
|
||||||
|
* `null` shall be specified.
|
||||||
|
* @param down A `boolean` specifying if a press or a release event should be sent. If omitted
|
||||||
|
* then both a press and release event are sent.
|
||||||
|
*/
|
||||||
|
public sendKey(keysym: number, code: string | null, down?: boolean): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the key sequence *left Control*, *left Alt*, *Delete*. This is a convenience wrapper
|
||||||
|
* around {@link sendKey}.
|
||||||
|
*/
|
||||||
|
public sendCtrlAltDel(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the keyboard focus on the remote session. Keyboard events will be sent to the remote
|
||||||
|
* server after this point.
|
||||||
|
*
|
||||||
|
* @param options A {@link FocusOptions} providing options to control how the focus will be
|
||||||
|
* performed. Please see {@link HTMLElement.focus} for available options.
|
||||||
|
*/
|
||||||
|
public focus(options?: FocusOptions): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove keyboard focus on the remote session. Keyboard events will no longer be sent to the
|
||||||
|
* remote server after this point.
|
||||||
|
*/
|
||||||
|
public blur(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request to shut down the remote machine. The capability `power` must be set for this method
|
||||||
|
* to have any effect.
|
||||||
|
*/
|
||||||
|
public machineShutdown(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a clean reboot of the remote machine. The capability `power` must be set for this
|
||||||
|
* method to have any effect.
|
||||||
|
*/
|
||||||
|
public machineReboot(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request a forced reset of the remote machine. The capability `power` must be set for this
|
||||||
|
* method to have any effect.
|
||||||
|
*/
|
||||||
|
public machineReset(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send clipboard data to the remote server.
|
||||||
|
*
|
||||||
|
* @param text A `string` specifying the clipboard data to send.
|
||||||
|
*/
|
||||||
|
public clipboardPasteFrom(text: string): void;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user