swiftwasm/JavaScriptKit

Cannot perform DataView.prototype.setBigUint64 on a detached ArrayBuffer

Closed this issue · 2 comments

hey hi

JavascriptKit 0.17.0

I'm using SwifWeb framework which is built on top of JavaScriptKit. Here is my view controller which contains a lot of DOM element objects created through JavaScriptKit. I'm not doing anything illegal. The weird things is that at some point app start crashing with Cannot perform DataView.prototype.setBigUint64 on a detached ArrayBuffer error. I think it is not related to some specific code. Before JavaScriptKit v0.17 I used v0.12 and these errors appeared very often. Now I thought this problem has been completely fixed, but it seems it still appears.

app.js:139 TypeError: Cannot perform DataView.prototype.setBigUint64 on a detached ArrayBuffer
    at DataView.setBigUint64 ()
    at clock_res_get (index.esm.js:114:167)
    at __wasi_clock_res_get (1ddb7b2a:0x3b79363)
    at clock_getres (1ddb7b2a:0x3b767a8)
    at __CFDateInitialize (1ddb7b2a:0x2ff76e7)
    at __CFInitialize (1ddb7b2a:0x2fb8851)
    at __wasm_call_ctors (1ddb7b2a:0x76f37)
    at _initialize (1ddb7b2a:0x76f56)
    at startWasiTask (app.js:133:26)

as a note as soon I removed sectionSelectFiled
i was able to add many more elements

this is the source code

//
//  FiscalConceptDestinationView.swift
//
//
//  Created by Victor Cantu on 9/28/22.
//

import Foundation
import TCFoundation
import TCCodyFire
import Web

class FiscalConceptDestinationView: Div {
    
    override class var name: String { "div" }
    
    let pocid: UUID
    
    @State var units: Int64
    
    private var callback: ((
        _ selectedPlace: InventoryPlaceType,
        _ storeid: UUID?,
        _ storeName: String,
        _ custAccountId: UUID?,
        _ placeid: UUID?,
        _ placeName: String,
        _ bodid: UUID?,
        _ bodName: String,
        _ secid: UUID?,
        _ secName: String,
        _ units: Int64,
        _ series: [String]
    ) -> ())
    
    init(
        pocid: UUID,
        units: Int64,
        callback: @escaping ((
            _ selectedPlace: InventoryPlaceType,
            _ storeid: UUID?,
            _ storeName: String,
            _ custAccountId: UUID?,
            _ placeid: UUID?,
            _ placeName: String,
            _ bodid: UUID?,
            _ bodName: String,
            _ secid: UUID?,
            _ secName: String,
            _ units: Int64,
            _ series: [String]
        ) -> ())
    ) {
        self.pocid = pocid
        self.units = units
        self.callback = callback
        
        super.init()
    }
    
    required init() {
        fatalError("init() has not been implemented")
    }
    
    @State var unitsToDisperse: String = ""
    
    @State var unitsToDisperseSubTitle: String = ""
    
    @State var selectedPlace: InventoryPlaceType? = nil
    
    /// Incase its going to a store  witch store will it be
    @State var selectedStoreId: UUID? = nil
    
    @State var selectedStoreName: String = ""
    
    var selectedBodId: UUID? = nil
    
    var preSelectedSectId: UUID? = nil
    
    @State var selectedBodIdListener: String = ""
    
    @State var selectedSecIdListener: String = ""
    
    @State var searchFolioString: String = ""
    
    @State var sectionSelectText = ""
    
    var availableSection: [CustStoreSeccionesSinc] = []
    
    @State var displayedSection: [CustStoreSeccionesSinc] = []
    
    @State var sectionSelectResultIsHidden = true
    
    /// Selected place EG: Order ID,  Store ID...
    var placeid: UUID? =  nil
    
    lazy var selecctionBox = Div()
        .margin(all: 3.px)
        .padding(all: 3.px)
    
    lazy var availableStoreBox = Div()
        .class(.roundDarkBlue)
        .padding(all: 3.px)
        .margin(all: 3.px)
        .maxHeight(250.px)
        .overflow(.auto)
    
