summaryrefslogtreecommitdiff
path: root/cli/js
diff options
context:
space:
mode:
Diffstat (limited to 'cli/js')
-rw-r--r--cli/js/deno_unstable.ts3
-rw-r--r--cli/js/globals.ts36
-rw-r--r--cli/js/lib.deno.ns.d.ts93
-rw-r--r--cli/js/lib.deno.shared_globals.d.ts54
-rw-r--r--cli/js/lib.deno.unstable.d.ts114
-rw-r--r--cli/js/ops/permissions.ts1
-rw-r--r--cli/js/permissions.ts79
-rw-r--r--cli/js/web/navigator.ts12
-rw-r--r--cli/js/web/permissions.ts181
9 files changed, 361 insertions, 212 deletions
diff --git a/cli/js/deno_unstable.ts b/cli/js/deno_unstable.ts
index 8744abba4..7d75c1c6a 100644
--- a/cli/js/deno_unstable.ts
+++ b/cli/js/deno_unstable.ts
@@ -19,9 +19,6 @@ export { shutdown, ShutdownMode } from "./net.ts";
export { listen, listenDatagram, connect } from "./net_unstable.ts";
export { startTls } from "./tls.ts";
export { kill } from "./ops/process.ts";
-export { permissions, Permissions } from "./permissions.ts";
-export { PermissionStatus } from "./permissions.ts";
-export type { PermissionName, PermissionState } from "./permissions.ts";
export { DiagnosticCategory } from "./diagnostics.ts";
export type {
Diagnostic,
diff --git a/cli/js/globals.ts b/cli/js/globals.ts
index 4548c8304..da6288bd2 100644
--- a/cli/js/globals.ts
+++ b/cli/js/globals.ts
@@ -7,7 +7,6 @@ import * as abortSignal from "./web/abort_signal.ts";
import * as blob from "./web/blob.ts";
import * as consoleTypes from "./web/console.ts";
import * as csprng from "./ops/get_random_values.ts";
-import type * as promiseTypes from "./web/promise.ts";
import * as customEvent from "./web/custom_event.ts";
import * as domException from "./web/dom_exception.ts";
import * as domFile from "./web/dom_file.ts";
@@ -17,16 +16,19 @@ import * as eventTarget from "./web/event_target.ts";
import * as formData from "./web/form_data.ts";
import * as fetchTypes from "./web/fetch.ts";
import * as headers from "./web/headers.ts";
+import * as navigator from "./web/navigator.ts";
+import * as permissions from "./web/permissions.ts";
+import * as performanceUtil from "./web/performance.ts";
+import type * as promiseTypes from "./web/promise.ts";
+import * as queuingStrategy from "./web/streams/queuing_strategy.ts";
+import * as readableStream from "./web/streams/readable_stream.ts";
+import * as request from "./web/request.ts";
import * as textEncoding from "./web/text_encoding.ts";
import * as timers from "./web/timers.ts";
+import * as transformStream from "./web/streams/transform_stream.ts";
import * as url from "./web/url.ts";
import * as urlSearchParams from "./web/url_search_params.ts";
import * as workers from "./web/workers.ts";
-import * as performanceUtil from "./web/performance.ts";
-import * as request from "./web/request.ts";
-import * as readableStream from "./web/streams/readable_stream.ts";
-import * as transformStream from "./web/streams/transform_stream.ts";
-import * as queuingStrategy from "./web/streams/queuing_strategy.ts";
import * as writableStream from "./web/streams/writable_stream.ts";
// These imports are not exposed and therefore are fine to just import the
@@ -221,24 +223,28 @@ export const windowOrWorkerGlobalScopeProperties = {
queuingStrategy.ByteLengthQueuingStrategyImpl
),
CountQueuingStrategy: nonEnumerable(queuingStrategy.CountQueuingStrategyImpl),
- crypto: readOnly(csprng),
- File: nonEnumerable(domFile.DomFileImpl),
CustomEvent: nonEnumerable(customEvent.CustomEventImpl),
+ crypto: readOnly(csprng),
DOMException: nonEnumerable(domException.DOMExceptionImpl),
ErrorEvent: nonEnumerable(errorEvent.ErrorEventImpl),
Event: nonEnumerable(event.EventImpl),
EventTarget: nonEnumerable(eventTarget.EventTargetImpl),
- URL: nonEnumerable(url.URLImpl),
- URLSearchParams: nonEnumerable(urlSearchParams.URLSearchParamsImpl),
- Headers: nonEnumerable(headers.HeadersImpl),
+ File: nonEnumerable(domFile.DomFileImpl),
FormData: nonEnumerable(formData.FormDataImpl),
- TextEncoder: nonEnumerable(textEncoding.TextEncoder),
- TextDecoder: nonEnumerable(textEncoding.TextDecoder),
+ Headers: nonEnumerable(headers.HeadersImpl),
+ navigator: nonEnumerable(new navigator.NavigatorImpl()),
+ Navigator: nonEnumerable(navigator.NavigatorImpl),
+ performance: writable(new performanceUtil.Performance()),
+ Permissions: nonEnumerable(permissions.PermissionsImpl),
+ PermissionStatus: nonEnumerable(permissions.PermissionStatusImpl),
ReadableStream: nonEnumerable(readableStream.ReadableStreamImpl),
- TransformStream: nonEnumerable(transformStream.TransformStreamImpl),
Request: nonEnumerable(request.Request),
Response: nonEnumerable(fetchTypes.Response),
- performance: writable(new performanceUtil.Performance()),
+ TextDecoder: nonEnumerable(textEncoding.TextDecoder),
+ TextEncoder: nonEnumerable(textEncoding.TextEncoder),
+ TransformStream: nonEnumerable(transformStream.TransformStreamImpl),
+ URL: nonEnumerable(url.URLImpl),
+ URLSearchParams: nonEnumerable(urlSearchParams.URLSearchParamsImpl),
Worker: nonEnumerable(workers.WorkerImpl),
WritableStream: nonEnumerable(writableStream.WritableStreamImpl),
};
diff --git a/cli/js/lib.deno.ns.d.ts b/cli/js/lib.deno.ns.d.ts
index 4a3417b5d..0b46a0c4d 100644
--- a/cli/js/lib.deno.ns.d.ts
+++ b/cli/js/lib.deno.ns.d.ts
@@ -19,6 +19,40 @@ declare interface ImportMeta {
main: boolean;
}
+declare interface Permissions {
+ /** Resolves to the current status of a permission.
+ *
+ * ```ts
+ * const status = await navigator.permissions.query({ name: "read", path: "/etc" });
+ * if (status.state === "granted") {
+ * data = await Deno.readFile("/etc/passwd");
+ * }
+ * ```
+ */
+ query(permissionDesc: Deno.PermissionDescriptor): Promise<PermissionStatus>;
+
+ /** Requests the permission, and resolves to the state of the permission.
+ *
+ * ```ts
+ * const status = await navigator.permissions.request({ name: "env" });
+ * if (status.state === "granted") {
+ * console.log(Deno.dir("home");
+ * } else {
+ * console.log("'env' permission is denied.");
+ * }
+ * ```
+ */
+ request(permissionDesc: Deno.PermissionDescriptor): Promise<PermissionStatus>;
+
+ /** Revokes a permission, and resolves to the state of the permission.
+ *
+ * ```ts
+ * const status = await Deno.revoke({ name: "run" });
+ * ```
+ */
+ revoke(permissionDesc: Deno.PermissionDescriptor): Promise<PermissionStatus>;
+}
+
declare namespace Deno {
/** A set of error constructors that are raised by Deno APIs. */
export const errors: {
@@ -1897,6 +1931,65 @@ declare namespace Deno {
* Requires `allow-run` permission. */
export function run<T extends RunOptions = RunOptions>(opt: T): Process<T>;
+ /** The name of a "powerful feature" which needs permission.
+ *
+ * See: https://w3c.github.io/permissions/#permission-registry
+ *
+ * Note that the definition of `PermissionName` in the above spec is swapped
+ * out for a set of Deno permissions which are not web-compatible. */
+ export type PermissionName =
+ | "run"
+ | "read"
+ | "write"
+ | "net"
+ | "env"
+ | "plugin"
+ | "hrtime";
+
+ export interface RunPermissionDescriptor {
+ name: "run";
+ }
+
+ export interface ReadPermissionDescriptor {
+ name: "read";
+ path?: string;
+ }
+
+ export interface WritePermissionDescriptor {
+ name: "write";
+ path?: string;
+ }
+
+ export interface NetPermissionDescriptor {
+ name: "net";
+ url?: string;
+ }
+
+ export interface EnvPermissionDescriptor {
+ name: "env";
+ }
+
+ export interface PluginPermissionDescriptor {
+ name: "plugin";
+ }
+
+ export interface HrtimePermissionDescriptor {
+ name: "hrtime";
+ }
+
+ /** Permission descriptors which define a permission and can be queried,
+ * requested, or revoked.
+ *
+ * See: https://w3c.github.io/permissions/#permission-descriptor */
+ export type PermissionDescriptor =
+ | RunPermissionDescriptor
+ | ReadPermissionDescriptor
+ | WritePermissionDescriptor
+ | NetPermissionDescriptor
+ | EnvPermissionDescriptor
+ | PluginPermissionDescriptor
+ | HrtimePermissionDescriptor;
+
interface InspectOptions {
depth?: number;
}
diff --git a/cli/js/lib.deno.shared_globals.d.ts b/cli/js/lib.deno.shared_globals.d.ts
index 0c32bd0ed..3492c0da1 100644
--- a/cli/js/lib.deno.shared_globals.d.ts
+++ b/cli/js/lib.deno.shared_globals.d.ts
@@ -1556,6 +1556,60 @@ declare const AbortSignal: {
new (): AbortSignal;
};
+type PermissionState = "denied" | "granted" | "prompt";
+
+interface PermissionStatusEventMap {
+ change: Event;
+}
+
+interface PermissionStatus extends EventTarget {
+ onchange: ((this: PermissionStatus, ev: Event) => any) | null;
+ readonly state: PermissionState;
+ addEventListener<K extends keyof PermissionStatusEventMap>(
+ type: K,
+ listener: (this: PermissionStatus, ev: PermissionStatusEventMap[K]) => any,
+ options?: boolean | AddEventListenerOptions
+ ): void;
+ addEventListener(
+ type: string,
+ listener: EventListenerOrEventListenerObject,
+ options?: boolean | AddEventListenerOptions
+ ): void;
+ removeEventListener<K extends keyof PermissionStatusEventMap>(
+ type: K,
+ listener: (this: PermissionStatus, ev: PermissionStatusEventMap[K]) => any,
+ options?: boolean | EventListenerOptions
+ ): void;
+ removeEventListener(
+ type: string,
+ listener: EventListenerOrEventListenerObject,
+ options?: boolean | EventListenerOptions
+ ): void;
+}
+
+/** Deno does not currently support any of the browser permissions, and so the
+ * `name` property of the global types is `undefined`. The Deno permissions
+ * that are supported are defined in the `lib.deno.ns.d.ts` and pull from the
+ * `Deno` namespace. */
+declare interface PermissionDescriptor {
+ name: undefined;
+}
+
+declare interface Permissions {
+ query(permissionDesc: PermissionDescriptor): Promise<PermissionStatus>;
+}
+
+declare const Permissions: {
+ prototype: Permissions;
+ new (): Permissions;
+};
+
+declare class Navigator {
+ readonly permissions: Permissions;
+}
+
+declare const navigator: Navigator;
+
interface ErrorConstructor {
/** See https://v8.dev/docs/stack-trace-api#stack-trace-collection-for-custom-exceptions. */
// eslint-disable-next-line @typescript-eslint/ban-types
diff --git a/cli/js/lib.deno.unstable.d.ts b/cli/js/lib.deno.unstable.d.ts
index cec4f7f46..f237cd4be 100644
--- a/cli/js/lib.deno.unstable.d.ts
+++ b/cli/js/lib.deno.unstable.d.ts
@@ -956,120 +956,6 @@ declare namespace Deno {
* Requires `allow-run` permission. */
export function kill(pid: number, signo: number): void;
- /** The name of a "powerful feature" which needs permission.
- *
- * See: https://w3c.github.io/permissions/#permission-registry
- *
- * Note that the definition of `PermissionName` in the above spec is swapped
- * out for a set of Deno permissions which are not web-compatible. */
- export type PermissionName =
- | "run"
- | "read"
- | "write"
- | "net"
- | "env"
- | "plugin"
- | "hrtime";
-
- /** The current status of the permission.
- *
- * See: https://w3c.github.io/permissions/#status-of-a-permission */
- export type PermissionState = "granted" | "denied" | "prompt";
-
- export interface RunPermissionDescriptor {
- name: "run";
- }
-
- export interface ReadPermissionDescriptor {
- name: "read";
- path?: string;
- }
-
- export interface WritePermissionDescriptor {
- name: "write";
- path?: string;
- }
-
- export interface NetPermissionDescriptor {
- name: "net";
- /** Optional url associated with this descriptor.
- *
- * If specified: must be a valid url. Expected format: <scheme>://<host_or_ip>[:port][/path]
- * If the scheme is unknown, callers should specify some scheme, such as x:// na:// unknown://
- *
- * See: https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml */
- url?: string;
- }
-
- export interface EnvPermissionDescriptor {
- name: "env";
- }
-
- export interface PluginPermissionDescriptor {
- name: "plugin";
- }
-
- export interface HrtimePermissionDescriptor {
- name: "hrtime";
- }
-
- /** Permission descriptors which define a permission and can be queried,
- * requested, or revoked.
- *
- * See: https://w3c.github.io/permissions/#permission-descriptor */
- export type PermissionDescriptor =
- | RunPermissionDescriptor
- | ReadPermissionDescriptor
- | WritePermissionDescriptor
- | NetPermissionDescriptor
- | EnvPermissionDescriptor
- | PluginPermissionDescriptor
- | HrtimePermissionDescriptor;
-
- export class Permissions {
- /** Resolves to the current status of a permission.
- *
- * ```ts
- * const status = await Deno.permissions.query({ name: "read", path: "/etc" });
- * if (status.state === "granted") {
- * data = await Deno.readFile("/etc/passwd");
- * }
- * ```
- */
- query(desc: PermissionDescriptor): Promise<PermissionStatus>;
-
- /** Revokes a permission, and resolves to the state of the permission.
- *
- * const status = await Deno.permissions.revoke({ name: "run" });
- * assert(status.state !== "granted")
- */
- revoke(desc: PermissionDescriptor): Promise<PermissionStatus>;
-
- /** Requests the permission, and resolves to the state of the permission.
- *
- * ```ts
- * const status = await Deno.permissions.request({ name: "env" });
- * if (status.state === "granted") {
- * console.log(Deno.dir("home");
- * } else {
- * console.log("'env' permission is denied.");
- * }
- * ```
- */
- request(desc: PermissionDescriptor): Promise<PermissionStatus>;
- }
-
- /** **UNSTABLE**: Under consideration to move to `navigator.permissions` to
- * match web API. It could look like `navigator.permissions.query({ name: Deno.symbols.read })`.
- */
- export const permissions: Permissions;
-
- /** see: https://w3c.github.io/permissions/#permissionstatus */
- export class PermissionStatus {
- state: PermissionState;
- constructor(state: PermissionState);
- }
-
/** **UNSTABLE**: New API, yet to be vetted. Additional consideration is still
* necessary around the permissions required.
*
diff --git a/cli/js/ops/permissions.ts b/cli/js/ops/permissions.ts
index 74b9ba0f0..cb1cd7402 100644
--- a/cli/js/ops/permissions.ts
+++ b/cli/js/ops/permissions.ts
@@ -1,7 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { sendSync } from "./dispatch_json.ts";
-import type { PermissionState } from "../permissions.ts";
interface PermissionRequest {
name: string;
diff --git a/cli/js/permissions.ts b/cli/js/permissions.ts
deleted file mode 100644
index ab0612ad4..000000000
--- a/cli/js/permissions.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-import * as permissionsOps from "./ops/permissions.ts";
-
-export type PermissionName =
- | "read"
- | "write"
- | "net"
- | "env"
- | "run"
- | "plugin"
- | "hrtime";
-// NOTE: Keep in sync with cli/permissions.rs
-
-export type PermissionState = "granted" | "denied" | "prompt";
-
-export interface RunPermissionDescriptor {
- name: "run";
-}
-
-export interface ReadPermissionDescriptor {
- name: "read";
- path?: string;
-}
-
-export interface WritePermissionDescriptor {
- name: "write";
- path?: string;
-}
-
-export interface NetPermissionDescriptor {
- name: "net";
- url?: string;
-}
-
-export interface EnvPermissionDescriptor {
- name: "env";
-}
-
-export interface PluginPermissionDescriptor {
- name: "plugin";
-}
-
-export interface HrtimePermissionDescriptor {
- name: "hrtime";
-}
-
-export type PermissionDescriptor =
- | RunPermissionDescriptor
- | ReadPermissionDescriptor
- | WritePermissionDescriptor
- | NetPermissionDescriptor
- | EnvPermissionDescriptor
- | PluginPermissionDescriptor
- | HrtimePermissionDescriptor;
-
-export class PermissionStatus {
- constructor(public state: PermissionState) {}
- // TODO(kt3k): implement onchange handler
-}
-
-export class Permissions {
- query(desc: PermissionDescriptor): Promise<PermissionStatus> {
- const state = permissionsOps.query(desc);
- return Promise.resolve(new PermissionStatus(state));
- }
-
- revoke(desc: PermissionDescriptor): Promise<PermissionStatus> {
- const state = permissionsOps.revoke(desc);
- return Promise.resolve(new PermissionStatus(state));
- }
-
- request(desc: PermissionDescriptor): Promise<PermissionStatus> {
- const state = permissionsOps.request(desc);
- return Promise.resolve(new PermissionStatus(state));
- }
-}
-
-export const permissions = new Permissions();
diff --git a/cli/js/web/navigator.ts b/cli/js/web/navigator.ts
new file mode 100644
index 000000000..351c311d0
--- /dev/null
+++ b/cli/js/web/navigator.ts
@@ -0,0 +1,12 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+
+import { PermissionsImpl as Permissions } from "./permissions.ts";
+
+export class NavigatorImpl implements Navigator {
+ permissions = new Permissions();
+}
+
+Object.defineProperty(NavigatorImpl, "name", {
+ value: "Navigator",
+ configurable: true,
+});
diff --git a/cli/js/web/permissions.ts b/cli/js/web/permissions.ts
new file mode 100644
index 000000000..b8ddc26a7
--- /dev/null
+++ b/cli/js/web/permissions.ts
@@ -0,0 +1,181 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+
+import * as permissionsOps from "../ops/permissions.ts";
+import { EventTargetImpl as EventTarget } from "./event_target.ts";
+
+const permissionNames = [
+ "read",
+ "write",
+ "net",
+ "env",
+ "run",
+ "plugin",
+ "hrtime",
+] as const;
+
+type PermissionName = typeof permissionNames[number];
+
+interface RunPermissionDescriptor {
+ name: "run";
+}
+
+interface ReadPermissionDescriptor {
+ name: "read";
+ path?: string;
+}
+
+interface WritePermissionDescriptor {
+ name: "write";
+ path?: string;
+}
+
+interface NetPermissionDescriptor {
+ name: "net";
+ url?: string;
+}
+
+interface EnvPermissionDescriptor {
+ name: "env";
+}
+
+interface PluginPermissionDescriptor {
+ name: "plugin";
+}
+
+interface HrtimePermissionDescriptor {
+ name: "hrtime";
+}
+
+type DenoPermissionDescriptor =
+ | RunPermissionDescriptor
+ | ReadPermissionDescriptor
+ | WritePermissionDescriptor
+ | NetPermissionDescriptor
+ | EnvPermissionDescriptor
+ | PluginPermissionDescriptor
+ | HrtimePermissionDescriptor;
+
+interface StatusCacheValue {
+ state: PermissionState;
+ status: PermissionStatusImpl;
+}
+
+export class PermissionStatusImpl extends EventTarget
+ implements PermissionStatus {
+ #state: { state: PermissionState };
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ onchange: ((this: PermissionStatus, event: Event) => any) | null = null;
+
+ get state(): PermissionState {
+ return this.#state.state;
+ }
+
+ constructor(state: { state: PermissionState }) {
+ super();
+ this.#state = state;
+ }
+
+ dispatchEvent(event: Event): boolean {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ let dispatched = super.dispatchEvent(event as any);
+ if (dispatched && this.onchange) {
+ this.onchange.call(this, event);
+ dispatched = !event.defaultPrevented;
+ }
+ return dispatched;
+ }
+
+ get [Symbol.toStringTag](): string {
+ return "PermissionStatus";
+ }
+}
+
+/** A cache of `PermissionStatus` objects and their last known state. */
+const statusCache = new Map<string, StatusCacheValue>();
+
+/** Cache the state of a descriptor and return its `PermissionStatus`. */
+function cache(
+ desc: DenoPermissionDescriptor,
+ state: PermissionState
+): PermissionStatusImpl {
+ let key = desc.name;
+ if ((desc.name === "read" || desc.name === "write") && desc.path) {
+ key += `-${desc.path}`;
+ } else if (desc.name === "net" && desc.url) {
+ key += `-${desc.url}`;
+ }
+ if (statusCache.has(key)) {
+ const status = statusCache.get(key)!;
+ if (status.state !== state) {
+ status.state = state;
+ status.status.dispatchEvent(new Event("change", { cancelable: false }));
+ }
+ return status.status;
+ }
+ const status: { state: PermissionState; status?: PermissionStatusImpl } = {
+ state,
+ };
+ status.status = new PermissionStatusImpl(status);
+ statusCache.set(key, status as StatusCacheValue);
+ return status.status;
+}
+
+function isValidDescriptor(
+ desc: PermissionDescriptor | DenoPermissionDescriptor
+): desc is DenoPermissionDescriptor {
+ return permissionNames.includes(desc.name as PermissionName);
+}
+
+export class PermissionsImpl implements Permissions {
+ query(
+ desc: PermissionDescriptor | DenoPermissionDescriptor
+ ): Promise<PermissionStatus> {
+ if (!isValidDescriptor(desc)) {
+ return Promise.reject(
+ new TypeError(
+ `The provided value "${desc.name}" is not a valid permission name.`
+ )
+ );
+ }
+ const state = permissionsOps.query(desc);
+ return Promise.resolve(cache(desc, state) as PermissionStatus);
+ }
+
+ revoke(
+ desc: PermissionDescriptor | DenoPermissionDescriptor
+ ): Promise<PermissionStatus> {
+ if (!isValidDescriptor(desc)) {
+ return Promise.reject(
+ new TypeError(
+ `The provided value "${desc.name}" is not a valid permission name.`
+ )
+ );
+ }
+ const state = permissionsOps.revoke(desc);
+ return Promise.resolve(cache(desc, state) as PermissionStatus);
+ }
+
+ request(
+ desc: PermissionDescriptor | DenoPermissionDescriptor
+ ): Promise<PermissionStatus> {
+ if (!isValidDescriptor(desc)) {
+ return Promise.reject(
+ new TypeError(
+ `The provided value "${desc.name}" is not a valid permission name.`
+ )
+ );
+ }
+ const state = permissionsOps.request(desc);
+ return Promise.resolve(cache(desc, state) as PermissionStatus);
+ }
+}
+
+Object.defineProperty(PermissionStatusImpl, "name", {
+ value: "PermissionStatus",
+ configurable: true,
+});
+Object.defineProperty(PermissionsImpl, "name", {
+ value: "Permissions",
+ configurable: true,
+});