diff --git a/examples/rollup.config.js b/examples/.rolluprc.cjs similarity index 66% rename from examples/rollup.config.js rename to examples/.rolluprc.cjs index d4e58727..65922fe9 100644 --- a/examples/rollup.config.js +++ b/examples/.rolluprc.cjs @@ -1,5 +1,6 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { nodeResolve } from '@rollup/plugin-node-resolve'; +'use strict'; + +const { nodeResolve } = require('@rollup/plugin-node-resolve'); function config(dir) { return { @@ -8,11 +9,15 @@ function config(dir) { file: `${dir}/bundle.js`, format: 'cjs', }, - plugins: [nodeResolve()], + plugins: [ + nodeResolve({ + preferBuiltins: true, + }) + ], }; } -export default [ +module.exports = [ config('custom-elements'), config('custom-events'), config('errors'), diff --git a/examples/package.json b/examples/package.json index 36542d2d..8b2d68c4 100644 --- a/examples/package.json +++ b/examples/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "clean": "rimraf */bundle.js", - "build": "rollup -c" + "build": "rollup --config .rolluprc.cjs" }, "dependencies": { "@locker/near-membrane-dom": "0.11.1" diff --git a/package.json b/package.json index 0a010ac8..38636c58 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ ], "description": "JavaScript Near Membrane Library to create a sandboxed environment", "module": "dist/index.js", - "types": "types/index.js", + "typings": "types/index.js", "scripts": { "clean": "lerna run clean --stream", "build": "lerna run build --stream", diff --git a/packages/near-membrane-base/package.json b/packages/near-membrane-base/package.json index fd19b8fb..3a823265 100644 --- a/packages/near-membrane-base/package.json +++ b/packages/near-membrane-base/package.json @@ -12,7 +12,7 @@ "main": "dist/index.cjs.js", "module": "dist/index.js", "sideEffects": false, - "types": "types/index.d.ts", + "typings": "types/index.d.ts", "scripts": { "clean": "rimraf dist types", "build": "tsc --project tsconfig.types.json && rollup --config .rolluprc.cjs", diff --git a/packages/near-membrane-base/src/connector.ts b/packages/near-membrane-base/src/connector.ts index f2f11b3a..fde908fc 100644 --- a/packages/near-membrane-base/src/connector.ts +++ b/packages/near-membrane-base/src/connector.ts @@ -1,6 +1,5 @@ import { createMembraneMarshall } from './membrane'; - -export type Connector = ReturnType; +import type { Connector } from './types'; const TypeErrorCtor = TypeError; diff --git a/packages/near-membrane-base/src/environment.ts b/packages/near-membrane-base/src/environment.ts index 15a5d9e6..ab54c45b 100644 --- a/packages/near-membrane-base/src/environment.ts +++ b/packages/near-membrane-base/src/environment.ts @@ -1,31 +1,18 @@ -import { +import type { CallableDefineProperties, CallableEvaluate, CallableGetPropertyValuePointer, CallableInstallLazyPropertyDescriptors, CallableLinkPointers, CallableSetPrototypeOf, - DistortionCallback, GetSelectedTarget, GetTransferableValue, HooksCallback, Pointer, ProxyTarget, -} from './membrane'; -import { Connector } from './connector'; -import { Instrumentation } from './instrumentation'; -import { PropertyKeys } from './types'; - -export interface VirtualEnvironmentOptions { - // Blue connector factory. - blueConnector: Connector; - // Optional distortion callback to tame functionalities observed through the membrane. - distortionCallback?: DistortionCallback; - // Red connector factory. - redConnector: Connector; - // Instrumentation library object. - instrumentation?: Instrumentation; -} + PropertyKeys, + VirtualEnvironmentOptions, +} from './types'; const LOCKER_NEAR_MEMBRANE_UNDEFINED_VALUE_SYMBOL = Symbol.for( '@@lockerNearMembraneUndefinedValue' diff --git a/packages/near-membrane-base/src/index.ts b/packages/near-membrane-base/src/index.ts index 5a23f788..0d494542 100644 --- a/packages/near-membrane-base/src/index.ts +++ b/packages/near-membrane-base/src/index.ts @@ -1,6 +1,5 @@ export * from './connector'; export * from './environment'; -export * from './instrumentation'; export * from './intrinsics'; export * from './membrane'; export * from './types'; diff --git a/packages/near-membrane-base/src/instrumentation.ts b/packages/near-membrane-base/src/instrumentation.ts deleted file mode 100644 index efa7dbb4..00000000 --- a/packages/near-membrane-base/src/instrumentation.ts +++ /dev/null @@ -1,12 +0,0 @@ -export interface Activity { - stop(data?: DataType): void; - error(data?: DataType): void; -} - -export type DataType = boolean | object | number | string; - -export interface Instrumentation { - startActivity(activityName: string, data?: DataType): Activity; - log(data?: DataType): void; - error(data?: DataType): void; -} diff --git a/packages/near-membrane-base/src/intrinsics.ts b/packages/near-membrane-base/src/intrinsics.ts index d53672e2..5cb4c99a 100644 --- a/packages/near-membrane-base/src/intrinsics.ts +++ b/packages/near-membrane-base/src/intrinsics.ts @@ -1,6 +1,6 @@ import { toSafeArray } from './utils'; import { VirtualEnvironment } from './environment'; -import { PropertyKeys } from './types'; +import type { PropertyKeys } from './types'; const { assign: ObjectAssign } = Object; const { ownKeys: ReflectOwnKeys } = Reflect; @@ -167,7 +167,7 @@ export function linkIntrinsics(env: VirtualEnvironment, globalObject: typeof glo // Remap intrinsics that are realm agnostic. for (let i = 0, { length } = ReflectiveIntrinsicObjectNames; i < length; i += 1) { const globalName = ReflectiveIntrinsicObjectNames[i]; - const reflectiveValue = globalObject[globalName]; + const reflectiveValue = (globalObject as any)[globalName]; if (reflectiveValue) { // Proxy.prototype is undefined. if (reflectiveValue.prototype) { diff --git a/packages/near-membrane-base/src/membrane.ts b/packages/near-membrane-base/src/membrane.ts index 59cfc500..34eae276 100644 --- a/packages/near-membrane-base/src/membrane.ts +++ b/packages/near-membrane-base/src/membrane.ts @@ -23,178 +23,57 @@ * it via `selectedTarget!`. */ import { toSafeWeakMap } from './utils'; -import { Activity, Instrumentation } from './instrumentation'; -import { Getter, PropertyKey, PropertyKeys, Setter } from './types'; - -type CallablePushTarget = ( - foreignTargetPointer: () => void, - foreignTargetTraits: number, - foreignTargetFunctionArity: number, - foreignTargetFunctionName: string, - foreignTargetTypedArrayLength: number -) => Pointer; -type CallablePushErrorTarget = CallablePushTarget; -type CallableApply = ( - targetPointer: Pointer, - thisArgPointerOrUndefined: PointerOrPrimitive, - ...args: PointerOrPrimitive[] -) => PointerOrPrimitive; -type CallableConstruct = ( - targetPointer: Pointer, - newTargetPointer: PointerOrPrimitive, - ...args: PointerOrPrimitive[] -) => PointerOrPrimitive; -type CallableDefineProperty = ( - targetPointer: Pointer, - key: PropertyKey, - configurable: boolean | symbol, - enumerable: boolean | symbol, - writable: boolean | symbol, - valuePointer: PointerOrPrimitive, - getterPointer: PointerOrPrimitive, - setterPointer: PointerOrPrimitive, - foreignCallableNonConfigurableDescriptorCallback: CallableNonConfigurableDescriptorCallback -) => boolean; -type CallableDeleteProperty = (targetPointer: Pointer, key: PropertyKey) => boolean; -type CallableGet = ( - targetPointer: Pointer, - targetTraits: number, - key: PropertyKey, - receiverPointerOrPrimitive: PointerOrPrimitive -) => PointerOrPrimitive; -type CallableGetOwnPropertyDescriptor = ( - targetPointer: Pointer, - key: PropertyKey, - foreignCallableDescriptorCallback: CallableDescriptorCallback -) => void; -type CallableGetPrototypeOf = (targetPointer: Pointer) => PointerOrPrimitive; -type CallableHas = (targetPointer: Pointer, key: PropertyKey) => boolean; -type CallableIsExtensible = (targetPointer: Pointer) => boolean; -type CallableOwnKeys = ( - targetPointer: Pointer, - foreignCallableKeysCallback: (...args: ReturnType) => void -) => void; -type CallablePreventExtensions = (targetPointer: Pointer) => number; -type CallableSet = ( - targetPointer: Pointer, - key: PropertyKey, - valuePointerOrPrimitive: PointerOrPrimitive, - receiverPointerOrPrimitive: PointerOrPrimitive -) => boolean; -type CallableDebugInfo = (...args: Parameters) => void; -type CallableGetLazyPropertyDescriptorStateByTarget = ( - targetPointer: Pointer -) => PointerOrPrimitive; -type CallableGetTargetIntegrityTraits = (targetPointer: Pointer) => number; -type CallableGetToStringTagOfTarget = (targetPointer: Pointer) => string; -type CallableGetTypedArrayIndexedValue = ( - targetPointer: Pointer, - index: PropertyKey -) => number | bigint; -type CallableInstallErrorPrepareStackTrace = () => void; -type CallableIsTargetLive = (targetPointer: Pointer) => boolean; -type CallableIsTargetRevoked = (targetPointer: Pointer) => boolean; -type CallableSerializeTarget = (targetPointer: Pointer) => SerializedValue | undefined; -type CallableSetLazyPropertyDescriptorStateByTarget = ( - targetPointer: Pointer, - statePointer: Pointer -) => void; -type CallableBatchGetPrototypeOfAndGetOwnPropertyDescriptors = ( - targetPointer: Pointer, - foreignCallableDescriptorsCallback: CallableDescriptorsCallback -) => PointerOrPrimitive; -type CallableBatchGetPrototypeOfWhenHasNoOwnProperty = ( - targetPointer: Pointer, - key: PropertyKey -) => PointerOrPrimitive; -type CallableBatchGetPrototypeOfWhenHasNoOwnPropertyDescriptor = ( - targetPointer: Pointer, - key: PropertyKey, - foreignCallableDescriptorCallback: CallableDescriptorCallback -) => PointerOrPrimitive; -type CallableDescriptorCallback = ( - key: PropertyKey, - configurable: boolean | symbol, - enumerable: boolean | symbol, - writable: boolean | symbol, - valuePointer: PointerOrPrimitive, - getterPointer: PointerOrPrimitive, - setterPointer: PointerOrPrimitive -) => void; -type CallableDescriptorsCallback = ( - ...descriptorTuples: [...Parameters] -) => void; -type CallableNonConfigurableDescriptorCallback = CallableDescriptorCallback; -interface ForeignPropertyDescriptor extends PropertyDescriptor { - foreign?: boolean; -} -type GlobalThisGetter = () => typeof globalThis; -interface HooksOptions { - distortionCallback?: DistortionCallback; - instrumentation?: Instrumentation; -} -type PointerOrPrimitive = Pointer | Primitive; -type Primitive = bigint | boolean | null | number | string | symbol | undefined; -type SerializedValue = bigint | boolean | number | string | symbol; -type ShadowTarget = ProxyTarget; -export type CallableDefineProperties = ( - targetPointer: Pointer, - ...descriptorTuples: [...Parameters] -) => void; -export type CallableEvaluate = (sourceText: string) => PointerOrPrimitive; -export type CallableGetPropertyValuePointer = (targetPointer: Pointer, key: PropertyKey) => Pointer; -export type CallableInstallLazyPropertyDescriptors = ( - targetPointer: Pointer, - ...ownKeysAndUnforgeableGlobalThisKeys: PropertyKeys -) => void; -export type CallableLinkPointers = (targetPointer: Pointer, foreignTargetPointer: Pointer) => void; -export type CallableSetPrototypeOf = ( - targetPointer: Pointer, - protoPointerOrNull: Pointer | null -) => boolean; -export type DistortionCallback = (target: ProxyTarget) => ProxyTarget; -export type GetSelectedTarget = Getter; -export type GetTransferableValue = (value: any) => PointerOrPrimitive; -export type HooksCallback = ( - globalThisPointer: Pointer | undefined, - getSelectedTarget: GetSelectedTarget | undefined, - getTransferableValue: GetTransferableValue | undefined, - callableGetPropertyValuePointer: CallableGetPropertyValuePointer | undefined, - callableEvaluate: CallableEvaluate | undefined, - callableLinkPointers: CallableLinkPointers | undefined, - callablePushErrorTarget: CallablePushErrorTarget, - callablePushTarget: CallablePushTarget, - callableApply: CallableApply, - callableConstruct: CallableConstruct, - callableDefineProperty: CallableDefineProperty, - callableDeleteProperty: CallableDeleteProperty, - callableGet: CallableGet, - callableGetOwnPropertyDescriptor: CallableGetOwnPropertyDescriptor, - callableGetPrototypeOf: CallableGetPrototypeOf, - callableHas: CallableHas, - callableIsExtensible: CallableIsExtensible, - callableOwnKeys: CallableOwnKeys, - callablePreventExtensions: CallablePreventExtensions, - callableSet: CallableSet, - callableSetPrototypeOf: CallableSetPrototypeOf, - callableDebugInfo: CallableDebugInfo, - callableDefineProperties: CallableDefineProperties | undefined, - callableGetLazyPropertyDescriptorStateByTarget: CallableGetLazyPropertyDescriptorStateByTarget, - callableGetTargetIntegrityTraits: CallableGetTargetIntegrityTraits, - callableGetToStringTagOfTarget: CallableGetToStringTagOfTarget, - callableGetTypedArrayIndexedValue: CallableGetTypedArrayIndexedValue, - callableInstallErrorPrepareStackTrace: CallableInstallErrorPrepareStackTrace, - callableInstallLazyPropertyDescriptors: CallableInstallLazyPropertyDescriptors | undefined, - callableIsTargetLive: CallableIsTargetLive, - callableIsTargetRevoked: CallableIsTargetRevoked, - callableSerializeTarget: CallableSerializeTarget, - callableSetLazyPropertyDescriptorStateByTarget: CallableSetLazyPropertyDescriptorStateByTarget, - callableBatchGetPrototypeOfAndGetOwnPropertyDescriptors: CallableBatchGetPrototypeOfAndGetOwnPropertyDescriptors, - callableBatchGetPrototypeOfWhenHasNoOwnProperty: CallableBatchGetPrototypeOfWhenHasNoOwnProperty, - callableBatchGetPrototypeOfWhenHasNoOwnPropertyDescriptor: CallableBatchGetPrototypeOfWhenHasNoOwnPropertyDescriptor -) => void; -export type Pointer = CallableFunction; -export type ProxyTarget = CallableFunction | any[] | object; +import type { + Activity, + CallableApply, + CallableBatchGetPrototypeOfAndGetOwnPropertyDescriptors, + CallableBatchGetPrototypeOfWhenHasNoOwnProperty, + CallableBatchGetPrototypeOfWhenHasNoOwnPropertyDescriptor, + CallableConstruct, + CallableDebugInfo, + CallableDefineProperties, + CallableDefineProperty, + CallableDeleteProperty, + CallableDescriptorCallback, + CallableDescriptorsCallback, + CallableEvaluate, + CallableGet, + CallableGetLazyPropertyDescriptorStateByTarget, + CallableGetOwnPropertyDescriptor, + CallableGetPrototypeOf, + CallableGetTargetIntegrityTraits, + CallableGetToStringTagOfTarget, + CallableGetTypedArrayIndexedValue, + CallableHas, + CallableInstallErrorPrepareStackTrace, + CallableInstallLazyPropertyDescriptors, + CallableIsExtensible, + CallableIsTargetLive, + CallableIsTargetRevoked, + CallableNonConfigurableDescriptorCallback, + CallableOwnKeys, + CallablePreventExtensions, + CallablePushErrorTarget, + CallablePushTarget, + CallableSerializeTarget, + CallableSet, + CallableSetLazyPropertyDescriptorStateByTarget, + CallableSetPrototypeOf, + ForeignPropertyDescriptor, + GetSelectedTarget, + Getter, + GlobalThisGetter, + HooksCallback, + HooksOptions, + Pointer, + PointerOrPrimitive, + PropertyKey, + PropertyKeys, + ProxyTarget, + SerializedValue, + Setter, + ShadowTarget, +} from './types'; const proxyTargetToLazyPropertyDescriptorStateMap: WeakMap = toSafeWeakMap( new WeakMap() @@ -441,10 +320,6 @@ export function createMembraneMarshall( return false; } - function identity(value: T): T { - return value; - } - const installErrorPrepareStackTrace = LOCKER_UNMINIFIED_FLAG ? () => { if (installedErrorPrepareStackTraceFlag) { @@ -757,7 +632,7 @@ export function createMembraneMarshall( weakMap.delete = WeakMapProtoDelete; weakMap.has = WeakMapProtoHas; weakMap.set = WeakMapProtoSet; - weakMap[SymbolToStringTag] = WeakMapProtoSymbolToStringTag; + (weakMap as any)[SymbolToStringTag] = WeakMapProtoSymbolToStringTag; ReflectSetPrototypeOf(weakMap, WeakMapProto); return weakMap; } @@ -767,8 +642,11 @@ export function createMembraneMarshall( foreignCallableHooksCallback: HooksCallback, options?: HooksOptions ): HooksCallback { + if (IS_IN_SHADOW_REALM) { + options = undefined; + } const { - distortionCallback = identity, + distortionCallback, instrumentation, // eslint-disable-next-line prefer-object-spread } = ObjectAssign({ __proto__: null }, options); @@ -846,7 +724,7 @@ export function createMembraneMarshall( const activateLazyOwnPropertyDefinition = IS_IN_SHADOW_REALM ? (target: object, key: PropertyKey, state: object) => { - state[key] = false; + (state as any)[key] = false; const foreignTargetPointer = getTransferablePointer(target); let safeDesc; try { @@ -973,7 +851,7 @@ export function createMembraneMarshall( const args = isApplyTrap ? argsOrNewTarget : thisArgOrArgs; const { length } = args; if (length !== 0) { - return this[ + return (this as any)[ arityToApplyOrConstructTrapNameRegistry[length] ?? arityToApplyOrConstructTrapNameRegistry.n ](shadowTarget, thisArgOrArgs, argsOrNewTarget); @@ -1042,7 +920,7 @@ export function createMembraneMarshall( const args = isApplyTrap ? argsOrNewTarget : thisArgOrArgs; const { length } = args; if (length !== 1) { - return this[ + return (this as any)[ arityToApplyOrConstructTrapNameRegistry[length] ?? arityToApplyOrConstructTrapNameRegistry.n ](shadowTarget, thisArgOrArgs, argsOrNewTarget); @@ -1121,7 +999,7 @@ export function createMembraneMarshall( const args = isApplyTrap ? argsOrNewTarget : thisArgOrArgs; const { length } = args; if (length !== 2) { - return this[ + return (this as any)[ arityToApplyOrConstructTrapNameRegistry[length] ?? arityToApplyOrConstructTrapNameRegistry.n ](shadowTarget, thisArgOrArgs, argsOrNewTarget); @@ -1209,7 +1087,7 @@ export function createMembraneMarshall( const args = isApplyTrap ? argsOrNewTarget : thisArgOrArgs; const { length } = args; if (length !== 3) { - return this[ + return (this as any)[ arityToApplyOrConstructTrapNameRegistry[length] ?? arityToApplyOrConstructTrapNameRegistry.n ](shadowTarget, thisArgOrArgs, argsOrNewTarget); @@ -1306,7 +1184,7 @@ export function createMembraneMarshall( const args = isApplyTrap ? argsOrNewTarget : thisArgOrArgs; const { length } = args; if (length !== 4) { - return this[ + return (this as any)[ arityToApplyOrConstructTrapNameRegistry[length] ?? arityToApplyOrConstructTrapNameRegistry.n ](shadowTarget, thisArgOrArgs, argsOrNewTarget); @@ -1412,7 +1290,7 @@ export function createMembraneMarshall( const args = isApplyTrap ? argsOrNewTarget : thisArgOrArgs; const { length } = args; if (length !== 5) { - return this[ + return (this as any)[ arityToApplyOrConstructTrapNameRegistry[length] ?? arityToApplyOrConstructTrapNameRegistry.n ](shadowTarget, thisArgOrArgs, argsOrNewTarget); @@ -1677,30 +1555,33 @@ export function createMembraneMarshall( if (proxyPointer) { return proxyPointer; } - const distortedTarget: ProxyTarget = IS_IN_SHADOW_REALM - ? originalTarget - : distortionCallback(originalTarget); - // If a distortion entry is found, it must be a valid proxy target. - if ( - distortedTarget !== originalTarget && - typeof distortedTarget !== typeof originalTarget - ) { - throw new TypeErrorCtor( - `Invalid distortion ${toSafeTemplateStringValue(originalTarget)}.` - ); + let distortionTarget: ProxyTarget; + if (distortionCallback) { + distortionTarget = distortionCallback(originalTarget); + // If a distortion entry is found, it must be a valid proxy target. + if ( + distortionTarget !== originalTarget && + typeof distortionTarget !== typeof originalTarget + ) { + throw new TypeErrorCtor( + `Invalid distortion ${toSafeTemplateStringValue(originalTarget)}.` + ); + } + } else { + distortionTarget = originalTarget; } let isPossiblyRevoked = true; let targetFunctionArity = 0; let targetFunctionName = ''; let targetTypedArrayLength = 0; let targetTraits = TargetTraits.IsObject; - if (typeof distortedTarget === 'function') { + if (typeof distortionTarget === 'function') { isPossiblyRevoked = false; targetFunctionArity = 0; targetTraits = TargetTraits.IsFunction; try { // Detect arrow functions. - if (!('prototype' in distortedTarget)) { + if (!('prototype' in distortionTarget)) { targetTraits |= TargetTraits.IsArrowFunction; } const safeLengthDesc = ReflectGetOwnPropertyDescriptor( @@ -1727,13 +1608,13 @@ export function createMembraneMarshall( } catch { isPossiblyRevoked = true; } - } else if (ArrayBufferIsView(distortedTarget)) { + } else if (ArrayBufferIsView(distortionTarget)) { isPossiblyRevoked = false; targetTraits = TargetTraits.IsArrayBufferView; try { targetTypedArrayLength = ReflectApply( TypedArrayProtoLengthGetter, - distortedTarget, + distortionTarget, [] ) as number; targetTraits |= TargetTraits.IsTypedArray; @@ -1745,7 +1626,7 @@ export function createMembraneMarshall( } if (isPossiblyRevoked) { try { - if (isArrayOrThrowForRevoked(distortedTarget)) { + if (isArrayOrThrowForRevoked(distortionTarget)) { targetTraits = TargetTraits.IsArray; } } catch { @@ -1753,7 +1634,7 @@ export function createMembraneMarshall( } } proxyPointer = foreignCallablePusher( - createPointer(distortedTarget), + createPointer(distortionTarget), targetTraits, targetFunctionArity, targetFunctionName, @@ -1889,7 +1770,7 @@ export function createMembraneMarshall( ) { const key = useThisArgAsTarget ? args[0] : args[1]; const state = getLazyPropertyDescriptorStateByTarget(target); - if (state?.[key]) { + if ((state as any)?.[key]) { // Activate the descriptor by triggering // its getter. // eslint-disable-next-line @typescript-eslint/no-unused-expressions @@ -1915,7 +1796,7 @@ export function createMembraneMarshall( ) { const { 0: key } = args; const state = getLazyPropertyDescriptorStateByTarget(thisArg); - if (state?.[key]) { + if ((state as any)?.[key]) { // Activate the descriptor by triggering // its getter. // eslint-disable-next-line @typescript-eslint/no-unused-expressions @@ -1945,11 +1826,11 @@ export function createMembraneMarshall( typeof target === 'function' ) { const state = getLazyPropertyDescriptorStateByTarget(target); - if (state?.[key]) { + if ((state as any)?.[key]) { // Activate the descriptor by triggering // its getter. // eslint-disable-next-line @typescript-eslint/no-unused-expressions - target[key]; + (target as any)[key]; } if (shouldFixChromeBug && target === globalThisRef) { return getFixedDescriptor!(target, key); @@ -2001,12 +1882,12 @@ export function createMembraneMarshall( ); for (let i = 0, { length } = ownKeys; i < length; i += 1) { const ownKey = ownKeys[i]; - const isLazyProp = !!state?.[ownKey]; + const isLazyProp = !!(state as any)?.[ownKey]; if (isLazyProp) { // Activate the descriptor by triggering // its getter. // eslint-disable-next-line @typescript-eslint/no-unused-expressions - target[ownKey]; + (target as any)[ownKey]; } if (isLazyProp || isFixingChromeBug) { const unsafeDesc = isFixingChromeBug @@ -2505,16 +2386,14 @@ export function createMembraneMarshall( this.staticToStringTag = 'Object'; // Define traps. if (isForeignTargetFunction) { - this.apply = - this[ - arityToApplyTrapNameRegistry[foreignTargetFunctionArity] ?? - arityToApplyTrapNameRegistry.n - ]; - this.construct = - this[ - arityToConstructTrapNameRegistry[foreignTargetFunctionArity] ?? - arityToConstructTrapNameRegistry.n - ]; + this.apply = (this as any)[ + arityToApplyTrapNameRegistry[foreignTargetFunctionArity] ?? + arityToApplyTrapNameRegistry.n + ]; + this.construct = (this as any)[ + arityToConstructTrapNameRegistry[foreignTargetFunctionArity] ?? + arityToConstructTrapNameRegistry.n + ]; } this.defineProperty = BoundaryProxyHandler.defaultDefinePropertyTrap; this.deleteProperty = BoundaryProxyHandler.defaultDeletePropertyTrap; @@ -3655,7 +3534,7 @@ export function createMembraneMarshall( targetPointer(); const target = selectedTarget!; selectedTarget = undefined; - const value = target?.[key]; + const value = (target as any)?.[key]; // Intentionally ignoring `document.all`. // https://developer.mozilla.org/en-US/docs/Web/API/Document/all // https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot @@ -3711,8 +3590,10 @@ export function createMembraneMarshall( return pointer(); }; if (DEV_MODE) { - pointerWrapper['[[OriginalTarget]]'] = pointer['[[OriginalTarget]]']; - pointerWrapper['[[Color]]'] = pointer['[[Color]]']; + pointerWrapper['[[OriginalTarget]]'] = (pointer as any)[ + '[[OriginalTarget]]' + ]; + pointerWrapper['[[Color]]'] = (pointer as any)['[[Color]]']; } return pointerWrapper; } @@ -4252,7 +4133,7 @@ export function createMembraneMarshall( const target = selectedTarget!; selectedTarget = undefined; try { - return target[index]; + return (target as any)[index]; } catch (error: any) { throw pushErrorAcrossBoundary(error); } @@ -4297,7 +4178,7 @@ export function createMembraneMarshall( } for (let i = 0, { length } = ownKeys; i < length; i += 1) { const ownKey = ownKeys[i]; - state[ownKey] = true; + (state as any)[ownKey] = true; ReflectDefineProperty( target, ownKey, @@ -4318,7 +4199,7 @@ export function createMembraneMarshall( // as non-enumerable. get(): any { activateLazyOwnPropertyDefinition(target, ownKey, state!); - return target[ownKey]; + return (target as any)[ownKey]; }, set(value: any) { activateLazyOwnPropertyDefinition(target, ownKey, state!); @@ -4748,27 +4629,33 @@ export function createMembraneMarshall( arityToConstructTrapNameRegistry.n = MINIFICATION_SAFE_TRAP_PROPERTY_NAMES[13]; const { prototype: BoundaryProxyHandlerProto } = BoundaryProxyHandler; - BoundaryProxyHandlerProto[arityToApplyTrapNameRegistry[0]] = applyTrapForZeroOrMoreArgs; - BoundaryProxyHandlerProto[arityToApplyTrapNameRegistry[1]] = applyTrapForOneOrMoreArgs; - BoundaryProxyHandlerProto[arityToApplyTrapNameRegistry[2]] = applyTrapForTwoOrMoreArgs; - BoundaryProxyHandlerProto[arityToApplyTrapNameRegistry[3]] = + (BoundaryProxyHandlerProto as any)[arityToApplyTrapNameRegistry[0]] = + applyTrapForZeroOrMoreArgs; + (BoundaryProxyHandlerProto as any)[arityToApplyTrapNameRegistry[1]] = + applyTrapForOneOrMoreArgs; + (BoundaryProxyHandlerProto as any)[arityToApplyTrapNameRegistry[2]] = + applyTrapForTwoOrMoreArgs; + (BoundaryProxyHandlerProto as any)[arityToApplyTrapNameRegistry[3]] = applyTrapForThreeOrMoreArgs; - BoundaryProxyHandlerProto[arityToApplyTrapNameRegistry[4]] = applyTrapForFourOrMoreArgs; - BoundaryProxyHandlerProto[arityToApplyTrapNameRegistry[5]] = applyTrapForFiveOrMoreArgs; - BoundaryProxyHandlerProto[arityToApplyTrapNameRegistry.n] = applyTrapForAnyNumberOfArgs; - BoundaryProxyHandlerProto[arityToConstructTrapNameRegistry[0]] = + (BoundaryProxyHandlerProto as any)[arityToApplyTrapNameRegistry[4]] = + applyTrapForFourOrMoreArgs; + (BoundaryProxyHandlerProto as any)[arityToApplyTrapNameRegistry[5]] = + applyTrapForFiveOrMoreArgs; + (BoundaryProxyHandlerProto as any)[arityToApplyTrapNameRegistry.n] = + applyTrapForAnyNumberOfArgs; + (BoundaryProxyHandlerProto as any)[arityToConstructTrapNameRegistry[0]] = constructTrapForZeroOrMoreArgs; - BoundaryProxyHandlerProto[arityToConstructTrapNameRegistry[1]] = + (BoundaryProxyHandlerProto as any)[arityToConstructTrapNameRegistry[1]] = constructTrapForOneOrMoreArgs; - BoundaryProxyHandlerProto[arityToConstructTrapNameRegistry[2]] = + (BoundaryProxyHandlerProto as any)[arityToConstructTrapNameRegistry[2]] = constructTrapForTwoOrMoreArgs; - BoundaryProxyHandlerProto[arityToConstructTrapNameRegistry[3]] = + (BoundaryProxyHandlerProto as any)[arityToConstructTrapNameRegistry[3]] = constructTrapForThreeOrMoreArgs; - BoundaryProxyHandlerProto[arityToConstructTrapNameRegistry[4]] = + (BoundaryProxyHandlerProto as any)[arityToConstructTrapNameRegistry[4]] = constructTrapForFourOrMoreArgs; - BoundaryProxyHandlerProto[arityToConstructTrapNameRegistry[5]] = + (BoundaryProxyHandlerProto as any)[arityToConstructTrapNameRegistry[5]] = constructTrapForFiveOrMoreArgs; - BoundaryProxyHandlerProto[arityToConstructTrapNameRegistry.n] = + (BoundaryProxyHandlerProto as any)[arityToConstructTrapNameRegistry.n] = constructTrapForAnyNumberOfArgs; if (DEV_MODE) { // @ts-ignore: Prevent read-only property error. diff --git a/packages/near-membrane-base/src/types.ts b/packages/near-membrane-base/src/types.ts index e1eff920..e9353842 100644 --- a/packages/near-membrane-base/src/types.ts +++ b/packages/near-membrane-base/src/types.ts @@ -1,4 +1,194 @@ +export interface Activity { + stop(data?: DataType): void; + error(data?: DataType): void; +} +export type CallableApply = ( + targetPointer: Pointer, + thisArgPointerOrUndefined: PointerOrPrimitive, + ...args: PointerOrPrimitive[] +) => PointerOrPrimitive; +export type CallableBatchGetPrototypeOfAndGetOwnPropertyDescriptors = ( + targetPointer: Pointer, + foreignCallableDescriptorsCallback: CallableDescriptorsCallback +) => PointerOrPrimitive; +export type CallableBatchGetPrototypeOfWhenHasNoOwnProperty = ( + targetPointer: Pointer, + key: PropertyKey +) => PointerOrPrimitive; +export type CallableBatchGetPrototypeOfWhenHasNoOwnPropertyDescriptor = ( + targetPointer: Pointer, + key: PropertyKey, + foreignCallableDescriptorCallback: CallableDescriptorCallback +) => PointerOrPrimitive; +export type CallableConstruct = ( + targetPointer: Pointer, + newTargetPointer: PointerOrPrimitive, + ...args: PointerOrPrimitive[] +) => PointerOrPrimitive; +export type CallableDebugInfo = (...args: Parameters) => void; +export type CallableDefineProperties = ( + targetPointer: Pointer, + ...descriptorTuples: [...Parameters] +) => void; +export type CallableDefineProperty = ( + targetPointer: Pointer, + key: PropertyKey, + configurable: boolean | symbol, + enumerable: boolean | symbol, + writable: boolean | symbol, + valuePointer: PointerOrPrimitive, + getterPointer: PointerOrPrimitive, + setterPointer: PointerOrPrimitive, + foreignCallableNonConfigurableDescriptorCallback: CallableNonConfigurableDescriptorCallback +) => boolean; +export type CallableDeleteProperty = (targetPointer: Pointer, key: PropertyKey) => boolean; +export type CallableDescriptorCallback = ( + key: PropertyKey, + configurable: boolean | symbol, + enumerable: boolean | symbol, + writable: boolean | symbol, + valuePointer: PointerOrPrimitive, + getterPointer: PointerOrPrimitive, + setterPointer: PointerOrPrimitive +) => void; +export type CallableDescriptorsCallback = ( + ...descriptorTuples: [...Parameters] +) => void; +export type CallableEvaluate = (sourceText: string) => PointerOrPrimitive; +export type CallableGet = ( + targetPointer: Pointer, + targetTraits: number, + key: PropertyKey, + receiverPointerOrPrimitive: PointerOrPrimitive +) => PointerOrPrimitive; +export type CallableGetLazyPropertyDescriptorStateByTarget = ( + targetPointer: Pointer +) => PointerOrPrimitive; +export type CallableGetOwnPropertyDescriptor = ( + targetPointer: Pointer, + key: PropertyKey, + foreignCallableDescriptorCallback: CallableDescriptorCallback +) => void; +export type CallableGetPropertyValuePointer = (targetPointer: Pointer, key: PropertyKey) => Pointer; +export type CallableGetPrototypeOf = (targetPointer: Pointer) => PointerOrPrimitive; +export type CallableGetTargetIntegrityTraits = (targetPointer: Pointer) => number; +export type CallableGetToStringTagOfTarget = (targetPointer: Pointer) => string; +export type CallableGetTypedArrayIndexedValue = ( + targetPointer: Pointer, + index: PropertyKey +) => number | bigint; +export type CallableHas = (targetPointer: Pointer, key: PropertyKey) => boolean; +export type CallableInstallErrorPrepareStackTrace = () => void; +export type CallableInstallLazyPropertyDescriptors = ( + targetPointer: Pointer, + ...ownKeysAndUnforgeableGlobalThisKeys: PropertyKeys +) => void; +export type CallableIsExtensible = (targetPointer: Pointer) => boolean; +export type CallableIsTargetLive = (targetPointer: Pointer) => boolean; +export type CallableIsTargetRevoked = (targetPointer: Pointer) => boolean; +export type CallableLinkPointers = (targetPointer: Pointer, foreignTargetPointer: Pointer) => void; +export type CallableNonConfigurableDescriptorCallback = CallableDescriptorCallback; +export type CallableOwnKeys = ( + targetPointer: Pointer, + foreignCallableKeysCallback: (...args: ReturnType) => void +) => void; +export type CallablePreventExtensions = (targetPointer: Pointer) => number; +export type CallablePushErrorTarget = CallablePushTarget; +export type CallablePushTarget = ( + foreignTargetPointer: () => void, + foreignTargetTraits: number, + foreignTargetFunctionArity: number, + foreignTargetFunctionName: string, + foreignTargetTypedArrayLength: number +) => Pointer; +export type CallableSerializeTarget = (targetPointer: Pointer) => SerializedValue | undefined; +export type CallableSetLazyPropertyDescriptorStateByTarget = ( + targetPointer: Pointer, + statePointer: Pointer +) => void; +export type CallableSet = ( + targetPointer: Pointer, + key: PropertyKey, + valuePointerOrPrimitive: PointerOrPrimitive, + receiverPointerOrPrimitive: PointerOrPrimitive +) => boolean; +export type CallableSetPrototypeOf = ( + targetPointer: Pointer, + protoPointerOrNull: Pointer | null +) => boolean; +export type Connector = ( + color: string, + foreignCallableHooksCallback: HooksCallback, + options?: HooksOptions | undefined +) => HooksCallback; +export type DataType = boolean | object | number | string; +export type DistortionCallback = (target: ProxyTarget) => ProxyTarget; +export interface ForeignPropertyDescriptor extends PropertyDescriptor { + foreign?: boolean; +} +export type GetSelectedTarget = Getter; export type Getter = () => any; +export type GetTransferableValue = (value: any) => PointerOrPrimitive; +export type GlobalThisGetter = () => typeof globalThis; +export type HooksCallback = ( + globalThisPointer: Pointer | undefined, + getSelectedTarget: GetSelectedTarget | undefined, + getTransferableValue: GetTransferableValue | undefined, + callableGetPropertyValuePointer: CallableGetPropertyValuePointer | undefined, + callableEvaluate: CallableEvaluate | undefined, + callableLinkPointers: CallableLinkPointers | undefined, + callablePushErrorTarget: CallablePushErrorTarget, + callablePushTarget: CallablePushTarget, + callableApply: CallableApply, + callableConstruct: CallableConstruct, + callableDefineProperty: CallableDefineProperty, + callableDeleteProperty: CallableDeleteProperty, + callableGet: CallableGet, + callableGetOwnPropertyDescriptor: CallableGetOwnPropertyDescriptor, + callableGetPrototypeOf: CallableGetPrototypeOf, + callableHas: CallableHas, + callableIsExtensible: CallableIsExtensible, + callableOwnKeys: CallableOwnKeys, + callablePreventExtensions: CallablePreventExtensions, + callableSet: CallableSet, + callableSetPrototypeOf: CallableSetPrototypeOf, + callableDebugInfo: CallableDebugInfo, + callableDefineProperties: CallableDefineProperties | undefined, + callableGetLazyPropertyDescriptorStateByTarget: CallableGetLazyPropertyDescriptorStateByTarget, + callableGetTargetIntegrityTraits: CallableGetTargetIntegrityTraits, + callableGetToStringTagOfTarget: CallableGetToStringTagOfTarget, + callableGetTypedArrayIndexedValue: CallableGetTypedArrayIndexedValue, + callableInstallErrorPrepareStackTrace: CallableInstallErrorPrepareStackTrace, + callableInstallLazyPropertyDescriptors: CallableInstallLazyPropertyDescriptors | undefined, + callableIsTargetLive: CallableIsTargetLive, + callableIsTargetRevoked: CallableIsTargetRevoked, + callableSerializeTarget: CallableSerializeTarget, + callableSetLazyPropertyDescriptorStateByTarget: CallableSetLazyPropertyDescriptorStateByTarget, + callableBatchGetPrototypeOfAndGetOwnPropertyDescriptors: CallableBatchGetPrototypeOfAndGetOwnPropertyDescriptors, + callableBatchGetPrototypeOfWhenHasNoOwnProperty: CallableBatchGetPrototypeOfWhenHasNoOwnProperty, + callableBatchGetPrototypeOfWhenHasNoOwnPropertyDescriptor: CallableBatchGetPrototypeOfWhenHasNoOwnPropertyDescriptor +) => void; +export interface HooksOptions { + distortionCallback?: DistortionCallback; + instrumentation?: Instrumentation; +} +export interface Instrumentation { + startActivity(activityName: string, data?: DataType): Activity; + log(data?: DataType): void; + error(data?: DataType): void; +} +export type Pointer = CallableFunction; +export type PointerOrPrimitive = Pointer | Primitive; +export type Primitive = bigint | boolean | null | number | string | symbol | undefined; export type PropertyKey = string | symbol; export type PropertyKeys = PropertyKey[]; +export type ProxyTarget = CallableFunction | any[] | object; +export type SerializedValue = bigint | boolean | number | string | symbol; export type Setter = (value: any) => void; +export type ShadowTarget = ProxyTarget; +export interface VirtualEnvironmentOptions { + blueConnector: Connector; + redConnector: Connector; + distortionCallback?: DistortionCallback; + instrumentation?: Instrumentation; +} diff --git a/packages/near-membrane-base/src/utils.ts b/packages/near-membrane-base/src/utils.ts index 36446be7..1917f143 100644 --- a/packages/near-membrane-base/src/utils.ts +++ b/packages/near-membrane-base/src/utils.ts @@ -48,7 +48,7 @@ const { } = ArrayProto as any; const ArrayUnscopables = Object.freeze( - Object.assign({ __proto__: null }, ArrayProto[SymbolUnscopables]) + Object.assign({ __proto__: null }, (ArrayProto as any)[SymbolUnscopables]) ); const { prototype: WeakMapProto } = WeakMapCtor; @@ -105,8 +105,8 @@ export function toSafeArray(array: T): T { array.toString = ArrayProtoToString; array.unshift = ArrayProtoUnshift; array.values = ArrayProtoValues; - array[SymbolIterator] = ArrayProtoSymbolIterator; - array[SymbolUnscopables] = ArrayUnscopables; + (array as any)[SymbolIterator] = ArrayProtoSymbolIterator; + (array as any)[SymbolUnscopables] = ArrayUnscopables; ReflectSetPrototypeOf(array, ArrayProto); return array; } @@ -117,7 +117,7 @@ export function toSafeWeakMap>(weakMap: T): T { weakMap.get = WeakMapProtoGet; weakMap.has = WeakMapProtoHas; weakMap.set = WeakMapProtoSet; - weakMap[SymbolToStringTag] = WeakMapProtoSymbolToStringTag; + (weakMap as any)[SymbolToStringTag] = WeakMapProtoSymbolToStringTag; ReflectSetPrototypeOf(weakMap, WeakMapProto); return weakMap; } diff --git a/packages/near-membrane-dom/package.json b/packages/near-membrane-dom/package.json index 8a0df4cd..e119972a 100644 --- a/packages/near-membrane-dom/package.json +++ b/packages/near-membrane-dom/package.json @@ -12,7 +12,7 @@ "main": "dist/index.cjs.js", "module": "dist/index.js", "sideEffects": false, - "types": "types/index.d.ts", + "typings": "types/index.d.ts", "scripts": { "clean": "rimraf dist types", "build": "tsc --project tsconfig.types.json && rollup --config .rolluprc.cjs", diff --git a/packages/near-membrane-dom/src/browser-realm.ts b/packages/near-membrane-dom/src/browser-realm.ts index 02027a09..386d8c8f 100644 --- a/packages/near-membrane-dom/src/browser-realm.ts +++ b/packages/near-membrane-dom/src/browser-realm.ts @@ -1,18 +1,15 @@ import { assignFilteredGlobalDescriptorsFromPropertyDescriptorMap, - Connector, createBlueConnector, createRedConnector, - DistortionCallback, getFilteredGlobalOwnKeys, - Getter, - Instrumentation, linkIntrinsics, - PropertyKeys, toSafeWeakMap, VirtualEnvironment, } from '@locker/near-membrane-base'; +import type { Connector, Getter, PropertyKeys } from '@locker/near-membrane-base/types'; +import type { BrowserEnvironmentOptions } from './types'; import { getCachedGlobalObjectReferences, filterWindowKeys, @@ -20,14 +17,6 @@ import { unforgeablePoisonedWindowKeys, } from './window'; -export interface BrowserEnvironmentOptions { - distortionCallback?: DistortionCallback; - endowments?: PropertyDescriptorMap; - globalObjectShape?: object; - keepAlive?: boolean; - instrumentation?: Instrumentation; -} - const IFRAME_SANDBOX_ATTRIBUTE_VALUE = 'allow-same-origin allow-scripts'; const ObjectCtor = Object; diff --git a/packages/near-membrane-dom/src/index.ts b/packages/near-membrane-dom/src/index.ts index 3a0c4c8d..b7ecdbc4 100644 --- a/packages/near-membrane-dom/src/index.ts +++ b/packages/near-membrane-dom/src/index.ts @@ -1,8 +1,9 @@ // eslint-disable-next-line no-restricted-exports -export { default, BrowserEnvironmentOptions } from './browser-realm'; -export { +export { default } from './browser-realm'; +export * from './types'; +export type { Connector, DistortionCallback, Instrumentation, ProxyTarget, -} from '@locker/near-membrane-base'; +} from '@locker/near-membrane-base/types'; diff --git a/packages/near-membrane-dom/src/types.ts b/packages/near-membrane-dom/src/types.ts new file mode 100644 index 00000000..af31054e --- /dev/null +++ b/packages/near-membrane-dom/src/types.ts @@ -0,0 +1,9 @@ +import { DistortionCallback, Instrumentation } from '@locker/near-membrane-base/types'; + +export interface BrowserEnvironmentOptions { + distortionCallback?: DistortionCallback; + endowments?: PropertyDescriptorMap; + globalObjectShape?: object; + keepAlive?: boolean; + instrumentation?: Instrumentation; +} diff --git a/packages/near-membrane-dom/src/window.ts b/packages/near-membrane-dom/src/window.ts index e2a81def..95d68fd9 100644 --- a/packages/near-membrane-dom/src/window.ts +++ b/packages/near-membrane-dom/src/window.ts @@ -7,9 +7,6 @@ const { ownKeys: ReflectOwnKeys, } = Reflect; -/** - * - Unforgeable object and prototype references - */ interface CachedBlueReferencesRecord extends Object { document: Document; DocumentProto: object; diff --git a/packages/near-membrane-node/package.json b/packages/near-membrane-node/package.json index 529b4c55..d396fcfe 100644 --- a/packages/near-membrane-node/package.json +++ b/packages/near-membrane-node/package.json @@ -12,7 +12,7 @@ "main": "dist/index.cjs.js", "module": "dist/index.js", "sideEffects": false, - "types": "types/index.d.ts", + "typings": "types/index.d.ts", "scripts": { "clean": "rimraf dist types", "build": "tsc --project tsconfig.types.json && rollup --config .rolluprc.cjs", diff --git a/packages/near-membrane-node/src/index.ts b/packages/near-membrane-node/src/index.ts index 0e37331c..1aae9889 100644 --- a/packages/near-membrane-node/src/index.ts +++ b/packages/near-membrane-node/src/index.ts @@ -1,8 +1,9 @@ // eslint-disable-next-line no-restricted-exports -export { default, NodeEnvironmentOptions } from './node-realm'; -export { +export { default } from './node-realm'; +export * from './types'; +export type { Connector, DistortionCallback, Instrumentation, ProxyTarget, -} from '@locker/near-membrane-base'; +} from '@locker/near-membrane-base/types'; diff --git a/packages/near-membrane-node/src/node-realm.ts b/packages/near-membrane-node/src/node-realm.ts index 9e403d5a..010e8e7f 100644 --- a/packages/near-membrane-node/src/node-realm.ts +++ b/packages/near-membrane-node/src/node-realm.ts @@ -1,25 +1,15 @@ import { assignFilteredGlobalDescriptorsFromPropertyDescriptorMap, - Connector, createBlueConnector, createRedConnector, - DistortionCallback, getFilteredGlobalOwnKeys, - Instrumentation, linkIntrinsics, - PropertyKeys, toSafeWeakMap, VirtualEnvironment, } from '@locker/near-membrane-base'; - +import type { Connector, PropertyKeys } from '@locker/near-membrane-base/types'; import { runInNewContext } from 'vm'; - -export interface NodeEnvironmentOptions { - distortionCallback?: DistortionCallback; - endowments?: PropertyDescriptorMap; - globalObjectShape?: object; - instrumentation?: Instrumentation; -} +import type { NodeEnvironmentOptions } from './types'; const ObjectCtor = Object; const { assign: ObjectAssign } = ObjectCtor; diff --git a/packages/near-membrane-node/src/types.ts b/packages/near-membrane-node/src/types.ts new file mode 100644 index 00000000..12c09657 --- /dev/null +++ b/packages/near-membrane-node/src/types.ts @@ -0,0 +1,8 @@ +import { DistortionCallback, Instrumentation } from '@locker/near-membrane-base/types'; + +export interface NodeEnvironmentOptions { + distortionCallback?: DistortionCallback; + endowments?: PropertyDescriptorMap; + globalObjectShape?: object; + instrumentation?: Instrumentation; +} diff --git a/tsconfig.json b/tsconfig.json index b7c4ffe9..5a1b51cb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,13 @@ { "compilerOptions": { - "target": "es2020", - "module": "es2020", - "moduleResolution": "node", "esModuleInterop": true, "lib": ["dom", "es2015", "es2016", "es2017", "es2018", "es2019", "es2020"], - "declaration": false, - // Enhance Strictness - "strict": true, - "noUnusedLocals": true, - "suppressImplicitAnyIndexErrors": true, + "module": "commonjs", + "moduleResolution": "node", + "target": "es2020", + // Enhance strictness. "noImplicitReturns": true, - "strictBindCallApply": false, + "noUnusedLocals": true, + "strict": true, } }