Latest version now handles mentions and hashtags (LIMITATION if you use one - then you need to use both)
Note I used Blockly as my function node but it wouldn't upload to the forum as it exceed 32000 char limit so I've copied the JS it generates into a function node for here
[{"id":"ba432f16a297f974","type":"inject","z":"dd99f8450c6d098a","name":"green","props":[{"p":"text","v":"@cheerlights.bsky.social #cheerlights This is test post using NodeRED - green grass","vt":"str"},{"p":"name","v":"xxxx.bsky.social","vt":"str"},{"p":"appPassword","v":"xxxxxxx","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":140,"y":600,"wires":[["8b34ec1fff3ecef6"]]},{"id":"931227442ccb14dd","type":"debug","z":"dd99f8450c6d098a","name":"debug 464","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":720,"wires":[]},{"id":"1467e34f3a46fe31","type":"http request","z":"dd99f8450c6d098a","name":"","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://bsky.social/xrpc/com.atproto.server.createSession","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":710,"y":670,"wires":[["3c32c66dcd937c19"]]},{"id":"f0ea247730c98478","type":"json","z":"dd99f8450c6d098a","name":"","property":"payload","action":"","pretty":false,"x":570,"y":630,"wires":[["1467e34f3a46fe31","c2cb04d260412407"]]},{"id":"6143d043c66e6d8c","type":"debug","z":"dd99f8450c6d098a","name":"debug 465","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"statusCode","statusType":"msg","x":1180,"y":810,"wires":[]},{"id":"bb3f01506e35f79e","type":"http request","z":"dd99f8450c6d098a","name":"","method":"POST","ret":"obj","paytoqs":"ignore","url":"https://bsky.social/xrpc/com.atproto.repo.createRecord","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[{"keyType":"Content-Type","keyValue":"","valueType":"application/json","valueValue":""}],"x":790,"y":810,"wires":[["6143d043c66e6d8c"]]},{"id":"e53f5f7745109a5a","type":"json","z":"dd99f8450c6d098a","name":"","property":"payload","action":"obj","pretty":false,"x":320,"y":770,"wires":[["3ebcd3d1c1454446"]]},{"id":"62a77df00a14da2a","type":"debug","z":"dd99f8450c6d098a","name":"debug 466","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":770,"wires":[]},{"id":"9d0922b21146d9e5","type":"template","z":"dd99f8450c6d098a","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{ \"repo\": \"{{flow.did}}\",\"collection\": \"app.bsky.feed.post\", \"record\": { \"$type\": \"app.bsky.feed.post\",\"text\": \"{{text}}\",\"createdAt\": \"{{myymd}}T{{mytimes}}.{{mymillis}}Z\"\n\n{{{facets}}}\n\n } }","output":"str","x":850,"y":720,"wires":[["931227442ccb14dd","e53f5f7745109a5a"]]},{"id":"027f19aca8f3549f","type":"simpletime","z":"dd99f8450c6d098a","name":"","mydate":false,"myymd":true,"myyear":false,"mymonth":false,"mymonthn":false,"mydom":false,"mydoy":false,"myday":false,"myhourpm":false,"myhour":false,"mytime":false,"mytimes":true,"myminute":false,"myminutes":false,"mysecond":false,"mymillis":true,"myepoch":false,"myrawdate":false,"mypm":false,"x":680,"y":720,"wires":[["9d0922b21146d9e5"]]},{"id":"3c32c66dcd937c19","type":"change","z":"dd99f8450c6d098a","name":"","rules":[{"t":"set","p":"did","pt":"flow","to":"payload.did","tot":"msg","dc":true},{"t":"set","p":"accessJwt","pt":"flow","to":"payload.accessJwt","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":890,"y":670,"wires":[["9d215bf0bde7d990","70f22979df50dff3"]]},{"id":"70f22979df50dff3","type":"change","z":"dd99f8450c6d098a","name":"","rules":[{"t":"delete","p":"headers","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":720,"wires":[["027f19aca8f3549f"]]},{"id":"3ebcd3d1c1454446","type":"template","z":"dd99f8450c6d098a","name":"","field":"headers","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{ \"Authorization\":\"Bearer {{flow.accessJwt}}\" }","output":"str","x":470,"y":770,"wires":[["e3543264d4471753"]]},{"id":"e3543264d4471753","type":"json","z":"dd99f8450c6d098a","name":"","property":"headers","action":"obj","pretty":false,"x":620,"y":770,"wires":[["62a77df00a14da2a","bb3f01506e35f79e"]]},{"id":"1a9817da605c639e","type":"template","z":"dd99f8450c6d098a","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"{\"identifier\":\"{{name}}\",\"password\":\"{{appPassword}}\"}","output":"str","x":440,"y":630,"wires":[["f0ea247730c98478"]]},{"id":"c2cb04d260412407","type":"debug","z":"dd99f8450c6d098a","name":"debug 467","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":630,"wires":[]},{"id":"9d215bf0bde7d990","type":"debug","z":"dd99f8450c6d098a","name":"debug 468","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":670,"wires":[]},{"id":"22f90199bd33d7ad","type":"debug","z":"dd99f8450c6d098a","name":"debug 469","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":580,"wires":[]},{"id":"8c3aec09fc23ed15","type":"switch","z":"dd99f8450c6d098a","name":"","property":"url","propertyType":"msg","rules":[{"t":"nempty"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":490,"y":550,"wires":[["8e0c6d1e7836e79a"],["45929b74029dac0a"]]},{"id":"8e0c6d1e7836e79a","type":"http request","z":"dd99f8450c6d098a","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":630,"y":500,"wires":[["340d28fba5b3725a","be81b2a0b4047cd1"]]},{"id":"340d28fba5b3725a","type":"change","z":"dd99f8450c6d098a","name":"","rules":[{"t":"set","p":"mentionDid","pt":"flow","to":"payload.did","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":830,"y":540,"wires":[["56b8cfc4cfcdeb84","66d96ecb386154c2"]]},{"id":"56b8cfc4cfcdeb84","type":"template","z":"dd99f8450c6d098a","name":"","field":"facets","fieldType":"msg","format":"handlebars","syntax":"mustache","template":",\n\"facets\": [\n{\n \"index\": {\n \"byteStart\": {{mentionStart}},\n \"byteEnd\": {{mentionEnd}}\n },\n \"features\": [\n {\n \"$type\": \"app.bsky.richtext.facet#mention\",\n \"did\": \"{{flow.mentionDid}}\"\n }\n ]\n},\n {\n \"index\": {\n \"byteStart\": {{hashtagStart}},\n \"byteEnd\": {{hashtagEnd}}\n },\n \"features\": [\n {\n \"$type\": \"app.bsky.richtext.facet#tag\",\n \"tag\": \"{{hashtag}}\"\n }\n ]\n }\n ]","output":"str","x":660,"y":580,"wires":[["b2bd616a8f37767c"]]},{"id":"b2bd616a8f37767c","type":"change","z":"dd99f8450c6d098a","name":"","rules":[{"t":"delete","p":"url","pt":"msg"},{"t":"delete","p":"headers","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":820,"y":580,"wires":[["22f90199bd33d7ad","1a9817da605c639e"]]},{"id":"5dcdb13abc220f42","type":"inject","z":"dd99f8450c6d098a","name":"plain","props":[{"p":"text","v":"This is test post using NodeRED","vt":"str"},{"p":"name","v":"xxxxx.bsky.social","vt":"str"},{"p":"appPassword","v":"xxxxxx","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":140,"y":560,"wires":[["8b34ec1fff3ecef6"]]},{"id":"66d96ecb386154c2","type":"debug","z":"dd99f8450c6d098a","name":"debug 470","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1180,"y":540,"wires":[]},{"id":"be81b2a0b4047cd1","type":"debug","z":"dd99f8450c6d098a","name":"debug 471","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":1180,"y":500,"wires":[]},{"id":"2c73ebab576739d5","type":"comment","z":"dd99f8450c6d098a","name":"Requires simpletime node","info":"","x":570,"y":460,"wires":[]},{"id":"a017dc0cd32db1dd","type":"function","z":"dd99f8450c6d098a","name":"Blocky generated JS","func":"var msgText, mentionStart, hashtagStart, mentionEnd, hashtagEnd, hashtag, facets;\n\n\nmsgText = String(msg['text']) + ' ';\nmentionStart = msgText.indexOf('@') + 1;\nhashtagStart = msgText.indexOf('#') + 1;\nif (mentionStart > 0) {\n mentionEnd = msgText.slice((mentionStart - 1), msgText.length).indexOf(' ') + 1;\n msg['url'] = ('https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=' + String(msgText.slice(((mentionStart + 1) - 1), mentionEnd - 1)));\n}\nif (hashtagStart > 0) {\n hashtagEnd = msgText.slice((hashtagStart - 1), msgText.length).indexOf(' ') + 1;\n hashtagEnd = hashtagStart + (hashtagEnd - 1);\n hashtag = msgText.slice(((hashtagStart + 1) - 1), hashtagEnd - 1);\n msg['hashtag'] = hashtag;\n node.status({fill:\"blue\", shape:\"ring\", text:hashtag});\n}\nmsg['mentionStart'] = (mentionStart - 1);\nmsg['mentionEnd'] = (mentionStart + (mentionEnd - 2));\nmsg['hashtagStart'] = (hashtagStart - 1);\nmsg['hashtagEnd'] = (hashtagEnd - 1);\nfacets = '';\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":500,"wires":[["8c3aec09fc23ed15"]]},{"id":"8b34ec1fff3ecef6","type":"junction","z":"dd99f8450c6d098a","x":250,"y":540,"wires":[["a017dc0cd32db1dd"]]},{"id":"45929b74029dac0a","type":"junction","z":"dd99f8450c6d098a","x":310,"y":590,"wires":[["1a9817da605c639e"]]}]
Note: the position of mentions and hashtags within a skeet have to be added on to the posted message as something called facets otherwise they just end up as plain text.
Further more, you have to look up something called the did which is BlueSky's internal id of a handle but at least that is easy to do
e.g simple get request that doesn't need authorisation
https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=cymplecy.bsky.social