Skip to content

Add fetch example for Lit Actions #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: v2
Choose a base branch
from
Draft
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
11 changes: 11 additions & 0 deletions code-examples/lit-actions/fetch/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Ethereum private key for signing transactions
# This should be a test account with no real funds
ETHEREUM_PRIVATE_KEY=0x...

# Lit Network to connect to: datil-dev, datil-test, or datil
# Default: datil-dev
LIT_NETWORK=datil-dev

# Enable debug logging
# Default: false
LIT_DEBUG=false
22 changes: 22 additions & 0 deletions code-examples/lit-actions/fetch/.spec.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "es6"
},
"sourceMaps": true,
"exclude": []
}
102 changes: 102 additions & 0 deletions code-examples/lit-actions/fetch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Lit Protocol Fetch Example

This example demonstrates how to use the `Lit.Actions.fetch` function to make HTTP requests from a Lit Action.

## Overview

The Lit Protocol allows you to execute JavaScript code in a decentralized, secure environment. One of the powerful features of Lit Actions is the ability to make HTTP requests to external APIs using the `Lit.Actions.fetch` function.

This example shows how to:

1. Connect to the Lit Network
2. Create an authentication signature
3. Define a Lit Action that makes an HTTP request to an external API
4. Execute the Lit Action
5. Process the response

## Prerequisites

- Node.js (v16 or higher)
- An Ethereum private key for signing authentication messages

## Environment Variables

Create a `.env` file in the root directory with the following variables:

```
# Ethereum private key for signing transactions
# This should be a test account with no real funds
ETHEREUM_PRIVATE_KEY=0x...

# Lit Network to connect to: datil-dev, datil-test, or datil
# Default: datil-dev
LIT_NETWORK=datil-dev

# Enable debug logging
# Default: false
LIT_DEBUG=false
```

## Usage

### Running the Example

```bash
pnpm nx test fetch
```

### Code Explanation

The example demonstrates a simple HTTP GET request to the JSONPlaceholder API:

```javascript
const litActionCode = `
const fetchResult = await Lit.Actions.fetch({
url: 'https://jsonplaceholder.typicode.com/todos/1',
method: 'GET'
});

const responseBody = await fetchResult.json();

Lit.Actions.setResponse({
response: JSON.stringify(responseBody)
});
`;
```

This Lit Action:
1. Makes a GET request to the JSONPlaceholder API
2. Parses the JSON response
3. Returns the response data

### API Reference

The `Lit.Actions.fetch` function accepts the following parameters:

- `url` (required): The URL to make the request to
- `method` (required): The HTTP method to use (GET, POST, PUT, DELETE, etc.)
- `headers`: Optional headers to include in the request
- `body`: Optional request body (for POST, PUT, etc.)
- `cache`: Optional cache mode
- `credentials`: Optional credentials mode
- `redirect`: Optional redirect mode
- `referrer`: Optional referrer
- `referrerPolicy`: Optional referrer policy
- `integrity`: Optional subresource integrity value
- `keepalive`: Optional keepalive flag
- `signal`: Optional AbortSignal to abort the request

## Security Considerations

When using `Lit.Actions.fetch` in production:

1. Be careful with the URLs you fetch from - only fetch from trusted sources
2. Consider rate limiting to avoid excessive requests
3. Handle errors gracefully
4. Be mindful of sensitive data in requests and responses
5. Consider using conditional access control for sensitive operations

## Further Reading

- [Lit Protocol Documentation](https://developer.litprotocol.com/)
- [Lit Actions API Reference](https://developer.litprotocol.com/v3/sdk/actions/)
22 changes: 22 additions & 0 deletions code-examples/lit-actions/fetch/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import baseConfig from '../../../eslint.config.mjs';

export default [
...baseConfig,
{
files: ['**/*.json'],
rules: {
'@nx/dependency-checks': [
'error',
{
ignoredFiles: [
'{projectRoot}/eslint.config.{js,cjs,mjs}',
'{projectRoot}/esbuild.config.{js,ts,mjs,mts}',
],
},
],
},
languageOptions: {
parser: await import('jsonc-eslint-parser'),
},
},
];
21 changes: 21 additions & 0 deletions code-examples/lit-actions/fetch/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* eslint-disable */
import { readFileSync } from 'fs';

// Reading the SWC compilation config for the spec files
const swcJestConfig = JSON.parse(
readFileSync(`${__dirname}/.spec.swcrc`, 'utf-8')
);

// Disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves
swcJestConfig.swcrc = false;

export default {
displayName: '@dev-guides-code/fetch',
preset: '../../../jest.preset.js',
testEnvironment: 'node',
transform: {
'^.+\\.[tj]s$': ['@swc/jest', swcJestConfig],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: 'test-output/jest/coverage',
};
45 changes: 45 additions & 0 deletions code-examples/lit-actions/fetch/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "@dev-guides-code/fetch",
"version": "0.0.1",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
"./package.json": "./package.json",
".": {
"development": "./src/index.ts",
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"default": "./dist/index.js"
}
},
"files": [
"dist",
"!**/*.tsbuildinfo"
],
"nx": {
"targets": {
"build": {
"executor": "@nx/esbuild:esbuild",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "code-examples/lit-actions/fetch/dist",
"main": "code-examples/lit-actions/fetch/src/index.ts",
"tsConfig": "code-examples/lit-actions/fetch/tsconfig.lib.json",
"format": [
"esm"
],
"declarationRootDir": "code-examples/lit-actions/fetch/src"
}
}
}
},
"dependencies": {
"@dev-guides-code/example-utils": "workspace:*",
"@lit-protocol/lit-node-client": "catalog:",
"ethers": "^6.13.5"
}
}
2 changes: 2 additions & 0 deletions code-examples/lit-actions/fetch/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './lib/example.js';
export * from './lib/litAction.js';
51 changes: 51 additions & 0 deletions code-examples/lit-actions/fetch/src/lib/example.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { runExample, cleanup } from './example.js';

describe('fetch', () => {
// Set a longer timeout for the entire test suite
jest.setTimeout(30000);

// Clean up after each test
afterEach(async () => {
await cleanup();
});

// Clean up after all tests
afterAll(async () => {
await cleanup();
});

it('should demonstrate a Lit Action that fetches data from an external API', async () => {
try {
console.log('Starting fetch test...');
const result = await runExample();

// Verify the result has all expected properties
expect(result).toHaveProperty('walletAddress');
expect(result).toHaveProperty('litActionCode');
expect(result).toHaveProperty('response');

// Verify the response contains the expected data from the API
const response = result.response;
expect(response).toBeDefined();

// Parse the response if it's a string
const parsedResponse = typeof response.response === 'string'
? JSON.parse(response.response)
: response.response;

// Check if the response has the expected structure from jsonplaceholder API
expect(parsedResponse).toHaveProperty('id');
expect(parsedResponse).toHaveProperty('title');
expect(parsedResponse).toHaveProperty('completed');
expect(parsedResponse).toHaveProperty('userId');

// Log the results for inspection
console.log('Fetch test completed successfully');
console.log('Wallet Address:', result.walletAddress);
console.log('Response:', JSON.stringify(result.response, null, 2));
} catch (error) {
console.error('Fetch test failed with error:', error);
throw error;
}
});
});
Loading