Fork me on GitHub
#clojurescript
<
2022-03-21
>
Pepijn de Vos09:03:09

This is what my project folder looks like today. I have no idea what could possibly have caused this. It's a shadow-cljs reagent webapp. They are all empty and date from the same time Saturday: -rw-rw-rw- 1 pepijn pepijn 0 19 mrt 15:24 ''$'\300\266''W'$'\250\371\177' I wasn't even working on my app in the weekend I think?? I'm just completely baffled and posting in case anyone has seen something like this before or any suspicion what it could be. They are not even valid UTF-8 or anything. It's nothing like the occasional :w file or whaterever. Just huge swaths of random binary filenames with no content, all created at the same time.

p-himik10:03:40

Are you sure you didn't run something like cat /dev/urandom | xargs -0 -l touch '{}'? :) No clue but an error in some script would definitely be my first guess.

Pepijn de Vos10:03:01

Ah silly me totally forgot I cated urandom into touch

😟 1
1
p-himik10:03:32

Happens every time. But yeah, that was just to demonstrate the principle. Although lengths of your file names are quite uniform, so it's unlikely to be completely random. You have .histfile or something like that in your shell - check what you were running in that time period.

Pepijn de Vos10:03:24

389  git commit -am "new design, fixes #53"
  390  git push
  391  sudo pacman -Syu
  392  klayout 
  393  klayout --edit
  394  klayout --help
  395  klayout -h
  396  klayout -e
  397  git status
  398  git checkout master
  399  git diff
  400  git stash
  401  git checkout master
  402  git pull
  403  make blinky-tangnano-synth.json
  404  code blinky-tangnano-synth.json 
  405  yosys -p show blinky-tangnano-synth.json 
The first item is a commit on friday, the next git commands are in a different project. Of course when I opened VS Code on saturday it opened into the last project, so the only thing I can imagine that the act of opening VS Code and then immediately switching to another project caused it to shit the bed.

Pepijn de Vos10:03:28

I'm 99% sure it happened after the last klayout command and before the next git command.

p-himik10:03:03

Thanks for the puzzle. :D

🙌 1
Pepijn de Vos11:03:01

whoa that is quite a bug...

Pepijn de Vos11:03:51

Quite funny that it seems to be the C++ plugin, but it created random files in the Cljs project rather than the C++ project I switched to.

thheller17:03:12

in case you are from russia or belarus it might also be https://twitter.com/bantg/status/1504213698658938881

thheller17:03:34

just read about this ... totally nuts

thheller17:03:01

but appears to be the other issues in case you other files are fine

Pepijn de Vos17:03:54

I should have a Dutch IP, but yea that's completely insane.

thheller17:03:58

guess I'll only run npm through docker or so in the future. can't trust this shit anymore.

p-himik17:03:14

Technically, you can't trust anything. Well, maybe only backups. No reason same thing couldn't happen with e.g. Maven. Quite easy to miss if you don't check transitive dependencies. Sure, people don't use ranges - but the potential to do harm is still there.

thheller18:03:11

yeah but this isn't the first time shit like this happened in npm

thheller18:03:19

never heard of it happening in maven

thheller18:03:44

especially what can't happen in maven is this stuff running on install

p-himik18:03:42

Ah, right, the install part is bonkers.

Pepijn de Vos18:03:14

A related problem is that npm is not immutable. So you can unpublish a package and break everyones dependencies.

p-himik18:03:55

That's why the lock files have integrity.

Ben14:03:43

I am trying to do (ns-map 'my.ns) from a cljs REPL (in lumo), but I get an error telling me that the ns-map var is undeclared. It works fine in the clj REPL. Is ns-map not available in ClojureScript?

p-himik14:03:57

That is correct.

pez15:03:25

I need a spread operator. 😃 I'm trying to make a library accept a log function and want to provide taoensso.timbre/log. But that is a macro. (fn [& msgs] (t/log msgs)) makes me log a list...

lilactown15:03:19

you could make another macro that takes a list and then spreads it out 😅

lilactown15:03:07

actually that won't work because then messages would need to be written literally

pez15:03:14

That's a pretty inconvenient API. 😃

lilactown15:03:27

yeah macros aren't very nice as the only public API

lilactown15:03:41

you could do something like

lilactown15:03:02

(doseq [msg msgs]
  (t/log msg))

pez15:03:10

That would give me one log row per message, right?

manutter5115:03:33

Could you do something like

`(fn [& msgs] (t/log ~@msgs)) 

pez15:03:15

That doesn't compile for reasons. I can do

(fn [& msgs] (t/debug `(~@msgs)))
But that just gives me the list 😃

