@htfn/cli
v0.1.7
Published
Hypertext Functions (HTFN) CLI (Alpha). To view our terms of service, please run: htfn terms
Readme
Hypertext Functions (Alpha)
JavaScript Functions that Speak HTTP
Create JavaScript (or TypeScript) functions that run in the cloud. Start building APIs, websites and single page applications in just a few key presses.
Build hypertext functions like this in seconds:
// myfunc.ts
export default function (req: Request) {
return Response.json({ message: "Hellorld!", url: req.url });
}Deploy the function immediately, no build step required: 🚀
htfn deploy myfunc ./myfunc.ts🥁 Drumroll please... https://myfunc-7klq1kn1srxlcmhm.fn.htfn.io
Platform
Hypertext functions do not run inside NodeJS, they use Google V8 directly, so functions cannot call any of the NodeJS APIs. This here is WinterCG country 🦇
Not all WinterCG runtime APIs are implemented (yet), but this is work in progress. At the moment, you can use the following:
fetch()console.*localStorage.*self.crypto.randomUUID()self.crypto.getRandomValues()setTimeout()setInterval()btoa()atob()TextDecoderTextEncoder
Please note that all assets (css, images, JavaScript bundles, etc.) are aggressively HTTP cached. It's best to implement
cache busting techniques. We use private caching, so
if you're iteratively building a function you can just temporarily turn your browser cache off.
This is alpha software and may be prone to bugs. Please be advised that your data is at risk and may be lost without warning. By using Hypertext Functions you agree with our terms of service.
Limitations
Hypertext Functions is currently a completely free service. The following limitations apply:
- Maximum of 3 hypertext functions per account
- Maximum of 1,000,000 versions per function
- Maximum of 500Mb of stored assets per account (including function code)
- Maximum of 100Mb of local storage per account
- Maximum of 20 calls per 30 seconds to
fetch()(per organisation) - Maximum of 10 custom domains
- Maximum of 80 environment variables
- 128Mb of memory per function call
- Timeout of 6 seconds per function call
Installation
Install Hypertext Functions CLI globally:
npm install -g @htfn/cli
htfn loginOr run directly via npx:
npx @htfn/cli loginIf your browser doesn't automatically open when logging in, use the following flag to get the login URL and copy/paste that into your browser instead:
htfn login --url
# or
npx @htfn/cli login --urlIMPORTANT: Hypertext Functions CLI tool requires NodeJS version >= 18.0.0
If you have a static token (used for things like CLI processes) you can provide an access token via the HTFN_TOKEN
environment variable and this will bypass login:
HTFN_TOKEN=<your_token> htfn whoamiGetting Started
Create a simple JavaScript hypertext function file with the following contents:
// hellorld.js
export default function (request) {
const name = new URL(request.url).searchParams.get('name') ?? 'World';
return Response.json({
message: `Hello ${name}`,
});
}Login to the Hypertext Functions service (authorization is currently only via GitHub - so you'll need a GitHub account to proceed).
htfn login
# or use this flag to get the login URL instead
htfn login --urlDeploy the function that we defined above.
htfn deploy hellorld ./hellorld.jsIf the deployment was a success, you'll be presented with a set of URLs to access your new function. The URL will look something like this:
https://hellorld-68efe810aa4648b8.fn.htfn.io/?name=JoeMonitor the logs for a hypertext function. Logs contain messages from console.log() as well as system events:
htfn log tail hellorldFunctions
List Functions
List all of your deployed functions:
htfn listFilter functions by name:
htfn list --filter=hellorldDisplay more information about each function in the list:
htfn list --extendedGet the list of functions as JSON:
htfn list --jsonList Function Versions
List versions of a particular hypertext function:
htfn versions hellorldFilter function versions by contents of the push message:
htfn versions hellorld --filter="critical update"Display more information about each function version in the list:
htfn versions hellorld --extendedGet the list of function versions as JSON:
htfn versions hellorld --jsonBuild a Function
Build and bundle a given function, sending the built JavaScript to stdout:
htfn build ./hellorld.jsHypertext Functions CLI tool is also bundled with ESBuild, so you can build TypeScript functions too :)
htfn build ./hellorld.tsPushing Function Versions
When you want to build and upload a new function version without making the new version "production":
htfn push hellorld ./hellorld.tsPush the new version with an associated message:
htfn push hellorld ./hellorld.ts --message="did some stuff and things"Push a new function version without building first, just upload the function as-is:
htfn push hellorld ./hellorld.ts --no-buildBuild & push a new function version, then promote the new version to "production":
htfn push hellorld ./hellorld.ts --promoteSometimes you may have a frontend bundle that your function may access when running in the client. E.g. let's say you build a server-side rendered ReactJS SPA that has some client-side code, you can build, bundle and push this as an asset too:
Note that the "client" file, in this case
App.tsx, must be in the root of your function directory
htfn push hellorld ./hellorld.ts --client=./App.tsxPromote
Promote any version of a hypertext function to be the "production" version.
Promote the "latest" function version to production:
htfn promote hellorld --latestPromote a particular function version to production, by passing the version ID:
htfn promote hellorld --version=TuetYWNHhmuSQ3xPoVLv9MPrune
You can prune a given hypertext function, whereby all non-production versions will be permanently deleted:
htfn prune hellorldUpload Assets
You may also upload a directory of assets (e.g. images, fonts, etc.) that will be served from the root of your function URL:
Note that in the following example there's a directory named
assetscontaining the assets you wish to upload
htfn push hellorld ./hellorld.ts --assets=./assetsDeploying
Putting it altogether - instead of building, pushing and promoting as separate commands, you can simply run the deploy
command to perform all of these things at once; build, push & promote at the same time:
htfn deploy hellorld ./hellorld.ts --assets=./assets --client=./App.tsxRemoving
You can permanently delete functions by removing them like so:
htfn remove hellorldWhere hellorld is the name of your function.
If you like to live dangerously, you can forcefully remove functions immediately:
htfn remove hellorld --forceDomains
You can add arbitrary domains to your hypertext functions, making your function production versions easier and more
memorable to access. At the moment, you can only add subdomains of htfn.io.
Add a Domain
Add a domain to the existing hypertext function, hellorld:
htfn domains add hellorld myfunction.htfn.ioList Domains
List domains for the hypertext function, hellorld:
htfn domains list hellorldRemove a Domain
Remove a domain from the hypertext function, hellorld:
htfn domains remove hellorld myfunction.htfn.ioEnvironment Variables
You can add the following types of environment variables:
- Organisation - env vars available to all of your hypertext functions
- Function - env vars available to a particular hypertext function
Function env vars trump organisation env vars. All env vars are strings.
Environment vars may be accessed via the process.env object in your hypertext function, like so:
export default function () {
return Response.json({ my_var_one: process.env.MY_VAR_ONE });
}Set Environment Variables
In order to set a value for MY_VAR_ONE:
# Set function env var
htfn env set func hellorld -e MY_VAR_ONE='val1'
# Set the same env var at organisation level
htfn env set org -e MY_VAR_ONE='val1'List Environment Variables
List env vars for a particular function:
htfn env list func hellorldList env vars for a your organisation:
htfn env list orgRemove Environment Variables
Remove a function env var
htfn env remove func hellorld -e MY_VAR_ONERemove an organisation env var
htfn env remove org -e MY_VAR_ONELogs
You can watch the tail of a particular hypertext function's log:
Tailing Logs
htfn log tail hellorldFilter by log level:
htfn log tail hellorld --level=errorOutput JSON:
htfn log tail hellorld --jsonOnly show log entries from a given date/time:
htfn log tail hellorld --from="2024-02-26 15:08:18"Search Logs
You can search the log by request ID (found in the response header of a called function):
htfn log find FRAMwPMUKfX8kmwDyW8Evc Output JSON:
htfn log find FRAMwPMUKfX8kmwDyW8Evc --jsonFilter by log level:
htfn log find FRAMwPMUKfX8kmwDyW8Evc --level=errorMiscellaneous
Some other hypertext function CLI commands that don't quite fit the categories above.
My Profile
Get details about your Hypertext Functions account and profile
htfn whoamiLogout
Log out of all of your active sessions, deleting all sessions in the process:
htfn logoutTerms of Service
View the Hyptertext Functions terms of service (opens in your browser):
htfn termsContact Us
Opens the Hypertext Functions contact form in your browser:
htfn contactFunction Examples
Some hypertext function ideas to get you started :)
Simple JSON Response
// simplejson.ts
export default function (req: Request): Response {
return Response.json({ message: "Hellorld!" });
}htfn deploy simplejson ./simplejson.tsSimple HTML Response
// simplehtml.ts
export default function (req: Request): Response {
return new Response(`<strong>Hellorld!</strong>`, { headers: {
"content-type": "text/html",
}});
}htfn deploy simplehtml ./simplehtml.tsSimple Fetch
// simplefetch.ts
export default async function (req: Request) {
const res = await fetch("https://example.com");
return new Response(await res.text(), { headers: {
"content-type": "text/html",
}});
}htfn deploy simplefetch ./simplefetch.tsWhat's My IP?
// myip.ts
export default function (req: Request) {
return Response.json({
your_ip: req.headers.get('x-real-ip'),
});
}htfn deploy myip ./myip.tsStorage
// storage.ts
export default function (req: Request) {
const message = new URL(req.url).searchParams.get('message') ?? 'default message';
// Make use of the full localStorage API, not just setItem() :)
// The local storage item "my_message" will be available in all of your hypertext functions
localStorage.setItem("my_message", message);
return Response.json({ message: localStorage.getItem("my_message") });
}htfn deploy storage ./storage.tsRandom v4 UUID
// randomuuid.ts
export default function (req: Request) {
return Response.json({
random_uuid: self.crypto.randomUUID(),
});
}htfn deploy randomuuid ./randomuuid.tsHono Framework
Use the Hono framework to build a REST API:
npm init
npm install hono// hono.ts
import { Hono } from 'hono';
const app = new Hono();
app.get('/users', (c) => c.json([{ name: 'Joe Bloggs' }]));
export default app.fetch;htfn deploy hono ./hono.tsMore examples to follow...
