Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions packages/graalvm/api/graalvm.api
Original file line number Diff line number Diff line change
Expand Up @@ -1754,8 +1754,10 @@ public final class elide/runtime/gvm/js/JsError {
public static synthetic fun of$default (Lelide/runtime/gvm/js/JsError;Ljava/lang/String;Ljava/lang/Throwable;Ljava/lang/Integer;[Lkotlin/Pair;ILjava/lang/Object;)Lelide/runtime/intrinsics/js/err/Error;
public final fun rangeError (Ljava/lang/String;Ljava/lang/Throwable;Z)Lelide/runtime/intrinsics/js/err/RangeError;
public static synthetic fun rangeError$default (Lelide/runtime/gvm/js/JsError;Ljava/lang/String;Ljava/lang/Throwable;ZILjava/lang/Object;)Lelide/runtime/intrinsics/js/err/RangeError;
public final fun typeError (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;Z)Lelide/runtime/intrinsics/js/err/TypeError;
public final fun typeError (Ljava/lang/String;Ljava/lang/Throwable;Z)Lelide/runtime/intrinsics/js/err/TypeError;
public final fun typeError (Ljava/lang/Throwable;Z)Lelide/runtime/intrinsics/js/err/TypeError;
public static synthetic fun typeError$default (Lelide/runtime/gvm/js/JsError;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;ZILjava/lang/Object;)Lelide/runtime/intrinsics/js/err/TypeError;
public static synthetic fun typeError$default (Lelide/runtime/gvm/js/JsError;Ljava/lang/String;Ljava/lang/Throwable;ZILjava/lang/Object;)Lelide/runtime/intrinsics/js/err/TypeError;
public static synthetic fun typeError$default (Lelide/runtime/gvm/js/JsError;Ljava/lang/Throwable;ZILjava/lang/Object;)Lelide/runtime/intrinsics/js/err/TypeError;
public final fun valueError (Ljava/lang/String;Ljava/lang/Throwable;Z)Lelide/runtime/intrinsics/js/err/ValueError;
Expand Down Expand Up @@ -5779,6 +5781,24 @@ public abstract interface class elide/runtime/intrinsics/testing/TestingAPI$Test
public abstract interface class elide/runtime/intrinsics/testing/TestingAPI$TestGraphNode$Test : elide/runtime/intrinsics/testing/TestingAPI$TestGraphNode {
}

public synthetic class elide/runtime/javascript/$NavigatorBuiltin$Definition : io/micronaut/context/AbstractInitializableBeanDefinitionAndReference {
public static final field $ANNOTATION_METADATA Lio/micronaut/core/annotation/AnnotationMetadata;
public fun <init> ()V
protected fun <init> (Ljava/lang/Class;Lio/micronaut/context/AbstractInitializableBeanDefinition$MethodOrFieldReference;)V
public fun instantiate (Lio/micronaut/context/BeanResolutionContext;Lio/micronaut/context/BeanContext;)Ljava/lang/Object;
public fun isEnabled (Lio/micronaut/context/BeanContext;)Z
public fun isEnabled (Lio/micronaut/context/BeanContext;Lio/micronaut/context/BeanResolutionContext;)Z
public fun load ()Lio/micronaut/inject/BeanDefinition;
}

public final synthetic class elide/runtime/javascript/$NavigatorBuiltin$Introspection : io/micronaut/inject/beans/AbstractInitializableBeanIntrospectionAndReference {
public static final field $ANNOTATION_METADATA Lio/micronaut/core/annotation/AnnotationMetadata;
public fun <init> ()V
public fun hasBuilder ()Z
public fun instantiate ()Ljava/lang/Object;
public fun isBuildable ()Z
}

public synthetic class elide/runtime/javascript/$QueueMicrotaskCallable$Definition : io/micronaut/context/AbstractInitializableBeanDefinitionAndReference {
public static final field $ANNOTATION_METADATA Lio/micronaut/core/annotation/AnnotationMetadata;
public fun <init> ()V
Expand All @@ -5796,6 +5816,19 @@ public final synthetic class elide/runtime/javascript/$QueueMicrotaskCallable$In
public fun isBuildable ()Z
}

public final class elide/runtime/javascript/NavigatorBuiltin : elide/runtime/gvm/internals/intrinsics/js/AbstractJsIntrinsic, elide/runtime/interop/ReadOnlyProxyObject {
public fun <init> ()V
public fun getMember (Ljava/lang/String;)Ljava/lang/Object;
public synthetic fun getMemberKeys ()Ljava/lang/Object;
public fun getMemberKeys ()[Ljava/lang/String;
public fun install (Lelide/runtime/intrinsics/GuestIntrinsic$MutableIntrinsicBindings;)V
}

public final class elide/runtime/javascript/NavigatorBuiltin$Navigator : org/graalvm/polyglot/proxy/ProxyInstantiable {
public fun <init> ()V
public fun newInstance ([Lorg/graalvm/polyglot/Value;)Ljava/lang/Object;
}

public final class elide/runtime/javascript/QueueMicrotaskCallable : elide/runtime/gvm/internals/intrinsics/js/AbstractJsIntrinsic, org/graalvm/polyglot/proxy/ProxyExecutable {
public fun <init> (Lelide/runtime/exec/GuestExecutorProvider;)V
public fun execute ([Lorg/graalvm/polyglot/Value;)Ljava/lang/Object;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,22 @@ import elide.runtime.intrinsics.js.err.JsError
return exc
}

/**
* [TypeError] constructor for spec-compliant type errors which accept a code and message.
*
* @param code Code string for the error.
* @param message String message for this error.
* @param cause Throwable error to wrap and consider the cause of this error.
* @param raise Whether to throw the error after wrapping. Defaults to `false`.
* @return Wrapped [TypeError], ready to be raised.
*/
@Throws(TypeError::class)
public fun typeError(code: String, message: String, cause: Throwable? = null, raise: Boolean = false): TypeError {
val exc = wrapped("[$code]: $message", cause, TypeError::class)
if (raise) throw exc
return exc
}

/**
* [RangeError] convenience function: wrap the provided [message] and optional [cause]; then, optionally [raise].
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2024-2025 Elide Technologies, Inc.
*
* Licensed under the MIT license (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://opensource.org/license/mit/
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under the License.
*/
@file:OptIn(DelicateElideApi::class)

package elide.runtime.javascript

import org.graalvm.polyglot.Value
import org.graalvm.polyglot.proxy.ProxyInstantiable
import jakarta.inject.Singleton
import elide.runtime.core.DelicateElideApi
import elide.runtime.gvm.api.Intrinsic
import elide.runtime.gvm.internals.intrinsics.js.AbstractJsIntrinsic
import elide.runtime.gvm.js.JsError
import elide.runtime.gvm.js.JsSymbol.JsSymbols.asPublicJsSymbol
import elide.runtime.interop.ReadOnlyProxyObject
import elide.runtime.intrinsics.GuestIntrinsic

// Name of the `navigator` object in the global scope.
private const val NAVIGATOR_NAME = "navigator"

// Name of the `userAgent` property on the `navigator` object.
private const val NAVIGATOR_UA_NAME = "userAgent"

// Public JavaScript symbol for the `navigator` object.
private val NAVIGATOR_SYMBOL = NAVIGATOR_NAME.asPublicJsSymbol()

// Name of the `Navigator` class in the global scope.
private const val NAVIGATOR_CLASS_NAME = "Navigator"

// Public JavaScript symbol for the `Navigator` class.
private val NAVIGATOR_CLASS_SYMBOL = NAVIGATOR_CLASS_NAME.asPublicJsSymbol()

// User-Agent token to include in the `navigator.userAgent` property.
private const val ELIDE_UA_TOKEN = "Elide/alpha-v1"

/**
* ## Navigator Built-in
*
* Built-in which provides the `navigator` object in the global JavaScript scope; this object mimics a subset of what is
* available in browsers.
*
* ### Standards Compliance
*
* The Navigator `userAgent` property is defined as part of the WinterTC Minimum Common API.
*
* [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator)
*/
@Singleton
@Intrinsic(NAVIGATOR_NAME) public class NavigatorBuiltin : ReadOnlyProxyObject, AbstractJsIntrinsic() {
public class Navigator : ProxyInstantiable {
override fun newInstance(vararg arguments: Value?): Any? = throw JsError.typeError(
"ERR_ILLEGAL_CONSTRUCTOR",
"Illegal constructor",
)
}

override fun install(bindings: GuestIntrinsic.MutableIntrinsicBindings) {
bindings[NAVIGATOR_SYMBOL] = this
bindings[NAVIGATOR_CLASS_SYMBOL] = Navigator()
}

override fun getMemberKeys(): Array<String> = arrayOf(NAVIGATOR_UA_NAME)

override fun getMember(key: String): Any? = when (key) {
NAVIGATOR_UA_NAME -> elideUserAgent()
else -> null
}

private fun elideUserAgent(): String = ELIDE_UA_TOKEN
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ private const val ENABLE_SUPPRESSIONS = true
"encodeURIComponent",
"escape",
"unescape",
"navigator",
"Navigator",
"Object",
"Function",
"Boolean",
Expand Down Expand Up @@ -151,8 +153,6 @@ private const val ENABLE_SUPPRESSIONS = true
"fetch",
"File",
"FormData",
"navigator",
"Navigator",
"PerformanceEntry",
"PerformanceMark",
"PerformanceMeasure",
Expand Down Expand Up @@ -211,7 +211,6 @@ private const val ENABLE_SUPPRESSIONS = true

// Globals which may fail to be found without failing tests (for instance, still under implementation).
private val allowMissingGlobals = sortedSetOf(
"navigator", // not yet implemented
"setImmediate", // not yet implemented
"clearImmediate", // not yet implemented
"structuredClone", // not yet implemented
Expand All @@ -226,7 +225,6 @@ private const val ENABLE_SUPPRESSIONS = true
"Event", // not yet implemented
"EventSource", // not yet implemented
"FormData", // not yet implemented
"Navigator", // not yet implemented
"WebSocket", // not yet implemented
"PerformanceEntry", // not yet implemented
"PerformanceMark", // not yet implemented
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ private const val ENABLE_SUPPRESSIONS = true
"TextDecoderStream",
"TextEncoderStream",
"URLPattern",
"navigator.userAgent",
"structuredClone",
)

Expand Down
Loading