manutter5116:03:21

Split the difference?

(fn [& msgs] `(t/log ~@msgs))

pez16:03:20

Then nothing happens. I'll see if I can figure out why...

craftybones15:03:36

Why not apply ?

craftybones15:03:47

Oh t/log is a macro

dnolen16:03:07

@pez just use the underlying function - a basic rule of macro writing is that it should be sugar - and that some explicit lib fn call will also suffice

pez16:03:46

This particular underlying function is a beast to use. Not a very friendly API for the users of my lib. 😃 https://github.com/ptaoussanis/timbre/blob/7bb3d648e1a49cf835233785fe2c07e43b2395da/src/taoensso/timbre.cljc#L526

pez16:03:07

I mean, my lib would just take a variadic function with the stuff to log, but for the lib users to provide it...

pez16:03:26

I guess the answer is that this is not possible to do in a convenient way when using timbre logging.

p-himik16:03:17

Sounds like it might warrant an issue for Timbre.

pez16:03:51

Thanks! I missed that one when scanning for related issues.

pez17:03:18

I submitted it as a question. Seems like a huge ask as a feature request. 😃 https://github.com/ptaoussanis/timbre/issues/350

👍 1
pez14:03:31

Seems like this should be possible if I almost do what @U050B88UR suggested and go one step down the abstraction layers. Peter T suggests using the log! macro. Though I haven't figured out just how yet. 😃

pez15:03:04

Turned out it wasn't really supported yet, even if that was the intention. Peter T is amazing. I've just tested version 5.2.0-SNAPSHOT and there I can wrap the log! macro like so:

(fn [& msgs] (t/log! :debug :p msgs))

🎉 1
1
chromalchemy17:03:45

I am trying to convert an ajax request to cljs. Here is the jquery version

$.ajax({
        type: 'GET',
        url: '',
        data: {
            _catalog: "getbitoutdoors1",
            _f: 3,
            _nrt: 1,
            _id: sku,
            _code: sku
        },
        async: true,
        crossDomain: true,
        success: function(data) {
            console.log(data);
            }
        },
        dataType: 'jsonp'
    });
here is my test version
(:require
    [lambdaisland.fetch :as fetch]
    [promesa.core :as p]
    [goog.object :as gobj]
    [cljs-bean.core :refer [bean ->clj ->js]])

(let [sku "test123product"
        fourp-inventory-api-url
        ""]
    (p/->
      (fetch/get fourp-inventory-api-url
        {:mode :no-cors
         :content-type "jsonp"
         :accept "jsonp"
         :query-params
           {:_catalog "getbitoutdoors1"
            :_f 3
            :_nrt 1
            :_id sku
            :_code sku}})
      js/console.log))
But I cant seem to get the data I can get from js side. As far as I can tell, response body is Null. Is using fetch the right approach? How can I return clojure data to inspect the result easier? (when I tried using js->clj or ->clj it still shows an object in the console (only full of meta atm).

p-himik17:03:52

You mean, there's nothing logged by js/console.log? Or is there :body nil?

chromalchemy17:03:45

but the response body is nested in the returned js object. Hard to see clearly what is being returned. Maybe I’m not doing the promise right?

chromalchemy17:03:37

Possibly a cors issue? This url is an external api. The working js ajax function is in some blessed theme code. I am trying to weave in some cljs, using shadow-cljs :target :npm-module and calling the cljs from js.

p-himik17:03:09

You're using all 3 of the libraries that I try my best to avoid at all costs. :D Can't really say whether it's your doing or their doing that something doesn't work. promesa is absolutely unnecessary when you don't do heavy promise work. And when you do such work, you might have better luck with core.async. lambdaisland.fetch is a thin wrapper about built-in js/fetch - I myself prefer regular and predictable interop over a library that not only might have potential bugs but also brings in a whole bunch of other dependencies, including a completely different promise library. cljs-bean is rarely needed given that interop just works. It's completely unneeded if you don't convert keywords to strings and back during interop. And it also has a bunch of peculiarities that you have to know.

p-himik17:03:59

> Possibly a cors issue? When anything strange is going on with your network requests, you should first check the JS console and the Network tab in your browser's DevTools. If there are errors - you will see them. If the response body is not what it's supposed to be - you will see it.

chromalchemy17:03:46

I realized I was running both versions on the same pageload. Turned the ajax one off. I can see from the network tab that the request is working, and the response data is there! But I’m not sure how to pull it out of all this.

p-himik17:03:24

The response is there. But the data doesn't seem to be - :body is set to an empty string. BTW you should definitely use https://github.com/binaryage/cljs-devtools

chromalchemy17:03:27

I can try simple js interop. I am not a strong js dev, so I was hoping for solid abstractions, but you know how that goes:unicorn_face:

p-himik17:03:17

You don't need to be a JS dev to use built-in JS API. MDN has great resources, and most of the things are very easy. And stuff that's not easy can't have a solid abstraction anyway.

oxalorg (Mitesh)17:03:14

Can you do something like this:

;; turn this
js/console.log

;; into this
(fn [resp]
  (js/console.log (clj->js resp)))

oxalorg (Mitesh)17:03:58

The body is probably null because it's not proper json?

chromalchemy17:03:49

jsonp ? I google this + cljs and couln’t find anything

chromalchemy17:03:05

just put [binaryage/devtools "1.0.5"] in shadow-cljs.edn :dependencies ?

p-himik17:03:36

The instruction is in the README. ;)

chromalchemy18:03:38

I think the formatter is working. Shadow-cljs adds it if it’s in deps.

👍 1
chromalchemy18:03:01

That simplified the console result But still empty string

chromalchemy18:03:17

I try to implement the simpler fn.

chromalchemy18:03:37

Should I be using something like cljs-http instead of fetch?

p-himik18:03:02

If you really want a wrapper, you can use anything you want. lambdaisland.fetch should be fine as well - assuming you know its API and how to use it. But same thing applies to any other library or built-in thing, including cljs-http or js/fetch.

p-himik18:03:49

When I'm doing requests myself, I just use js/fetch. When I'm doing requests via re-frame, I'm transitively using cljs-http just because the :http-xhrio effect uses it.

chromalchemy18:03:42

What is your fetch method to encode query params?

chromalchemy18:03:03

I still cant get the value out of there :thinking_face: Gotta stop for now. When I have more time I will try to implement a query param encoder. Thank you for the help though!

👍 1
chromalchemy18:03:06

The data is in the reponse in the network tab.

([{"test123product":["test123product,12455,0","test123product-BL,Test Product - Do not remove Color = Blue,20","test123product-GR,Test Product - Do not remove Color = Green,0","test123product-RE,Test Product - Do not remove Color = Red,0","test123product-ST,Test Product - Do not remove Color = Stock 0,0","testnewsku,Test Product - Do not remove Color = Unavilable,0"],"total":20}])  
Hopefully I can access it easily when I learn better interop.

p-himik18:03:16

Also, the data that you're sending is strange. It looks like a JSON array but wrapped in parentheses for some reason. Doubt any of the decoders knows how to deal with that - maybe that's where the problem lies, like Mitesh mentioned above.

chromalchemy18:03:29

That is the data that is being fetched. Maybe it’s jsonp?

chromalchemy18:03:06

what is you opinon on the js-interop lib? Same as cljs-bean?

p-himik18:03:35

> That is the data that is being fetched. I understand that. But why is it being served that way? Is there a content-type header that specifies what type it's supposed to be? > what is you opinon on the js-interop lib? In the age of externs inference and when we have goog.object and built-in interop, such libraries are completely unneeded.

chromalchemy19:03:09

content type: text/html ? This app we are requesting from (we don’t control) is definitely random and shoddy.

oxalorg (Mitesh)19:03:10

> Maybe it’s jsonp? jsonP usually has a callback which is provided -or- a default callback returned. This just looks like malformed JSON, check the server why it's adding those extra round parens.

oxalorg (Mitesh)19:03:46

^or check if you can provide it a callback param like ?callback=myJsonPCallbackFunc

chromalchemy19:03:24

I am only on client side. Ok I’ll try that.

oxalorg (Mitesh)19:03:00

Also can you change

:content-type "jsonp"
:accept "jsonp"
to just "json"

chromalchemy19:03:00

I havent implemented a bespoke fetch fn yet with the query params. But if I can just get the string I can parse that.

chromalchemy19:03:43

I tried that. Same result.

oxalorg (Mitesh)19:03:01

> But if I can just get the string I can parse that. If you want this try to remove the :content-type options from fetch. If a content-type is added, we try to parse using that

chromalchemy19:03:03

Feel free to hit it yourself if you want, It’s an open api.

oxalorg (Mitesh)19:03:06

otherwise we return the body as is

oxalorg (Mitesh)19:03:21

Sure give me a sec Ill try it out 🙂

p-himik19:03:49

It just ignores the accept header.

chromalchemy19:03:51

I tried omitting the content-type too, no change.

p-himik19:03:29

Whatever that API is, it's not that great. Given how it has added (), I would make sure to either find a better API or to at least find proper documentation on this one. Who knows what else they might've invented.

chromalchemy19:03:42

They are a “Total Mess”!!! I probably should have set up a proxy server to route around them long ago. But for now it’s the only live inventory data I have.

chromalchemy19:03:45

btw the front end for this inventory/shipping product looks like it was frozen in web 1.0!

p-himik19:03:35

Then you'll have to read the body as a string, chop off the starting ( and the ending ) and parse the rest with js/JSON.parse.

p-himik19:03:11

And hope for the best.

chromalchemy19:03:14

Any pointers how to read body? I can’t find that string in my response data.

p-himik19:03:12

That is normal because it's served as HTML.

p-himik19:03:50

> Any pointers how to read body? I can’t find that string in my response data. Start with plain fetch in the JS console, learn how to read the body there, then use interop to write the same thing in CLJS and process the body in CLJS.

p-himik19:03:35

And also, there's definitely CORS at play - I couldn't use fetch within the browser from a different domain.

oxalorg (Mitesh)19:03:43

@U09D96P9B The problem is that the above API doesn't return proper CORS headers.

oxalorg (Mitesh)19:03:16

When you use :mode :no-cors it only supresses the exception, client js still can't access the api response

oxalorg (Mitesh)19:03:02

There is no way around this except for setting up a proxy serevr

p-himik19:03:48

Right. If you have a backend, make that request on the backend instead. If you don't have a backend, there are CORS-"fixing" thirdparty proxy servers out there, easy to find.

chromalchemy19:03:24

I guess the jquery ajax theme code is dealing with the cors better somehow. Same codebase. When I run it in the console I definitely see cors errors.

chromalchemy19:03:50

So even if my devtools network response view shows the data from the request, my code might still not be able to get it (because of cors issues)? I guess that make sense from a security standpoint…

chromalchemy19:03:13

Maybe that is what jsonp does, get’s around the CORS issues?

p-himik19:03:24

In the jQuery request above, what is the value of sku?

p-himik19:03:01

Also, is that jQuery code running within the browser or on Node?

chromalchemy19:03:30

test123product
Browser

chromalchemy19:03:07

for reference: cljs-http has some accomodation of jsonp https://github.com/r0man/cljs-http#jsonp

chromalchemy19:03:07

> Requesting a file from another domain can cause problems, due to cross-domain policy. > Requesting an external script from another domain does not have this problem. > JSONP uses this advantage, and request files using the script tag instead of the XMLHttpRequest object. https://www.w3schools.com/js/js_json_jsonp.asp#:~:text=JSONP%20stands%20for%20JSON%20with,instead%20of%20the%20XMLHttpRequest%20object.

chromalchemy19:03:09

Looks like someone had to use jquery itself from cljs to do something like this. https://gist.github.com/mjg123/1098417

p-himik19:03:02

I'm rather confused and very intrigued because I don't understand how jQuery manages to work around this.

p-himik19:03:35

LOL, yeah, you're right - jQuery just adds a <script> tag and removes it right after the response is received. That's why () are not a problem.

p-himik20:03:30

> JSONP is vulnerable to the data source replacing the innocuous function call with malicious code, which is why it has been superseded by https://en.wikipedia.org/wiki/Cross-origin_resource_sharing (available since 2009https://en.wikipedia.org/wiki/JSONP#cite_note-caniuse-cors-3) in modern applications. That's some ancient API you're using. Or it was written by ancient people. :) Given that quoted statement, I wouldn't be that eager to trust it. I'd probably try to use a proxy and regular JSON.parse instead.

chromalchemy20:03:33

I tried this, but gettings errors

(let [inventory-api-url
      ""
      jsonp (goog.net.Jsonp. (Uri. inventory-api-url) "jsoncallback")]
  (.send jsonp nil success-handler error-handler))
via https://stackoverflow.com/questions/31349911/how-to-implement-a-jsonp-call

chromalchemy20:03:20

Thanks for the feedback. I’ll probably just use the jquery to feed the data to my cljs for now. And look for alternatives like you mention.

p-himik20:03:28

It seems that GCC now requires you to use goog.html.TrustedResourceUrl instead of goog.Uri when it comes to JSONP. Also note that you don't need to use goog.net.Jsonp when you use the import from the SO post - you can just use Jsonp.

p-himik20:03:27

Trouble with all of that, as that quoted statement says, is that if 4plx sends you some malicious code instead of the data that you expect, that code will be executed on your very web page. It can do anything.

chromalchemy20:03:30

> That’s some ancient API you’re using. Or it was written by ancient people. :) I love these quotes. I can use them to share with my boss why I’m not off the deep end when I’m burning lots of time figuring out the inane behaviors of this product for potential integrations.

p-himik20:03:53

:D Happy to help Hmm, the TrustedResourceUrl approach still doesn't work "because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled." jQuery does more "magic" than I realized.

p-himik20:03:35

Oh wow, OK. jQuery listens for the load error event and treats the error as a success. This whole approach is what people call jugaad.

chromalchemy20:03:22

> treats the error as a success These inconsistencies confirm my aversion to js. But i will take your advice to heart and use the pure stuff more directly.

chromalchemy20:03:58

If I REALLY needed to write this in cljs. Could I do the jquery magic myself?

p-himik20:03:30

Certainly - it's just JS code. You can extract the relevant parts and load them from a JS file or rewrite them in CLJS.

chromalchemy20:03:21

I was forged in IE6 days (more like 10 years), so I’ve been very jaded. Which is why i found Clojure! :smiling_face_with_3_hearts:

p-himik20:03:07

Yeah, same, although I was fortunate enough to mostly deal with backend and desktop programming in that era. Fortunately, modern JS is much nicer. But not without its issues, of course.

p-himik20:03:51

And to be fair, this whole issue is orthogonal to the language - it's just an artifact of the history of web browsers' security.

chromalchemy20:03:03

Fair enough. Thanks again for all the insights and helping test this!

👍 1
popeye18:03:48

Is this correct way to append color? [:div.label-message {:color "#F4847CD"} "POPUP"}]

p-himik18:03:57

What do you mean by "append"? With that hiccup, you're specifying a particular text color on the element (well, not only text, but mainly text).

p-himik18:03:36

Also, your :color seems to have one extra character.

popeye18:03:18

how it should be then ?

popeye18:03:34

i meant by default it will be in black! how to make it in red /

p-himik18:03:26

How should I know - it's your choice of color, not mine. :) The # color specification AFAIK respects only the first 6 characters - i.e. 24 bits. If you want to make your text red, just write "red" or :red there.

popeye18:03:09

I got that! :div.label-message {:style {:color "red"}}

popeye18:03:15

adding a style key

p-himik18:03:25

Oh, dang, sorry - completely missed that somehow.