I have moved my blog to Hugo, and now I’m hosting it on arashTaher.com
Content Scripts Not Loading for JSON Pages in Firefox
Ran into a weird issue where my content script wasn’t loading for a page in Firefox (Manifest V2). Worked fine in Chrome (Manifest V3). Turns out, Firefox only injects content scripts into HTML pages, not JSON responses (Content-Type: application/json). Makes sense—content scripts need a DOM, and JSON doesn’t have one.
I didn’t find this problem to be mentioned anywhere else, so here’s a quick blog post to explain it.
I was trying to grab a JSON token from http://localhost:8000/extension/auth and send it back to my extension. Chrome handled it, but Firefox just wouldn’t run the script.
Fix: Swap JSON for HTML
Instead of a raw JSON response, I made the server return an HTML page with the response now in a hidden form field.
Here’s the initial version of the content.js file:
const response = document.body.textContent;
try {
const data = JSON.parse(response);
if (data.token) {
// Send the token back to the options page
chrome.runtime.sendMessage({
type: "TOKEN",
token: data.token,
});
} else if (data.errorCode) {
console.error("Error from auth response:", data);
}
} catch (e) {
console.error("Failed to parse response:", e);
}
And now, instead I server HTML and get the token from the hidden field in form:
(function() {
// Try to find the token immediately
let tokenField = document.getElementById('token');
// If not found, set up a small delay to try again
// (in case our script runs before the element is available)
if (!tokenField) {
setTimeout(function() {
tokenField = document.getElementById('token');
if (tokenField && tokenField.value) {
chrome.runtime.sendMessage({
type: "TOKEN",
token: tokenField.value,
});
console.log("Token found and sent (delayed)");
}
}, 500);
} else if (tokenField && tokenField.value) {
chrome.runtime.sendMessage({
type: "TOKEN",
token: tokenField.value,
});
console.log("Token found and sent (immediate)");
}
})();
Why It Works
The HTML response lets Firefox run the content script, and the hidden field holds the JSON. Works in Chrome too. If you can’t change the server, you could use webRequest in the background script, but this felt cleaner.
Takeaway
Firefox won’t run content scripts on JSON pages. Serve HTML instead. It’s a better solution anyway. It’s strange to serve JSON to the user!
Summary of OAuth 2.0 and Bearer Token Usage
Here’s a summary of my notes regarding OAuth 2.0, access and bearer token, and their usages.
Links and references at the end.
HTTP authentication header: Authorization: <type> <credentials>
Authentication schemes:
- Basic: base64-encoded credentials
- Bearer: bearer tokens to access OAuth 2.0-protected resources (Give the bearer of this token access)
The bearer token is a type of access token, which does NOT require PoP (proof-of-possession) mechanism.
RFC 6750 describes how to make protected resource requests when the OAuth access token is a bearer token.
RFC 6749 covers main auth flows, called grants.
An OAuth grant is a specific flow that results in an access token.
Access token (most of time Bearer) is the end product of a grant auth flow in OAuth.
RFC 7519: JWT
Access token is like a currency note e.g 100$ bill . One can use the currency note without being asked any/many questions:
- Access token = payment methods
- Bearer token = cash
In OAuth 2, when user requests to the server for a token sending user and password through SSL, the server returns two things: an Access token and a Refresh token:
{
"access_token": "AYjcyMzY3ZDhiNmJkNTY",
"refresh_token": "RjY2NjM5NzA2OWJjuE7c",
"token_type": "bearer",
"expires": 3600
}
Presence of refresh token mean the access token will expire.
This access token, is of type bearer and can be JWT token, because the server can make decisions based on whats inside the token
Tokens vs. API keys
User-specific authentication is a hallmark of bearer token usage
API keys are used for identifying and authenticating the application or client rather than an individual user. It’s static and the scope of a set of APIs.
With API kets expiration happens manually.
API keys define the source of the requesting entity, whereas API tokens identify the user and their rights.
Implementing Bearer Tokens
Example: Generating a JWT bearer token:
// Generate and issue a bearer token
function issueToken(userId) {
const token = jwt.sign({ userId }, 'your-secret-key', { expiresIn: '1h' });
return token;
}
Middleware to use the token:
// Middleware for bearer token authentication
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.sendStatus(401);
}
jwt.verify(token, 'your-secret-key', (err, decoded) => {
if (err) {
return res.sendStatus(403);
}
// Add the decoded information to the request object
req.user = decoded;
next();
});
}
// Protected route
app.get('/api/protected-resource', authenticateToken, (req, res) => {
// Access the user information from req.user
const userId = req.user.userId;
// Fetch the protected resource and send the response
res.json({ message: `Protected resource accessed by user ${userId}` });
});
Links and refernces
https://stackoverflow.blog/2022/12/22/the-complete-guide-to-protecting-your-apis-with-oauth2/
https://datatracker.ietf.org/doc/html/rfc6749
https://www.oauth.com/oauth2-servers/making-authenticated-requests/
https://stackoverflow.com/questions/25838183/what-is-the-oauth-2-0-bearer-token-exactly
https://medium.com/@arunchaitanya/wtf-is-bearer-token-an-in-depth-explanation-60695b581928
Build Tailwind v4 locally with Docker
I had some issues setting up Tailwind v4 build locally with Docker.
Key Changes from Tailwind v3
First, it was all the changes from version 3:
- No more
initstep: Running theinitcommand will get you an error - No need for
tailwind.config.jsfile
Source Path Issue
Main changes from earlier version are covered in this discussion on Tailwind’s GitHub page: “Beginner tutorial for setting up tailwind v4 using the standalone CLI“
Recommended is to add source("../") to the import, so Tailwind know where to find the files.
Root Directory Bug
But even doing that, I had issues building the CSS file.
As it turned out, there was a bug in Tailwind which was causing the issue and was addressed here: Fix resolve_globs crash when at root directory
Basically, the build process was crashing when the build took place in root.
Changing Working Directory
By checking the tailwind CLI options, I found out about the cwd option. It lets you change the working directory where the command looks for files.
By adding that, I remove the source from the CSS file.
Working Solution
Putting it all together, here’s my style.css and Dockerfile for building Tailwind locally:
/* style.css */
@import "tailwindcss";
# Dockerfile
FROM node:alpine
WORKDIR /tailwind
RUN npm init -y && npm install tailwindcss @tailwindcss/cli
CMD npx @tailwindcss/cli --cwd /templates -i /src/style.css -o /dst/style.css --watch
Go Error Handling Techniques: Exploring Sentinel Errors, Custom Types, and Client-Facing Errors
In this blog post, I share my experiments with error handling in Go. I’m new to Go, and there’s a lot to learn, but one important aspect is proper error handling: I wanted to know how to keep track of the error cause, how to enrich its context, and finally how to present it to the clients.
This is just me documenting the things I’ve read and tried so far. Let me know what you think. I’m here to learn and improve.
Defining Errors in Go
An error in Go is an interface that implements the Error() string method. You can create an error using the errors.New function, which “creates errors whose only content is a text message”:
err := errors.New("This is an error")
Now, let’s create a sentinel error:
import "errors"
var errDbConnection = errors.New("db connection")
These exported error variables are called sentinel errors. They represent specific failure conditions in a program, such as io.EOF, sql.ErrNoRows, and various errors in the fs package.
Since there’s only one global definition of a sentinel error, you can check for it using a simple equality operator:
err := db.QueryRow("SELECT items LIMIT 1").Scan()
if err != nil && err != sql.ErrNoRows {
log.Fatal(err)
}
Issues with Sentinel Errors
Sentinel errors have two primary issues:
- They are not descriptive enough: Sentinel errors often do not carry additional context about the failure.
- They can become part of your public API: Since sentinel errors are typically global, they can unintentionally become part of a program’s public API.
For a deeper dive, check out Don’t just check errors, handle them gracefully. (Note that this article is a bit outdated, especially since Go 1.13 deprecates github.com/pkg/errors.)
Enriching Error Messages with Context
To address the lack of descriptiveness in sentinel errors, we can add more data to our errors. Here’s an example where we add context to a query execution error:
func NewQueryExecutionError(query string, err error) error {
return errors.New(fmt.Sprintf("query execution failed for %v: %v", query, err))
}
This provides more context around the error, but how do we later check the underlying error?
If you create errors by appending strings like the example above, you’ll have to search for substrings in the error message:
err := NewQueryExecutionError("foo", someError)
if strings.Contains(err.Error(), "foo") {
log.Fatal(err)
}
The issue here is that changing the error message will break this check.
A Better Way: Custom Error Types
To overcome this, let’s move to a more structured error-handling approach by creating custom error types.
In the following example, we have a Record type, and we’ll handle reading a file, parsing its contents, and returning a record.
First, define a dummy Record type:
type Record struct {
num int
str string
}
Next, create a sentinel error and a readFile function to simulate reading a file:
var errFileRead = errors.New("reading file failed")
func readFile(fileName string) (string, error) {
data, err := os.ReadFile(fileName)
if err != nil {
fmt.Printf("[readFile] function: %v\n", err)
return "", errFileRead
}
return string(data), nil
}
As you can see, after logging the error returned by ReadFile, we return our own custom errFileRead error.
We then parse the file content in the readInput function, which returns a more descriptive error by calling NewRecordParseError:
func readInput(fileName string) (int, string, error) {
data, err := readFile(fileName)
if err != nil {
return 0, "", NewRecordParseError("cannot open the file", fileName, err)
}
var num int
var str string
_, err = fmt.Sscanln(data, &num, &str)
if err != nil {
return 0, "", NewRecordParseError("parsing file", fileName, err)
}
return num, str, nil
}
The custom error type RecordParseError holds additional context about the error:
type RecordParseError struct {
fileName string
innerError error
}
func (p *RecordParseError) Error() string {
return fmt.Sprintf("parsing %q: %v", p.fileName, p.innerError)
}
func (p *RecordParseError) Unwrap() error {
return p.innerError
}
The Unwrap method allows us to use Go’s errors.Is and errors.As for unwrapping nested errors.
These are critical concepts that you can read more about the in this blog post on Go website.
It’s better to check them out before moving on with the post.
Propagating and Wrapping Errors
In the fetchData function, we propagate the error and wrap it with more context using fmt.Errorf:
func fetchData(fileName string) (*Record, error) {
num, str, err := readInput(fileName)
if err != nil {
return nil, fmt.Errorf("reading record: %w", err)
}
return &Record{num, str}, nil
}
Structuring Errors for Clients
Up to this point, the errors are intended for internal usage, and it’s not something that we want to send to the clients that have called this function.
When exposing errors to external clients, you often want structured error responses. To handle this, I created an AppError type that includes an error code and message:
type AppError struct {
ErrorCode string
ErrorMessage string
innerError error
}
func (e *AppError) Error() string {
return e.innerError.Error()
}
You can then create specific application errors, like so:
var FetchDataAppErrorCode = "FETCH_DATA_ERROR"
func NewFetchDataAppError(err error) error {
return &AppError{
ErrorMessage: fmt.Sprintf("fetching data: %v", err),
ErrorCode: FetchDataAppErrorCode,
innerError: err,
}
}
Wrapping Up the Application
Here’s how we tie everything together in the runApp function:
func runApp() (*Record, error) {
res, err := fetchData("input.txt")
if err == nil {
return res, nil
}
return nil, NewFetchDataAppError(err)
}
The main function then shows how we can use errors.Is and errors.As to unwrap and check error types:
func main() {
res, err := runApp()
if err == nil {
fmt.Println("Program succeeded: ", res)
return
}
if err == errFileRead {
// False: This will not work, since we're checking with the error instance
fmt.Printf("1. reading file: %v\n", err)
}
if errors.Is(err, errFileRead) {
// True: Unwrapped error is errDbConnection
fmt.Printf("2. reading file: %v\n", err)
}
if errors.Is(err, &RecordParseError{}) {
// False: &RecordParseError{} is not the same as err
fmt.Printf("3. parsing input: %v\n", err)
}
var parsingError *RecordParseError
if errors.As(err, &parsingError) {
// True: err is of the RecordParseError type
fmt.Printf("4. parsing input: %v\n", err)
}
if strings.Contains(err.Error(), "reading record") {
// True: We can check the exact error message
fmt.Printf("5. app: %v\n", err)
}
var appErr *AppError
if errors.As(err, &appErr) {
// There's only one error of AppError type
if appErr.ErrorCode == FetchDataAppErrorCode {
fmt.Printf("6. App failed: %v\n", appErr)
}
fmt.Printf(`7. HTTP 400 Response: {"error_code": "%s", error_message: "%s" }`, appErr.ErrorCode, appErr.ErrorMessage)
fmt.Println()
} else {
fmt.Println("8. HTTP 500", err)
return
}
}
And by passing a file name that does not exist, I get this output:
> go run main.go
[readFile] function: open input.txt: no such file or directory
2. reading file: reading record: parsing "input.txt": can not open the file reading file
4. parsing input: reading record: parsing "input.txt": can not open the file reading file
5. app: reading record: parsing "input.txt": can not open the file reading file
6. App failed: reading record: parsing "input.txt": can not open the file reading file
7. HTTP 400 Response: {"error_code": "FETCH_DATA_ERROR", error_message: "fetching data: reading record: parsing "input.txt": can not open the file reading file" }
Here you can find the code for the application in Go Playground.
In this post, I explored different techniques for error handling in Go. I started with basic sentinel errors and gradually moved towards custom error types that add more context. I also demonstrated how to structure errors for client-facing applications using AppError. While these techniques cover various aspects of Go error handling, I’m eager to hear your thoughts and suggestions for improvement.
Edits:
8 Sep: Updated the error messages after this comment on Reddit to remove all the “failure” repetitions
NeoVim as IDE for TypeScript
NeoVim as IDE for Typescript
Here’s the list of some plugins you can use in NeoVim to make it a full-fledge IDE for developing Typescript projects:

