Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/solid-heads-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@lit-protocol/lit-client': minor
---

LitClient now offers `getIpfsId` via `@lit-protocol/lit-client/ipfs`, letting apps compute CIDv0 hashes (e.g., `await getIpfsId('hello')`) while keeping bundles lean.

```ts
import { getIpfsId } from '@lit-protocol/lit-client/ipfs';
const cid = await getIpfsId('hello');
```
5 changes: 3 additions & 2 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,10 @@
]
},
{
"group": "Access Control Conditions",
"group": "Utilities",
"pages": [
"sdk/sdk-reference/access-control-conditions/functions/createAccBuilder"
"sdk/sdk-reference/access-control-conditions/functions/createAccBuilder",
"sdk/sdk-reference/lit-client/functions/getIpfsId"
]
},
{
Expand Down
39 changes: 39 additions & 0 deletions docs/sdk/sdk-reference/lit-client/functions/getIpfsId.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: getIpfsId
description: Generate CIDv0 hashes with the Lit Client IPFS helper
---

## Overview

`getIpfsId` is an optional helper exported via `@lit-protocol/lit-client/ipfs`. It produces CIDv0 IPFS identifiers identical to the Lit SDK v7 utility while remaining fully tree-shakeable from the main client bundle.

## Usage

```ts
import { getIpfsId } from '@lit-protocol/lit-client/ipfs';

const cid = await getIpfsId('console.log("hello lit")');
// cid === 'Qm...'

const bytes = new TextEncoder().encode('console.log("hello lit")');
const sameCid = await getIpfsId(bytes);
// sameCid === cid
```

## Parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| input | `string \| Uint8Array \| ArrayBuffer \| ArrayBufferView` | Source content to hash. Strings are UTF-8 encoded automatically; buffers and typed views are accepted directly. |

## Returns

```
// A CIDv0 string beginning with Qm
Promise<Qm${string}>
```

## Notes

- The helper delegates to the same hashing routine used in v7 (`typestub-ipfs-only-hash`) and can be imported without pulling the entire Lit Client into your bundle.
- Binary payloads do not need to be stringified first—pass any `Uint8Array`, `ArrayBuffer`, or typed view directly and the helper will normalize it before hashing.
2 changes: 2 additions & 0 deletions packages/lit-client/ipfs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { getIpfsId } from '../src/ipfs/getIpfsId';
export type { IpfsCidV0 } from '../src/ipfs/getIpfsId';
1 change: 1 addition & 0 deletions packages/lit-client/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ export default {
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/packages/lit-client',
setupFilesAfterEnv: ['../../jest.setup.js'],
testEnvironment: 'node',
};
20 changes: 20 additions & 0 deletions packages/lit-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,29 @@
"main": "./index.js",
"typings": "./index.d.ts",
"types": "./index.d.ts",
"exports": {
".": {
"types": "./index.d.ts",
"require": "./index.js",
"import": "./index.js"
},
"./ipfs": {
"types": "./ipfs/index.d.ts",
"require": "./ipfs/index.js",
"import": "./ipfs/index.js"
}
},
"typesVersions": {
"*": {
"ipfs": [
"ipfs/index.d.ts"
]
}
},
"dependencies": {
"@lit-protocol/uint8arrays": "7.1.1",
"bs58": "^6.0.0",
"typestub-ipfs-only-hash": "^4.0.0",
"zod": "3.24.3"
},
"peerDependencies": {
Expand Down
25 changes: 25 additions & 0 deletions packages/lit-client/src/ipfs/getIpfsId.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { getIpfsId } from './getIpfsId';

const encoder = new TextEncoder();

describe('getIpfsId', () => {
it('creates a CIDv0 for string input', async () => {
await expect(getIpfsId('hello')).resolves.toBe(
'QmWfVY9y3xjsixTgbd9AorQxH7VtMpzfx2HaWtsoUYecaX'
);
});

it('creates the same CIDv0 for byte input', async () => {
const bytes = encoder.encode('hello');
await expect(getIpfsId(bytes)).resolves.toBe(
'QmWfVY9y3xjsixTgbd9AorQxH7VtMpzfx2HaWtsoUYecaX'
);
});

it('throws when input type is unsupported', async () => {
await expect(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getIpfsId(123 as any)
).rejects.toThrow(/ArrayBufferView/);
});
});
71 changes: 71 additions & 0 deletions packages/lit-client/src/ipfs/getIpfsId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import * as Hash from 'typestub-ipfs-only-hash';

export type IpfsCidV0 = `Qm${string}`;

type SupportedInput = string | Uint8Array | ArrayBuffer | ArrayBufferView;

// Ensure string inputs are encoded without relying on Node's global Buffer, falling back to util.TextEncoder when needed.
const encodeString = (value: string): Uint8Array => {
if (typeof TextEncoder !== 'undefined') {
return new TextEncoder().encode(value);
}

try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { TextEncoder: NodeTextEncoder } = require('util');
return new NodeTextEncoder().encode(value);
} catch (error) {
throw new Error('TextEncoder is not available in this environment');
}
};

const toUint8Array = (value: ArrayBuffer | ArrayBufferView): Uint8Array => {
// TypedArray/DataView instances expose a shared buffer; slice the relevant window into a standalone Uint8Array.
if (ArrayBuffer.isView(value)) {
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
}

return new Uint8Array(value);
};

const normalizeInput = (input: SupportedInput): Uint8Array => {
// Accommodate all portable input shapes while keeping the helper tree-shakeable and browser-friendly.
if (typeof input === 'string') {
return encodeString(input);
}

if (input instanceof Uint8Array) {
return input;
}

if (typeof ArrayBuffer !== 'undefined') {
if (input instanceof ArrayBuffer) {
return toUint8Array(input);
}

if (ArrayBuffer.isView(input)) {
return toUint8Array(input);
}
}

throw new TypeError(
'Input must be provided as a string, Uint8Array, ArrayBuffer or ArrayBufferView'
);
};

/**
* Generate a CIDv0 IPFS identifier for the provided content.
*/
export const getIpfsId = async (input: SupportedInput): Promise<IpfsCidV0> => {
const normalizedInput = normalizeInput(input);
const hashOf = Hash.of as unknown as (
value: string | Uint8Array
) => Promise<string>;
const cid = await hashOf(normalizedInput);

if (!cid.startsWith('Qm')) {
throw new Error('Generated IPFS CID is not CIDv0');
}

return cid as IpfsCidV0;
};
2 changes: 2 additions & 0 deletions packages/lit-client/src/ipfs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { getIpfsId } from './getIpfsId';
export type { IpfsCidV0 } from './getIpfsId';
Loading
Loading