lee
lee2y 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
Jamal
Jamal2y ago
hi
lee
leeOP2y ago
hi. i see Presley is typing the answer (he built this 🙂 )
presley
presley2y 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.
Jamal
Jamal2y 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
leeOP2y ago
there is no semicolon after "use node"
Jamal
Jamal2y ago
...my auto formatter adds that but okay
lee
leeOP2y 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.
Jamal
Jamal2y ago
oh ok thanks
lee
leeOP2y 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
presley2y 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();
},
});
Jamal
Jamal2y 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
presley2y ago
yeah, this is fine too.
Jamal
Jamal2y ago
but thank you i will remember this
presley
presley2y 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.
Jamal
Jamal2y ago
understood, thanks for the help

Did you find this page helpful?