### Fetch JSON Directory Listing Example
Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers
An example demonstrating how to fetch a JSON directory listing from an IPFS mirror URL. The file/folder list can be accessed using await response.json().
```javascript
url = 'ipfs://bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze/wiki/'
response = await fetch(url, {
headers: {
Accept: 'application/json'
}
})
```
--------------------------------
### Example URL Query Parameter
Source: https://agregore.mauve.moe/docs/tutorials/texteditor
An example of a URL query parameter used to specify a file to load or save.
```url
?url=./example.txt
```
--------------------------------
### Install Ollama
Source: https://agregore.mauve.moe/docs/ai
Installs Ollama on your system using a curl command. This is a prerequisite for running local LLM models.
```bash
curl -fsSL https://ollama.com/install.sh | sh
```
--------------------------------
### Handle Upload Start and Completion Events
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-dir-upload
Update the loadSidebar function in lib.js to handle 'dirUploadStart' by showing a modal dialog, and 'dirUpload' to update the modal and redirect after a delay.
```javascript
dirUploadForm.addEventListener('dirUploadStart', e => {
const modalDiv = document.createElement('dialog')
modal.id = 'uploadStatus'
modal.innerHTML = `
Uploading ${e.detail.fileCount} file(s)
`
document.body.appendChild(modal)
modal.showModal()
})
dirUploadForm.addEventListener('dirUpload', e => {
console.log('onDirUpload', e)
let modal = document.getElementById('uploadStatus')
modal.innerHTML = `
Upload complete. You will be redirected shortly
`
setTimeout(te => window.location = e.detail.cid, 5000)
})
```
--------------------------------
### Navigate to a Blank Site
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-1
Resets the browser's location to a specific IPFS CID, effectively starting with a blank site for development.
```javascript
window.location = 'ipfs://bafybeiczsscdsbs7ffqz55asqdf3smv6klcw3gofszvwlyarci47bgf354'
```
--------------------------------
### Adding Google Search Provider
Source: https://agregore.mauve.moe/docs/search-provider
Example of how to add Google as a custom search provider by specifying its search URI template. Ensure the template includes '%s' for the search query.
```text
https://www.google.com/search?q=%s
```
--------------------------------
### Configure LLM Settings in .agregorerc
Source: https://agregore.mauve.moe/docs/ai
Example JSON configuration for the .agregorerc file to enable and configure the local LLM API, specifying the base URL, API key, and model.
```json
{
"llm": {
"enabled": true,
"baseURL": "http://127.0.0.1:11434/v1/",
"apiKey": "ollama",
"model": "qwen2.5-coder"
}
}
```
--------------------------------
### Fetch File with GET Method (Explicit)
Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers
Explicitly using the 'GET' method for fetching a file. This is functionally equivalent to omitting the method option.
```javascript
await fetch('ipfs://CID/example.txt', { method: 'GET' })
```
--------------------------------
### Get Function as String
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-1
This snippet demonstrates how to get the string representation of a JavaScript function using the `.toString()` method. This is useful for saving functions to files on IPFS.
```javascript
async function updateSite(newPageContent){
let cid = window.location.hostname
const resp = await fetch(`ipfs://${cid}/index.html`, {method: 'put', body: newPageContent})
const newLocation = resp.headers.get('location')
window.location = newLocation
}
updateSite.toString()
```
--------------------------------
### Initialize PubSub on Form Submit
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat
Attaches an event listener to a form to initialize the PubSub class and start listening for messages when the form is submitted.
```javascript
window.addEventListener('load', (event) => {
const form = document.getElementById('roomNameForm')
form.addEventListener('submit', event => {
event.preventDefault()
const channelName = document.getElementById('channelNameInput').value
console.log('start pubsub', channelName)
window.pubsub = new PubSub(channelName)
window.pubsub.listenForMsg().catch(console.error)
})
})
```
--------------------------------
### Adding Bing Search Provider
Source: https://agregore.mauve.moe/docs/search-provider
Example of how to add Bing as a custom search provider by specifying its search URI template. Ensure the template includes '%s' for the search query.
```text
https://www.bing.com/search?q=%s
```
--------------------------------
### Get JSON Directory Listing
Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers
Request a JSON array of files and folders in a directory by setting the 'Accept' header to 'application/json'.
```javascript
var response = await fetch('ipfs://CID/example/', {
headers: {Accept: 'application/json'}
})
```
--------------------------------
### Initialize ACE Editor in showEditor Function
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-3rdparty-dep
Update the showEditor function in lib.js to initialize the ACE editor instance and set up the form submission handler to get content from the editor. This prepares the editor for user interaction.
```javascript
async function showEditor(){
let editorDiv = document.getElementById("editor")
if (!editorDiv){
editorDiv = document.createElement('div')
editorDiv.id = 'editor'
}
editorDiv.style = `display: flex;
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgb(233 233 233 / 95%);
`
const editorStyle = document.createElement('style') //+
editorStyle.innerHTML = "#idForm pre { flex-grow: 1; margin: 0; }" //+
document.body.appendChild(editorStyle) //+
editorDiv.innerHTML = `
Files
`
document.body.appendChild(editorDiv)
window.editor = ace.edit("idContentInput") //+
const form = document.getElementById('idForm')
form.onsubmit = e => {
e.preventDefault()
const filename = document.getElementById('idFilenameInput').value
//- const content = document.getElementById('idContentInput').value
const content = window.editor.getValue() //+
updateSite(filename, content)
}
await loadSidebar()
}
```
--------------------------------
### Edit File
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-2
Opens the editor interface and loads the content of the specified file. Use this to start editing an existing file.
```javascript
async function editFile(filename){
openEditor()
loadFile(filename)
}
```
--------------------------------
### Get Hyper URL from Site Name
Source: https://agregore.mauve.moe/docs/snippets
Generates a Hyperdrive key and returns its URL. Ensure the Agregore service is running and accessible.
```javascript
async function getHyperURL(siteName) {
const response = await fetch(`hyper://localhost/?key=${siteName}`, { method: 'POST' });
if (!response.ok) {
throw new Error(`Failed to generate Hyperdrive key: ${await response.text()}`);
}
return await response.text()
}
```
--------------------------------
### Load lib.js and Get updateSite Function
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-1
Injects the 'lib.js' script into the document's head to make the 'updateSite' function available in the global scope. It also attempts to retrieve the function's string representation.
```javascript
let script = document.createElement('script')
script.src = 'lib.js'
document.head.appendChild(script)
updateSite.toString()
```
--------------------------------
### Dispatch Custom Event on Directory Upload Start
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-dir-upload
In upload.js, add a line within the onSubmit handler to dispatch a 'dirUploadStart' event, passing the file count. This signals the beginning of the upload process.
```javascript
const fileInput = document.querySelector('#dirForm input[type="file"]')
this.dispatchEvent(new CustomEvent('dirUploadStart', { detail: { fileCount: fileInput.files.length } })) // <--- Add this line
const newCid = await batchUpload(fileInput.files, pathPrefix)
```
--------------------------------
### Display Chat Interface and Handle Message Submission
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat
Adds code to display the chat interface and hide the initial room setup. It also sets up an event listener to send messages when the form is submitted.
```javascript
onopen(e) {
// ...
document.getElementById('setup').classList.add('hidden')
document.getElementById('chat').classList.remove('hidden')
document.getElementById('roomName').innerHTML = this.channelName
document.querySelector('#chatForm').addEventListener('submit', e => {
e.preventDefault()
let textInput = document.querySelector('#chat input')
fetch(`pubsub://${this.channelName}/`, {
method: 'POST',
body: JSON.stringify({message: textInput.value}),
}).catch(console.error)
textInput.value = ''
})
}
```
--------------------------------
### Initialize Gallery and Lightbox Functionality
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery
Set up click event listeners for images to open the lightbox and for the lightbox image to close it.
```javascript
function galleryInit(){
layout()
for (const img of document.querySelectorAll('.gallery .row img')){
img.addEventListener('click', e => {
document.querySelector('.lightBox img').src = img.src
document.querySelector('.lightBox').classList.remove('hidden')
})
}
document.querySelector('.lightBox img').addEventListener('click', e =>
document.querySelector('.lightBox').classList.add('hidden')
)
}
```
--------------------------------
### Initialize PubSub Class
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat
Sets up the PubSub class to handle IPFS PUBSUB connections. This code snippet is intended to be added to 'pubsub.js'.
```javascript
class PubSub {
constructor(channelName) {
this.channelName = channelName
}
}
```
--------------------------------
### Fetch and Add Website Files
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-3
Fetches 'index.html' and 'lib.js' from a URL and adds them to the site using the addFiles function.
```javascript
let resp = await fetch('https://www.thebacklog.net/projects/agregore-web-apps/amt3.js')
const libjs = await resp.text()
resp = await fetch('https://www.thebacklog.net/projects/agregore-web-apps/amt3-index.tmpl')
const indexhtml = await resp.text()
addFiles([
new File([indexhtml], 'index.html', {type: 'text/html'})
new File([libjs], 'lib.js', {type: 'text/javascript'})
])
```
--------------------------------
### Initialize PubSub Class
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat
Defines the basic structure for the PubSub class, holding the channel name.
```javascript
class PubSub {
constructor(channelName){
this.channelName=channelName
}
}
```
--------------------------------
### Get IPLD Data
Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers
You can get raw IPLD data from a CID using the `ipld` protocol scheme. The data pointed to by the CID will not be interpreted as UnixFS and will use raw IPLD traversal.
```APIDOC
## GET ipld://CID/example
### Description
Retrieves raw IPLD data from a CID using raw IPLD traversal.
### Method
GET
### Endpoint
ipld://CID/example
### Parameters
#### Query Parameters
- **Accept** (string) - Optional - The desired response format (e.g., `application/json`, `application/vnd.ipld.dag-json`, `application/vnd.ipld.dag-cbor`).
### Response
#### Success Response (200)
- Raw IPLD data in the requested format.
### Request Example
```javascript
await fetch('ipld://CID/example', {
method: 'GET',
headers: {
'Accept': "application/json"
}
})
```
```
--------------------------------
### Getting Editor Content
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-3rdparty-dep
Retrieve the current content from the ACE editor instance within an onSubmit callback.
```javascript
const content = window.editor.getValue()
```
--------------------------------
### Basic HTML Structure for Chat App
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat
Sets up the initial HTML for the chat application, including a title, a form for selecting a room name, and links to JavaScript files.
```html
PUBSUB chat
IPFS PUBSUB chat
```
--------------------------------
### Get raw IPLD data from a CID
Source: https://agregore.mauve.moe/docs/ipfs-protocol-handlers
Use the 'ipld://' protocol scheme to get raw IPLD data from a CID. The data will not be interpreted as UnixFS and will use raw IPLD traversal with the path. Path segments can have custom parameters separated by ';', and URL encoding can be used for special characters. The 'Accept' header can re-encode the data into 'application/json', 'application/vnd.ipld.dag-json', or 'application/vnd.ipld.dag-cbor'.
```javascript
await fetch('ipld://CID/example', {
method: 'GET',
headers: {
'Accept': "application/json"
}
})
```
--------------------------------
### Load Script and Create index.html with Delay
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-1
Injects the 'lib.js' script and then, after a 1-second delay, updates 'index.html' with content including the script tag. This ensures the script is loaded before the HTML is updated.
```javascript
let script = document.createElement('script')
script.src = 'lib.js'
document.head.appendChild(script)
setTimeout( () => updateSite('index.html', `
Page title
Hello world
`), 1000)
```
--------------------------------
### Get IPNS URL from Site Name
Source: https://agregore.mauve.moe/docs/snippets
Generates an IPNS key and returns its URL. This function requires the Agregore service to be running.
```javascript
async function getIPNSURL(siteName) {
const response = await fetch(`ipns://localhost/?key=${siteName}`, { method: 'POST' });
if (!response.ok) {
throw new Error(`Failed to generate IPNS key: ${await response.text()}`);
}
await response.text()
return response.headers.get('Location')
}
```
--------------------------------
### Complete lib.js Code
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-3
Contains the final implementation of publishSite, updateSite, and the beginning of loadFile for lib.js.
```javascript
async function publishSite(){
let resp = await fetch('ipns://localhost/?key=mysite', {method: 'POST'})
const key = resp.headers.get('location')
resp = await fetch(key, {method: 'POST', body: window.origin})
window.location = new URL(resp.headers.get('location')).origin
}
async function updateSite(filename, content){
const resp = await fetch(`${window.origin}/${filename}`, {method: 'put', body: content})
const newLocation = resp.headers.get('location')
window.location = new URL(newLocation).origin
}
async function loadFile(filename){
```
--------------------------------
### Populate Sidebar with File List
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-2
Fetches the list of files in the current directory using listDir, then dynamically creates an unordered list of clickable file links to populate the sidebar. Clicking a file loads it into the editor.
```javascript
const sidebar = document.getElementById('idSidebar')
const files = await listDir(window.origin)
const list = document.createElement('ul')
list.style = "list-style: none; padding-inline-start: 0;"
files.map( file => {
let li = document.createElement('li')
li.innerHTML = `${file}`
li.querySelector('a').onclick = e => loadFile(file)
```
--------------------------------
### Assemble Code for Uploading
Source: https://agregore.mauve.moe/docs/tutorials/p2pad-code-editor
Prepares HTML, CSS, and JavaScript into a single HTML file format and converts it to a Blob for uploading. Shows a loading spinner during the process.
```javascript
export async function assembleCode() {
// Implementation to assemble and upload the code
}
```
--------------------------------
### Setting ACE Editor Mode
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-3rdparty-dep
Set the editor's mode based on certain conditions. This example shows setting it to CSS or plain text.
```javascript
editor.session.setMode("ace/mode/css")
} else {
editor.session.setMode("ace/mode/text")
```
--------------------------------
### Placeholder for Upload File Function
Source: https://agregore.mauve.moe/docs/tutorials/drag-and-drop
This is a placeholder indicating where the main file upload logic resides. The actual implementation is detailed in the full code example.
```javascript
async function uploadFile(file) {
// ... [full code above]
}
```
--------------------------------
### HTML Structure for Image Gallery
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery
Sets up the basic HTML for an image gallery using nested divs and placeholder images. Includes CSS for flexbox layout.
```html
Image gallery
```
--------------------------------
### List IPFS Directory Contents in Console
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-2
Tests the listDir function by calling it with the current origin. Expects to return an array of file names like ['index.html', 'lib.js'].
```javascript
await listDir(window.origin)
```
--------------------------------
### Clown Theme JSON
Source: https://agregore.mauve.moe/docs/theming
An example of a highly contrasting and vibrant theme, referred to as the 'Clown Theme'. Use with caution due to its intense color palette.
```json
{
"theme": {
"font-family": "Arial",
"background": "#0000ff",
"text": "#00ff00",
"page": "#ff0000",
"primary": "#ffff00",
"secondary": "#ffffff",
"border-radius": "1em"
}
}
```
--------------------------------
### JavaScript to Get Form Data
Source: https://agregore.mauve.moe/docs/snippets
This JavaScript snippet retrieves form data from the 'saveForm' element, extracting filename, save type, and site name.
```javascript
saveForm.onsubmit = (e) => {
e.preventDefault()
const formData = new FormData(saveForm)
const filename = formData.get('fileName')
const saveType = formData.get('saveType')
const siteName = formData.get('siteName')
}
```
--------------------------------
### Placeholder for Generate Hyperdrive Key Function
Source: https://agregore.mauve.moe/docs/tutorials/drag-and-drop
This is a placeholder indicating where the Hyperdrive key generation logic resides. The actual implementation is detailed in the full code example.
```javascript
async function generateHyperdriveKey(name) {
// ... [full code above]
}
```
--------------------------------
### Minimal HTML Structure for Agregore Editor
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-3rdparty-dep
This is the updated index.html file. It now only includes a single script tag for lib.js, as all other resources are loaded dynamically by the showEditor function.
```html
Agregore self-hosted devenv V2
Agregore self-hosted devenv V2
```
--------------------------------
### JavaScript to Get URL Parameter
Source: https://agregore.mauve.moe/docs/tutorials/texteditor
Extracts the 'url' search parameter from the current page's URL. This is used to specify a text file to be loaded into the editor.
```javascript
function getURLFromSearch() {
const {searchParams} = new URL(window.location)
const url = searchParams.get('url')
return url
}
```
--------------------------------
### JavaScript Function to Handle File Picker
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery
This asynchronous JavaScript function, `handleHelpClick`, utilizes the `showOpenFilePicker` API to allow users to select multiple image files. It then minimizes the help overlay and adds the selected files to the gallery.
```javascript
async function handleHelpClick(e){
e.stopPropagation()
const opts = {
types: [
{
description: "Images",
accept: {
"image/*": [".png", ".gif", ".jpeg", ".jpg"],
},
},
],
excludeAcceptAllOption: true,
multiple: true,
startIn: "pictures",
}
let result = await showOpenFilePicker(opts)
document.querySelector('.helpOverlay').classList.add('small')
for (const fileHandle of result){
let file = await fileHandle.getFile()
await addFileToGallery(file)
}
}
```
--------------------------------
### Basic HTML Structure for Theme Builder
Source: https://agregore.mauve.moe/docs/tutorials/themebuilder-tutorial
This HTML provides the basic structure for the Theme Builder tutorial, including headings and paragraphs that will be styled by the CSS.
```html
Theme Builder
The Idea ✨
Jesse is using the Agregore theme (found here or here) to keep their apps looking cohesive. They want to change up the theme, so they navigate to ipns://themebuild.er to play around with the colors until they find something they like.
Preamble
This tutorial assumes a very basic level of web development experience as well as a small familiarity with p2p web protocols or IPFS. Maybe you've made a handful of single page web apps and have heard about the distributed web before but haven't really played around with it.
Getting Started 🏁
To keep things simple for this tutorial I'm just going to use an online code playground (I used JSFiddle specifically) as our dev environment. Of course, you're free to use whatever you want, but that's the context that surround this tutorial.
We will use Agregore's built in IPFS Fetch API to publish our site on IPFS. At the time of writing the latest version for Agregore can be found here.
Developing Our App
So, let's start making our app, our basic endgoal here is to have some color pickers to choose the theme colors, an "example page" to reflect the color changes, and a way for the user to "save" those changes.
First let's set up our file, if you navigate to agregore://theme/style.css we're just going to copy paste this whole thing into the css.
Once you've done that, delete the second line (the @import url("agregore://theme/vars.css")) and replace it with the following:
If you took a peek at agregore://theme/vars.css you might notice that this looks very similar because it's essentially that file. The reason we're doing things this was is because we're gonna want to be able to mess with the CSS file and edit it freely.
After we've done that we're going to want to have some content for the CSS to style. For that I decided to use this tutorial up to this point!
```
--------------------------------
### HTML Form for Directory Upload
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-dir-upload
Sets up an HTML form with inputs for an optional path prefix and a file input that accepts directories using the `webkitdirectory` attribute.
```html
Agregore IPFS directory upload
Agregore IPFS directory upload
```
--------------------------------
### HTML Structure for Drag and Drop App
Source: https://agregore.mauve.moe/docs/tutorials/drag-and-drop
Sets up the basic HTML for a drag-and-drop file upload application, including a protocol selector, a drop zone, and a list for uploaded file URLs. External CSS and JavaScript files are linked for styling and functionality.
```html
Drag and Drop to IPFS and HypercoreDrop a file here
```
--------------------------------
### Listen for Pub/Sub Messages
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-pub-sub-chat
Sets up an EventSource to listen for messages on a specific Pub/Sub channel. Requires the channel name to be available.
```javascript
async listenForMsg() {
let es = new EventSource(`pubsub://${this.channelName}/?format=json`)
es.onmessage = this.onmessage
es.onopen = this.onopen
es.onerror = this.onerror
}
```
--------------------------------
### Add Publish Button to Sidebar
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-browser-devenv/part-3
Adds a 'Publish site' button to the sidebar if the current origin starts with 'ipfs://'. Clicking the button calls the publishSite function.
```javascript
if (window.origin.startsWith('ipfs://')){
const button = document.createElement('button')
button.innerHTML = 'Publish site'
button.onclick = e => {
e.preventDefault()
publishSite()
}
sidebar.appendChild(button)
}
```
--------------------------------
### Upload File and Add URL
Source: https://agregore.mauve.moe/docs/tutorials/dlinktree-builder
Handles the creation of a File object and initiates the upload process, then adds the resulting URL to the UI.
```javascript
const file = new File([blob], "index.html", { type: 'text/html' });
// Upload the file
const response = await uploadFile(file);
addURL(response.url);
}
```
--------------------------------
### Setup Drag and Drop Event Handlers
Source: https://agregore.mauve.moe/docs/tutorials/drag-and-drop
Configures the 'ondragover' and 'ondrop' event handlers for the upload box element. It prevents the default dragover behavior and processes dropped files.
```javascript
const uploadBox = $('#uploadBox');
uploadBox.ondragover = () => false;
uploadBox.ondrop = async (e) => {
e.preventDefault();
const { dataTransfer } = e;
if (!dataTransfer) return;
for (const file of dataTransfer.files) {
await uploadFile(file);
}
};
```
--------------------------------
### HTML for Help Overlay with File Selector Button
Source: https://agregore.mauve.moe/docs/tutorials/ipfs-gallery
This updated HTML snippet enhances the help overlay by adding a button that triggers a file selector, providing an alternative to drag-and-drop for adding images.
```html
Drag and drop images to begin or . Click anywhere to view the gallery.
```
--------------------------------
### HTML Structure for P2Pad Code Editor
Source: https://agregore.mauve.moe/docs/tutorials/p2pad-code-editor
Sets up the basic HTML document, including meta tags, title, CSS link, and the main layout for the code editor. It defines text areas for HTML, CSS, and JavaScript input, and an iframe for output preview.
```html
P2Pad: Real-Time Editor
↻
```
--------------------------------
### JavaScript to Load URL Content into Editor
Source: https://agregore.mauve.moe/docs/tutorials/texteditor
Combines the functions to get a URL from the search parameters and load its text content into the editor's textarea. This code should be placed at the top of the JavaScript section.
```javascript
const url = getURLFromSearch()
if(url) {
const text = await loadTextFromURL(url)
editorBox.value = text
}
```
--------------------------------
### Basic HTML Structure for Text Editor
Source: https://agregore.mauve.moe/docs/tutorials/texteditor
Sets up the fundamental HTML elements for the text editor, including a header, a textarea for editing, and dialog elements for file loading and creation.
```html