wbthomason/packer.nvim
First and foremost, you need to have a proper package manager for NeoVim, so you can easily add, remove and update the plugins. The recommended plugin manager as of now for NeoVim is Packer.
junegunn/fzf junegunn/fzf.vim
FZF helps you to easily navigate between files and find them with fuzzy search.
neovim/nvim-lspconfig
It’s a “collection of configurations for the built-in LSP client”. LSP enables features like auto-complete, go to definition and many more.
airblade/vim-gitgutter
For better integration between the editor environment and Git, I use two plugins. First one is GitGutter. This plugin “shows git diff markers in the sign column and stages/previews/undoes hunks and partial hunks”. If you learn the short keys, you can easily and quickly move between changes and undo or stage each hunk.
tpope/vim-fugitive
The second plugin that I use for Git, is Vim Fugitive. It’s a wrapper for Git commands and provides nice integration between Git and the editor. With this plugin installed, you have access to Git commands inside the editor. I usually use this for the diffs, staging files and committing the changes.
tpope/vim-commentary
Comments stuff out without much of a hassle. All you need to learn is `gc` and `gcc`
preservim/nerdtree
This is a must-have plugin for me. During the development, I like to have an overview of the files and quick visual access to where this file that I’m editing resides and what other files are in the same directory.
One of the very few mappings that I have added to my configurations are for NERDTree to find and show me the current file in the sidebar:
map <Leader>e :NERDTreeFind<CR>
In case you’re interested to try these settings, go to my dotfiles repository on GitHub.
Generate randoms, more than numbers
- In the landing page of your website, you want to have the picture of your customers right by their testimonial
- You are looking for a cover to use on a piece of music
- A random picture to use for an Instagram post
- For your profile picture, you would like to use a random anime character
- For your new project, you’re looking for a cool new name
All these questions can be answered using “generative adversarial network” (GAN) which is used to create fake versions of almost anything.
Visit This X Does Not Exist for collection of these websites.

