514 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			514 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**
 | 
						|
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 | 
						|
 * SPDX-License-Identifier: Apache-2.0.
 | 
						|
 */
 | 
						|
 | 
						|
#include "class_binder.h"
 | 
						|
 | 
						|
#ifdef _MSC_VER
 | 
						|
#    pragma warning(disable : 4204)
 | 
						|
#endif /* _MSC_VER */
 | 
						|
 | 
						|
struct aws_napi_class_info_impl {
 | 
						|
    const struct aws_napi_method_info *ctor_method;
 | 
						|
 | 
						|
    napi_ref constructor;
 | 
						|
 | 
						|
    struct {
 | 
						|
        void *instance;
 | 
						|
        napi_finalize finalizer;
 | 
						|
        bool is_wrapping;
 | 
						|
    } wrapping;
 | 
						|
};
 | 
						|
 | 
						|
/* Make sure our static storage is big enough */
 | 
						|
AWS_STATIC_ASSERT(sizeof(struct aws_napi_class_info) >= sizeof(struct aws_napi_class_info_impl));
 | 
						|
 | 
						|
/*
 | 
						|
 * Populates an aws_napi_argument object from a napi value.
 | 
						|
 *
 | 
						|
 * \param env               The node environment.
 | 
						|
 * \param value             The value to pull the value from.
 | 
						|
 * \param expected_type     The type you expect the value to be. Pass napi_undefined to accept anything.
 | 
						|
 * \param accept_undefined  Whether or not to accept expected_type OR undefined
 | 
						|
 * \param out_value         The argument object to populate.
 | 
						|
 */
 | 
						|
