Project

Projects: a repo deployed to a URL, with what the running app needs.

repo = noclick.Repo.from_name("booking", create_if_missing=True)
app = noclick.Project.from_name("booking", repo=repo, create_if_missing=True)
app.bind("DB", noclick.Database.from_name("booking-db", create_if_missing=True))
app.secrets.set("MAPS_API_KEY", "...")
deployment = app.deploy().wait()
print(deployment.url)   # https://booking.noclick.site

A deploy of the production branch goes live at app.url; any other branch gets a preview URL of its own. Bindings, secrets and schedules apply from the next deployment.

Inside the running app, noclick.Project.current() is the app itself, signed in by its deployment (no key in the app's code), and the whole client acts as a key of the app's user: app.database("DB") reaches what it's bound to, noclick.Agent.from_name(..., create_if_missing=True) makes what it needs, app.ai and app.agent("SUPPORT") think and talk as the app, and app.verify_request(...) checks a scheduled request. What the app spends counts toward its budget_usd_per_month ($10 unless set) and its user's cap.

class Project

An app: a repo deployed to a URL. Project.fromName("booking", { repo, createIfMissing: true }) is lazy; project.deploy() builds and ships it.

Attributes
idstring
namestring
urlstring

Its production URL (https://<name>.noclick.site until a domain serves it).

hostnamestring

Its own name under NoClick's user-sites domain (booking.noclick.site), which never changes (NoClick moves only an app it publishes, when it's renamed where it was published from).

repoIdstring | null

Null for an app NoClick publishes (published).

publishedboolean

NoClick publishes its files itself (an automation's interface): it has no repo, and deploys when it's published again from there.

workflow{ id: string; name: string | null } | null

The automation it was published from, or null for every other app.

runtimeProjectRuntime

auto (each deployment runs where its commit says: Deployment.runtime), edge (JavaScript frameworks and files) or container (any server, in any language).

frameworkstring | null

On edge: nextjs, remix, astro, vite or static; on container: python, node or docker (the repo's own Dockerfile); under auto either, which names its runtime. Detected at each build when None.

productionBranchstring

The branch whose deploys go live.

domainNamesstring[]

The live hostnames of the domains serving it, oldest first; domains() loads the domains.

deployOnPushDeployOnPush

What a push to its repo deploys by itself: off, production or all.

previewResourcesPreviewResources

branch: each preview branch gets its own copy of every resource its code names, made the first time it writes to one (until then it reads production's), so preview data never reaches production; shared: previews use production's resources. New apps start with branch.

budgetUsdPerMonthnumber | null

The most it may spend in a calendar month, in US dollars: $10 unless its maker set another; null only for an app NoClick publishes.

checkPathsstring[]

The paths a Deployment.check() loads when it names none, and what a promote checks before production switches to a release (empty: promotes aren't checked).

regionRegionName | null

The region its server code is placed near, fixed when it was created.

userIdstring | null
createdAtDate | null
productionDeployment | null

The deployment serving url (null before the first production deploy).

repoRepo | null

The repo it deploys from (null for an app NoClick publishes).

secretsProjectSecrets

Its secrets: app.secrets.set("MAPS_API_KEY", "...").

settingsProjectSettings

Its plain settings: project.settings.set("PUBLIC_BASE_URL", "...").

emailProjectEmail

Transactional email from the app.

paymentsProjectPayments

Payments into an account the owner claims.

signInProjectSignIn

Sign-in for the app's own users.

aiProjectAI

AI acting as the app, from its own code: app.ai.chat(...).

createstatic

static create(name: string, options?: ProjectCreateOptions): Promise<Project>

Create a project (unique per user; a duplicate throws Conflict with existingId) that deploys repo, or a new, empty repo of the same name when omitted. Nothing is deployed until deploy().

Parameters
namestringrequired
options.repoRepo | string

The repo it deploys (a Repo or its id); a new, empty repo of the project's name when omitted.

options.runtimeProjectRuntime

auto (the default) runs each deployment where its commit says: on the edge (a wrangler config naming its entry, a JavaScript framework, or only files: server code in isolates, static files served from everywhere) or in a container that scales to zero (a Dockerfile, or a server in another language: Flask, Django, Go, or a Node server with a start script), and the deployment says which and why. edge or container pins it there whatever the commit has.

options.frameworkstring

On edge: nextjs, remix, astro, vite or static; on container: python, node or docker (the repo's own Dockerfile); under auto either, which names its runtime. Detected from the repo at each build when omitted.

options.productionBranchstring

The branch whose deploys go live; the repo's default branch when omitted.

options.budgetUsdPerMonthnumber | null

The most the app may spend in a calendar month, in US dollars: hosting and builds, its calls to what it's bound to, its email, its AI and its agent turns. Every app gets one: $10 unless you pass another (an agent making a site sets one that fits it). At it the app's paid calls stop and its pages keep serving; at twice it its pages pause. In fromName, null removes it.

options.regionRegionName

The region its server code is placed near (regions()), for good: put it with the database it binds, so its queries stay short. Omitted, your account's default region, else us-east; its static files are served from everywhere. It says where the code runs, not where data stays (that's the database's and bucket's region). An existing app elsewhere makes fromName throw Conflict naming its region.

options.deployOnPushDeployOnPush

What a push deploys by itself: off (the default: only deploy() deploys), production (a push to the production branch deploys it) or all (a push to any other branch deploys a preview too).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The new project, loaded. Nothing is deployed until deploy().

fromNamestatic

static fromName(
  name: string,
  options?: ProjectCreateOptions & { createIfMissing?: boolean },
): Project

A lazy reference to the project called name for the current (or given) user. With createIfMissing your code is the definition: it's created on first use, and an existing project whose repo, runtime, framework, production branch, budget or deployOnPush differ is updated to match (one you leave out is never changed).

Parameters
namestringrequired
options.repoRepo | string

The repo it deploys (a Repo or its id); a new, empty repo of the project's name when omitted.

options.createIfMissingboolean
options.runtimeProjectRuntime

auto (the default) runs each deployment where its commit says: on the edge (a wrangler config naming its entry, a JavaScript framework, or only files: server code in isolates, static files served from everywhere) or in a container that scales to zero (a Dockerfile, or a server in another language: Flask, Django, Go, or a Node server with a start script), and the deployment says which and why. edge or container pins it there whatever the commit has.

options.frameworkstring

On edge: nextjs, remix, astro, vite or static; on container: python, node or docker (the repo's own Dockerfile); under auto either, which names its runtime. Detected from the repo at each build when omitted.

options.productionBranchstring

The branch whose deploys go live; the repo's default branch when omitted.

options.budgetUsdPerMonthnumber | null

The most the app may spend in a calendar month, in US dollars: hosting and builds, its calls to what it's bound to, its email, its AI and its agent turns. Every app gets one: $10 unless you pass another (an agent making a site sets one that fits it). At it the app's paid calls stop and its pages keep serving; at twice it its pages pause. In fromName, null removes it.

(omit to leave it unchanged)
options.regionRegionName

The region its server code is placed near (regions()), for good: put it with the database it binds, so its queries stay short. Omitted, your account's default region, else us-east; its static files are served from everywhere. It says where the code runs, not where data stays (that's the database's and bucket's region). An existing app elsewhere makes fromName throw Conflict naming its region.

options.deployOnPushDeployOnPush

What a push deploys by itself: off (the default: only deploy() deploys), production (a push to the production branch deploys it) or all (a push to any other branch deploys a preview too).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A project that loads (or is created, or brought in step with your definition) the first time it's used. Nothing is sent yet.

currentstatic

static current(options?: { client?: NoClick }): Project

The app this code runs in, from inside a deployment. NoClick puts the deployment's own credential in its environment (NOCLICK_DEPLOYMENT_TOKEN), so the app's code holds no key, and the whole client (Agent, Database, AI, ...) acts as a key of the app's user, attributed to the app. What its code makes or buys (a phone number, a domain) is the app's own; its user's other resources it reads and uses but never changes or deletes (on one bound to the app, it may clear its data); it never reaches another app, another user or what another app's code made, and never mints keys, sets a cap or budget, changes policy, answers approvals, accepts terms for a person or reads secrets' values (PermissionDenied). What it spends, buys (each renewal too) and starts that bills later (its numbers' calls and texts, its automations, MCP servers, channels, machines and cards) counts toward the app's budget: a purchase must fit what's left of it, and one in a person's name throws ApprovalRequired until they approve it. The app's code decides who may make it do what: policy doesn't judge its calls. Outside a deployment it throws Unauthenticated; pass client to act with a key of your own instead.

Parameters
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The app, loaded on first use. Nothing is sent yet.

fromIdstatic

static fromId(projectId: string, options?: CallOptions): Project

A lazy reference to a project by id.

Parameters
projectIdstringrequired
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
Returns

A project that loads the first time you read a field. Nothing is sent yet.

getstatic

static get(projectId: string, options?: CallOptions): Promise<Project>

Load a project by id now; an unknown id raises noclick.NotFound.

Parameters
projectIdstringrequired
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The project, loaded, with its production deployment.

liststatic

static list(options?: ReadOptions & { limit?: number }): Promise<Project[]>

The current user's projects (the account's own outside asUser, or those userFilter covers).

Parameters
options.limitnumber

Return at most this many.

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

Every matching project, newest first, fetched page by page, each with its production deployment.

listPagestatic

static listPage(options?: ReadOptions & PageOptions): Promise<Page<Project>>

One page of projects; pass nextCursor back as cursor.

Parameters
options.cursorstring | null

The next_cursor of the page before; omit it for the first page.

options.limitnumber

Return at most this many.

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A page whose data holds the projects and whose next_cursor is None on the last page.

analyticsSummarystatic

static analyticsSummary(
  options?: ReadOptions & { period?: AnalyticsPeriod; tz?: string },
): Promise<AnalyticsSummary>

Every app's requests over the last period (7d by default) and how many failed, in one read however many apps there are: each production site's, over the same window analytics reads, its days starting in tz (UTC when omitted). Which apps: the current user's, or those userFilter covers, as list. Requests, not visitors.

Parameters
options.periodAnalyticsPerioddefault "7d"
options.tzstring
options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

Its AnalyticsSummary: one line per app, newest first.

update

update(
  changes: {
    repo?: Repo | string;
    runtime?: ProjectRuntime;
    framework?: string | null;
    productionBranch?: string;
    budgetUsdPerMonth?: number | null;
    deployOnPush?: DeployOnPush;
    previewResources?: PreviewResources;
    checkPaths?: string[];;
  },
): Promise<this>

Change the repo it deploys, its runtime, its framework (null: detected at each build), its productionBranch, its budgetUsdPerMonth (an app with code always has one: null throws InvalidRequest), what a push deploys (deployOnPush), the paths a promote checks first (checkPaths, up to 10, each starting with /; [] stops checking) or whether previews get their own resources (previewResources: branch or shared). A new repo, runtime, framework or branch applies from the next deployment (what's live keeps serving where it runs until then), the rest at once; its user's cap still applies either way. A field you leave out is unchanged. Pinning a runtime the app's framework doesn't run on throws InvalidRequest: change the framework with it.

Parameters
changes{ repo?: Repo | string; runtime?: ProjectRuntime; framework?: string | null; productionBranch?: string; budgetUsdPerMonth?: number | null; deployOnPush?: DeployOnPush; previewResources?: PreviewResources; checkPaths?: string[]; }required
Returns

This app, updated. A field you leave out is unchanged.

deploy

deploy(
  options?: { branch?: string; commit?: string },
): Promise<Operation<Deployment>>

Build and deploy branch (the production branch when omitted) at its head, or at commit. wait() resolves to the ready Deployment; a failed build rejects with OperationFailed, whose details.deployment_id names the deployment to read the build log of.

Parameters
options.branchstring
options.commitstring
Returns

An operation whose .wait() gives the Deployment, ready. A failed build raises noclick.OperationFailed, whose deployment_id names the deployment to read the build log of.

deployments

deployments(
  options?: { branch?: string; limit?: number },
): Promise<Deployment[]>

Its deployments, newest first: limit of them (20 by default), of every branch or of branch.

Parameters
options.branchstring
options.limitnumber

Return at most this many.

(default 20)
Returns

Up to limit deployments (20 by default; None for all), fetched page by page.

rollback

rollback(to: Deployment | string): Promise<Operation<Deployment>>

Serve an earlier ready deployment at url again, without rebuilding: one routing change, live within a minute (to.promote()). It covers the app's last 10 production deployments; an older one is built again from its commit.

Parameters
toDeployment | stringrequired
Returns

An operation whose .wait() gives that deployment (or, past the window, the one built from its commit), now production.

bind

bind(
  name: string,
  resource: Bindable | string,
  options?: { kind?: BindingKind },
): Promise<Binding>

Give the app resource under name: a Database, Bucket, Connection, Dict, Queue, Secret or Agent, or its id with kind. Binding a name again replaces what it pointed at; it takes effect at the next deployment. An agent is the app's user's own or one of your account's, and the app talks to it as itself (see agent).

Parameters
namestringrequired
resourceBindable | stringrequired
options.kindBindingKind
Returns

The binding, naming the resource.

bindings

bindings(): Promise<Binding[]>

What the app is given, by name.

Returns

Each binding with the resource it names.

unbind

unbind(name: string): Promise<void>

Take name away from the app at the next deployment; the resource itself is kept.

Parameters
namestringrequired

database

database(name: string): Promise<Database>

The database bound to the app as name (from the app's own code, Project.current(), or yours).

Parameters
namestringrequired
Returns

The noclick.Database; a name bound to something else raises noclick.InvalidRequest, an unbound one noclick.NotFound.

bucket

bucket(name: string): Promise<Bucket>

The bucket bound to the app as name.

Parameters
namestringrequired
Returns

dict

dict(name: string): Promise<Dict>

The dict bound to the app as name.

Parameters
namestringrequired
Returns

queue

queue(name: string): Promise<Queue>

The queue bound to the app as name.

Parameters
namestringrequired
Returns

connection

connection(name: string): Promise<Connection>

The connection bound to the app as name: the app runs its operations as the account that connected it.

Parameters
namestringrequired
Returns

agent

agent(name: string): Promise<Agent>

The agent bound to the app as name. From the app's own code it acts as the app: message, send and ask start turns in the app's own conversations, and history and conversations read only those. A key the app passes (visitor-91c2) always names a thread of the app's (app:<app id>:visitor-91c2 to your own key, which reads it; no other app reaches it). The agent's policy still judges its tool calls, and its turns are billed like any turn, attributed to the app. Anything else (update, delete, its triggers, memory, wake-ups or children) throws PermissionDenied from the app, unless its code made the agent. A preview's code talks to it in threads of the preview's own (app-preview:<app id>:<key>), its tools answering from a simulated world; no app's code talks to an agent holding the noclick tool.

const assistant = await Project.current().agent("ASSISTANT");
const reply = await assistant.message(text, { conversation: visitorId });
Parameters
namestringrequired
Returns

verifyRequest

verifyRequest(
  payload: string | Uint8Array | ArrayBuffer,
  headers: WebhookHeaders,
  options?: { toleranceS?: number },
): Promise<void>

Check that a request to the app came from one of its schedules: payload is the raw body exactly as it arrived, headers its headers. Its NoClick-Signature is checked against the app's signing secret, which NoClick sets in the deployment's environment (NOCLICK_SIGNING_SECRET); a timestamp more than toleranceS (300) from now is refused. Sends nothing; throws WebhookSignatureError.

await app.verifyRequest(await request.text(), request.headers);
Parameters
headersWebhookHeadersrequired
payloadstring | Uint8Array | ArrayBufferrequired
options.toleranceSnumberdefault 300

schedule

schedule(
  cron: Cron,
  options: { path: string; name?: string },
): Promise<Schedule>

POST path on the app on every tick of cron. A schedule is keyed by name (the path when omitted), so calling this again with the same one updates it rather than adding another.

Parameters
cronCronrequired
options.pathstringrequired
options.namestring
Returns

The schedule, active, with its next_run.

schedules

schedules(): Promise<Schedule[]>

Its schedules.

Returns

Each schedule with its status, next_run and how its last_run went.

addDomain

addDomain(name: string): Promise<Domain>

Serve the app at the domain name too: pointed at once if bought through NoClick (at its name and www), else connected and pending_dns until its records are set; each name is live once its certificate is issued. A subdomain of a domain your account holds (ana.acmebooking.com) can serve any project, a user's included, from a key acting for the whole account: its record is written under a bought domain, none is needed under one connected with wildcard (live within minutes), and records lists it otherwise.

Parameters
namestringrequired
Returns

The noclick.Domain, with its status.

domains

domains(): Promise<Domain[]>

The domains that serve the app.

Returns

Each noclick.Domain with its status.

removeDomain

removeDomain(name: string): Promise<void>

Stop serving the app at name (a bare domain's www too). The domain itself is kept: a bought one stays yours, and one connected for the app stays connected until you delete it.

Parameters
namestringrequired

logs

logs(options?: ProjectLogsOptions): Promise<LogLine[]>

What the app printed while serving, oldest first; lines are kept 7 days.

Parameters
options.sinceDate | string

The first limit lines after this time; the last limit lines when omitted.

options.level"warn" | "error"
options.deploymentDeployment | string

One deployment's lines (a Deployment or its id).

options.limitnumber

100 by default, at most 1,000.

(default 100)
Returns

The lines. Pass the last one's at as since to read on from there.

analytics

analytics(options?: ProjectAnalyticsOptions): Promise<ProjectAnalytics>

How the app's traffic went over the last period (24h, 7d by default, or 30d): its requests each hour (24h) or day, starting in tz (an IANA time zone; UTC when omitted), how many failed, the totals against the same length of time before, by status, how long answers took to begin and the busiest paths. environment: its production site (the default), its previews (preview) or both (all). Every request its sites answered counts, its static files and API calls included, people's and bots' alike: requests, not visitors.

Parameters
options.periodAnalyticsPeriod

7d by default.

(default "7d")
options.environment"production" | "preview" | "all"

Its production site (the default), its previews, or both.

(default "production")
options.tzstring

The IANA time zone its hours and days start in (Europe/Paris); UTC when omitted.

Returns

Its ProjectAnalytics, read from NoClick's record of each request.

usage

usage(): Promise<ProjectUsage>

What the app has spent this month, against its budget: everything it cost in usd, split byType, and limitedBy, what refuses its paid calls now.

Returns

Requests served, compute in cpu_ms, usd and its budget_usd, what refuses its paid calls (limited_by), and the period_start it counts from.

export

export(): Promise<Operation<ExportBundle>>

Package everything the app is, to run it elsewhere: its code as a git bundle, apps/<name>.json with its settings, bindings and secret names (never values), and each database, bucket, dict and queue it binds, each in its own export's format. wait() resolves to the ExportBundle. To put the code on GitHub, use the repo's exportToGithub.

Returns

An operation whose .wait() gives an noclick.ExportBundle.

delete

delete(options?: { deleteData?: boolean }): Promise<TrashItem>

Delete the app: it goes offline within seconds and to the trash, restorable for 30 days with everything it had (releases, settings, secrets, bindings, schedules, domains), served again with no build. The repo and bound data are kept unless deleteData, which moves the repo to the trash too, with whatever no other app binds. Returns its TrashItem.

Parameters
options.deleteDataboolean
Returns

Its TrashItem: restore() serves it again where it was.

Deployment

class Deployment

One build of a project at one commit. status goes queued, building, then ready (serving at url), failed (error says why) or canceled. production is true for the one serving the project's own URL.

Attributes
idstring
projectIdstring
branchstring
commitstring | null

The sha it was built from.

commitMessagestring | null
statusDeploymentStatus
urlstring | null

Where this deployment serves (a preview URL unless it's production).

productionboolean
environmentDeploymentEnvironment

production for a deploy of the production branch, preview for any other: whose secrets it was built with. A promoted preview keeps preview and serves with production's secrets.

startedBy"deploy" | "push"

deploy (a deploy(), or promoting a retired one) or push (the app deploys on push).

errorstring | null

Why the build failed, or why a push couldn't deploy, in one line (null unless failed).

runtimeDeploymentRuntime | null

Where it runs: edge or container, chosen when its build starts (null until then).

runtimeReasonstring | null

Why it runs there, in words: the app's pinned runtime, or what its commit has ("a Dockerfile describes its server").

createdAtDate | null
readyAtDate | null
lastCheckJsonObject | null

Its latest check, in short: { operation_id, passed, url, checked_at, paths: [{ path, ok, status, problem }] } (null before its first). The check's operation has the whole of it.

fromIdstatic

static fromId(deploymentId: string, options?: CallOptions): Deployment

A lazy reference to a deployment by id.

Parameters
deploymentIdstringrequired
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
Returns

A deployment that loads the first time you read a field. Nothing is sent yet.

getstatic

static get(deploymentId: string, options?: CallOptions): Promise<Deployment>

Load a deployment by id now; an unknown id raises noclick.NotFound.

Parameters
deploymentIdstringrequired
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The deployment, loaded.

logs

logs(
  options?: { kind?: "build" | "runtime"; limit?: number },
): Promise<LogLine[]>

Its build output (kind: "build", the default) or what it printed while serving ("runtime"), oldest first.

Parameters
options.kind"build" | "runtime"default "build"
options.limitnumber

Return at most this many.

Returns

The lines, or the last limit of them. A build keeps every line; runtime lines are kept 7 days.

cancel

cancel(): Promise<this>

Stop a deployment that's still queued or building; one that already finished is left as it is.

Returns

This deployment, canceled unless it had already finished.

check

check(paths?: string[]): Promise<Operation<DeploymentCheck>>

Load paths of this ready deployment where it serves (its preview URL, or the app's URL in production) in a browser: each one's HTTP status, load time, console errors and a screenshot kept as a file the chat shows. Without paths, the app's checkPaths (else its home page). A deployment no URL serves now can't be checked (Conflict). The browser is billed at its provider's price, by the second. wait() resolves to a DeploymentCheck.

const checked = await (await preview.check(["/", "/book"])).wait();
for (const page of checked.paths) console.log(page.path, page.status, page.problem, page.screenshot?.url);
Parameters
pathsstring[]
Returns

An operation whose .wait() gives a DeploymentCheck; passed is False when a path answered 400 or more, didn't load, or a script on it threw.

requests

requests(options?: { since?: Date | string }): Promise<RequestOutcomes>

How the requests this deployment served went since since (the last 24 hours when omitted, at most 7 days back): how many, by status, the error rate and the slowest routes, from what its host recorded of each request.

Parameters
options.sinceDate | string
Returns

Its RequestOutcomes, read from NoClick's record of each request it answered, files included.

promote

promote(options?: { force?: boolean }): Promise<Operation<Deployment>>

Make this ready deployment the production one; its URL starts serving this build within a minute. A preview is released again with production's secrets, without a build. Instant rollback covers the app's last 10 production deployments, and each branch's newest preview for 30 days; promoting an older one builds its commit again (a project.deploy operation). wait() resolves to the deployment now production.

An app with checkPaths checks the deployment first and doesn't promote one that fails (the operation fails with the check in its error; production keeps serving); force: true promotes it without the check. The databases the app binds are bookmarked first: undoing the promote (Operation.undo()) puts them back as they were, with the release before.

Parameters
options.forceboolean
Returns

An operation whose .wait() gives this deployment (or, past the window, the one built from its commit), now production.

Schedule

class Schedule

A project's cron job: NoClick POSTs path on the app on every tick of cron (read in tz). When 5 runs in a row fail the same way over at least 30 minutes it pauses itself (pausedReason says why) until resume().

Attributes
idstring
projectIdstring
namestring

What keys it within the project (the path unless you named it).

cronstring

The five-field cron expression.

tzstring
pathstring
status"active" | "paused"

active or paused.

pausedReasonstring | null
nextRunDate | null
lastRunDate | null
lastStatus"succeeded" | "failed" | null

succeeded (a 2xx answer) or failed; null before the first run.

lastErrorstring | null

Why the last run failed, in one line (Answered 500.); null after a success.

createdAtDate | null

fromIdstatic

static fromId(scheduleId: string, options?: CallOptions): Schedule

A lazy reference to a schedule by id.

Parameters
scheduleIdstringrequired
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
Returns

A schedule that loads the first time you read a field. Nothing is sent yet.

getstatic

static get(scheduleId: string, options?: CallOptions): Promise<Schedule>

Load a schedule by id now; an unknown id raises noclick.NotFound.

Parameters
scheduleIdstringrequired
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The schedule, loaded.

pause

pause(): Promise<this>

Stop firing until resume().

Returns

This schedule, paused.

resume

resume(): Promise<this>

Fire again from the next tick, clearing pausedReason.

Returns

This schedule, active, with its next_run.

runNow

runNow(): Promise<this>

Call its path once now and wait for the answer (at most 30 seconds); a paused schedule stays paused.

Returns

This schedule, with last_run and last_status from that call.

delete

delete(): Promise<void>

Delete the schedule; it stops firing.

ProjectSecrets

class ProjectSecrets

project.secrets: values the running app reads from its environment by name, set for production deployments, previews or both. Values are write-only; nothing reads one back. An app's environment holds 128 values in all, NoClick's own and each bound secret's included.

set

set(
  name: string,
  value: string,
  options?: { environment?: SecretEnvironment },
): Promise<void>

Set name to value (at most 5 KB), replacing any value it had, for environment: production (deploys of the production branch, and what's promoted), preview (every other branch) or all (the default). It reaches the app at the next deployment; keep a larger value in a bound Secret or bucket the app reads.

Parameters
namestringrequired
valuestringrequired
options.environmentSecretEnvironment

list

list(
  options?: { environment?: SecretEnvironment },
): Promise<Record<string, Date | null>>

Each secret set for environment (all by default) and when its value was last set, never the value.

Parameters
options.environmentSecretEnvironment
Returns

Each secret's name mapped to when its value was last set.

delete

delete(
  name: string,
  options?: { environment?: SecretEnvironment },
): Promise<void>

Delete name from environment (all by default); the app stops seeing it at the next deployment.

Parameters
namestringrequired
options.environmentSecretEnvironment

versions

versions(
  name: string,
  options?: { environment?: SecretEnvironment },
): Promise<Version[]>

What name held before each change or deletion of the last 30 days, newest first, in environment (all by default), never the values.

Parameters
namestringrequired
options.environmentSecretEnvironment
Returns

Each earlier version, with its environment.

restore

restore(name: string, version: Version | string): Promise<void>

Set name back to version's value in its environment (deleted since, it's back).

Parameters
namestringrequired
versionVersion | stringrequired

ProjectSettings

class ProjectSettings

project.settings: plain values the running app reads from its environment by name, such as a feature flag or a public URL. Unlike secrets they read back and show in the console.

set

set(name: string, value: string): Promise<void>

Set name to value (at most 4 KB); it reaches the app at the next deployment.

Parameters
namestringrequired
valuestringrequired

list

list(): Promise<Record<string, string>>

Each setting's name and value.

Returns

Each setting's name mapped to its value.

delete

delete(name: string): Promise<void>

Delete name; the app stops seeing it at the next deployment.

Parameters
namestringrequired

versions

versions(name: string): Promise<Version[]>

What name held before each change or deletion of the last 30 days, newest first, with each value.

Parameters
namestringrequired
Returns

Each earlier version.

restore

restore(name: string, version: Version | string): Promise<string>

Set name back to version's value (deleted since, it's back); returns the value it holds again.

Parameters
namestringrequired
versionVersion | stringrequired
Returns

The value it holds again.

ProjectAI

class ProjectAI

project.ai: AI acting as the app, from the app's own code (Project.current()). Every call is billed to your account and attributed to the app and its user: it counts toward the app's budgetUsdPerMonth and its user's cap, and throws SpendCapExceeded once either is used up (PaymentRequired once your account's balance is). Only the app acts as the app: on a project reached with your own key, each call throws InvalidRequest (use AI there, for the app's user).

Attributes
baseUrlstring

The OpenAI-compatible endpoint, for an OpenAI client in the app's code; pair it with headers().

chat

chat(
  messages: string | readonly (AIChatMessage | string)[],
  options?: Omit<AIChatOptions, "user" | "client">,
): Promise<ChatReply>

AI.chat as the app; model: "agent:<name>" reaches only an agent bound to the app, in its own conversations.

Parameters
messagesstring | readonly (AIChatMessage | string)[]required
options.modelstring

An OpenRouter id with the openrouter/ prefix, or agent:<name> for one of your agents; NoClick's default when omitted.

options.maxTokensnumber
options.temperaturenumber
options.responseFormatJsonObject

Ask for JSON: { type: "json_schema", json_schema: ... }.

options.toolsJsonObject[]

OpenAI-format tool definitions, such as await toolkit.definitions({ format: "openai" }). An agent takes none.

options.conversationstring

An agent's conversation to continue (reply.conversation); only the messages after the last assistant message are sent.

options.signalAbortSignal
Returns

The answer: its text, the message to append, and what it cost.

embed

embed(
  texts: string | readonly string[],
  options?: { model?: string; dimensions?: number },
): Promise<Embeddings>

AI.embed as the app.

Parameters
textsstring | readonly string[]required
options.modelstring
options.dimensionsnumber
Returns

One vector per text, in order, with their length and what the call cost.

image

image(
  prompt: string,
  options?: { model?: string; size?: string },
): Promise<GeneratedImage>

AI.image as the app.

Parameters
promptstringrequired
options.modelstring
options.sizestring
Returns

The image: a signed url that lasts 24 hours, its size and what it cost.

transcribe

transcribe(
  audio: string | Uint8Array | ArrayBuffer | Blob,
  options?: {
    model?: string;
    language?: string;
    speakers?: boolean | string[];
  },
): Promise<Transcript>

AI.transcribe as the app: an https URL to a recording, or its bytes.

Parameters
audiostring | Uint8Array | ArrayBuffer | Blobrequired
options.modelstring
options.languagestring
options.speakersboolean | string[]
Returns

The transcript: its text, timed segments, the language and how long the audio was.

models

models(options?: { kind?: AIModelKind }): Promise<AIModel[]>

The models the app can call; kind: "agent" lists the agents bound to it.

Parameters
options.kindAIModelKind
Returns

Every matching model with its prices in US dollars, the default of each kind first.

headers

headers(): Promise<Record<string, string>>

The deployment's credential as the bearer, for an OpenAI client's defaultHeaders: every call is the app's.

Returns

Authorization.

Binding

interface Binding

A resource the running app reads by name.

Attributes
namestring
kindBindingKind
resourceIdstring
resourceNamestring | null
createdAtDate | null
rawJsonObject

The response JSON exactly as the API sent it.

LogLine

interface LogLine

One line an app printed, or its build did.

Attributes
atDate | null
level"info" | "warn" | "error"
messagestring
deploymentIdstring | null
rawJsonObject

The response JSON exactly as the API sent it.

ProjectUsage

interface ProjectUsage

What an app spent this month so far, against its budget.

Attributes
requestsnumber
cpuMsnumber
usdnumber

Everything the app spent: hosting, builds, its calls to what it's bound to, its email, its AI and its agent turns.

periodStartDate | null
budgetUsdnumber | null

Its budgetUsdPerMonth (null without one).

limitedBy"project" | "user" | "account" | null

What refuses its paid calls now: its own budget, its user's cap or your account's balance; null while they go through.

byTypeRecord<string, number>

usd split by the spend types of Usage.series({ groupBy: "type" }): apps, ai, model_tokens, ...

rawJsonObject

The response JSON exactly as the API sent it.

DeploymentCheck

interface DeploymentCheck

What Deployment.check() saw where the deployment serves (url): passed when every path did.

Attributes
deploymentIdstring
urlstring
passedboolean
pathsPathCheck[]
checkedAtDate | null
costUsdnumber

What the browser cost: its provider's price, by the second.

rawJsonObject

The response JSON exactly as the API sent it.

PathCheck

interface PathCheck

One path a check loaded in a browser. ok is false when it answered 400 or more, didn't load within 30 seconds, or a script threw and nothing caught it (problem says which); other console errors are reported without failing it.

Attributes
pathstring
urlstring

Where it ended up.

okboolean
problemstring | null
statusnumber | null
loadMsnumber | null

From the navigation to the load event (null when it didn't load in time).

titlestring | null
consoleErrorsConsoleError[]

Each {"kind", "message"}: exception (uncaught), console (console.error) or browser (a file that failed to load, ...).

screenshotJsonObject | null

The screenshot, an account file the chat shows: { id, name, url, mime_type, ... } (null when the page couldn't be opened).

rawJsonObject

The response JSON exactly as the API sent it.

RequestOutcomes

interface RequestOutcomes

How the requests a deployment served between since and until went. errors counts answers of 500 or more and requests never answered ("none" in byStatus); sampled is true when there were more than the 2,000 newest it read, or the record of a very busy app is a sample, each request in it counted for the ones it stands for.

Attributes
requestsnumber
errorsnumber
errorRatenumber | null
byStatusRecord<string, number>
slowestRoutesRouteTiming[]
sampledboolean
sinceDate | null
untilDate | null
rawJsonObject

The response JSON exactly as the API sent it.

RouteTiming

interface RouteTiming

One route's requests: how many, how many failed, and their times in milliseconds.

Attributes
methodstring
pathstring
requestsnumber
errorsnumber
p50Msnumber
p95Msnumber
maxMsnumber

ProjectAnalytics

interface ProjectAnalytics

How an app's traffic went over a period, from since up to until: the requests its sites answered and the errors among them (an answer of 500 or more, or none) with their errorRate, byStatus ({ "200": 1180, "404": 21, none: 1 }), how long answers took to begin (p50Ms, p95Ms), each interval's (hour or day, starting in tz) in series, the busiest topPaths, and the same length of time just before since (previousRequests, previousErrors). Counted from NoClick's record of every request, its files and API calls included: requests, not visitors. sampled: a very busy app's record is a sample, each request in it counted for the ones it stands for.

Attributes
periodAnalyticsPeriod
environmentNonNullable<ProjectAnalyticsOptions["environment"]>
interval"hour" | "day"
tzstring
sinceDate | null
untilDate | null
requestsnumber
errorsnumber
errorRatenumber | null
byStatusRecord<string, number>
p50Msnumber | null
p95Msnumber | null
seriesTrafficInterval[]
topPathsPathTraffic[]
previousRequestsnumber
previousErrorsnumber
sampledboolean
rawJsonObject

The response JSON exactly as the API sent it.

TrafficInterval

interface TrafficInterval

One hour or day of an app's traffic: the requests from at on, and how many of them failed.

Attributes
atDate | null
requestsnumber
errorsnumber

PathTraffic

interface PathTraffic

One of an app's busiest paths: its requests, how many failed, and their 95th-percentile time in milliseconds.

Attributes
pathstring
requestsnumber
errorsnumber
p95Msnumber | null

AnalyticsSummary

interface AnalyticsSummary

Every app's requests over a period (from since up to until, days starting in tz), read at once: apps newest first, an app nobody reached at 0. Requests, not visitors. sampled: a very busy app's record is a sample, each request in it counted for the ones it stands for.

Attributes
periodAnalyticsPeriod
tzstring
sinceDate | null
untilDate | null
appsAppRequests[]
sampledboolean
rawJsonObject

The response JSON exactly as the API sent it.

of

of(app: Project | string): AppRequests

One app's line (a Project or its id); one the summary didn't cover reads as 0.

Parameters
appProject | stringrequired
Returns

The AppRequests of app (a Project or its id); one the summary didn't cover reads as 0.

AppRequests

interface AppRequests

One app's requests to its production site over a summary's period, and how many failed.

Attributes
projectIdstring
requestsnumber
errorsnumber

ProjectEmail

class ProjectEmail

app.email: transactional email from the app's own address (receipts, booking confirmations), rate-capped and charged per recipient. One-time sign-in codes go through sendCode, on a lane of their own; newsletters and announcements through broadcast, on a stream of their own.

enable

enable(options?: EmailEnableOptions): Promise<EmailSetup>

Turn email on, or change what you pass (the rest keeps its value). With a domain, broadcasts go from the same name on its news. subdomain. The first call answers pending while NoClick sets up the app's sending (what it sends meanwhile goes out once that's done). A domain bought through NoClick gets its DNS records written and turns active within minutes; any other is connected for you and records lists what to add (within seconds of this call).

Parameters
options.domainstring | ApiObject

A Domain or its name; without one the app sends from its default address. A subdomain of a domain your account holds may send any project's mail, a user's included, from a key acting for the whole account.

options.fromAddressstring

On domain: noreply@<domain> unless you pass one.

options.fromNamestring
options.postalAddressstring

The address every broadcast's footer carries, as the law asks of bulk mail; broadcast needs one.

Returns

The setup: active when the app can send now, pending while NoClick sets up its sending (what it sends meanwhile goes out once that's done), or pending_dns while the domain's records aren't seen yet.

status

status(): Promise<EmailSetup>

How the app sends email, with the domain's records checked again (off if never enabled).

Returns

The current setup; status is off if email was never enabled.

send

send(options: EmailSendOptions): Promise<SentEmail>

Send one message; ActionRequired while the domain's records are pending, RateLimited past the daily limit.

Parameters
options.textstring
options.htmlstring
options.replyTostring
options.idempotencyKeystring

Makes a retried send safe: the same key sends once.

options.tostring | readonly string[]required

One address, or up to 10 that each receive the message.

options.subjectstringrequired
Returns

The message as accepted, usually queued; messages() shows whether it was delivered.

sendCode

sendCode(
  to: string,
  code: string,
  options?: EmailCodeOptions,
): Promise<SentEmail>

Send a one-time code (4-12 letters and digits) to to in a short message NoClick writes in the app's name. Codes have a daily limit of their own, apart from dailyLimit; one address gets at most 5 in 15 minutes (RateLimited). Each is charged as one message. app.signIn sends its codes this way.

Parameters
tostringrequired
codestringrequired
options.purpose"sign_in" | "verify_email"

sign_in (the default) or verify_email.

(default "sign_in")
options.expiresInSnumber

Said in the message: 60-86400 seconds.

options.idempotencyKeystring

Makes a retried create safe: the same key returns the first result. Generated when omitted.

Returns

The message, kind code; its subject names the purpose, never the code.

messages

messages(
  options?: {
    to?: string;
    limit?: number;
    environment?: "production" | "preview";
  },
): Promise<SentEmail[]>

The messages the app sent, newest first: 50 unless limit says (to keeps one address's, environment those its production or its previews sent). A preview's code reaches only the account's own people, so environment: "preview" is its outbox: each message names the recipients it kept in captured, with the text and html it would have sent.

Parameters
options.tostring
options.limitnumber

Return at most this many.

(default 50)
options.environment"production" | "preview"
Returns

Up to limit messages (50 unless you say; None reads them all), each with its delivery status, whether it was opened and why it bounced.

broadcast

broadcast(options: EmailBroadcastOptions): Promise<Operation<Broadcast>>

Send one message to many people who asked for it (a newsletter, an announcement). Anyone who unsubscribed from the app's broadcasts (until they opt in again and you resubscribe them), bounced or complained is skipped. It goes out on a bulk stream of its own under broadcastDailyLimit, from broadcastFromAddress, so a campaign never pauses transactional mail; it needs a domain of the app's own (ActionRequired on the default sender) and goes out at the pace mail can be sent, so a large one takes minutes. Every message carries its recipient's own List-Unsubscribe header with one-click unsubscribe, and a footer with an unsubscribe link and the postalAddress (ActionRequired until there is one). wait() resolves to the Broadcast.

Parameters
options.idempotencyKeystringrequired

Names the broadcast: sending again with the same key sends nothing new. Required.

options.textstring
options.htmlstring
options.replyTostring
options.toreadonly string[]required

Up to 50,000 addresses; listing them says each one opted in to mail from the app.

options.subjectstringrequired
Returns

An operation whose .wait() gives the Broadcast: how many it was sent to and who was skipped, and why.

resubscribe

resubscribe(address: string): Promise<boolean>

Lift address's unsubscribe from the app's broadcasts once they've asked for them again and confirmed it (a click on a link you emailed that address); call it only on such a confirmed opt-in. A bounce or a spam complaint isn't lifted. Resolves to true if the address was unsubscribed, false if it wasn't.

Parameters
addressstringrequired
Returns

True if the address was unsubscribed and now gets broadcasts again, False if it wasn't unsubscribed.

EmailSetup

interface EmailSetup

How an app sends email. status is off (never enabled), pending (NoClick is setting up the app's sending, usually within a minute; mail sent meanwhile goes out once it's set up, and pendingReason says why when setting it up failed), pending_dns (the domain's records aren't seen yet: a domain bought through NoClick turns active within minutes), active, or paused (too many bounces or spam complaints; pausedReason says which: bounce_rate, complaint_rate, mailbox_provider_feedback or blocklisted). Broadcasts go out apart, from the domain's news. subdomain, with a status of their own.

Attributes
status"off" | "pending" | "pending_dns" | "active" | "paused"
fromAddressstring | null

The address mail goes out from, like bookings@acmebooking.com.

fromNamestring | null

The display name recipients see, like Acme Booking.

domainstring | null

The sending domain; null while the app uses its default sender.

recordsDnsRecord[]

What DNS must hold for mail to send and land: DKIM and a bounce subdomain (MX and SPF) for the domain and its news. subdomain, and a recommended DMARC policy.

dailyLimitnumber | null

How many messages the app may send a day; it grows as its mail keeps landing.

sentTodaynumber | null

Sent since midnight UTC.

pausedReasonstring | null
pendingReasonstring | null

Why the app's sending isn't set up yet, once setting it up failed (NoClick keeps trying); else null.

postalAddressstring | null

The postal address every broadcast's footer carries (null until you give one).

broadcastDailyLimitnumber | null

How many recipients its broadcasts may reach a day, apart from dailyLimit.

broadcastStatus"off" | "needs_domain" | "pending" | "pending_dns" | "active" | "paused"

needs_domain (the default sender doesn't send broadcasts), pending, pending_dns, active or paused.

broadcastFromAddressstring | null

The address broadcasts go out from, on the news. subdomain.

broadcastSentTodaynumber | null

Broadcast recipients sent to since midnight UTC.

broadcastPausedReasonstring | null
rawJsonObject

The response JSON exactly as the API sent it.

canSendboolean

Whether send goes out now (status is active).

SentEmail

interface SentEmail

One message an app sent; error says why it bounced or failed. complained is best-effort: some mailbox providers, Gmail among them, report no single complaint. Sent to several recipients, it shows the worst any met (a bounce, a complaint), else how far the slowest got.

A preview's code reaches only the account's own people (its owner and the members of the owner's workspaces): every other copy is kept, never sent or charged, and named in captured; a message whose every copy was kept is captured, with the text and html it would have sent. messages({ environment: "preview" }) is the preview's outbox.

Attributes
idstring
tostring[]
subjectstring | null
status"queued" | "sent" | "delivered" | "bounced" | "complained" | "failed" | "captured"
openedboolean | null

Whether it was opened, as far as can be told (privacy proxies open some mail on the reader's behalf); null for a message with no HTML, or a sign-in code, which aren't tracked.

bouncedboolean
errorstring | null
atDate | null

When it was sent.

kind"message" | "code" | "broadcast"

message (send), code (sendCode) or broadcast.

environment"production" | "preview"

Where the code that sent it runs.

capturedstring[]

The recipients a preview kept rather than sent to.

textstring | null

What a kept message would have said; null once a message went out.

htmlstring | null
rawJsonObject

The response JSON exactly as the API sent it.

Broadcast

interface Broadcast

One broadcast an app sent: how many it was sent to, and those it skipped, each { to, reason } with reason unsubscribed, bounced, complained or invalid. From a preview, only the account's own people get it: captured counts the copies kept.

Attributes
idstring
subjectstring | null
sentnumber
skippedJsonObject[]
capturednumber
rawJsonObject

The response JSON exactly as the API sent it.

ProjectPayments

class ProjectPayments

app.payments: take payments without a payments account of your own. NoClick opens a test account and puts its keys in the app's secrets; the owner claims it to take real money.

enable

enable(options?: PaymentsEnableOptions): Promise<PaymentsSetup>

Open the app's test account (country required the first time; NotAvailable for one the processor doesn't serve), or answer the one it has. After testExpiresAt passes unclaimed it opens a fresh one with new keys; a disconnected account reconnects once the owner reinstalled NoClick's payments app.

Parameters
options.countrystring

Where the owner's business is (ISO 3166-1 alpha-2): required the first time, fixed after.

options.ownerEmailstring

Who the processor reminds before an unclaimed test account expires (your account's email unless given).

options.businessNamestring

Prefills the claim (the app's name unless given).

Returns

The setup in test mode, with the claim_url to send the owner.

status

status(): Promise<PaymentsSetup>

Where the app's payments stand: mode moves from test to claimed to live; processor is there even while off.

Returns

The current setup; mode moves from test to claimed to live. processor is there even while off, so an app's payment code can be written before enable().

PaymentsSetup

interface PaymentsSetup

Where an app's payments go. mode is off, test (a test account waiting to be claimed), claimed (the owner is finishing the steps claimStep names), live (live keys are in the app's production secrets and the account can take payments) or disconnected (the owner removed NoClick's payments app or its keys). Money goes straight to the owner's account; NoClick takes no cut.

Attributes
mode"off" | "test" | "claimed" | "live" | "disconnected"
claimStep"claim" | "application" | "install" | "verification" | null

While claiming: claim (send the owner claimUrl), application (the owner gives the payment processor their business details), install (the owner installs NoClick's payments app on their live account) or verification (the processor is verifying the business).

nextStepstring | null

What to do now, in a sentence.

claimUrlstring | null

Where the owner claims the account: a NoClick link that always leads to their next step, working until testExpiresAt.

testExpiresAtDate | null

When the test account and its data are deleted unless claimed; after that enable() opens a fresh one.

dashboardUrlstring | null

The owner's own dashboard at the payment processor, once claimed.

secretsstring[]

The project secrets that hold the account's keys: live keys in production once live, test keys in previews always.

processorstring | null

Which payment processor apps are paid through, by the name its own client library goes by, so the app's code can pick the library that reads secrets. It's the same for every app, so status() reports it even while off, and code can be written before enable().

countrystring | null

Where the business is (ISO 3166-1 alpha-2), fixed when the account was opened.

webhookUrlstring | null

Where the processor delivers the account's events: the app's /api/payments/webhook.

rawJsonObject

The response JSON exactly as the API sent it.

ProjectSignIn

class ProjectSignIn

app.signIn: accounts for the app's own users. Enabling it commits sign-in code into the app's repo and keeps the users in the app's bound database.

enable

enable(
  providers: readonly SignInProvider[],
  options?: SignInEnableOptions,
): Promise<Operation<SignInSetup>>

Commit sign-in for providers to branch (the default branch unless given), create usersTable (users) and the tables it needs in the bound database and deploy; nextjs, remix and astro apps, and a static site as it is, with a worker in front of its files (NotAvailable for client-only vite, or a site already running its own worker). google, apple and microsoft sign in through NoClick with nothing to set up (google and microsoft on your own client when named in ownCredentials); github uses your own client. A file holding edits of yours is never overwritten: the change goes on a branch of its own. wait() gives the SignInSetup.

Parameters
providersreadonly SignInProvider[]required
options.ownCredentialsreadonly Exclude<SignInProvider, "email" | "apple">[]

Of google and microsoft, those that sign in with your own client at the provider, to show your own name on its screen (set its id and secret as the app's secrets: missingSecrets). The rest, and apple, sign in through NoClick, with nothing to set up; github always uses your own client. Omitted, each provider keeps how it signs in now.

options.usersTablestringdefault "users"
options.databasestring

The binding of the database to keep users in; needed only when the app binds more than one.

options.branchstring
Returns

An operation whose wait() gives the SignInSetup once the code is committed and deployed.

upgrade

upgrade(options?: { branch?: string }): Promise<Operation<SignInSetup>>

Move the sign-in code to the library version NoClick ships now (updateAvailable), with the same providers and the same care for edited files. wait() gives the SignInSetup.

Parameters
options.branchstring
Returns

An operation whose wait() gives the SignInSetup.

status

status(): Promise<SignInSetup>

The app's sign-in: its providers, where its users are kept and what it still needs (off if never enabled).

Returns

The current setup; status is off if sign-in was never enabled.

SignInSetup

interface SignInSetup

An app's sign-in. status is off, installing (a change is being committed and deployed), active or failed (the first change failed; a later one that fails leaves sign-in active, with error). The code lives in the app's repo, the users in usersTable.

Attributes
status"off" | "installing" | "active" | "failed"
providersstring[]

email (a one-time code by email), google, apple, microsoft, github.

managedProvidersstring[]

The providers that sign in through NoClick, with nothing to set up at the provider (its screen names NoClick). The rest of providers but email use your own client there.

usersTablestring | null
tablesstring[]

Every table sign-in keeps: usersTable first, then its sessions, linked accounts, pending codes and rate limits.

databasestring | null

The binding of the database the users are kept in.

librarystring

The open-source library the code is written with, and its version.

versionstring | null
updateAvailablestring | null

A newer version NoClick ships (upgrade() moves to it), else null.

commitstring | null

The commit that added or last changed sign-in.

branchstring | null

Where that commit went when it wasn't the production branch (yours, or one NoClick made beside your edits).

editedFilesstring[]

Files holding edits of yours that the last change left alone, committing on branch instead.

callbackUrlsRecord<string, string>

Where each provider on your own client sends people back to; register it with that provider.

missingSecretsstring[]

Project secrets a provider on your own client still needs (GOOGLE_CLIENT_ID, ...).

secretsstring[]

The secrets NoClick writes itself and never shows: AUTH_SECRET, AUTH_URL, AUTH_PROXY_SECRET, and the app's client of NoClick's sign-in (NOCLICK_SIGN_IN_CLIENT_ID, _SECRET) while any provider is managed.

errorJsonObject | null
rawJsonObject

The response JSON exactly as the API sent it.