@monimesl/dot-simulator 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simulator.js","names":[],"sources":["../../../../core/dist/index.js","../../src/compatibility.ts","../../src/host-calls.ts","../../src/permissions.ts","../../src/host.ts","../../src/versions.ts","../../src/paths.ts","../../src/client/dash/system.ts","../../src/client/dom.ts","../../src/client/dash/ui.ts","../../src/client/dash/index.ts","../../src/client/dash/permissions.ts","../../src/client/wire.ts","../../src/client/simulator.ts"],"sourcesContent":["//#region src/view/component.ts\nfunction defineComponent(manifest) {\n\treturn {\n\t\tprops: {},\n\t\tevents: [],\n\t\t...manifest\n\t};\n}\nfunction eventProp(event) {\n\treturn `on${event.charAt(0).toUpperCase()}${event.slice(1)}`;\n}\nfunction isEventProp(name) {\n\tconst letterAfterOn = name.charAt(2);\n\treturn name.startsWith(\"on\") && letterAfterOn >= \"A\" && letterAfterOn <= \"Z\";\n}\nfunction eventName(prop) {\n\tconst name = prop.slice(2);\n\treturn name.charAt(0).toLowerCase() + name.slice(1);\n}\nfunction componentRegistry(manifests) {\n\tconst registry = {};\n\tfor (const manifest of manifests) {\n\t\tif (manifest.name in registry) throw new Error(`Component <${manifest.name}> is defined twice`);\n\t\tregistry[manifest.name] = manifest;\n\t}\n\treturn registry;\n}\n//#endregion\n//#region src/view/values.ts\nfunction toText(value) {\n\tswitch (typeof value) {\n\t\tcase \"string\": return value;\n\t\tcase \"number\":\n\t\tcase \"boolean\":\n\t\tcase \"bigint\": return String(value);\n\t\tcase \"object\": return value === null ? \"\" : JSON.stringify(value);\n\t\tdefault: return \"\";\n\t}\n}\nfunction toList(value) {\n\tif (Array.isArray(value)) return value;\n\tif (typeof value === \"object\" && value !== null && Symbol.iterator in value) return Array.from(value);\n\treturn [];\n}\n//#endregion\n//#region src/source/location.ts\nfunction createLocator(source) {\n\tconst lineStarts = [0];\n\tfor (let index = 0; index < source.length; index++) if (source[index] === \"\\n\") lineStarts.push(index + 1);\n\treturn (offset) => {\n\t\tlet low = 0;\n\t\tlet high = lineStarts.length - 1;\n\t\twhile (low < high) {\n\t\t\tconst middle = Math.floor((low + high + 1) / 2);\n\t\t\tif (lineStarts[middle] <= offset) low = middle;\n\t\t\telse high = middle - 1;\n\t\t}\n\t\treturn {\n\t\t\tline: low + 1,\n\t\t\tcolumn: offset - lineStarts[low] + 1,\n\t\t\toffset\n\t\t};\n\t};\n}\nfunction locationAt(source, offset) {\n\treturn createLocator(source)(offset);\n}\nfunction locatedMessage(message, file, location) {\n\tconst where = [\n\t\tfile,\n\t\tlocation?.line,\n\t\tlocation?.column\n\t].filter((part) => part !== void 0).join(\":\");\n\treturn where ? `${where}: ${message}` : message;\n}\n//#endregion\n//#region src/source/error.ts\nvar SourceError = class extends Error {\n\treason;\n\tfile;\n\tloc;\n\tconstructor(reason, file, location) {\n\t\tsuper(locatedMessage(reason, file, location));\n\t\tthis.reason = reason;\n\t\tthis.file = file;\n\t\tthis.loc = location;\n\t}\n};\n//#endregion\n//#region src/view/components/button.ts\nconst Button = defineComponent({\n\tname: \"Button\",\n\tprops: {\n\t\tvariant: [\"primary\", \"secondary\"],\n\t\tdisabled: \"boolean\"\n\t},\n\tevents: [\"click\"],\n\tchildren: \"text\"\n});\n//#endregion\n//#region src/view/components/image.ts\nconst Image = defineComponent({\n\tname: \"Image\",\n\tprops: {\n\t\tsrc: \"string\",\n\t\talt: \"string\",\n\t\twidth: \"number\",\n\t\theight: \"number\"\n\t},\n\tevents: [\"load\", \"error\"],\n\tchildren: \"none\"\n});\n//#endregion\n//#region src/view/components/input.ts\nconst Input = defineComponent({\n\tname: \"Input\",\n\tprops: {\n\t\tvalue: \"string\",\n\t\tplaceholder: \"string\",\n\t\tlabel: \"string\",\n\t\ttype: [\n\t\t\t\"text\",\n\t\t\t\"number\",\n\t\t\t\"email\",\n\t\t\t\"phone\",\n\t\t\t\"password\"\n\t\t],\n\t\tmaxLength: \"number\",\n\t\tdisabled: \"boolean\"\n\t},\n\tevents: [\"change\", \"submit\"],\n\tchildren: \"none\"\n});\n//#endregion\n//#region src/view/components/text.ts\nconst Text = defineComponent({\n\tname: \"Text\",\n\tprops: { variant: [\n\t\t\"title\",\n\t\t\"body\",\n\t\t\"caption\"\n\t] },\n\tchildren: \"text\",\n\tinline: true\n});\n//#endregion\n//#region src/view/components/view.ts\nconst View = defineComponent({\n\tname: \"View\",\n\tprops: {\n\t\tdirection: [\"column\", \"row\"],\n\t\tgap: [\n\t\t\t\"none\",\n\t\t\t\"small\",\n\t\t\t\"medium\",\n\t\t\t\"large\"\n\t\t],\n\t\talign: [\n\t\t\t\"stretch\",\n\t\t\t\"start\",\n\t\t\t\"center\",\n\t\t\t\"end\"\n\t\t],\n\t\tvariant: [\"plain\", \"card\"]\n\t},\n\tevents: [\"tap\"],\n\tchildren: \"elements\"\n});\n//#endregion\n//#region src/view/components/index.ts\nconst builtinComponents = {\n\tButton,\n\tImage,\n\tInput,\n\tText,\n\tView\n};\nconst builtinRegistry = componentRegistry(Object.values(builtinComponents));\n//#endregion\n//#region src/event/emitter.ts\nvar EventEmitter = class {\n\t#listeners = /* @__PURE__ */ new Map();\n\ton(name, listener) {\n\t\tconst listeners = this.#listeners.get(name) ?? /* @__PURE__ */ new Set();\n\t\tthis.#listeners.set(name, listeners);\n\t\tlisteners.add(listener);\n\t\treturn () => listeners.delete(listener);\n\t}\n\temit(name, ...args) {\n\t\tthis.#listeners.get(name)?.forEach((listener) => listener(...args));\n\t}\n};\n//#endregion\n//#region src/event/core.ts\nfunction createEvent(type, detail = {}) {\n\treturn {\n\t\ttype,\n\t\tdetail\n\t};\n}\n//#endregion\n//#region src/host/host.ts\nfunction hostTransport() {\n\tconst transport = globalThis.__hostTransport;\n\tif (!transport) throw new Error(\"No Dot host found: expected `globalThis.__hostTransport` to be available at runtime. Dots run inside the Dash App, or a simulator via `dotctl dev`.\");\n\treturn transport;\n}\n//#endregion\n//#region src/host/context.ts\nconst DEFAULT_SYSTEM_CONTEXT = {\n\tscheme: \"light\",\n\tappState: \"active\"\n};\n//#endregion\n//#region src/host/calls.ts\nvar HostError = class extends Error {\n\tname = \"HostError\";\n\tcode;\n\tconstructor(code, message) {\n\t\tsuper(message);\n\t\tthis.code = code;\n\t}\n};\nlet connectedCaller = null;\nfunction connectHost(caller) {\n\tconnectedCaller = caller;\n}\nfunction callHost(method, params, options = {}) {\n\tif (!connectedCaller) {\n\t\tconst error = new HostError(\"unsupported\", `No host to run \"${method}\": host calls run in the service`);\n\t\treturn createHostRequest(Promise.reject(error));\n\t}\n\treturn connectedCaller(method, params, options);\n}\nfunction createHostRequest(promise, cancel = () => {}) {\n\tconst request = promise;\n\trequest.cancel = cancel;\n\treturn request;\n}\n//#endregion\n//#region src/host/permissions.ts\nconst PERMISSIONS = [\"account\"];\nfunction isPermission(value) {\n\treturn PERMISSIONS.includes(value);\n}\n//#endregion\n//#region src/version/semantic-version.ts\nconst SEMVER_PATTERN = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/;\nfunction isSemanticVersion(value) {\n\treturn typeof value === \"string\" && SEMVER_PATTERN.test(value);\n}\nfunction majorVersion(version) {\n\treturn parseVersion(version).major;\n}\nfunction isVersionAtLeast(version, minimum) {\n\treturn compareVersions(version, minimum) >= 0;\n}\nfunction compareVersions(left, right) {\n\tconst leftVersion = parseVersion(left);\n\tconst rightVersion = parseVersion(right);\n\tconst differences = [\n\t\tleftVersion.major - rightVersion.major,\n\t\tleftVersion.minor - rightVersion.minor,\n\t\tleftVersion.patch - rightVersion.patch\n\t];\n\tfor (const difference of differences) if (difference !== 0) return difference;\n\treturn comparePrereleases(leftVersion.prerelease, rightVersion.prerelease);\n}\nfunction parseVersion(version) {\n\tconst match = SEMVER_PATTERN.exec(version);\n\tif (!match) throw new Error(`\"${version}\" is not a semantic version`);\n\tconst [, major, minor, patch, prerelease] = match;\n\treturn {\n\t\tmajor: Number(major),\n\t\tminor: Number(minor),\n\t\tpatch: Number(patch),\n\t\tprerelease: prerelease === void 0 ? [] : prerelease.split(\".\")\n\t};\n}\nfunction comparePrereleases(left, right) {\n\tif (left.length === 0 || right.length === 0) return right.length - left.length;\n\tconst shared = Math.min(left.length, right.length);\n\tfor (let index = 0; index < shared; index++) {\n\t\tconst order = compareIdentifiers(left[index], right[index]);\n\t\tif (order !== 0) return order;\n\t}\n\treturn left.length - right.length;\n}\nfunction compareIdentifiers(left, right) {\n\tconst leftIsNumber = /^\\d+$/.test(left);\n\tconst rightIsNumber = /^\\d+$/.test(right);\n\tif (leftIsNumber && rightIsNumber) return Number(left) - Number(right);\n\tif (leftIsNumber) return -1;\n\tif (rightIsNumber) return 1;\n\tif (left < right) return -1;\n\tif (left > right) return 1;\n\treturn 0;\n}\n//#endregion\n//#region src/host/react.ts\nconst REACT_HOST_PATH = \"/__dot/react/\";\nconst REACT_HOST_MODULES = {\n\treact: \"react.js\",\n\t\"react/jsx-runtime\": \"react-jsx-runtime.js\",\n\t\"react-dom/client\": \"react-dom-client.js\"\n};\nfunction reactHostUrl(dotReactVersion, file) {\n\treturn `${REACT_HOST_PATH}${majorVersion(dotReactVersion)}/${file}`;\n}\nfunction isReactCompatible(hostVersion, dotVersion) {\n\treturn majorVersion(hostVersion) === majorVersion(dotVersion) && isVersionAtLeast(hostVersion, dotVersion);\n}\nfunction newestReactOfMajor(versions, major) {\n\treturn versions.filter((version) => majorVersion(version) === major).sort(compareVersions).at(-1);\n}\n//#endregion\n//#region src/protocol/transport.ts\nfunction createAdaptorTransport(adapter) {\n\treturn {\n\t\tpost: (message) => adapter.postMessage(message),\n\t\tlisten(listener) {\n\t\t\tconst onMessage = (event) => listener(event.data);\n\t\t\tadapter.addEventListener(\"message\", onMessage);\n\t\t\treturn () => adapter.removeEventListener(\"message\", onMessage);\n\t\t}\n\t};\n}\nfunction createTransportPair() {\n\tconst firstListeners = /* @__PURE__ */ new Set();\n\tconst secondListeners = /* @__PURE__ */ new Set();\n\tconst createSide = (ownListeners, otherListeners) => ({\n\t\tpost: (message) => {\n\t\t\tconst copy = JSON.parse(JSON.stringify(message));\n\t\t\totherListeners.forEach((listener) => listener(copy));\n\t\t},\n\t\tlisten(listener) {\n\t\t\townListeners.add(listener);\n\t\t\treturn () => ownListeners.delete(listener);\n\t\t}\n\t});\n\treturn [createSide(firstListeners, secondListeners), createSide(secondListeners, firstListeners)];\n}\nconst PAGE_HOOKS = Object.keys({\n\tonLoad: true,\n\tonShow: true,\n\tonHide: true,\n\tonUnload: true\n});\n//#endregion\n//#region src/page/navigation.ts\nconst MAX_STACK_DEPTH = 8;\nconst PAGE_ID = /^[A-Za-z0-9_-]+(?:\\/[A-Za-z0-9_-]+)*$/;\nfunction isPageId(value) {\n\treturn PAGE_ID.test(value);\n}\nvar NavigationStack = class {\n\tlimit;\n\t#pages = [];\n\t#nextInstanceId = 1;\n\tconstructor(limit = 8) {\n\t\tthis.limit = limit;\n\t}\n\tget pages() {\n\t\treturn this.#pages;\n\t}\n\tget top() {\n\t\treturn this.#pages.at(-1);\n\t}\n\t/**\n\t* Applies a navigation, or refuses it and returns false: a push onto a full stack, or going back\n\t* from the first page (which the host handles itself, e.g. by closing the dot).\n\t*/\n\tapply(navigation) {\n\t\tswitch (navigation.action) {\n\t\t\tcase \"push\":\n\t\t\t\tif (this.#pages.length >= this.limit) return false;\n\t\t\t\tbreak;\n\t\t\tcase \"replace\":\n\t\t\t\tthis.#pages.pop();\n\t\t\t\tbreak;\n\t\t\tcase \"reset\":\n\t\t\t\tthis.#pages = [];\n\t\t\t\tbreak;\n\t\t\tcase \"back\": {\n\t\t\t\tconst count = Math.min(navigation.delta, this.#pages.length - 1);\n\t\t\t\tif (count < 1) return false;\n\t\t\t\tthis.#pages = this.#pages.slice(0, -count);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\tconst { page, options } = navigation;\n\t\tthis.#pages = [...this.#pages, {\n\t\t\tinstanceId: this.#nextInstanceId++,\n\t\t\tpage,\n\t\t\toptions\n\t\t}];\n\t\treturn true;\n\t}\n};\n//#endregion\n//#region src/page/state.ts\nfunction applyChanges(state, changes) {\n\tconst next = { ...state };\n\tfor (const [key, value] of Object.entries(changes)) if (value !== void 0) next[key] = value;\n\treturn next;\n}\n//#endregion\n//#region src/messageChannel.ts\nvar MessageChannel = class {\n\t#transport;\n\t#handlers = /* @__PURE__ */ new Map();\n\tconstructor(transport) {\n\t\tthis.#transport = transport;\n\t}\n\tsend(type, payload) {\n\t\tthis.#transport.post({\n\t\t\ttype,\n\t\t\tpayload\n\t\t});\n\t}\n\thandle(type, handler) {\n\t\tconst previous = this.#handlers.get(type);\n\t\tthis.#handlers.set(type, handler);\n\t\treturn previous;\n\t}\n\tlisten(onError) {\n\t\treturn this.#transport.listen((rawMessage) => {\n\t\t\tconst message = rawMessage;\n\t\t\tconst handler = this.#handlers.get(message.type);\n\t\t\tif (!handler) {\n\t\t\t\tonError(/* @__PURE__ */ new Error(`No handler registered for message \"${message.type}\"`), message);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\thandler(message.payload);\n\t\t\t} catch (error) {\n\t\t\t\tonError(error, message);\n\t\t\t}\n\t\t});\n\t}\n};\n//#endregion\nexport { Button, DEFAULT_SYSTEM_CONTEXT, EventEmitter, HostError, Image, Input, MAX_STACK_DEPTH, MessageChannel, NavigationStack, PAGE_HOOKS, PERMISSIONS, REACT_HOST_MODULES, REACT_HOST_PATH, SEMVER_PATTERN, SourceError, Text, View, applyChanges, builtinComponents, builtinRegistry, callHost, compareVersions, componentRegistry, connectHost, createAdaptorTransport, createEvent, createHostRequest, createLocator, createTransportPair, defineComponent, eventName, eventProp, hostTransport, isEventProp, isPageId, isPermission, isReactCompatible, isSemanticVersion, isVersionAtLeast, locatedMessage, locationAt, majorVersion, newestReactOfMajor, reactHostUrl, toList, toText };\n\n//# sourceMappingURL=index.js.map","import { isReactCompatible, isVersionAtLeast, majorVersion } from '@monimesl/dot-core';\n\nimport type { HostManifest } from './manifest';\n\nexport type IncompatibilityReason = 'runtimeTooOld' | 'dashTooOld' | 'reactUnavailable';\n\n// The two versions a host knows about itself.\nexport interface HostVersions {\n // The Dash version this host is, checked against the dot's `dash.minVersion`.\n readonly dashVersion: string;\n // The oldest @monimesl/dot-runtime this host runs. Dots built with an older one must be rebuilt.\n readonly minRuntimeVersion: string;\n // The React versions the host ships. Left out by a host that serves the React the dot was built\n // with, as the simulator does.\n readonly reactVersions?: readonly string[] | undefined;\n}\n\n// Why a host refuses to open a dot: it was built with a runtime older than the host runs, it needs\n// a newer Dash than the host is, or it imports a React the host doesn't ship.\nexport class IncompatibleDotError extends Error {\n override readonly name = 'IncompatibleDotError';\n readonly reason: IncompatibilityReason;\n\n constructor(reason: IncompatibilityReason, message: string) {\n super(message);\n this.reason = reason;\n }\n}\n\n// Throws an IncompatibleDotError when a host with these versions cannot run the dot.\nexport function checkCompatibility(\n manifest: HostManifest,\n { dashVersion, minRuntimeVersion, reactVersions }: HostVersions,\n): void {\n if (!isVersionAtLeast(manifest.runtime, minRuntimeVersion)) {\n throw new IncompatibleDotError(\n 'runtimeTooOld',\n `This dot was built with Dot runtime ${manifest.runtime}, but this host runs ${minRuntimeVersion} or newer. ` +\n 'Rebuild it with a newer @monimesl/dot-runtime.',\n );\n }\n const minDashVersion = manifest.dash?.minVersion;\n if (minDashVersion !== undefined && !isVersionAtLeast(dashVersion, minDashVersion)) {\n throw new IncompatibleDotError(\n 'dashTooOld',\n `This dot needs Dash ${minDashVersion} or newer, and this is Dash ${dashVersion}.`,\n );\n }\n if (\n reactVersions !== undefined &&\n !reactVersions.some((version) => isReactCompatible(version, manifest.react))\n ) {\n throw new IncompatibleDotError(\n 'reactUnavailable',\n `This dot needs React ${manifest.react} or a newer ${majorVersion(manifest.react)}.x, which this host doesn't ship.`,\n );\n }\n}\n","import type {\n DotPermission,\n HostErrorCode,\n HostResult,\n LogicLayerMessages,\n} from '@monimesl/dot-core';\nimport { HostError } from '@monimesl/dot-core';\n\nimport type { PermissionGate } from './permissions';\n\nexport interface HostCall {\n readonly method: string;\n readonly params: unknown;\n // Aborted when the call ends early: cancelled, out of time, or dismissed with its page.\n readonly signal: AbortSignal;\n}\n\n// Runs one host method. Throw a `HostError` to fail with its code; anything else fails as `failed`.\nexport type HostHandler = (call: HostCall) => unknown;\n\n// A method that needs a permission: it runs only if the dot declared it and the person allowed it.\nexport interface PermissionedHandler {\n readonly permission: DotPermission;\n readonly handle: HostHandler;\n}\n\nexport type HostHandlers = Readonly<Record<string, HostHandler | PermissionedHandler>>;\n\nconst UI_METHOD_PREFIX = 'dash.ui.';\n\ninterface RunningCall {\n readonly method: string;\n readonly controller: AbortController;\n timer?: ReturnType<typeof setTimeout>;\n}\n\n// Runs the service's host calls with `handlers`, and answers each call exactly once.\nexport class HostCallRunner {\n readonly #handlers: HostHandlers;\n readonly #permissions: PermissionGate;\n readonly #answer: (result: HostResult) => void;\n readonly #running = new Map<number, RunningCall>();\n\n constructor(\n handlers: HostHandlers,\n permissions: PermissionGate,\n answer: (result: HostResult) => void,\n ) {\n this.#handlers = handlers;\n this.#permissions = permissions;\n this.#answer = answer;\n }\n\n run({ id, method, params, timeout }: LogicLayerMessages['hostCall']): void {\n const entry = this.#handlers[method];\n if (!entry) {\n this.#answer({ id, error: { code: 'unsupported', message: `This host has no \"${method}\"` } });\n return;\n }\n const call: RunningCall = { method, controller: new AbortController() };\n if (timeout !== undefined) {\n call.timer = setTimeout(() => {\n this.#fail(id, new HostError('timeout', `\"${method}\" took longer than ${timeout}ms`));\n }, timeout);\n }\n this.#running.set(id, call);\n void this.#invoke(id, entry, { method, params, signal: call.controller.signal });\n }\n\n // The service stopped waiting, so the call ends without an answer.\n cancel(id: number): void {\n this.#end(id)?.controller.abort();\n }\n\n // Dialogs belong to the page on top: when it changes, the ones still open are dismissed.\n dismissUI(): void {\n for (const [id, call] of this.#running) {\n if (call.method.startsWith(UI_METHOD_PREFIX)) {\n this.#fail(id, new HostError('cancelled', 'The page it was shown on is no longer on top'));\n }\n }\n }\n\n async #invoke(\n id: number,\n entry: HostHandler | PermissionedHandler,\n call: HostCall,\n ): Promise<void> {\n try {\n if (typeof entry === 'function') {\n this.#succeed(id, await entry(call));\n return;\n }\n await this.#permissions.check(call.method, entry.permission, call.signal);\n this.#succeed(id, await entry.handle(call));\n } catch (error) {\n this.#fail(id, error);\n }\n }\n\n #succeed(id: number, value: unknown): void {\n if (this.#end(id)) {\n this.#answer({ id, value });\n }\n }\n\n #fail(id: number, error: unknown): void {\n const call = this.#end(id);\n if (!call) {\n return;\n }\n call.controller.abort();\n this.#answer({ id, error: describeError(error) });\n }\n\n #end(id: number): RunningCall | undefined {\n const call = this.#running.get(id);\n if (call) {\n this.#running.delete(id);\n clearTimeout(call.timer);\n }\n return call;\n }\n}\n\nfunction describeError(error: unknown): { code: HostErrorCode; message: string } {\n if (error instanceof HostError) {\n return { code: error.code, message: error.message };\n }\n return { code: 'failed', message: error instanceof Error ? error.message : String(error) };\n}\n","import type { DotPermission } from '@monimesl/dot-core';\nimport { HostError } from '@monimesl/dot-core';\n\n// A dot asking for a permission it declared, the first time a call needs it.\nexport interface PermissionRequest {\n readonly dotName: string;\n readonly permission: DotPermission;\n // Why the dot needs it, from its dot.json.\n readonly reason: string;\n}\n\n// Each permission a dot declared in its dot.json, with the reason Dash shows the person.\nexport type DeclaredPermissions = Readonly<Partial<Record<string, string>>>;\n\n// Asks the person, and resolves with whether they allowed it. `signal` aborts when the call that\n// needs the permission ends first; the host then takes its prompt down and rejects.\nexport type AskPermission = (request: PermissionRequest, signal: AbortSignal) => Promise<boolean>;\n\n// Lets a call that needs a permission through only if the dot declared it and the person allowed\n// it. The person is asked once per run; the answer, yes or no, is kept.\nexport class PermissionGate {\n readonly #dotName: string;\n readonly #declared: DeclaredPermissions;\n readonly #ask: AskPermission;\n readonly #answers = new Map<DotPermission, boolean>();\n\n constructor(dotName: string, declared: DeclaredPermissions, ask: AskPermission) {\n this.#dotName = dotName;\n this.#declared = declared;\n this.#ask = ask;\n }\n\n // Rejects with a `denied` HostError when the call may not run.\n async check(method: string, permission: DotPermission, signal: AbortSignal): Promise<void> {\n const reason = this.#declared[permission];\n if (reason === undefined) {\n throw new HostError(\n 'denied',\n `\"${method}\" needs the \"${permission}\" permission. Add it to dot.json's permissions, with the reason Dash shows the person.`,\n );\n }\n let allowed = this.#answers.get(permission);\n if (allowed === undefined) {\n allowed = await this.#ask({ dotName: this.#dotName, permission, reason }, signal);\n this.#answers.set(permission, allowed);\n }\n if (!allowed) {\n throw new HostError('denied', `The person did not allow \"${permission}\"`);\n }\n }\n}\n","import type {\n Envelope,\n HostLayerMessages,\n HostResult,\n LogicLayerMessages,\n Navigation,\n SystemContext,\n Transport,\n} from '@monimesl/dot-core';\nimport { NavigationStack } from '@monimesl/dot-core';\n\nimport type { HostVersions } from './compatibility';\nimport { checkCompatibility } from './compatibility';\nimport type { HostHandlers } from './host-calls';\nimport { HostCallRunner } from './host-calls';\nimport type { HostManifest } from './manifest';\nimport type { AskPermission } from './permissions';\nimport { PermissionGate } from './permissions';\n\nexport type Direction = 'toService' | 'toWebview' | 'toHost' | 'fromHost';\n\nexport interface HostOptions extends HostVersions {\n ui: Transport;\n logic: Transport;\n manifest: HostManifest;\n systemContext: SystemContext;\n // The methods dots may call, such as `dash.ui.alert`; any other is answered `unsupported`.\n handlers?: HostHandlers;\n // Asks the person for a permission the dot declared, the first time a method needs it.\n askPermission: AskPermission;\n observe?: (direction: Direction, message: Envelope) => void;\n}\n\nexport interface Host {\n stop(): void;\n // false on the first page, where a device closes the dot instead.\n back(): boolean;\n setSystemContext(context: SystemContext): void;\n}\n\n// The host contract in JavaScript; native hosts implement the same in Swift or Kotlin.\n// Throws an IncompatibleDotError, before either layer hears anything, if it cannot run the dot.\nexport function startHost({\n logic,\n ui,\n manifest,\n dashVersion,\n minRuntimeVersion,\n systemContext,\n handlers = {},\n askPermission,\n observe,\n}: HostOptions): Host {\n checkCompatibility(manifest, { dashVersion, minRuntimeVersion });\n const stack = new NavigationStack();\n let context = systemContext;\n const permissions = new PermissionGate(manifest.name, manifest.permissions ?? {}, askPermission);\n const calls = new HostCallRunner(handlers, permissions, (result) => {\n const message: Envelope<'hostResult', HostResult> = { type: 'hostResult', payload: result };\n observe?.('fromHost', message);\n logic.post(message);\n });\n const broadcast = (message: Envelope) => {\n observe?.('fromHost', message);\n ui.post(message);\n logic.post(message);\n };\n const syncStack = () => {\n const message: Envelope<'syncStack', HostLayerMessages['syncStack']> = {\n type: 'syncStack',\n payload: { pages: stack.pages, limit: stack.limit },\n };\n broadcast(message);\n };\n const syncSystemContext = () => {\n const message: Envelope<'syncSystemContext', HostLayerMessages['syncSystemContext']> = {\n type: 'syncSystemContext',\n payload: context,\n };\n broadcast(message);\n };\n const navigate = (navigation: Navigation): boolean => {\n if (navigation.action !== 'back' && !manifest.pages.includes(navigation.page)) {\n return false;\n }\n const previousTop = stack.top;\n if (!stack.apply(navigation)) {\n return false;\n }\n syncStack();\n if (stack.top !== previousTop) {\n calls.dismissUI();\n }\n return true;\n };\n\n // Only the page on top may navigate; a request from a page below it is dropped.\n const navigateFromPage = ({ from, ...navigation }: LogicLayerMessages['navigate']) => {\n if (from === stack.top?.instanceId) {\n navigate(navigation);\n }\n };\n // Service messages meant for the host itself; every other one is relayed to the webview.\n const hostMessageHandlers = new Map<string, (payload: unknown) => void>([\n ['navigate', (payload) => navigateFromPage(payload as LogicLayerMessages['navigate'])],\n ['hostCall', (payload) => calls.run(payload as LogicLayerMessages['hostCall'])],\n ['hostCancel', (payload) => calls.cancel((payload as LogicLayerMessages['hostCancel']).id)],\n ]);\n\n const stopService = logic.listen((raw) => {\n const message = raw as Envelope;\n const handleHostMessage = hostMessageHandlers.get(message.type);\n if (handleHostMessage) {\n observe?.('toHost', message);\n handleHostMessage(message.payload);\n return;\n }\n observe?.('toWebview', message);\n ui.post(message);\n });\n const stopWebview = ui.listen((raw) => {\n const message = raw as Envelope;\n observe?.('toService', message);\n logic.post(message);\n if (message.type === 'connect') {\n syncSystemContext();\n navigate({ action: 'reset', page: manifest.entry, options: {} });\n }\n });\n return {\n back: () => navigate({ action: 'back', delta: 1 }),\n setSystemContext: (next) => {\n context = next;\n syncSystemContext();\n },\n stop: () => {\n stopService();\n stopWebview();\n },\n };\n}\n","import type { HostVersions } from './compatibility';\n\n// The Dash version the simulator acts as, for dots that set `dash.minVersion`.\nexport const SIMULATED_DASH_VERSION = '1.0.0';\n\n// The oldest @monimesl/dot-runtime whose bundles the simulator's bridge runs. Raise it when the\n// messages between the layers and the host change in a way older runtimes don't understand.\nexport const MIN_RUNTIME_VERSION = '0.1.0-alpha.1';\n\nexport const SIMULATOR_VERSIONS: HostVersions = {\n dashVersion: SIMULATED_DASH_VERSION,\n minRuntimeVersion: MIN_RUNTIME_VERSION,\n};\n","export const CLIENT_PATH = '/__dot/';\nexport const EVENTS_PATH = `${CLIENT_PATH}events`;\n\nexport const DOT_PATH = '/dot/';\nexport const WEBVIEW_URL = `${DOT_PATH}ui/index.html`;\nexport const SERVICE_URL = `${DOT_PATH}logic/dot.js`;\nexport const MANIFEST_URL = `${DOT_PATH}manifest.json`;\n","import type { TorchState, VibrateOptions } from '@monimesl/dot-dash';\n\nconst SHAKE_DURATION_MS = 300;\n\nconst SHAKE: Keyframe[] = [\n { transform: 'translateX(0)' },\n { transform: 'translateX(-5px)' },\n { transform: 'translateX(5px)' },\n { transform: 'translateX(-3px)' },\n { transform: 'translateX(3px)' },\n { transform: 'translateX(0)' },\n];\n\nexport async function vibrate(\n phone: HTMLElement,\n note: (text: string) => void,\n options: VibrateOptions,\n): Promise<void> {\n note(`vibrated: ${options.style}`);\n await phone.animate(SHAKE, { duration: SHAKE_DURATION_MS }).finished;\n}\n\nexport function torch(phone: HTMLElement, note: (text: string) => void, state: TorchState): void {\n phone.dataset.torch = state;\n note(`torch: ${state}`);\n}\n","export function element<T extends Element>(selector: string): T {\n const node = document.querySelector<T>(selector);\n if (!node) {\n throw new Error(`Simulator page is missing ${selector}`);\n }\n return node;\n}\n\nexport function createElement<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n className: string,\n text?: string,\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n node.className = className;\n if (text !== undefined) {\n node.textContent = text;\n }\n return node;\n}\n","import { HostError } from '@monimesl/dot-core';\nimport type { AlertAction, AlertOptions, AlertResult } from '@monimesl/dot-dash';\n\nimport { createElement } from '../dom';\n\n// dash.ui.alert always sends actions, but a host does not trust what the service sends.\nconst DEFAULT_ACTIONS: AlertAction[] = [{ id: 'ok', label: 'OK' }];\n\nexport function alert(\n phone: HTMLElement,\n options: AlertOptions,\n signal: AbortSignal,\n): Promise<AlertResult> {\n return new Promise((resolve, reject) => {\n const layer = createElement('div', 'dialog-layer');\n const dialog = createElement('div', 'dialog');\n dialog.setAttribute('role', 'alertdialog');\n const body = createElement('div', 'dialog-body');\n body.append(createElement('div', 'dialog-title', options.title));\n if (options.message) {\n body.append(createElement('div', 'dialog-message', options.message));\n }\n const actions = options.actions ?? DEFAULT_ACTIONS;\n // Two actions sit side by side, as on iOS; more are stacked.\n const buttons = createElement(\n 'div',\n actions.length === 2 ? 'dialog-actions' : 'dialog-actions stacked',\n );\n for (const action of actions) {\n const button = createElement('button', action.role ?? 'default', action.label);\n button.addEventListener('click', () => {\n layer.remove();\n resolve({ action: action.id });\n });\n buttons.append(button);\n }\n dialog.append(body, buttons);\n layer.append(dialog);\n signal.addEventListener('abort', () => {\n layer.remove();\n reject(new HostError('cancelled', 'The alert was dismissed'));\n });\n phone.append(layer);\n });\n}\n","import type { AlertOptions, TorchState, VibrateOptions } from '@monimesl/dot-dash';\n\nimport type { HostHandlers } from '../../host-calls';\nimport { vibrate, torch } from './system';\nimport { alert } from './ui';\n\n// Stand-ins for what a device does natively, drawn on the simulated phone.\nexport function dashHandlers(phone: HTMLElement, note: (text: string) => void): HostHandlers {\n return {\n 'dash.ui.alert': ({ params, signal }) => alert(phone, params as AlertOptions, signal),\n 'dash.system.vibrate': ({ params }) => vibrate(phone, note, params as VibrateOptions),\n 'dash.system.torch': ({ params }) =>\n torch(phone, note, (params as { state: TorchState }).state),\n };\n}\n","import type { DotPermission } from '@monimesl/dot-core';\n\nimport type { PermissionRequest } from '../../permissions';\nimport { alert } from './ui';\n\n// Finishes \"Allow “Counter” to …?\".\nconst PERMISSION_SUMMARIES: Record<DotPermission, string> = {\n account: 'see your Dash account: your name, and your email or phone',\n};\n\n// Asks as Dash would: the dot's name, what it wants, and the reason from its dot.json.\nexport async function askPermission(\n phone: HTMLElement,\n note: (text: string) => void,\n request: PermissionRequest,\n signal: AbortSignal,\n): Promise<boolean> {\n const { action } = await alert(\n phone,\n {\n title: `Allow “${request.dotName}” to ${PERMISSION_SUMMARIES[request.permission]}?`,\n message: request.reason,\n actions: [\n { id: 'deny', label: \"Don't Allow\", role: 'cancel' },\n { id: 'allow', label: 'Allow' },\n ],\n },\n signal,\n );\n const allowed = action === 'allow';\n if (allowed) {\n note(`permission ${request.permission}: allowed`);\n } else {\n note(`permission ${request.permission}: not allowed`);\n }\n return allowed;\n}\n","import type { Transport } from '@monimesl/dot-core';\n\n// Native bridges only carry strings, so JSON-encoding here makes state that a device could not\n// carry fail in the simulator too.\ninterface Wire {\n readonly dot: string;\n}\n\nfunction isWire(data: unknown): data is Wire {\n return typeof (data as Partial<Wire> | null)?.dot === 'string';\n}\n\nexport function wireTransport(channel: Transport): Transport {\n return {\n post: (message) => channel.post({ dot: JSON.stringify(message) } satisfies Wire),\n listen: (listener) =>\n channel.listen((data) => {\n if (isWire(data)) {\n listener(JSON.parse(data.dot));\n }\n }),\n };\n}\n\n// The simulator page and the webview's iframe, each accepting messages only from the other.\nexport function windowChannel(other: () => Window | null): Transport {\n return {\n post: (message) => other()?.postMessage(message, location.origin),\n listen(listener) {\n const onMessage = (event: MessageEvent) => {\n if (event.source === other()) {\n listener(event.data);\n }\n };\n window.addEventListener('message', onMessage);\n return () => window.removeEventListener('message', onMessage);\n },\n };\n}\n","import type { AppState, ColorScheme, Envelope, SystemContext } from '@monimesl/dot-core';\nimport { createAdaptorTransport } from '@monimesl/dot-core';\n\nimport type { Direction, Host } from '../host';\nimport type { HostManifest } from '../manifest';\nimport { checkCompatibility } from '../compatibility';\nimport { startHost } from '../host';\nimport { SIMULATOR_VERSIONS } from '../versions';\nimport { CLIENT_PATH, EVENTS_PATH, MANIFEST_URL, WEBVIEW_URL } from '../paths';\nimport { dashHandlers } from './dash';\nimport { askPermission } from './dash/permissions';\nimport { createElement, element } from './dom';\nimport { windowChannel, wireTransport } from './wire';\n\nconst MAX_LOG_ENTRIES = 500;\n\nconst screen = element<HTMLIFrameElement>('#screen');\nconst log = element<HTMLOListElement>('#log');\nconst errorBanner = element<HTMLPreElement>('#error');\nconst phone = element<HTMLDivElement>('.phone');\nconst schemeSelect = element<HTMLSelectElement>('#scheme');\nconst browserDark = matchMedia('(prefers-color-scheme: dark)');\n\ninterface RunningApp {\n readonly host: Host;\n readonly worker: Worker;\n}\n\nlet runningApp: RunningApp | null = null;\nlet launchCount = 0;\n\nasync function launch(): Promise<void> {\n stopRunningApp();\n launchCount += 1;\n const thisLaunch = launchCount;\n if (log.childElementCount > 0) {\n note('dot restarted');\n }\n\n let manifest: HostManifest;\n try {\n const response = await fetch(MANIFEST_URL);\n manifest = (await response.json()) as HostManifest;\n } catch {\n showError(`Nothing to run: ${MANIFEST_URL} is missing. Did the build fail?`);\n return;\n }\n // Another reload started while the manifest loaded; only the newest launch may start the dot.\n if (thisLaunch !== launchCount) {\n return;\n }\n\n // startHost checks too, but checking first means a refused dot never starts a worker.\n try {\n checkCompatibility(manifest, SIMULATOR_VERSIONS);\n } catch (error) {\n screen.src = 'about:blank';\n showError((error as Error).message);\n return;\n }\n\n const worker = new Worker(`${CLIENT_PATH}service-bridge.js`);\n const service = wireTransport(createAdaptorTransport(worker));\n const webview = wireTransport(windowChannel(() => screen.contentWindow));\n const host = startHost({\n logic: service,\n ui: webview,\n manifest,\n ...SIMULATOR_VERSIONS,\n systemContext: systemContext(),\n handlers: dashHandlers(phone, note),\n askPermission: (request, signal) => askPermission(phone, note, request, signal),\n observe: record,\n });\n worker.addEventListener('error', (event) => showError(`Service crashed: ${event.message}`));\n screen.src = WEBVIEW_URL;\n runningApp = { host, worker };\n}\n\nfunction stopRunningApp(): void {\n if (!runningApp) {\n return;\n }\n runningApp.host.stop();\n runningApp.worker.terminate();\n runningApp = null;\n}\n\nfunction goBack(): void {\n if (runningApp && !runningApp.host.back()) {\n note('back on the first page: a device would close the dot');\n }\n}\n\nconst ARROWS: Record<Direction, string> = {\n toHost: 'both --> host',\n fromHost: 'host --> both',\n toService: 'ui --> logic',\n toWebview: 'logic <-- ui',\n};\n\nfunction note(text: string): void {\n log.append(createElement('li', 'note', text));\n}\n\nfunction record(direction: Direction, message: Envelope): void {\n const entry = createElement('li', direction);\n const details = document.createElement('details');\n const summary = document.createElement('summary');\n const time = new Date().toLocaleTimeString([], { hour12: false });\n summary.append(\n createElement('span', 'time', time),\n createElement('span', 'arrow', ARROWS[direction]),\n createElement('span', 'type', message.type),\n );\n const payload = document.createElement('pre');\n payload.textContent = JSON.stringify(message.payload, null, 2);\n details.append(summary, payload);\n entry.append(details);\n if (message.type === 'error') {\n entry.classList.add('failed');\n }\n log.append(entry);\n while (log.childElementCount > MAX_LOG_ENTRIES) {\n log.firstElementChild?.remove();\n }\n log.scrollTop = log.scrollHeight;\n}\n\nfunction syncLaunch(): void {\n launch().catch((error: unknown) => {\n showError(`Could not start the dot: ${String(error)}`);\n });\n}\n\nfunction showError(message: string | null): void {\n errorBanner.hidden = message === null;\n errorBanner.textContent = message ?? '';\n}\n\nfunction systemContext(): SystemContext {\n return { scheme: schemeSelect.value as ColorScheme, appState: appState() };\n}\n\n// Leaving the simulator's tab stands in for leaving Dash.\nfunction appState(): AppState {\n if (document.visibilityState === 'hidden') {\n return 'background';\n }\n return 'active';\n}\n\nfunction browserScheme(): ColorScheme {\n return browserDark.matches ? 'dark' : 'light';\n}\n\nfunction changeScheme(scheme: ColorScheme): void {\n schemeSelect.value = scheme;\n phone.dataset.scheme = scheme;\n runningApp?.host.setSystemContext(systemContext());\n}\n\nconst events = new EventSource(EVENTS_PATH);\nevents.addEventListener('reload', () => {\n showError(null);\n syncLaunch();\n});\nevents.addEventListener('build-error', (event) => showError(String(event.data)));\n\nelement('#reload').addEventListener('click', syncLaunch);\nelement('#back').addEventListener('click', goBack);\nelement('#clear').addEventListener('click', () => log.replaceChildren());\nschemeSelect.addEventListener('change', () => changeScheme(schemeSelect.value as ColorScheme));\nbrowserDark.addEventListener('change', () => changeScheme(browserScheme()));\ndocument.addEventListener('visibilitychange', () => {\n runningApp?.host.setSystemContext(systemContext());\n});\n\nchangeScheme(browserScheme());\nsyncLaunch();\n"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ (function() {
2
+ //#region src/client/wire.ts
3
+ function isWire(data) {
4
+ return typeof data?.dot === "string";
5
+ }
6
+ function wireTransport(channel) {
7
+ return {
8
+ post: (message) => channel.post({ dot: JSON.stringify(message) }),
9
+ listen: (listener) => channel.listen((data) => {
10
+ if (isWire(data)) listener(JSON.parse(data.dot));
11
+ })
12
+ };
13
+ }
14
+ function windowChannel(other) {
15
+ return {
16
+ post: (message) => other()?.postMessage(message, location.origin),
17
+ listen(listener) {
18
+ const onMessage = (event) => {
19
+ if (event.source === other()) listener(event.data);
20
+ };
21
+ window.addEventListener("message", onMessage);
22
+ return () => window.removeEventListener("message", onMessage);
23
+ }
24
+ };
25
+ }
26
+ //#endregion
27
+ //#region src/client/webview-bridge.ts
28
+ globalThis.__hostTransport = wireTransport(windowChannel(() => window.parent));
29
+ //#endregion
30
+ })();
31
+
32
+ //# sourceMappingURL=webview-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webview-bridge.js","names":[],"sources":["../../src/client/wire.ts","../../src/client/webview-bridge.ts"],"sourcesContent":["import type { Transport } from '@monimesl/dot-core';\n\n// Native bridges only carry strings, so JSON-encoding here makes state that a device could not\n// carry fail in the simulator too.\ninterface Wire {\n readonly dot: string;\n}\n\nfunction isWire(data: unknown): data is Wire {\n return typeof (data as Partial<Wire> | null)?.dot === 'string';\n}\n\nexport function wireTransport(channel: Transport): Transport {\n return {\n post: (message) => channel.post({ dot: JSON.stringify(message) } satisfies Wire),\n listen: (listener) =>\n channel.listen((data) => {\n if (isWire(data)) {\n listener(JSON.parse(data.dot));\n }\n }),\n };\n}\n\n// The simulator page and the webview's iframe, each accepting messages only from the other.\nexport function windowChannel(other: () => Window | null): Transport {\n return {\n post: (message) => other()?.postMessage(message, location.origin),\n listen(listener) {\n const onMessage = (event: MessageEvent) => {\n if (event.source === other()) {\n listener(event.data);\n }\n };\n window.addEventListener('message', onMessage);\n return () => window.removeEventListener('message', onMessage);\n },\n };\n}\n","import { windowChannel, wireTransport } from './wire';\n\nglobalThis.__hostTransport = wireTransport(windowChannel(() => window.parent));\n"],"mappings":";;CAQA,SAAS,OAAO,MAA6B;EAC3C,OAAO,OAAQ,MAA+B,QAAQ;CACxD;CAEA,SAAgB,cAAc,SAA+B;EAC3D,OAAO;GACL,OAAO,YAAY,QAAQ,KAAK,EAAE,KAAK,KAAK,UAAU,OAAO,EAAE,CAAgB;GAC/E,SAAS,aACP,QAAQ,QAAQ,SAAS;IACvB,IAAI,OAAO,IAAI,GACb,SAAS,KAAK,MAAM,KAAK,GAAG,CAAC;GAEjC,CAAC;EACL;CACF;CAGA,SAAgB,cAAc,OAAuC;EACnE,OAAO;GACL,OAAO,YAAY,MAAM,CAAC,EAAE,YAAY,SAAS,SAAS,MAAM;GAChE,OAAO,UAAU;IACf,MAAM,aAAa,UAAwB;KACzC,IAAI,MAAM,WAAW,MAAM,GACzB,SAAS,MAAM,IAAI;IAEvB;IACA,OAAO,iBAAiB,WAAW,SAAS;IAC5C,aAAa,OAAO,oBAAoB,WAAW,SAAS;GAC9D;EACF;CACF;;;CCpCA,WAAW,kBAAkB,cAAc,oBAAoB,OAAO,MAAM,CAAC"}
@@ -0,0 +1,93 @@
1
+ import { DotPermission, Envelope, SystemContext, Transport } from "@monimesl/dot-core";
2
+ //#region src/permissions.d.ts
3
+ interface PermissionRequest {
4
+ readonly dotName: string;
5
+ readonly permission: DotPermission;
6
+ readonly reason: string;
7
+ }
8
+ type DeclaredPermissions = Readonly<Partial<Record<string, string>>>;
9
+ type AskPermission = (request: PermissionRequest, signal: AbortSignal) => Promise<boolean>;
10
+ //#endregion
11
+ //#region src/manifest.d.ts
12
+ interface HostManifest {
13
+ readonly name: string;
14
+ readonly runtime: string;
15
+ readonly react: string;
16
+ readonly entry: string;
17
+ readonly pages: readonly string[];
18
+ readonly dash?: {
19
+ readonly minVersion?: string | undefined;
20
+ } | undefined;
21
+ readonly permissions?: DeclaredPermissions | undefined;
22
+ }
23
+ //#endregion
24
+ //#region src/compatibility.d.ts
25
+ type IncompatibilityReason = 'runtimeTooOld' | 'dashTooOld' | 'reactUnavailable';
26
+ interface HostVersions {
27
+ readonly dashVersion: string;
28
+ readonly minRuntimeVersion: string;
29
+ readonly reactVersions?: readonly string[] | undefined;
30
+ }
31
+ export declare class IncompatibleDotError extends Error {
32
+ readonly name = "IncompatibleDotError";
33
+ readonly reason: IncompatibilityReason;
34
+ constructor(reason: IncompatibilityReason, message: string);
35
+ }
36
+ export declare function checkCompatibility(manifest: HostManifest, { dashVersion, minRuntimeVersion, reactVersions }: HostVersions): void;
37
+ //#endregion
38
+ //#region src/host-calls.d.ts
39
+ interface HostCall {
40
+ readonly method: string;
41
+ readonly params: unknown;
42
+ readonly signal: AbortSignal;
43
+ }
44
+ type HostHandler = (call: HostCall) => unknown;
45
+ interface PermissionedHandler {
46
+ readonly permission: DotPermission;
47
+ readonly handle: HostHandler;
48
+ }
49
+ type HostHandlers = Readonly<Record<string, HostHandler | PermissionedHandler>>;
50
+ //#endregion
51
+ //#region src/host.d.ts
52
+ type Direction = 'toService' | 'toWebview' | 'toHost' | 'fromHost';
53
+ interface HostOptions extends HostVersions {
54
+ ui: Transport;
55
+ logic: Transport;
56
+ manifest: HostManifest;
57
+ systemContext: SystemContext;
58
+ handlers?: HostHandlers;
59
+ askPermission: AskPermission;
60
+ observe?: (direction: Direction, message: Envelope) => void;
61
+ }
62
+ interface Host {
63
+ stop(): void;
64
+ back(): boolean;
65
+ setSystemContext(context: SystemContext): void;
66
+ }
67
+ export declare function startHost({ logic, ui, manifest, dashVersion, minRuntimeVersion, systemContext, handlers, askPermission, observe }: HostOptions): Host;
68
+ //#endregion
69
+ //#region src/versions.d.ts
70
+ export declare const SIMULATED_DASH_VERSION = "1.0.0";
71
+ export declare const MIN_RUNTIME_VERSION = "0.1.0-alpha.1";
72
+ export declare const SIMULATOR_VERSIONS: HostVersions;
73
+ //#endregion
74
+ //#region src/server.d.ts
75
+ interface SimulatorOptions {
76
+ dotDir: string;
77
+ reactHostDir?: string | undefined;
78
+ name?: string;
79
+ port?: number | undefined;
80
+ host?: string;
81
+ clientDir?: string;
82
+ }
83
+ interface Simulator {
84
+ readonly url: string;
85
+ reload(): void;
86
+ error(message: string): void;
87
+ close(): Promise<void>;
88
+ }
89
+ export declare const DEFAULT_PORT = 3680;
90
+ export declare function startSimulator({ dotDir, reactHostDir, name, port, host, clientDir }: SimulatorOptions): Promise<Simulator>;
91
+ //#endregion
92
+ export type { AskPermission, DeclaredPermissions, Direction, Host, HostCall, HostHandler, HostHandlers, HostManifest, HostOptions, HostVersions, IncompatibilityReason, PermissionRequest, PermissionedHandler, Simulator, SimulatorOptions };
93
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/permissions.ts","../../src/manifest.ts","../../src/compatibility.ts","../../src/host-calls.ts","../../src/host.ts","../../src/versions.ts","../../src/server.ts"],"mappings":";;UAIiB;WACN;WACA,YAAY;WAEZ;;KAIC,sBAAsB,SAAS,QAAQ;KAIvC,iBAAiB,SAAS,mBAAmB,QAAQ,gBAAgB;;;UCbhE;WACN;WAEA;WAEA;WACA;WACA;WACA;aAAkB;;WAClB,cAAc;;;;KCRb;UAGK;WAEN;WAEA;WAGA;;qBAKE,6BAA6B;WACtB;WACT,QAAQ;EAEL,YAAA,QAAQ,uBAAuB;;wBAO7B,mBACd,UAAU,gBACR,aAAa,mBAAmB,iBAAiB;;;UCtBpC;WACN;WACA;WAEA,QAAQ;;KAIP,eAAe,MAAM;UAGhB;WACN,YAAY;WACZ,QAAQ;;KAGP,eAAe,SAAS,eAAe,cAAc;;;KCPrD;UAEK,oBAAoB;EACnC,IAAI;EACJ,OAAO;EACP,UAAU;EACV,eAAe;EAEf,WAAW;EAEX,eAAe;EACf,WAAW,WAAW,WAAW,SAAS;;UAG3B;EACf;EAEA;EACA,iBAAiB,SAAS;;wBAKZ,YACd,OACA,IACA,UACA,aACA,mBACA,eACA,UACA,eACA,WACC,cAAc;;;qBCjDJ;qBAIA;qBAEA,oBAAoB;;;UCGhB;EACf;EAGA;EACA;EACA;EACA;EACA;;UAGe;WACN;EACT;EACA,MAAM;EACN,SAAS;;qBAGE;wBAmBS,iBACpB,QACA,cACA,MACA,MACA,MACA,aACC,mBAAmB,QAAQ"}