static napi_status s_argument_parse(
 | 
						|
    napi_env env,
 | 
						|
    napi_value value,
 | 
						|
    napi_valuetype expected_type,
 | 
						|
    bool accept_undefined,
 | 
						|
    struct aws_napi_argument *out_value) {
 | 
						|
 | 
						|
    out_value->node = value;
 | 
						|
    AWS_NAPI_CALL(env, napi_typeof(env, value, &out_value->type), { return status; });
 | 
						|
 | 
						|
    if (expected_type != napi_undefined && out_value->type != expected_type &&
 | 
						|
        !(accept_undefined && out_value->type == napi_undefined)) {
 | 
						|
        switch (expected_type) {
 | 
						|
            case napi_string:
 | 
						|
                napi_throw_type_error(env, NULL, "Class binder argument expected a string");
 | 
						|
                return napi_string_expected;
 | 
						|
 | 
						|
            case napi_number:
 | 
						|
                napi_throw_type_error(env, NULL, "Class binder argument expected a number");
 | 
						|
                return napi_number_expected;
 | 
						|
 | 
						|
            default:
 | 
						|
                napi_throw_type_error(env, NULL, "Class binder argument wrong type");
 | 
						|
                return napi_generic_failure;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    switch (out_value->type) {
 | 
						|
        case napi_boolean: {
 | 
						|
            AWS_NAPI_CALL(env, napi_get_value_bool(env, value, &out_value->native.boolean), { return status; });
 | 
						|
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        case napi_string: {
 | 
						|
            AWS_NAPI_CALL(env, aws_byte_buf_init_from_napi(&out_value->native.string, env, value), { return status; });
 | 
						|
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        case napi_number: {
 | 
						|
            AWS_NAPI_CALL(env, napi_get_value_int64(env, value, &out_value->native.number), {
 | 
						|
                napi_throw_type_error(env, NULL, "Class binder argument expected a number");
 | 
						|
                return status;
 | 
						|
            });
 | 
						|
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        case napi_external: {
 | 
						|
            AWS_NAPI_CALL(env, napi_get_value_external(env, value, &out_value->native.external), {
 | 
						|
                napi_throw_type_error(env, NULL, "Class binder argument expected an external");
 | 
						|
                return status;
 | 
						|
            });
 | 
						|
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        case napi_object: {
 | 
						|
            /* Attempt to unwrap the object, just in case */
 | 
						|
            napi_status result = napi_unwrap(env, value, &out_value->native.external);
 | 
						|
            if (result != napi_ok) {
 | 
						|
                out_value->native.external = NULL;
 | 
						|
            }
 | 
						|
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        default:
 | 
						|
            /* Don't process, just leave as node value */
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    return napi_ok;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Cleans up an aws_napi_argument object populated by s_argument_parse.
 | 
						|
 *
 | 
						|
 * \param env           The node environment.
 | 
						|
 * \param value         The value to clean up.
 | 
						|
 */
 | 
						|
static void s_argument_cleanup(napi_env env, struct aws_napi_argument *value) {
 | 
						|
    (void)env;
 | 
						|
 | 
						|
    switch (value->type) {
 | 
						|
        case napi_string:
 | 
						|
            aws_byte_buf_clean_up(&value->native.string);
 | 
						|
            break;
 | 
						|
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Used as the class's constructor
 | 
						|
 */
 | 
						|
static napi_value s_constructor(napi_env env, napi_callback_info info) {
 | 
						|
 | 
						|
    napi_value node_args[AWS_NAPI_METHOD_MAX_ARGS];
 | 
						|
    napi_value node_this = NULL;
 | 
						|
    size_t num_args = AWS_ARRAY_SIZE(node_args);
 | 
						|
    struct aws_napi_class_info_impl *class_info = NULL;
 | 
						|
    AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, node_args, &node_this, (void **)&class_info), {
 | 
						|
        napi_throw_error(env, NULL, "Failed to retreive callback information");
 | 
						|
        return NULL;
 | 
						|
    });
 | 
						|
    if (num_args > AWS_NAPI_METHOD_MAX_ARGS) {
 | 
						|
        num_args = AWS_NAPI_METHOD_MAX_ARGS;
 | 
						|
    }
 | 
						|
 | 
						|
    napi_value result = NULL;
 | 
						|
 | 
						|
    /* Check if we're wrapping an existing object or creating a new one */
 | 
						|
    if (class_info->wrapping.is_wrapping) {
 | 
						|
        AWS_FATAL_ASSERT(num_args == 0);
 | 
						|
 | 
						|
        AWS_NAPI_CALL(
 | 
						|
            env,
 | 
						|
            napi_wrap(env, node_this, class_info->wrapping.instance, class_info->wrapping.finalizer, class_info, NULL),
 | 
						|
            {
 | 
						|
                napi_throw_error(env, NULL, "Failed to wrap http_request");
 | 
						|
                return NULL;
 | 
						|
            });
 | 
						|
 | 
						|
    } else {
 | 
						|
        const struct aws_napi_method_info *method = class_info->ctor_method;
 | 
						|
 | 
						|
        /* If there is no ctor method, don't both doing anything more, just return the empty object */
 | 
						|
        if (method->method) {
 | 
						|
            struct aws_napi_argument args[AWS_NAPI_METHOD_MAX_ARGS];
 | 
						|
            AWS_ZERO_ARRAY(args);
 | 
						|
 | 
						|
            if (num_args < method->num_arguments) {
 | 
						|
                napi_throw_error(env, NULL, "Class binder constructor given incorrect number of arguments");
 | 
						|
                return NULL;
 | 
						|
            }
 | 
						|
 | 
						|
            for (size_t i = 0; i < num_args; ++i) {
 | 
						|
                if (s_argument_parse(env, node_args[i], method->arg_types[i], i >= method->num_arguments, &args[i])) {
 | 
						|
                    goto cleanup_arguments;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            struct aws_napi_callback_info cb_info = {
 | 
						|
                .node_this = node_this,
 | 
						|
                .native_this = node_this,
 | 
						|
                .num_args = num_args,
 | 
						|
            };
 | 
						|
            cb_info.arguments = args;
 | 
						|
 | 
						|
            method->method(env, &cb_info);
 | 
						|
 | 
						|
        cleanup_arguments:
 | 
						|
            for (size_t i = 0; i < method->num_arguments; ++i) {
 | 
						|
                s_argument_cleanup(env, &args[i]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Callback used to return the value of a property. Expects 0 arguments.
 | 
						|
 */
 | 
						|
static napi_value s_property_getter(napi_env env, napi_callback_info info) {
 | 
						|
 | 
						|
    void *native_this = NULL;
 | 
						|
 | 
						|
    napi_value node_this = NULL;
 | 
						|
    size_t num_args = 0;
 | 
						|
    void *data = NULL;
 | 
						|
    AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, NULL, &node_this, &data), {
 | 
						|
        napi_throw_error(env, NULL, "Failed to retreive callback information");
 | 
						|
        return NULL;
 | 
						|
    });
 | 
						|
    if (num_args != 0) {
 | 
						|
        napi_throw_error(env, NULL, "Class binder getter needs exactly 0 arguments");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    AWS_NAPI_CALL(env, napi_unwrap(env, node_this, &native_this), {
 | 
						|
        napi_throw_error(env, NULL, "Class binder property getter must be called on a wrapped object");
 | 
						|
        return NULL;
 | 
						|
    });
 | 
						|
 | 
						|
    const struct aws_napi_property_info *property = data;
 | 
						|
 | 
						|
    if (!property->getter) {
 | 
						|
        napi_throw_error(env, NULL, "Property is not readable");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    napi_value result = property->getter(env, native_this);
 | 
						|
 | 
						|
#if DEBUG_BUILD
 | 
						|
    /* In debug builds, validate that getters are returning the correct type */
 | 
						|
    napi_valuetype result_type = napi_undefined;
 | 
						|
    AWS_NAPI_CALL(env, napi_typeof(env, result, &result_type), { return NULL; });
 | 
						|
    AWS_FATAL_ASSERT(property->type == napi_undefined || property->type == result_type);
 | 
						|
#endif
 | 
						|
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Callback used to set the value of a property. Expects 1 argument.
 | 
						|
 */
 | 
						|
static napi_value s_property_setter(napi_env env, napi_callback_info info) {
 | 
						|
 | 
						|
    void *native_this = NULL;
 | 
						|
 | 
						|
    napi_value node_this = NULL;
 | 
						|
    napi_value node_value;
 | 
						|
    size_t num_args = 1;
 | 
						|
    void *data = NULL;
 | 
						|
    AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, &node_value, &node_this, &data), {
 | 
						|
        napi_throw_error(env, NULL, "Failed to retreive callback information");
 | 
						|
        return NULL;
 | 
						|
    });
 | 
						|
    if (num_args != 1) {
 | 
						|
        napi_throw_error(env, NULL, "Class binder setter needs exactly 1 arguments");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    AWS_NAPI_CALL(env, napi_unwrap(env, node_this, &native_this), {
 | 
						|
        napi_throw_error(env, NULL, "Class binder setter must be called on instance of a wrapped object");
 | 
						|
        return NULL;
 | 
						|
    });
 | 
						|
 | 
						|
    const struct aws_napi_property_info *property = data;
 | 
						|
 | 
						|
    if (!property->setter) {
 | 
						|
        napi_throw_error(env, NULL, "Property is not writable");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    struct aws_napi_argument new_value;
 | 
						|
    if (s_argument_parse(env, node_value, property->type, false, &new_value)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    property->setter(env, native_this, &new_value);
 | 
						|
 | 
						|
    s_argument_cleanup(env, &new_value);
 | 
						|
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Callback used to call a method on a bound object.
 | 
						|
 */
 | 
						|
static napi_value s_method_call(napi_env env, napi_callback_info info) {
 | 
						|
 | 
						|
    void *native_this = NULL;
 | 
						|
    struct aws_napi_argument args[AWS_NAPI_METHOD_MAX_ARGS];
 | 
						|
    AWS_ZERO_ARRAY(args);
 | 
						|
 | 
						|
    napi_value node_this = NULL;
 | 
						|
    napi_value node_args[AWS_NAPI_METHOD_MAX_ARGS];
 | 
						|
    size_t num_args = AWS_ARRAY_SIZE(node_args);
 | 
						|
    void *data = NULL;
 | 
						|
    AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, node_args, &node_this, &data), {
 | 
						|
        napi_throw_error(env, NULL, "Failed to retreive callback information");
 | 
						|
        return NULL;
 | 
						|
    });
 | 
						|
    if (num_args > AWS_NAPI_METHOD_MAX_ARGS) {
 | 
						|
        num_args = AWS_NAPI_METHOD_MAX_ARGS;
 | 
						|
    }
 | 
						|
 | 
						|
    struct aws_napi_method_info *method = data;
 | 
						|
    if (num_args < method->num_arguments) {
 | 
						|
        napi_throw_error(env, NULL, "Bound class's method requires more arguments");
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((method->attributes & napi_static) == 0) {
 | 
						|
        AWS_NAPI_CALL(env, napi_unwrap(env, node_this, &native_this), {
 | 
						|
            napi_throw_error(env, NULL, "Bound class's method must be called on instance of the class");
 | 
						|
            return NULL;
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    napi_value result = NULL;
 | 
						|
 | 
						|
    for (size_t i = 0; i < num_args; ++i) {
 | 
						|
        if (s_argument_parse(env, node_args[i], method->arg_types[i], i >= method->num_arguments, &args[i])) {
 | 
						|
            goto cleanup_arguments;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    struct aws_napi_callback_info cb_info = {
 | 
						|
        .node_this = node_this,
 | 
						|
        .native_this = native_this,
 | 
						|
        .num_args = num_args,
 | 
						|
    };
 | 
						|
    cb_info.arguments = args;
 | 
						|
 | 
						|
    result = method->method(env, &cb_info);
 | 
						|
 | 
						|
cleanup_arguments:
 | 
						|
    for (size_t i = 0; i < num_args; ++i) {
 | 
						|
        s_argument_cleanup(env, &args[i]);
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
bool aws_napi_method_next_argument(
 | 
						|
    napi_valuetype expected_type,
 | 
						|
    const struct aws_napi_callback_info *cb_info,
 | 
						|
    const struct aws_napi_argument **next_arg) {
 | 
						|
 | 
						|
    if (!*next_arg) {
 | 
						|
        *next_arg = cb_info->arguments;
 | 
						|
    } else {
 | 
						|
        (*next_arg)++;
 | 
						|
    }
 | 
						|
 | 
						|
    const size_t current_index = (*next_arg) - cb_info->arguments;
 | 
						|
    return current_index <= cb_info->num_args &&
 | 
						|
           ((expected_type == napi_undefined && (*next_arg)->type != napi_undefined) ||
 | 
						|
            (expected_type == (*next_arg)->type));
 | 
						|
}
 | 
						|
 | 
						|
static napi_status s_get_symbol(napi_env env, const char *symbol_name, napi_value *result) {
 | 
						|
    napi_value global = NULL;
 | 
						|
    AWS_NAPI_CALL(env, napi_get_global(env, &global), { return status; });
 | 
						|
 | 
						|
    napi_value symbol = NULL;
 | 
						|
    AWS_NAPI_CALL(env, napi_get_named_property(env, global, "Symbol", &symbol), { return status; });
 | 
						|
    AWS_NAPI_CALL(env, napi_get_named_property(env, symbol, symbol_name, result), { return status; });
 | 
						|
 | 
						|
    return napi_ok;
 | 
						|
}
 | 
						|
 | 
						|
napi_status aws_napi_define_class(
 | 
						|
    napi_env env,
 | 
						|
    napi_value exports,
 | 
						|
    const struct aws_napi_method_info *constructor,
 | 
						|
    const struct aws_napi_property_info *properties,
 | 
						|
    size_t num_properties,
 | 
						|
    const struct aws_napi_method_info *methods,
 | 
						|
    size_t num_methods,
 | 
						|
    struct aws_napi_class_info *class_info) {
 | 
						|
 | 
						|
    AWS_FATAL_ASSERT(constructor->name);
 | 
						|
    AWS_FATAL_ASSERT(constructor->attributes == napi_default);
 | 
						|
 | 
						|
    struct aws_napi_class_info_impl *impl = (struct aws_napi_class_info_impl *)class_info;
 | 
						|
    impl->ctor_method = constructor;
 | 
						|
 | 
						|
    struct aws_allocator *allocator = aws_napi_get_allocator();
 | 
						|
 | 
						|
    const size_t num_descriptors = num_properties + num_methods;
 | 
						|
    napi_property_descriptor *descriptors =
 | 
						|
        aws_mem_calloc(allocator, num_descriptors, sizeof(napi_property_descriptor));
 | 
						|
 | 
						|
    size_t desc_i = 0;
 | 
						|
 | 
						|
    for (size_t prop_i = 0; prop_i < num_properties; ++prop_i) {
 | 
						|
        napi_property_descriptor *desc = &descriptors[desc_i++];
 | 
						|
        const struct aws_napi_property_info *property = &properties[prop_i];
 | 
						|
 | 
						|
        AWS_FATAL_ASSERT(property->name || property->symbol);
 | 
						|
        AWS_FATAL_ASSERT(property->getter || property->setter);
 | 
						|
 | 
						|
        if (property->symbol) {
 | 
						|
            AWS_NAPI_CALL(env, s_get_symbol(env, property->symbol, &desc->name), { return status; });
 | 
						|
        } else {
 | 
						|
            desc->utf8name = property->name;
 | 
						|
        }
 | 
						|
        desc->data = (void *)property;
 | 
						|
        desc->getter = s_property_getter;
 | 
						|
        desc->setter = s_property_setter;
 | 
						|
        desc->attributes = property->attributes;
 | 
						|
    }
 | 
						|
 | 
						|
    for (size_t method_i = 0; method_i < num_methods; ++method_i) {
 | 
						|
        napi_property_descriptor *desc = &descriptors[desc_i++];
 | 
						|
        const struct aws_napi_method_info *method = &methods[method_i];
 | 
						|
 | 
						|
        AWS_FATAL_ASSERT(method->name || method->symbol);
 | 
						|
        AWS_FATAL_ASSERT(method->method);
 | 
						|
 | 
						|
        if (method->symbol) {
 | 
						|
            AWS_NAPI_CALL(env, s_get_symbol(env, method->symbol, &desc->name), { return status; });
 | 
						|
        } else {
 | 
						|
            desc->utf8name = method->name;
 | 
						|
        }
 | 
						|
        desc->data = (void *)method;
 | 
						|
        desc->method = s_method_call;
 | 
						|
        desc->attributes = method->attributes;
 | 
						|
    }
 | 
						|
 | 
						|
    napi_value node_constructor = NULL;
 | 
						|
    AWS_NAPI_CALL(
 | 
						|
        env,
 | 
						|
        napi_define_class(
 | 
						|
            env,
 | 
						|
            constructor->name,
 | 
						|
            NAPI_AUTO_LENGTH,
 | 
						|
            s_constructor,
 | 
						|
            class_info,
 | 
						|
            num_descriptors,
 | 
						|
            descriptors,
 | 
						|
            &node_constructor),
 | 
						|
        { return status; });
 | 
						|
 | 
						|
    /* Don't need descriptors anymore */
 | 
						|
    aws_mem_release(allocator, descriptors);
 | 
						|
 | 
						|
    /* Reference the constructor for later user */
 | 
						|
    AWS_NAPI_CALL(env, napi_create_reference(env, node_constructor, 1, &impl->constructor), { return status; });
 | 
						|
 | 
						|
    AWS_NAPI_CALL(env, napi_set_named_property(env, exports, constructor->name, node_constructor), { return status; });
 | 
						|
 | 
						|
    return napi_ok;
 | 
						|
}
 | 
						|
 | 
						|
napi_status aws_napi_wrap(
 | 
						|
    napi_env env,
 | 
						|
    struct aws_napi_class_info *class_info,
 | 
						|
    void *native,
 | 
						|
    napi_finalize finalizer,
 | 
						|
    napi_value *result) {
 | 
						|
 | 
						|
    struct aws_napi_class_info_impl *impl = (struct aws_napi_class_info_impl *)class_info;
 | 
						|
 | 
						|
    /* Retrieve the constructor */
 | 
						|
    napi_value constructor = NULL;
 | 
						|
    AWS_NAPI_CALL(env, napi_get_reference_value(env, impl->constructor, &constructor), {
 | 
						|
        napi_throw_error(env, NULL, "Failed to dereference constructor value");
 | 
						|
        return status;
 | 
						|
    });
 | 
						|
 | 
						|
    /* Set our handy-dandy global state */
 | 
						|
    impl->wrapping.is_wrapping = true;
 | 
						|
    impl->wrapping.instance = native;
 | 
						|
    impl->wrapping.finalizer = finalizer;
 | 
						|
    AWS_NAPI_CALL(env, napi_new_instance(env, constructor, 0, NULL, result), {
 | 
						|
        napi_throw_error(env, NULL, "Failed to construct class-bound object");
 | 
						|
        return status;
 | 
						|
    });
 | 
						|
    AWS_ZERO_STRUCT(impl->wrapping);
 | 
						|
 | 
						|
    /* The constructor function will have called napi_wrap onto result */
 | 
						|
 | 
						|
    return napi_ok;
 | 
						|
}
 | 
						|
 | 
						|
napi_status aws_napi_define_function(napi_env env, napi_value exports, struct aws_napi_method_info *method) {
 | 
						|
 | 
						|
    /* Set static attribute so that s_method_call doesn't try to unwrap the this object */
 | 
						|
    method->attributes = napi_static;
 | 
						|
 | 
						|
    /* Create the function object */
 | 
						|
    napi_value node_function = NULL;
 | 
						|
    AWS_NAPI_CALL(
 | 
						|
        env, napi_create_function(env, method->name, NAPI_AUTO_LENGTH, s_method_call, method, &node_function), {
 | 
						|
            return status;
 | 
						|
        });
 | 
						|
 | 
						|
    /* Initialize the name from the symbol if necessary, otherwise use the utf8 name */
 | 
						|
    napi_value node_name = NULL;
 | 
						|
    if (method->symbol) {
 | 
						|
        AWS_NAPI_CALL(env, s_get_symbol(env, method->symbol, &node_name), { return status; });
 | 
						|
    } else {
 | 
						|
        AWS_NAPI_CALL(
 | 
						|
            env, napi_create_string_utf8(env, method->name, NAPI_AUTO_LENGTH, &node_name), { return status; });
 | 
						|
    }
 | 
						|
 | 
						|
    /* Export the function */
 | 
						|
    AWS_NAPI_CALL(env, napi_set_property(env, exports, node_name, node_function), { return status; });
 | 
						|
 | 
						|
    return napi_ok;
 | 
						|
}
 |