{"id":25407307,"url":"https://github.com/uditdc/sample-todo-with-bls","last_synced_at":"2026-07-03T11:08:43.475Z","repository":{"id":230924572,"uuid":"639830655","full_name":"uditdc/sample-todo-with-bls","owner":"uditdc","description":null,"archived":false,"fork":false,"pushed_at":"2023-05-12T10:19:57.000Z","size":8,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-13T10:59:20.364Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uditdc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-05-12T10:19:47.000Z","updated_at":"2023-05-12T10:20:01.000Z","dependencies_parsed_at":"2024-04-01T16:42:43.012Z","dependency_job_id":null,"html_url":"https://github.com/uditdc/sample-todo-with-bls","commit_stats":null,"previous_names":["uditdc/sample-todo-with-bls"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/uditdc/sample-todo-with-bls","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditdc%2Fsample-todo-with-bls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditdc%2Fsample-todo-with-bls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditdc%2Fsample-todo-with-bls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditdc%2Fsample-todo-with-bls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uditdc","download_url":"https://codeload.github.com/uditdc/sample-todo-with-bls/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uditdc%2Fsample-todo-with-bls/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35083251,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-03T02:00:05.635Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-16T06:45:44.323Z","updated_at":"2026-07-03T11:08:43.442Z","avatar_url":"https://github.com/uditdc.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Build a Serverless To-Do App with Blockless Functions\n\nIn this tutorial, we will show you how to build a simple todo application using the Blockless Network and a variety of modules and tools. We will cover how to connect to the network using the Blockless CLI, read data from the standard input and environment variables using the memory module, interact with the InterPlanetary File System (IPFS) using the ipfs module, send HTTP requests and receive responses from servers using the http module, and store data in the cloud using the AWS s3 module.\n\nBy following the steps in this tutorial, you will learn how to use these powerful tools to build applications that can interact with the Blockless Network and make use of its unique features. You will be able to use this knowledge to create your own applications and explore the full capabilities of the Blockless ecosystem. You will learn how to:\n\n- Connect to the Blockless Network using the Blockless CLI\n- Read data from the standard input and environment variables using the memory module\n- Interact with the InterPlanetary File System (IPFS) using the ipfs module\n- Send HTTP requests and receive responses from servers using the http module\n- Use Amazon S3 to store data in the cloud using the awss3 module\n- Build the Todo Application\n\nBy the end of this tutorial, you will have a fully functional todo application that you can deploy and run on the Blockless Network. Let’s get started!\n\n## Connecting to the Blockless Network\n\nThe Blockless Command Line Interface (CLI) is a tool that allows you to interact with the Blockless Network and manage your applications from the command line.\n\nTo install the Blockless CLI, you can use the following command:\n\n```bash\n$ sudo sh -c \"curl https://raw.githubusercontent.com/BlocklessNetwork/cli/main/download.sh | bash\"\n```\n\nor\n\n```bash\n$ sudo sh -c \"wget https://raw.githubusercontent.com/BlocklessNetwork/cli/main/download.sh -v -O download.sh; chmod +x download.sh; ./download.sh; rm -rf download.sh\"\n```\n\nTo connect to the Blockless Network, you need to use the login command:\n\n```bash\n$ bls login\n```\n\nYou will be prompted to enter your on-chain identity and password. Enter the credentials that you created when you set up your account on the Blockless Network.\n\nOnce you are logged in, you can use the Blockless CLI to deploy and manage your applications on the network.\n\n```bash\n$ bls function deploy\n$ bls function list\n$ bls function logs\n```\n\nFor a complete list of available commands, you can use the help command:\n\n```bash\n$ bls help\n```\n\n## Reading from the Standard Input\n\nYou can use the memory.Stdin class to read data from the standard input. This can be useful if you want to pass data to your application when it is run.\n\n```tsx\nlet stdin = new memory.Stdin().read().toJSON();\nif (stdin) {\n  let results = stdin.get(\"results\");\n  if (results) {\n    let newValue = Number.parseFloat(results.toString()) + 1000;\n  }\n}\n```\n\n## Reading Environment Variables\n\nYou can use the memory.EnvVars class to read environment variables. This can be useful if you want to access configuration data or other global values.\n\n```tsx\nlet envVars = new memory.EnvVars().read().toJSON();\nif (envVars) {\n  let environmentValue = envVars.get(\"ENV_VAR_NAME\");\n  if (environmentValue) {\n    Console.log(\"Hello \" + environmentValue.toString());\n  }\n}\n```\n\n## Interacting with IPFS\n\nThe ipfs module in Blockless allows you to access and manipulate data stored on the IPFS network.\n\nTo use the ipfs module in your Blockless application, you need to import it in your main AssemblyScript file:\n\n```tsx\nimport { ipfs } from \"../assembly\";\n```\n\n## Listing Files and Directories\n\nYou can use the ipfs.ipfsFileList function to list the files and directories in a given path. The function takes a path as an argument and returns an array of file names.\n\nHere is an example of how to list the files and directories in the root directory:\n\n```tsx\nlet files = ipfs.ipfsFileList(\"/\");\nif (files != null)\n  Console.log(`Files and directories: ${files!.toString()}`);\n```\n\n## Removing Files and Directories\n\nYou can use the ipfs.ipfsFileRemove function to delete a file or directory from IPFS. The function takes a path, a flag for whether to delete recursively, and a flag for whether to force the delete as arguments. It returns a boolean indicating whether the delete was successful.\n\nHere is an example of how to delete the file or directory at the path “/1”:\n\n```tsx\nlet isDeleted = ipfs.ipfsFileRemove(\"/1\", true, true);\nConsole.log(`Delete successful: ${isDeleted}`);\n```\n\n## Creating Directories\n\nYou can use the ipfs.ipfsCreateDir function to create a new directory in IPFS. The function takes a path and a flag for whether to create the directory recursively as arguments. It returns a boolean indicating whether the directory was created successfully.\n\nHere is an example of how to create the directory at the path “/1”:\n\n```tsx\nlet isCreated = ipfs.ipfsCreateDir(\"/1\", true);\nConsole.log(`Directory creation successful: ${isCreated}`);\n```\n\n## Writing to Files\n\nYou can use the ipfs.ipfsFileWrite function to write data to a file in IPFS. The function takes a FileWriteOptions object and a Uint8Array of data as arguments. It returns a boolean indicating whether the write was successful.\n\nHere is an example of how to write the data [65, 66, 67, 68, 69, 70] (representing the ASCII values for the characters ‘ABCDEF’) to a file named “/2.txt”:\n\n```tsx\nlet filename = \"/2.txt\";\nlet wopts = new FileWriteOptions(filename);\nlet isWritten = ipfs.ipfsFileWrite(wopts, [65, 66, 67, 68, 69, 70]);\n console.log(`Write successful: ${isWritten}`);\n```\n\n## Reading from Files\n\nYou can use the ipfs.ipfsFileRead function to read data from a file in IPFS. The function takes a path, a starting position, and a Uint8Array to store the data as arguments. It returns the number of bytes read.\n\nHere is an example of how to read the data from the file “/2.txt”:\n\n```tsx\nlet buf = new Array\u003cu8\u003e(1024);\nlet numBytesRead = ipfs.ipfsFileRead(\"/2.txt\", 0, buf);\nlet data = String.UTF8.decodeUnsafe(buf.dataStart, numBytesRead);\n console.log(`Read ${numBytesRead} bytes: ${data}`);\n```\n\n## Getting File Stats\n\nYou can use the ipfs.ipfsFileStat function to get information about a file in IPFS, such as its size and creation time. The function takes a path as an argument and returns a FileStat object.\n\nHere is an example of how to get the file stats for the file “/2.txt”:\n\n```tsx\nlet fstat = ipfs.ipfsFileStat(\"/2.txt\");\nif (fstat != null) {\n  Console.log(`File stats for \"/2.txt\":`);\n  Console.log(`Size: ${fstat!.size}`);\n  Console.log(`Creation time: ${fstat!.ctime}`);\n}\n```\n\nThat concludes the tutorial section on interacting with IPFS using the ipfs module. You should now be able to list, remove, create, write to, read from, and get information about files and directories on the IPFS network.\n\n## Sending HTTP Requests\n\nThe http module in Blockless allows you to send HTTP requests and receive responses from servers.\n\nTo use the http module in your Blockless application, you need to import it in your main AssemblyScript file:\n\n```tsx\nimport { http } from \"../assembly\";\n```\n\nTo send an HTTP request, you can use the http.HttpOpen function. This function takes a URL and an HttpOptions object as arguments and returns an HttpHandle object.\n\nHere is an example of how to send a GET request to the URL “http://httpbin.org/anything”:\n\n```tsx\nlet handle = http.HttpOpen(\n  \"http://httpbin.org/anything\",\n  new http.HttpOptions(\"GET\")\n);\n```\n\n## Receiving HTTP Responses\n\nOnce you have sent an HTTP request and received an HttpHandle object, you can use various functions of the HttpHandle class to get information about the response.\n\nGetting the Response Headers You can use the HttpHandle.getHeader function to get the value of a specific response header. The function takes a header name as an argument and returns the value of the header as a string.\n\nHere is an example of how to get the “Content-Type” header from an HttpHandle object:\n\n```tsx\nlet contentType = handle.getHeader(\"Content-Type\");\n```\n\n## Getting the Response Body\n\nYou can use the HttpHandle.getAllBody function to get the entire response body as a string.\n\n```tsx\nlet body = handle.getAllBody();\n```\n\n## Closing the Connection\n\nOnce you have finished using an HttpHandle object, you should close the connection to the server by calling the HttpHandle.close\n\n```tsx\nhandle.close();\n```\n\nThat concludes the tutorial section on sending HTTP requests and receiving responses using the http module. You should now be able to send various types of HTTP requests, get information about the responses, and properly close the connections\n\n## Other Features\n\nThe http module also provides other features that you may find useful in your projects.\n\n### Setting Request Headers\n\nYou can set request headers when sending an HTTP request by passing an object with header name-value pairs as the third argument to the http.HttpOpen function.\n\n```tsx\nlet data = { message: \"Hello, world!\" };\nlet handle = http.HttpOpen(\n  \"http://httpbin.org/anything\",\n  new http.HttpOptions(\"POST\"),\n  { \"Content-Type\": \"application/json\" },\n  json.JSON.stringify(data)\n);\n```\n\n## Setting Up Amazon S3\n\nBefore you can use the awss3 module in your Blockless application, you need to set up an Amazon Web Services (AWS) account and create a bucket in Amazon S3.\n\n- Go to the AWS website and create an account.\n- Follow the instructions in the AWS documentation to create a bucket in Amazon S3.\n- Make note of your AWS access key ID and secret access key, which you will need to use the awss3 module.\n\n## Importing the Module\n\nTo use the awss3 module in your Blockless application, you need to import it in your main AssemblyScript file:\n\n```tsx\nimport { Bucket, S3Configure } from \"../assembly/awss3\";\n```\n\n## Connecting to Amazon S3\n\nTo connect to Amazon S3, you need to create a S3Configure object with your AWS access key ID, secret access key, and the endpoint of your bucket.\n\n```tsx\nlet s3Config = new S3Configure(\n  \"your-access-key-id\",\n  \"your-secret-access-key\",\n  \"your-bucket-endpoint\"\n);\n```\n\nThen, you can create a Bucket object with the name of your bucket and the S3Configure object.\n\n```tsx\nlet bucket = new Bucket(\"your-bucket-name\", s3Config);\n```\n\n## Storing Data in Amazon S3\n\nWith a Bucket object, you can use the Bucket.putObject function to store data in Amazon S3. The function takes a path\n\n```tsx\nlet data = [65, 66, 67, 68, 69, 70]; // ASCII values for 'ABCDEF'\nlet success = bucket.putObject(\"/path/to/file.txt\", data);\nif (success) {\n  Console.log(\"Data stored successfully in Amazon S3.\");\n} else {\n  Console.log(\"Error storing data in Amazon S3.\");\n}\n```\n\n## Retrieving Data from Amazon S3\n\nYou can use the Bucket.getObject function to retrieve data from Amazon S3. The function takes a path and returns a Uint8Array with the data.\n\n```tsx\nlet data = bucket.getObject(\"/path/to/file.txt\");\nif (data != null) {\n  Console.log(`Data retrieved from Amazon S3: ${data}`);\n} else {\n  Console.log(\"Error retrieving data from Amazon S3.\");\n}\n```\n\n## Listing Objects in a Bucket\n\nYou can use the Bucket.list function to get a list of objects in a bucket. The function takes a prefix as an argument and returns a string with the names of the objects separated by newlines.\n\n```tsx\nlet objects = bucket.list(\"/path/to/prefix\");\nif (objects != null) {\n  Console.log(`Objects in bucket with prefix \"/path/to/prefix\":`);\n  Console.log(objects);\n```\n\n## Deleting Objects in a Bucket\n\nYou can use the Bucket.deleteObject function to delete an object in a bucket. The function takes a path and returns a boolean indicating whether the delete was successful.\n\n```tsx\nlet success = bucket.deleteObject(\"/path/to/file.txt\");\nif (success) {\n  Console.log(\"Object deleted successfully from Amazon S3.\");\n} else {\n  Console.log(\"Error deleting object from Amazon S3.\");\n}\n```\n\nThat concludes the tutorial section on using the awss3 module to store data in Amazon S3. You should now be able to connect to your bucket, store data, retrieve data, list objects, and delete objects in your bucket.\n\n## Building the Todo Application\n\nCreating a New AssemblyScript Project with the Blockless CLI In this section, we will use the Blockless CLI to create a new project and set up an AssemblyScript environment. We will then install the necessary dependencies for our todo application and start building our code.\n\nFollow these steps to create a new AssemblyScript project with the Blockless CLI and set up your development environment:\n\n- Open a terminal and navigate to the directory where you want to create your project.\n- Run the bls function init command to create a new project with a default AssemblyScript configuration.\n\n```bash\n$ bls function init\n```\n\n- The bls function init command will create a new directory with the following structure:\n\n```\nmy-project/\n├── package.json\n├── assembly\n│   └── index.ts\n└── package-lock.json\n```\n\n- The package.json file contains the dependencies and scripts for your project. The assembly directory contains your AssemblyScript source code, and the package-lock.json file is used to manage the dependencies of your project.\n- To add the necessary dependencies for your project, open the package.json file and add the following dependencies:\n\n```json\n\"dependencies\": {  \"as-wasi\": \"^0.4.0\",  \"as-aws-s3\": \"^0.4.0\",  \"as-http\": \"^0.4.0\",  \"as-ipfs\": \"^0.4.0\",  \"as-memory\": \"^0.4.0\",  \"as-json\": \"^0.4.0\"},\n```\n\n- Save the package.json file and run the npm install command to install the dependencies.\n\n```bash\n$ npm install\n```\n\n- You are now ready to start building your AssemblyScript code in the assembly/index.ts file. You can use the memory, ipfs, http, and awss3 modules to interact with the Blockless Network and build your todo application.\n\n## Get Building!\n\nTo build the todo application, you will need to use the memory, ipfs, and http modules. You can start by importing these modules in your main AssemblyScript file:\n\n```tsx\nimport { memory } from \"../assembly\";\nimport { json, ipfs } from \"../assembly\";\nimport { http } from \"../assembly\";\n```\n\nNext, you can define a Todo class that represents a single todo item. The class should have a text field for the todo text and a completed field for the completion status. You can also define methods for reading and writing the todo from IPFS and for sending HTTP requests to update the todo status on the server.\n\n```tsx\nclass Todo {\n  text: string;\n  completed: boolean;\n\n  constructor(text: string, completed: boolean) {\n    this.text = text;\n    this.completed = completed;\n  }\n\n  // Reads the todo from IPFS\n  read(): Todo | null {\n    let data = ipfs.ipfsFileRead(\"/todo.json\");\n    if (data == null) {\n      return null;\n    }\n    let jsonString = String.UTF8.decodeUnsafe(data.dataStart, data.length);\n    let jsonObject = \u003cjson.JSON.Obj\u003ejson.JSON.parse(jsonString);\n    let kvs = jsonObject.valueOf();\n    if (kvs == null) {\n      return null;\n    }\n    let text = kvs.get(\"text\");\n    let completed = kvs.get(\"completed\");\n    if (text == null || completed == null) {\n      return null;\n    }\n    return new Todo(text, completed);\n  }\n\n  // Writes the todo to IPFS\n  write(): boolean {\n    let jsonObject = json.JSON.obj();\n    jsonObject.set(\"text\", this.text);\n    jsonObject.set(\"completed\", this.completed);\n    let jsonString = json.JSON.stringify(jsonObject);\n    let data = String.UTF8.encode(jsonString);\n    return ipfs.ipfsFileWrite(new ipfs.FileWriteOptions(\"/todo.json\"), data);\n  }\n\n// Sends an HTTP request to update the todo status on the server\n  update(): boolean {\n    let options = new http.HttpOptions(\"POST\", \"/update\");\n    options.setHeader(\"Content-Type\", \"application/json\");\n    let jsonObject = json.JSON.obj();\n    jsonObject.set(\"text\", this.text);\n    jsonObject.set(\"completed\", this.completed);\n    let jsonString = json.JSON.stringify(jsonObject);\n    let data = String.UTF8.encode(jsonString);\n    options.setBody(data);\n    let handle = http.HttpOpen(\"http://example.com\", options);\n    if (handle == null) {\n      return false;\n    }\n    let statusCode = handle.getStatusCode();\n    handle.close();\n    return statusCode == 200;\n  }\n}\n\n```\n\nWith the Todo class defined, you can now create the main function for your application. In this function, you can create a new Todo object and read it from IPFS. You can then display the todo text and a prompt for the user to enter a new status for the todo (either “completed” or “not completed”).\n\n```tsx\nexport function main(): void {\n  let todo = new Todo(\"Buy milk\", false).read();\n  if (todo == null) {\n    Console.log(\"Error reading todo from IPFS.\");\n    return;\n  }\n  Console.log(`Current todo: ${todo.text} (${todo.completed ? \"completed\" : \"not completed\"})`);\n  Console.log(\"Enter new status (completed/not completed):\");\n  let stdin = new memory.Stdin().read().toJSON();\n  if (stdin == null) {\n    Console.log(\"Error reading from standard input.\");\n    return;\n  }\n  let results = stdin.get(\"results\");\n  if (results == null) {\n    Console.log(\"Error reading from standard input.\");\n    return;\n  }\n  let status = results.toString();\n  if (status == \"completed\") {\n    todo.completed = true;\n  } else if (status == \"not completed\") {\n    todo.completed = false;\n  } else {\n    Console.log(\"Invalid status entered.\");\n    return;\n  }\n  if (!todo.write()) {\n    Console.log(\"Error writing todo to IPFS.\");\n    return;\n  }\n  if (!todo.update()) {\n    Console.log(\"Error updating todo on server.\");\n    return;\n  }\n  Console.log(\"Todo updated successfully.\");\n}\n```\n\nWith the main function defined, you can now build and run your todo application. You can use the Blockless CLI to compile your AssemblyScript code and deploy it to the Blockless Network.\n\n```bash\n$ bls function build$ bls function deploy\n```\n\nTo test your application, you can use the bls function invoke command to run the main function and interact with it via the command line.\n\n```bash\n$ bls function invokeCurrent todo: Buy milk (not completed)Enter new status (completed/not completed):completedTodo updated successfully.\n```\n\nCongratulations, you have now built a simple todo application using the Blockless Network! You can continue to build and improve your application by using other modules and features available in the Blockless ecosystem.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuditdc%2Fsample-todo-with-bls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuditdc%2Fsample-todo-with-bls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuditdc%2Fsample-todo-with-bls/lists"}