Recursive asynchronous function call
One of the well-known Redis clients for NodeJS is ioredis. When I was trying to work with Redis streams using this library, I used the example they provide in their GitHub page. When I read the code, I noticed in order to constantly listen for new messages, they have used a recursive call to an asynchronous function:
async function listenForMessage(lastId = "$") {
const results = await redis.xread("block", 0, "STREAMS", "mystream", lastId);
const [key, messages] = results[0]; // `key` equals to "mystream"
messages.forEach(processMessage);
// Pass the last id of the results to the next round.
await listenForMessage(messages[messages.length - 1][0]);
}
listenForMessage();
The XREAD function blocks the execution, until we receive another message in the stream; Then it recalls itself to get another message on the stream.
My question was if this is a safe approach to iterate over the message we receive; Specifically, I was interested to know whether we’ll have stack overflow over time, or some mechanism like tail call optimization will take care of the growing stack.
To check this, I simply logged the stack after each call: console.trace()
And then I ran the code and started adding items to the Redis stream in one second intervals:redis-cli -r -1 -i 0.2 xadd mystream '*' item 1
In this way you can see the stack trace, and it becomes obvious that function calls pile up; Every function call will wait for the return value of the previous one, and it will lead to memory leak.
By the way, don’t forget to set stack trace limit when running the program, otherwise you’ll see only 10 frames: --stack_trace_limit=200
How to solve it?
Just don’t await on the function call! You don’t need the result and by letting the current execution to be finished, the stack frame can be released.
SQL and Asking Questions
What’s the difference between relational and NoSQL databases and when do you choose one over the other?
Strangely, not many developers can give you some comprehensive and tangible answer for this question. I’m not going to delve into the details, because there’s already so many places that explain the differences (mainly data model, data structure, scaling and development model).
I just decided to write this post because right now I found another very compelling reason for using relational database over document based databases when I was listening to “The Change log” podcast, episode “What’s so exciting about Postgres?“

