C&C Docs
Log in
Tooling

Getting started

Everything on the other pages starts with one binary, cnc: it scaffolds an app, serves it while you edit, runs its tests and ships it. A command line is not something a page can run, so the steps below are terminal output, shortened.

1. cnc new — a working app

No account and no network needed. The tree has a page, a layout, a schema with seed rows, two services, and a test beside the page and the service.

$ cnc new app shop
created app in ~/shop

$ cd shop && find . -type f -not -name '.*' | sort
./blocks/index.html
./blocks/index.mjs
./blocks/index.test.ts
./cnc.json
./migrations/001-starter.json
./seeds/User.json
./seeds/_Translation.json
./services/greeter.json
./services/greeter.mjs
./services/greeter.test.ts
./services/heartbeat.json
./services/heartbeat.mjs
./templates/default.html
./tsconfig.json

2. cnc dev — serve it and edit

Open the address and edit a file. Save blocks/about.html and /about exists; an open page reloads by itself. A file that does not compile breaks only its own route, which answers with the file and the reason, and the next save is the fix.

$ cnc dev
cnc dev: closure held in memory
cnc dev: serving ~/shop on http://localhost:3000
cnc dev: the registry is https://cloud.clickncode.com (the built-in default)
$ curl -i http://localhost:3000/broken
HTTP/1.1 500 Internal Server Error
content-type: text/plain; charset=utf-8

blocks/broken.html: cannot compile: return (((()

3. cnc test — check it

A test sits beside what it tests and says its kind by the function it calls: test.block asks for a page through the whole serving path, test.widget, test.service and test.browser do the same for theirs. Each test gets a freshly seeded database of its own.

// blocks/index.test.ts — beside the page it tests
import { test } from '@cnc/test'

test.block('the page answers', async (t) => {
  const page = await t.get('/')
  t.expect(page.status).to.equal(200)
  t.expect(page.find('h1').exists).to.be.true
})
$ cnc test
✓ blocks/index.test.ts  the page answers
✓ blocks/index.test.ts  a visitor is nobody, and a person is who they are
✓ services/greeter.test.ts  greet says hello to whoever is named
✓ services/greeter.test.ts  the greeting is the secret the deployment holds
✓ services/greeter.test.ts  lookup reaches the host greeter.json declares, faked here
5 passed, 0 failed, 0 skipped, 1.0s

4. cnc deploy — ship it

Sign in once, then deploy: the app is served from the hosted platform with its own database. Deploying keeps a version private; publishing it to the registry lets other people find it, fork it with cnc new, or depend on it as a module.

$ cnc login                    # asks for your address and password
$ cnc deploy                   # sends the tree, privately, and prints its address
$ cnc deploy --host shop.example.com
$ cnc registry publish         # puts this version in front of people
$ cnc version patch            # the next change: bump, then deploy again