    lazy var unitsToDisperseField = InputText(self.$unitsToDisperse)
        .class(.textFiledBlackDark)
        .placeholder("0")
        .textAlign(.right)
        .width(50.px)
        .height(28.px)
        .onKeyDown { tf, event in
            guard let _ = Float(event.key) else {
                if !ignoredKeys.contains(event.key) {
                    event.preventDefault()
                }
                return
            }
        }
        .onFocus { tf in
            tf.select()
        }
    
    lazy var bodegaSelect = Select(self.$selectedBodIdListener)
        .class(.textFiledBlackDark)
    
    lazy var sectionSelect = Select(self.$selectedSecIdListener)
        .class(.textFiledBlackDark)
    

    lazy var sectionSelectFiled = InputText(self.$sectionSelectText)
        .class(.textFiledBlackDark)
        .placeholder("Seleccione Seccion")
        .width(90.percent)
        .fontSize(23.px)
        .height(28.px)
        .onFocus {
            self.sectionSelectResultIsHidden = false
        }
        .onBlur{
            Dispatch.asyncAfter(1.3) {
                self.sectionSelectResultIsHidden = true
            }
        }
    
    lazy var searchFolioField = InputText(self.$searchFolioString)
    
    lazy var sectionSelectResult = Div{
        
    }
        .hidden(self.$sectionSelectResultIsHidden)
        .backgroundColor(.grayBlackDark)
        .borderRadius(all: 24.px)
        .minHeight(100.px)
        .maxHeight(400.px)
        .overflow(.auto)
    