Analytics! Or more simply, asking questions. Imagine you’ve got tons of data and now you want to find out about “How many users signed up during the last week?” If you’re using a document db, now you’ve got to go and traverse through those documents three layers deep, something that might not be very much easy.
On the other hand, this is just so darn easy in relational databases, it’s actually what SQL was designed to do. This might not be something you need right when you start your project, but as it gets bigger, you definitely want to ask more and more these sorts of questions.
It’s not that you can’t do these in NoSQL, but both the ease and also the efficiency makes relational databases the clear winner when it comes to analytics.
How to write your first Firefox add-on?
Due to U.S. trade controls law restrictions, your GitHub account has been restricted.
This is the message that’s been recently sent to Iranian developers from GitHub, stating their accounts has been restricted.

So I thought this might be a good time to try writing my first add-on for Firefox. It seemed like a trivial task and I was curious how much it’s going to take my time. Simple tasks must be simple to do.
At first I tried to remove the banner in browser inspector. All I had to do was to set display property to none for the element and it was gone.
So, that’s what we want our add-on to do: To simply set a CSS property for an element.
Write the extension
MDN web docs has a page called Your first extension and I followed the steps it said:
At first I created a directory for my add-on.
Then I created manifest.json file. This file is the skeleton of your extension; What files does it include, a short description, extension version, icons and everything else.
content_scripts section is the most interesting part: You define in what domains, which scripts must be injected.
I wanted to modify appearance of GitHub, which means all I wanted to do was to add a CSS property. So I modified content_scripts in manifest.json to look like this:
"content_scripts": [ { "matches": ["*://*.github.com/*"], "css": ["github-warn.css"], }
And in github-warn.css I wrote this:
div.position-relative.js-header-wrapper > div.js-notice.flash-warn { display: none }
Run and debug
Now let’s test the add-on. First we must load it into the browser. To do so go to about:debugging in FireFox and click on “Load Temporary add-on”. By selecting a file in your add-on directory it will be loaded in FireFox.
And now when we go to GitHub we no longer see the banner.
But there’s a problem: It seems it take a little bit of time before we see our CSS effects in browser. When you open the site you can see the banner when page is being loaded and after a few seconds it disappears.
To solve this issue we have to change when the CSS get’s injected. It can be altered by run_at property in content_scripts: "run_at" : "document_start"
It worth to take a glance of content_scripts parameters in here.
Publish
There are two options for add-on publishing:
-
Self publish: You will be given the signed
.xpifile that you can distribute yourself. -
Publishing on FireFox Add-on’s page (AMO)
In either cases first you have to login to Mozilla Developer Hub and upload your zipped add-on directory. To do so, go to your add-on directory and run:
zip -r github-warn.zip .
Tip: If you’re on macOS, to avoid.DS_Store and __MACOSX are not included in zip file. You can delete them by executing this command:
zip -d github-warn.zip __MACOSX/* .DS_Store
After you’ve uploaded the zip file you can choose between self-publishing and publishing on AMO. In case you choose the latter, it might take about a day or two before your extensions be approved and becomes publicly available. Self
You can access the add-on code explained in this post on GitHub.



