Projects β
Projects are serverless applications deployed to Web URLs. Projects in Netzo are programmed using Deno, a simple, modern and secure runtime for JavaScript and TypeScript. In essence, a project consist of collections of static files that are automatically hosted by netzo. Each Project is deployed to its own unique URL and ran globally at the network edge when an HTTP Request is made to its URL. netzo/lib
can be used within projects to make coding projects even simpler.
Listen to HTTP requests
Note that to make a project invokable at its edge URL, its entrypoint must register an HTTP server to listen to and respond to incoming HTTP requests. Otherwise, a project can still be used as a module to export code meant to be imported imported by other projects via their URL.
Creating Projects β
Head over to the Projects page within a Workspace and click the Create button.
Give a unique name for the project and select a starting template. We'll select the basic TypeScript example for now.
Add the necessary environment variables in the drawer to the right.
Project URLs β
Projects can be invoked via HTTP requests to any of:
- Production URL:
https://{uid}.netzo.io
- Preview URL:
https://{deploymentId}.netzo.io
Project UID
The project uid
MUST be globally unique, between 3-42 characters and contain only lowercase letters a-z
, numbers 1-9
and hyphens -
. You can change it in Project > Settings > General.
Deployments are booted on first request, not on deployment
Note that deploying a Project will save its latest changes but won't actually boot the new deployment until invoking it for the first time. Due to this, the first request after deployment could take a bit longer, following requests should be almost instant.
CORS Headers β
To be able to invoke a Project from the browser, you'll need to enable CORS. By default, CORS headers will be set to *
unless you specify otherwise in the Response
headers.
Header | Description | Default |
---|---|---|
access-control-allow-origin | a space-separated list of origins allowed to access the resource | * |
access-control-allow-methods | a comma-separated list of HTTP methods allowed to access the resource | * |
access-control-allow-headers | a comma-separated list of HTTP headers allowed to access the resource | * |
WARNING
If overwriting the default of *
for access-control-allow-origin
, include "https://app.netzo.io"
as allowed origin to be able to invoke the project from within Netzo, otherwise the request will be blocked by the browser automatically due to CORS.
For example, to allow all origins, methods and headers for the Project:
serve((_req: Request): Response => new Response("Hello World!"));
serve((_req: Request): Response => new Response("Hello World!"));
To allow only a specific origin, method or header you can overwrite the defaults of *
individually or all at once as follows:
serve((_req: Request): Response => new Response("Hello World!", {
headers: {
"access-control-allow-origin": "https://app.netzo.io",
"access-control-allow-methods": "GET, POST",
"access-control-allow-headers": "x-foo, x-bar"
}
}));
serve((_req: Request): Response => new Response("Hello World!", {
headers: {
"access-control-allow-origin": "https://app.netzo.io",
"access-control-allow-methods": "GET, POST",
"access-control-allow-headers": "x-foo, x-bar"
}
}));
Modules β
Modules are reusable code bundles distributed via URLs. Netzo makes it easy to author and deploy Modules on the click of a button. Modules can be private
or public
, in which case they can be imported by third-party scripts (without authentication).
import
allows you to include and use local or remote modules in your code.export
allows you to expose code to be imported by other modules.
Module resolution
Deno adopts browser-like module resolution, meaning that file names must be specified in full. File extensions are are used to serve file contents with the appropriate Content-Type
header. If no Content-Type
header is present, it will be resolved based on its extension. For example, a file named foo.ts
will be served with Content-Type: application/typescript
.
No special treatment for index.(ts|js)
Deno encourages using mod.(ts|js)
as the module entry point, as there is no special handling for index.(ts|js)
paths. This is to avoid the common practice of importing files by ommiting the index.(ts|js)
filename (common in Node.js), which goes against web URL semantics.
Import Maps β
Import maps allows control over what URLs get fetched by import
statements and import()
expressions. They can be thought of as shortcuts to map short and memorable aliases to (longer) import URLs. Deno will resolve imports based on an import_map.json
file.
{
"imports": {
"netzo/": "https://deno.land/netzo/"
}
}
{
"imports": {
"netzo/": "https://deno.land/netzo/"
}
}
The location of the import_map.json
file can be set via the importMap
field of deno.json
. By default, this is the root of the Deno module.
Hosting β
Netzo will automatically host all your modules under https://api.netzo.io/deployments/{id}/{...path}
with path
being a valid file path including etension (e.g. components/Table.tsx
). Files will be served with their corresponding Content-Type
header by Netzo, for example text/html
for .html
files.
Module best practices
For simpler modules it is recommended to have a single mod.(ts|js)
file at the module entry point. When modularizing a larger module, it adviced to keep the mod.(ts|js)
entry point as lean as possible (using only import
/export
statements), keeping business logic in other files.
Publishing β
Modules can also be published to the Deno ecosystem via the official https://deno.land/x hosting service. It caches releases of open source modules and serves them at one easy to remember domain. Navigate to their official docs to learn more.
Runtime Environment β
Runtime APIs β
The following Web and Deno APIs are supported on the runtime.
- addEventListener
- Cache
- Durable Objects
- Encoding
- Fetch
- FetchEvent
- Headers
- HTMLRewriter
- KV
- Request
- Response
- ScheduledEvent
- Streams
- Web Crypto
- Web standards
- WebSockets
- eval()
- new Function()
INFO
To learn more, you can always head over to the Deno documentation
(Virtual) Filesystem β
Projects have access to a read-only virtual filesystem that is scoped to the Project's files and mounted at file:///src/
. Reading outside of the project root is not allowed.
Netzo supports a limited set of the file system APIs available in Deno. These file system APIs can access static files from your deployments.
The APIs that are available are:
Deno.cwd
returns the current working directory of your deployment.Deno.readDir
allows listing the contents of a directory.Deno.readFile
allows reading a file into memory.Deno.readTextFile
allows reading a file into memory (decoded as UTF-8 string).Deno.open
allows opening a file, returning a file handleDeno.stat
reads a file system entry's metadata.Deno.lstat
reads a file system entry's metadata (without following symlinks).Deno.realPath
reads a file system entry's metadata (without following symlinks).Deno.readLink
returns the target path for a symlink.
Absolute file paths must be passed as a URL
object
On unix "file:///..."
is treated as a relative path, therefore absolute file paths must be passed as a URL
object new URL("file:///...")
instead of a string "file:///..."
.
For example, a file example.txt
at the project root can be read in multiple ways:
await Deno.readTextFile("example.txt");
await Deno.readTextFile("./example.txt");
await Deno.readTextFile("/src/example.txt");
await Deno.readTextFile("file:///src/example.txt"); // β throws error
await Deno.readTextFile(new URL("file:///src/example.txt"));
await Deno.readTextFile("example.txt");
await Deno.readTextFile("./example.txt");
await Deno.readTextFile("/src/example.txt");
await Deno.readTextFile("file:///src/example.txt"); // β throws error
await Deno.readTextFile(new URL("file:///src/example.txt"));
Refer to the Deno documentation for more information.
Import Assertions for JSON modules
Note that .json
files can be imported via import assertions with the assert
keyword:
import data from "./data.json" assert { type: "json" };
import data from "./data.json" assert { type: "json" };
This is equivalent to reading the file and parsing it as JSON:
const data = JSON.parse(await Deno.readTextFile("./data.json"));
const data = JSON.parse(await Deno.readTextFile("./data.json"));
Regions β
Netzo deploys projects globally to the edge. Each new Request is served from the closest region to the client making the request. The following regions are available:
- Taiwan:
asia-east1
- Taiwan:
- Hong Kong:
asia-east2
- Hong Kong:
- Tokyo:
asia-northeast1
- Tokyo:
- Osaka:
asia-northeast2
- Osaka:
- Seoul:
asia-northeast3
- Seoul:
- Mumbai:
asia-south1
- Mumbai:
- Delhi:
asia-south2
- Delhi:
- Singapore:
asia-southeast1
- Singapore:
- Jakarta:
asia-southeast2
- Jakarta:
- Sydney:
australia-southeast1
- Sydney:
- Melbourne:
australia-southeast2
- Melbourne:
- Warsaw:
europe-central2
- Warsaw:
- Finland:
europe-north1
- Finland:
- Belgium:
europe-west1
- Belgium:
- London:
europe-west2
- London:
- Frankfurt:
europe-west3
- Frankfurt:
- Netherlands:
europe-west4
- Netherlands:
- Zurich:
europe-west6
- Zurich:
- Milan:
europe-west8
- Milan:
- Paris:
europe-west9
- Paris:
- Tel Aviv:
me-west1
- Tel Aviv:
- Madrid:
europe-southwest1
- Madrid:
- MontrΓ©al:
northamerica-northeast1
- MontrΓ©al:
- Toronto:
northamerica-northeast2
- Toronto:
- SΓ£o Paulo:
southamerica-east1
- SΓ£o Paulo:
- Chile:
southamerica-west1
- Chile:
- Iowa:
us-central1
- Iowa:
- South Carolina:
us-east1
- South Carolina:
- North Virginia:
us-east4
- North Virginia:
- Ohio:
us-east5
- Ohio:
- Texas:
us-south1
- Texas:
- Oregon:
us-west1
- Oregon:
- California:
us-west2
- California:
- Utah:
us-west3
- Utah:
- Nevada:
us-west4
- Nevada:
This list will be updated as new regions are added.