    @DOM override var body: DOM.Content {
        
        /// Main Seccion
        Div{
            
            /// Header
            Div {
                
                Img()
                    .closeButton(.uiView3)
                    .onClick{
                        self.remove()
                    }
                 
                H2(self.$units.map{ ($0 == 1) ? "Ubicacion de 1 producto" : "Ubicacion de \($0.toString) productos" })
                    .maxWidth(90.percent)
                    .class(.oneLineText)
                    .marginLeft(7.px)
                    .color(.cornflowerBlue)
                
            }
            .paddingBottom(3.px)
            
            Div().class(.clear)
            
            Div {
                Span("Colocar")
                    .marginRight(7.px)
                
                self.unitsToDisperseField
                    .marginRight(7.px)
                
                Span(self.$unitsToDisperse.map{
                    
                    guard let int = Int($0) else {
                        return "unidades"
                    }
                    
                    if int == 1 {
                        return "unidad"
                    }
                    else{
                        return "unidades"
                    }
                    
                })
                
            }
            .fontSize(23.px)
            .paddingBottom(3.px)
            
            Div().class(.clear)
            
            self.selecctionBox
            
        }
        .top(25.percent)
        .backgroundColor(.grayBlack)
        .borderRadius(all: 24.px)
        .position(.absolute)
        .padding(all: 12.px)
        .width(40.percent)
        .left(30.percent)
        .color(.white)
        .hidden(self.$selectedPlace.map { $0 != nil })
        
        /// Store
        Div{
            /// Header
            Div {
                
                Img()
                    .closeButton(.uiView3)
                    .onClick{
                        self.remove()
                    }
                 
                H2(self.$unitsToDisperseSubTitle)
                    .color(.cornflowerBlue)
                    .maxWidth(90.percent)
                    .class(.oneLineText)
                    .marginLeft(7.px)
                
            }
            .paddingBottom(3.px)
            .align(.left)
            
            Div().class(.clear)
            
            self.availableStoreBox
                .hidden(self.$selectedStoreId.map { $0 != nil })
             
            Div {
                H2( self.$selectedStoreName )
                    .color(.white)
                
                Div().class(.clear).height(7.px)
                
                Div {
                    Label("Bodega")
                        .fontSize(18.px)
                        .color(.gray)
                    
                    Div{
                        self.bodegaSelect
                            .width(90.percent)
                            .fontSize(23.px)
                            .height(28.px)
                            
                    }
                }
                .class(.section)
                
                Div().class(.clear).height(7.px)
                
                Div {
                    Label("Seccion")
                        .fontSize(18.px)
                        .color(.gray)
                    
                    Div{
//                        self.sectionSelect
//                            .width(90.percent)
//                            .fontSize(23.px)
//                            .height(28.px)
                        self.sectionSelectFiled
                    }
                    
                   
                    
                    
                }
                .class(.section)
                
                
                Div{
                    self.sectionSelectResult
                }
                .position(.absolute)
                .class(.section)
                .width(95.percent)
                
                
                Div().class(.clear).height(7.px)
                
                Div {
                    Div("Agregar")
                        .onClick {
                            
                            guard let _store = self.selectedStoreId else{
                                showAlert(.alerta, "Seleccione Tienda")
                                return
                            }
                            
                            guard let _bod = UUID(uuidString: self.selectedBodIdListener) else {
                                showAlert(.alerta, "Seleccione Bodega")
                                return
                            }
                            
                            guard let _sec = UUID(uuidString: self.selectedSecIdListener) else {
                                showAlert(.alerta, "Seleccione Bodega")
                                return
                            }
                            
                            self.callback(
                                .store, // selectedPlace
                                _store, // storeid
                                self.selectedStoreName, // storeName
                                nil, // custAccountId
                                nil, // placeid
                                "", // placeName
                                _bod, // bodid
                                (bodegas[_bod]?.name ?? "N/A"), // bodName
                                _sec, // secid
                                (seccions[_sec]?.name ?? "N/A"), // secName
                                self.units, // units
                                [] // series
                            )
                            
                            self.remove()
                        }
                    .class(.uibtnLargeOrange)
                }
                .align(.right)
                
            }
            .hidden(self.$selectedStoreId.map { $0 == nil })
            
        }
        .top(25.percent)
        .backgroundColor(.grayBlack)
        .borderRadius(all: 24.px)
        .position(.absolute)
        .padding(all: 12.px)
        .width(40.percent)
        .left(30.percent)
        .color(.white)
        .hidden(self.$selectedPlace.map { $0 != .store })
        
        /// Order
        Div{
            
            /// Header
            Div {
                
                Img()
                    .closeButton(.uiView3)
                    .onClick{
                        self.remove()
                    }
                 
                H2(self.$unitsToDisperseSubTitle)
                    .maxWidth(90.percent)
                    .class(.oneLineText)
                    .marginLeft(7.px)
                    .color(.cornflowerBlue)
                
            }
            .paddingBottom(3.px)
            
            Div().class(.clear).height(12.px)
            
            Div{
                Label("Ingrese Folio")
                    .color(.lightGray)
                    .fontSize(23.px)
                
                Div{
                    self.searchFolioField
                        .class(.textFiledBlackDarkLarge)
                        .placeholder("Ingrese Folio")
                        .width(90.percent)
                        .fontSize(23.px)
                        .height(27.px)
                        .onEnter { tf in
                            self.searchFolio()
                        }
                }
            }
            .class(.section)
            
            Div().class(.clear).height(12.px)
            
            Div{
                Div("Buscar Folio")
                    .onClick {
                        self.searchFolio()
                    }
                .class(.uibtnLargeOrange)
            }
            .align(.right)
            
        }
        .top(25.percent)
        .backgroundColor(.grayBlack)
        .borderRadius(all: 24.px)
        .position(.absolute)
        .padding(all: 12.px)
        .width(40.percent)
        .left(30.percent)
        .color(.white)
        .hidden(self.$selectedPlace.map { $0 != .order })
        
        /*
        /// Sold
        Div{
            
            /// Header
            Div {
                
                Img()
                    .closeButton(.uiView3)
                    .onClick{
                        self.remove()
                    }
                 
                H2(self.$unitsToDisperseSubTitle)
                    .maxWidth(90.percent)
                    .class(.oneLineText)
                    .marginLeft(7.px)
                    .color(.cornflowerBlue)
                
            }
            .paddingBottom(3.px)
            
            Div().class(.clear)
        }
        .top(25.percent)
        .backgroundColor(.grayBlack)
        .borderRadius(all: 24.px)
        .position(.absolute)
        .padding(all: 12.px)
        .width(40.percent)
        .left(30.percent)
        .color(.white)
        .hidden(self.$selectedPlace.map { $0 != .sold })
        
        /// Merm
        Div{
            
            /// Header
            Div {
                
                Img()
                    .closeButton(.uiView3)
                    .onClick{
                        self.remove()
                    }
                 
                H2(self.$unitsToDisperseSubTitle)
                    .maxWidth(90.percent)
                    .class(.oneLineText)
                    .marginLeft(7.px)
                    .color(.cornflowerBlue)
                
            }
            .paddingBottom(3.px)
            
            Div().class(.clear)
        }
        .top(25.percent)
        .backgroundColor(.grayBlack)
        .borderRadius(all: 24.px)
        .position(.absolute)
        .padding(all: 12.px)
        .width(40.percent)
        .left(30.percent)
        .color(.white)
        .hidden(self.$selectedPlace.map { $0 != .merm })
        
        /// Return to vendor
        Div{
            
            /// Header
            Div {
                
                Img()
                    .closeButton(.uiView3)
                    .onClick{
                        self.remove()
                    }
                 
                H2(self.$unitsToDisperseSubTitle)
                    .maxWidth(90.percent)
                    .class(.oneLineText)
                    .marginLeft(7.px)
                    .color(.cornflowerBlue)
                
            }
            .paddingBottom(3.px)
            
            Div().class(.clear)
        }
        .top(25.percent)
        .backgroundColor(.grayBlack)
        .borderRadius(all: 24.px)
        .position(.absolute)
        .padding(all: 12.px)
        .width(40.percent)
        .left(30.percent)
        .color(.white)
        .hidden(self.$selectedPlace.map { $0 != .returnToVendor })
         */
    }
    
