lee
lee16mo ago

Could not resolve "node:crypto"

convex/shard.ts:3:24:
3 │ import * as crypto from 'node:crypto';
╵ ~~~~~~~~~~~~~

The package "node:crypto" wasn't found on the file system but is built into node. Are you trying
to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
convex/shard.ts:3:24:
3 │ import * as crypto from 'node:crypto';
╵ ~~~~~~~~~~~~~

The package "node:crypto" wasn't found on the file system but is built into node. Are you trying
to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
how can i use nodejs packages on the server side? i see it says platform: node but i dont see this config in the dashboard @CodingWithJamal
15 Replies
CodingWithJamal
CodingWithJamal16mo ago
hi
lee
leeOP16mo ago
hi. i see Presley is typing the answer (he built this 🙂 )
presley
presley16mo ago
Convex can use two runtimes - Convex's runtime where queries, mutations and actions run and Node.js where you can run actions. You can use crypto in Convex's runtime but it is a global. See "Supported APIs" here https://docs.convex.dev/functions/runtimes. If you need to use a node API not available in Convex's environment, you should use an action function and make it run in Node.js by adding "use node" at the top of the file.
CodingWithJamal
CodingWithJamal16mo ago
okay thanks @presley im still getting the same error but crypto should be built into the node runtime right?
'use node';

import * as crypto from 'node:crypto';

function generateAPIToken(): string {
const rb = crypto.randomBytes(32).toString('hex');
const ht = crypto.createHash('sha256').update(rb).digest('hex');
const hash = crypto.createHash('sha256');
hash.update(ht);
return hash.digest('hex');
}
'use node';

import * as crypto from 'node:crypto';

function generateAPIToken(): string {
const rb = crypto.randomBytes(32).toString('hex');
const ht = crypto.createHash('sha256').update(rb).digest('hex');
const hash = crypto.createHash('sha256');
hash.update(ht);
return hash.digest('hex');
}
lee
leeOP16mo ago
there is no semicolon after "use node"
CodingWithJamal
CodingWithJamal16mo ago
...my auto formatter adds that but okay
lee
leeOP16mo ago
btw if you don't want to use node, you can use the crypto global (remove the import line) which has a slightly different api https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API
Web Crypto API - Web APIs | MDN
The Web Crypto API is an interface allowing a script to use cryptographic primitives in order to build systems using cryptography.
CodingWithJamal
CodingWithJamal16mo ago
oh ok thanks
lee
leeOP16mo ago
oh i was wrong about the semicolon. the problem is you used single quotes 'use node'; but only double quotes are supported "use node";. sorry for the confusion
presley
presley16mo ago
@CodingWithJamal actually the single vs double quotes nor the semi-column matters. Sorry about the confusion. I just tested with the following code and the deployed and ran fine from the dashboard .
'use node';

import * as crypto from 'node:crypto';

function generateAPIToken(): string {
const rb = crypto.randomBytes(32).toString('hex');
const ht = crypto.createHash('sha256').update(rb).digest('hex');
const hash = crypto.createHash('sha256');
hash.update(ht);
return hash.digest('hex');
}

import { action } from "./_generated/server";

export const doSomething = action({
handler: () => {
return generateAPIToken();
},
});
'use node';

import * as crypto from 'node:crypto';

function generateAPIToken(): string {
const rb = crypto.randomBytes(32).toString('hex');
const ht = crypto.createHash('sha256').update(rb).digest('hex');
const hash = crypto.createHash('sha256');
hash.update(ht);
return hash.digest('hex');
}

import { action } from "./_generated/server";

export const doSomething = action({
handler: () => {
return generateAPIToken();
},
});
CodingWithJamal
CodingWithJamal16mo ago
oh..
async function generateAPIToken() {
try {
// Generate a cryptographically secure random array of bytes
const randomBytes = new Uint8Array(32);
window.crypto.getRandomValues(randomBytes);

// Convert the random bytes to a hex string
const rbHex = Array.from(randomBytes)
.map((byte) => byte.toString(16).padStart(2, '0'))
.join('');

// Calculate the hash using SHA-256
const encoder = new TextEncoder();
const rbData = encoder.encode(rbHex);
const hashBuffer = await window.crypto.subtle.digest('SHA-256', rbData);

// Convert the hash to a hex string
const hashArray = Array.from(new Uint8Array(hashBuffer));
const htHex = hashArray
.map((byte) => byte.toString(16).padStart(2, '0'))
.join('');

return htHex;
} catch (error) {
throw error;
}
}
async function generateAPIToken() {
try {
// Generate a cryptographically secure random array of bytes
const randomBytes = new Uint8Array(32);
window.crypto.getRandomValues(randomBytes);

// Convert the random bytes to a hex string
const rbHex = Array.from(randomBytes)
.map((byte) => byte.toString(16).padStart(2, '0'))
.join('');

// Calculate the hash using SHA-256
const encoder = new TextEncoder();
const rbData = encoder.encode(rbHex);
const hashBuffer = await window.crypto.subtle.digest('SHA-256', rbData);

// Convert the hash to a hex string
const hashArray = Array.from(new Uint8Array(hashBuffer));
const htHex = hashArray
.map((byte) => byte.toString(16).padStart(2, '0'))
.join('');

return htHex;
} catch (error) {
throw error;
}
}
I just finished rewriting for browser :haHAA:
presley
presley16mo ago
yeah, this is fine too.
CodingWithJamal
CodingWithJamal16mo ago
but thank you i will remember this
presley
presley16mo ago
let me know if you ran into further issues but "use node" should work and we have tried to make all variants of that work 🙂 One clarification. This is not "for browser" per say, but for "Convex's runtime" that is similar to Cloudflare & co in that it supports most APIs but is not full Node.
CodingWithJamal
CodingWithJamal16mo ago
understood, thanks for the help