Skip to content

Commit fe5d061

Browse files
authored
Merge pull request #969 from LIT-Protocol/feature/jss-133-naga-feature-request
Feature/jss 133 naga feature request
2 parents 2ccfde5 + b5eefa9 commit fe5d061

File tree

10 files changed

+827
-2
lines changed

10 files changed

+827
-2
lines changed

.changeset/solid-heads-repeat.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@lit-protocol/lit-client': minor
3+
---
4+
5+
LitClient now offers `getIpfsId` via `@lit-protocol/lit-client/ipfs`, letting apps compute CIDv0 hashes (e.g., `await getIpfsId('hello')`) while keeping bundles lean.
6+
7+
```ts
8+
import { getIpfsId } from '@lit-protocol/lit-client/ipfs';
9+
const cid = await getIpfsId('hello');
10+
```

docs/docs.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,10 @@
9191
]
9292
},
9393
{
94-
"group": "Access Control Conditions",
94+
"group": "Utilities",
9595
"pages": [
96-
"sdk/sdk-reference/access-control-conditions/functions/createAccBuilder"
96+
"sdk/sdk-reference/access-control-conditions/functions/createAccBuilder",
97+
"sdk/sdk-reference/lit-client/functions/getIpfsId"
9798
]
9899
},
99100
{
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
title: getIpfsId
3+
description: Generate CIDv0 hashes with the Lit Client IPFS helper
4+
---
5+
6+
## Overview
7+
8+
`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.
9+
10+
## Usage
11+
12+
```ts
13+
import { getIpfsId } from '@lit-protocol/lit-client/ipfs';
14+
15+
const cid = await getIpfsId('console.log("hello lit")');
16+
// cid === 'Qm...'
17+
18+
const bytes = new TextEncoder().encode('console.log("hello lit")');
19+
const sameCid = await getIpfsId(bytes);
20+
// sameCid === cid
21+
```
22+
23+
## Parameters
24+
25+
| Name | Type | Description |
26+
| ---- | ---- | ----------- |
27+
| input | `string \| Uint8Array \| ArrayBuffer \| ArrayBufferView` | Source content to hash. Strings are UTF-8 encoded automatically; buffers and typed views are accepted directly. |
28+
29+
## Returns
30+
31+
```
32+
// A CIDv0 string beginning with Qm
33+
Promise<Qm${string}>
34+
```
35+
36+
## Notes
37+
38+
- 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.
39+
- 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.

packages/lit-client/ipfs/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { getIpfsId } from '../src/ipfs/getIpfsId';
2+
export type { IpfsCidV0 } from '../src/ipfs/getIpfsId';

packages/lit-client/jest.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ export default {
1313
moduleFileExtensions: ['ts', 'js', 'html'],
1414
coverageDirectory: '../../coverage/packages/lit-client',
1515
setupFilesAfterEnv: ['../../jest.setup.js'],
16+
testEnvironment: 'node',
1617
};

packages/lit-client/package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,29 @@
2525
"main": "./index.js",
2626
"typings": "./index.d.ts",
2727
"types": "./index.d.ts",
28+
"exports": {
29+
".": {
30+
"types": "./index.d.ts",
31+
"require": "./index.js",
32+
"import": "./index.js"
33+
},
34+
"./ipfs": {
35+
"types": "./ipfs/index.d.ts",
36+
"require": "./ipfs/index.js",
37+
"import": "./ipfs/index.js"
38+
}
39+
},
40+
"typesVersions": {
41+
"*": {
42+
"ipfs": [
43+
"ipfs/index.d.ts"
44+
]
45+
}
46+
},
2847
"dependencies": {
2948
"@lit-protocol/uint8arrays": "7.1.1",
3049
"bs58": "^6.0.0",
50+
"typestub-ipfs-only-hash": "^4.0.0",
3151
"zod": "3.24.3"
3252
},
3353
"peerDependencies": {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { getIpfsId } from './getIpfsId';
2+
3+
const encoder = new TextEncoder();
4+
5+
describe('getIpfsId', () => {
6+
it('creates a CIDv0 for string input', async () => {
7+
await expect(getIpfsId('hello')).resolves.toBe(
8+
'QmWfVY9y3xjsixTgbd9AorQxH7VtMpzfx2HaWtsoUYecaX'
9+
);
10+
});
11+
12+
it('creates the same CIDv0 for byte input', async () => {
13+
const bytes = encoder.encode('hello');
14+
await expect(getIpfsId(bytes)).resolves.toBe(
15+
'QmWfVY9y3xjsixTgbd9AorQxH7VtMpzfx2HaWtsoUYecaX'
16+
);
17+
});
18+
19+
it('throws when input type is unsupported', async () => {
20+
await expect(
21+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
22+
getIpfsId(123 as any)
23+
).rejects.toThrow(/ArrayBufferView/);
24+
});
25+
});
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import * as Hash from 'typestub-ipfs-only-hash';
2+
3+
export type IpfsCidV0 = `Qm${string}`;
4+
5+
type SupportedInput = string | Uint8Array | ArrayBuffer | ArrayBufferView;
6+
7+
// Ensure string inputs are encoded without relying on Node's global Buffer, falling back to util.TextEncoder when needed.
8+
const encodeString = (value: string): Uint8Array => {
9+
if (typeof TextEncoder !== 'undefined') {
10+
return new TextEncoder().encode(value);
11+
}
12+
13+
try {
14+
// eslint-disable-next-line @typescript-eslint/no-var-requires
15+
const { TextEncoder: NodeTextEncoder } = require('util');
16+
return new NodeTextEncoder().encode(value);
17+
} catch (error) {
18+
throw new Error('TextEncoder is not available in this environment');
19+
}
20+
};
21+
22+
const toUint8Array = (value: ArrayBuffer | ArrayBufferView): Uint8Array => {
23+
// TypedArray/DataView instances expose a shared buffer; slice the relevant window into a standalone Uint8Array.
24+
if (ArrayBuffer.isView(value)) {
25+
return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
26+
}
27+
28+
return new Uint8Array(value);
29+
};
30+
31+
const normalizeInput = (input: SupportedInput): Uint8Array => {
32+
// Accommodate all portable input shapes while keeping the helper tree-shakeable and browser-friendly.
33+
if (typeof input === 'string') {
34+
return encodeString(input);
35+
}
36+
37+
if (input instanceof Uint8Array) {
38+
return input;
39+
}
40+
41+
if (typeof ArrayBuffer !== 'undefined') {
42+
if (input instanceof ArrayBuffer) {
43+
return toUint8Array(input);
44+
}
45+
46+
if (ArrayBuffer.isView(input)) {
47+
return toUint8Array(input);
48+
}
49+
}
50+
51+
throw new TypeError(
52+
'Input must be provided as a string, Uint8Array, ArrayBuffer or ArrayBufferView'
53+
);
54+
};
55+
56+
/**
57+
* Generate a CIDv0 IPFS identifier for the provided content.
58+
*/
59+
export const getIpfsId = async (input: SupportedInput): Promise<IpfsCidV0> => {
60+
const normalizedInput = normalizeInput(input);
61+
const hashOf = Hash.of as unknown as (
62+
value: string | Uint8Array
63+
) => Promise<string>;
64+
const cid = await hashOf(normalizedInput);
65+
66+
if (!cid.startsWith('Qm')) {
67+
throw new Error('Generated IPFS CID is not CIDv0');
68+
}
69+
70+
return cid as IpfsCidV0;
71+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { getIpfsId } from './getIpfsId';
2+
export type { IpfsCidV0 } from './getIpfsId';

0 commit comments

Comments
 (0)