    override func buildUI() {
        super.buildUI()
        
        self.class(.transparantBlackBackGround)
        position(.absolute)
        height(100.percent)
        width(100.percent)
        top(0.px)
        left(0.px)
        
        $unitsToDisperse.listen {
            
            guard let int = Int64($0) else{
                self.unitsToDisperseSubTitle = "Ubicacion de \($0) productos"
                return
            }
            
            if int == 1 {
                self.unitsToDisperseSubTitle = "Ubicacion de \($0) productos"
            }
            else{
                self.unitsToDisperseSubTitle = "Ubicacion de \($0) productos"
            }
            
            self.units = int
            
        }
        /*
        $selectedBodIdListener.listen {
            
            self.sectionSelect.innerHTML = ""
            
            self.selectedSecIdListener = ""
            
            self.sectionSelect.appendChild(
                Option("Seleccione Seccion")
                    .value("")
            )
            
            let _bodid = UUID(uuidString: $0)
            
            if self.selectedBodId == _bodid {
                return
            }
            
            guard let _bodid = _bodid else {
                return
            }
//
//            var sectionRefrence: [String:CustStoreSeccionesSinc] = [:]
//
//            seccions.forEach { item, sect in
//                if sect.custStoreBodegas == _bodid {
//                    sectionRefrence[sect.name] = sect
//                }
//            }
//
//            let sorted = sectionRefrence.sorted { $0.0 > $1.0 }
//
//            self.availableSection = sorted.map{$1}
            
            /*
            _sect.forEach { sect in
                
                let opt = Option(sect.name)
                    .value(sect.id.uuidString)
                
                if sect.id == self.preSelectedSectId {
                    self.selectedSecIdListener = sect.id.uuidString
                    opt.selected(true)
                }
                
                self.sectionSelect.appendChild(opt)
                
            }
            */
        }
        
        $sectionSelectText.listen {
            
            let term = $0.uppercased()
            
            if term.isEmpty {
                self.displayedSection = self.availableSection
                return
            }
            
            var sections: [CustStoreSeccionesSinc] = []
            
            var included: [String] = []
            
            // Starts with
            self.availableSection.forEach { section in
                if section.name.uppercased().hasPrefix(term) {
                    sections.append(section)
                    included.append(section.name)
                }
            }
            
            // Contains
            self.availableSection.forEach { section in
                if section.name.uppercased().hasPrefix(term) && !included.contains(section.name){
                    sections.append(section)
                }
            }
        }
        
        $displayedSection.listen {
            
            self.sectionSelectResult.innerHTML = ""
            
            $0.forEach { section in
                self.sectionSelectResult.appendChild(
                    Div(section.name)
                        .class(.uibtn)
                        .color(.white)
                )
            }
            
        }
        
        $selectedSecIdListener.listen {
            
        }
        
        stores.forEach { id, store in
            if id == custCatchStore {
                availableStoreBox.appendChild(
                    Div(store.name)
                        .class(.uibtnLargeOrange)
                        .width(97.percent)
                        .onClick {
                            self.selectStore(storeid: id, storeName: store.name)
                        }
                )
            }
        }
        
        stores.forEach { id, store in
            if id != custCatchStore {
                availableStoreBox.appendChild(
                    Div(store.name)
                        .class(.uibtnLarge)
                        .width(97.percent)
                        .onClick {
                            self.selectStore(storeid: id, storeName: store.name)
                        }
                )
            }
        }
        
        InventoryPlaceType.allCases.forEach { type in
            selecctionBox.appendChild(
                Div(type.description)
                    .class(.uibtnLarge)
                    .width(97.percent)
                    .onClick {
                        self.proccessUnits(type: type)
                    }
            )
        }
        
        unitsToDisperse = units.toString
        */
    }
    
    override func didAddToDOM() {
        super.didAddToDOM()
        
        self.unitsToDisperseField.select()
        
    }
    
    func proccessUnits(type: InventoryPlaceType) {
        
        guard let _units = Int64(unitsToDisperse) else{
            showAlert(.alerta, "Ingrese una cantidad valida")
            self.unitsToDisperseField.select()
            return
        }
        
        if _units > units {
            showAlert(.alerta, "Ingrese menos unidades, no tiene \(_units.toString) unidades")
            self.unitsToDisperseField.select()
            return
        }
        
        if _units < units {
            showAlert(.alerta, "Ingrese mas de una unidad")
            self.unitsToDisperseField.select()
            return
        }
        
        guard self.units > 0 else {
            showAlert(.alerta, "Ingrese una cantidad valida")
            self.unitsToDisperseField.select()
            return
        }
        
        switch type {
        case .store:
            
            print("select .store")
            
            print("No of strores \(stores.count)")
            
            if stores.count == 1 {
                
                guard let store = stores.first?.value else {
                    return
                }
                
                self.selectStore(storeid: store.id, storeName: store.name)
            }
            
            self.selectedPlace = type
            
        case .order:
            self.selectedPlace = type
            self.searchFolioField.select()
        case .sold:
            
            addToDom(ConfirmView(
                type: .yesNo,
                title: "Confirme Accion",
                message: "Confirme que va marcar como vendido.",
                callback: { isConfirmed in
                    if isConfirmed {
                        
                        self.callback(
                            .sold, // selectedPlace
                            custCatchStore, // storeid
                            "", // storeName
                            nil, // custAccountId
                            nil, // placeid
                            "", // placeName
                            nil, // bodid
                            "", // bodName
                            nil, // secid
                            "", // secName
                            self.units, // units
                            [] // series
                        )
                        
                        self.remove()
                    }
                }
            ))
            
        case .merm:
            
            addToDom(ConfirmView(
                type: .yesNo,
                title: "Confirme Accion",
                message: "Confirme que va marcar como mermado.",
                callback: { isConfirmed in
                    if isConfirmed {
                        
                        self.callback(
                            .merm, // selectedPlace
                            custCatchStore, // storeid
                            "", // storeName
                            nil, // custAccountId
                            nil, // placeid
                            "", // placeName
                            nil, // bodid
                            "", // bodName
                            nil, // secid
                            "", // secName
                            self.units, // units
                            [] // series
                        )
                        
                        self.remove()
                    }
                }
            ))
            
        case .returnToVendor:
            
            addToDom(ConfirmView(
                type: .yesNo,
                title: "Confirme Accion",
                message: "Confirme que va regrear vendedor.",
                callback: { isConfirmed in
                    if isConfirmed {
                        
                        self.callback(
                            .returnToVendor, // selectedPlace
                            custCatchStore, // storeid
                            "", // storeName
                            nil, // custAccountId
                            nil, // placeid
                            "", // placeName
                            nil, // bodid
                            "", // bodName
                            nil, // secid
                            "", // secName
                            self.units, // units
                            [] // series
                        )
                        
                        self.remove()
                    }
                }
            ))
        }
        
    }
    
    func selectStore( storeid: UUID, storeName: String) {
        
        /// The store is not same so i will only add to oder since reciving store must decide where it fisicly goes
        if storeid != custCatchStore {
            
            self.callback(
                .store, // selectedPlace
                storeid, // storeid
                storeName, // storeName
                nil, // custAccountId
                nil, // placeid
                "", // placeName
                nil, // bodid
                "Por Eligir", // bodName
                nil, // secid
                "Por Eligir", // secName
                self.units, // units
                [] // series
            )
            
            self.remove()
        }
        /// will load place since  it goes in the order
        else{
            
            loadingView(show: true)
            
            API.custPOCV1.getPOCBodSec(pocid: pocid, storeid: custCatchStore) { resp in
            
                loadingView(show: false)
                
                guard let resp = resp else {
                    showError(.errorDeCommunicacion, .serverConextionError)
                    return
                }
                
                guard resp.status == .ok else {
                    showError(.errorGeneral, resp.msg)
                    return
                }
                
                guard let data = resp.data else {
                    showError(.errorGeneral, "No se obtuvo data de la respuesta")
                    return
                }
                
                self.preSelectedSectId = data.section
                
                var bods: [CustStoreBodegasSinc] = []
                
                bodegas.forEach { bodid, bodData in
                    if bodData.custStore == custCatchStore {
                        bods.append(bodData)
                    }
                }
                
                var _selectedBodegaId: UUID? = nil
                
                if bods.count == 1 {
                    _selectedBodegaId = bods.first?.id
                }
                else if data.bodega != nil {
                    _selectedBodegaId = data.bodega
                }
                
                bods.forEach { bod in
                    
                    let opt = Option(bod.name)
                        .value(bod.id.uuidString)
                    
                    if let _sel = _selectedBodegaId {
                        if _sel ==  bod.id {
                            
                            self.selectedBodIdListener = _sel.uuidString
                            
                            opt.selected(true)
                            
                        }
                    }
                    
                    self.bodegaSelect.appendChild(opt)
                    
                }
                
                self.selectedStoreId = custCatchStore
                
                self.selectedStoreName = storeName
                
                
            }
        }
    }
    
    func searchFolio() {
        
        var term = searchFolioString
            .purgeSpaces
            .pseudo
        
        if searchFolioString.isEmpty {
            showAlert( .alerta, "Ingrese Folio")
            return
        }
        
        if !term.contains("-") {
            term = "-\(term)"
        }
        
        loadingView(show: true)
        
        API.custOrderV1.searchFolio(
            term: term,
            accountid: nil,
            tag1: "",
            tag2: "",
            tag3: "",
            tag4: "",
            description: nil,
            timeEnd: nil,
            timeInit: nil
        ) { resp in
            
            loadingView(show: false)
            
            guard let resp = resp else {
                showError(.errorDeCommunicacion, .serverConextionError)
                return
            }
            
            guard resp.status == .ok else {
                showError(.errorGeneral, resp.msg)
                return
            }
            
            guard let order = resp.data.orders.first else {
                showError( .errorGeneral, "No se localizo folio, revice de nuevo.")
                return
            }
            
            
            self.callback(
                .order, // selectedPlace
                custCatchStore, // storeid
                "Pendiente elegir tienda", // storeName
                order.custAcct, // custAccountId
                order.id, // placeid
                order.folio, // placeName
                nil, // bodid
                "", // bodName
                nil, // secid
                "", // secName
                self.units, // units
                [] // series
            )
            
            self.remove()
            
        }
    }
}

I'm not sure how the SwiftWeb framework works, but it looks like it doesn't apply a patch for wasmer's wasi implementation like https://github.com/swiftwasm/carton/blob/74b8ca6e1d5ebef70ff6ecebf445b5a9674f83a1/entrypoint/common.js#L135-L152

Thanks for forwarding issue to the SwifWeb team, they made a fix that you suggested.
I have been doing various stress tests and everything seems to be working fine now.