syntaqxPersonal-data erasure has an intake, a staff case with its trail, and cleanup that identity commits with the purge and retries until each service confirms it; one-time-code fields work with password managers and take recovery codes; the Ask panel closes when you follow a link from it. Settings → Account records an erasure request (identity request_erasure / my_erasure, migration 0049), even when a workspace you own alone or billing stands in the way of closing the account; it deletes nothing, keeps the first deadline when asked again, and the deadline is the same day next calendar month, clamped to its last day. sudo → Customers → Privacy lists the cases (the sidebar counts open ones), records a request received elsewhere with its original receipt time (an intake for an open case joins its trail and can only move the deadline earlier), shows each case's trail of intake, reviews, refusal or completion, and refuses completion while the account or any of its cleanup jobs remain or any of the seven evidence areas is empty. Purging an account or a workspace now writes five purge jobs (avatar, Chat, Notify, Artifacts, the lifecycle event) in the same D1 batch as the deletion, guarded like every statement in it, so a restore that won leaves neither; the 15-minute tick runs them, keeps a failure pending with backoff to 16 hours, never stores a response body, and clears a done job's payload. Publishing user.deleted or workspace.deleted is delivery to the bus, not proof its consumers finished. A workspace's jobs carry its members at purge time and its former slugs no live workspace holds. Chat (migration 0006): the person's direct message with g1t goes with its answers and pending job; in shared conversations only the person is shut out and their messages show as ghost, where before the room's clear told every member's tab the conversation was emptied and dropped others' pending answers; a workspace's channels are deleted 500 messages at a time within a budget, answering pending until done; the channels to visit are listed once with the tombstone; tombstones, looked up by key with new indexes, refuse late messages, members, reactions, channels, settings, emoji and meter rows. Notify: an erased feed drops later deliveries quietly instead of throwing; a purged workspace's slug can be made again by the person whose username it is, so its marks are times, not bans: notifications from before the purge are dropped, counts, seeds and visits refused for a day, and its presence room refuses only words said before the purge; the purge reaches identity's members and the room's people under every slug, and clears complete:, forgot: and the workspace's notification level. Artifacts (migration 0010): unshared private folios and their files, versions, search rows and vectors go; authorship (now also cleared_by and repo_spaces.added_by) shows as ghost and mention lists drop the username; a workspace is swept a page at a time and resumes after a failure; full-text rows of a document are deleted by document; an index run that races an erasure writes no full-text row without a chunk row and takes back the vectors it wrote; a room's destroy waits for its index run; ordinary page deletion now destroys the page's live document. Not covered automatically, and listed in docs/operations/privacy-erasure.md as manual review: comment threads inside shared documents' live state and version snapshots, private-space pages, rooms of pages deleted before this, folio trash past 200 rooms, earlier folios' version and upload blobs, former members' and outsiders' notifications, backups. One-time codes: the sign-in's second step, two-factor settings and email confirmation share otpInputProps (lib/otp.ts): a stable id and label, autocomplete one-time-code, no password-manager ignore attributes; the sign-in field takes either kind of code at recovery-code length whichever is chosen, and Use a recovery code switches the keyboard. The Ask panel closes on every completed navigation (location.key), including its direct-message link and citations to the page you are on and back or forward; links opened in another tab and revalidation leave it open. The Privacy Policy distinguishes closure from erasure; the authentication guide says how to ask and how recovery codes are entered; the services page lists identity's new CHAT, NOTIFY and ARTIFACTS bindings. Deploy migrations first, then chat, notify and artifacts before identity, then web and sudo. Checked: cargo test -p g1t-identity --lib (175) and its wasm32 check; node --test conformance/erasure.test.mjs (11, new: a shared channel's room shuts out only the erased member, a large channel deleted in chunks with late writes refused, a reclaimed slug keeps new notifications and presence, vectors taken back after a racing erasure, an upload sweep resuming after a failure, late deliveries dropped quietly); artifacts' 126 tests and typecheck, notify's 49 and typecheck, chat's typecheck; the site's tsc -b --force, 926 tests (new: otp) and a production build; sudo's typecheck, 156 tests and build; contracts' 48; the deploy tool's tests (the one failure is services/runner/base.json, from separate uncommitted runner work); the docs build.f10f3ecHistory
README.md
g1t/detect
Says what a g1t.page build of the checkout would find, without building or deploying anything: the same rules g1t/deploy builds with.
steps:
- uses: actions/checkout@v5
- id: detect
uses: g1t/detect@v1
- if: steps.detect.outputs.kind == 'none'
run: echo "::error::Nothing here would be served."
- if: steps.detect.outputs.framework == 'hugo'
run: echo "A Hugo site, served from ${{ steps.detect.outputs.output-dir }}"
- if: steps.detect.outputs.install != ''
run: ${{ steps.detect.outputs.install }}yaml
Inputs
| Input | Default | |
|---|---|---|
root-dir | The checkout | Where the project is in the checkout. |
build-command | None | A build command of your own, as g1t/deploy takes it. |
output-dir | None | An output folder of your own, as g1t/deploy takes it. |
build-as | auto | What it is built as: auto, static, workers or docker (Container), as g1t/deploy takes it. |
dockerfile | None | A Dockerfile's path of your own, as g1t/deploy takes it. |
Outputs
| Output | |
|---|---|
kind | workers (a wrangler.jsonc, wrangler.json or wrangler.toml, a framework's Cloudflare adapter, or a Node.js server run as a Worker), static (a site a build writes), html (the files as they are), container (a server that is not run as a Worker, a framework set up to need a server, or a Dockerfile with nothing else to serve) or none (nothing to serve). |
framework | The framework it is built with, from the table below; node for a Node.js server run as a Worker; for a container without one, dockerfile, or the server g1t writes a Dockerfile for (node, django, flask, fastapi, python, go, rails, rack, laravel, php). Empty when there is none. |
dockerfile | A container's own Dockerfile, relative to the project. Empty when g1t writes one, and for anything that is not a container. |
port | The port a container listens on: its Dockerfile's EXPOSE, else 8080. |
entry | For a Node.js server run as a Worker, the file that starts it, relative to the project. Empty for anything else. |
install | How dependencies are installed, from the lockfile: npm ci, pnpm install --frozen-lockfile, and so on, and bundle install for Jekyll. Empty when there is nothing to install. |
build | What builds it: your command, the package's build script (npm run build), the framework's own command, or wrangler deploy --dry-run for Workers. Empty when nothing does. |
output-dir | The folder served, relative to the project (. for the project itself): yours, a Workers project's assets directory, the folder the framework writes, or the first of dist, build, out, public, _site, .output/public that exists. Empty when a build has yet to write it, as for a Cloudflare adapter's Worker. |
When kind is none, the step's log says what to change or add, such as
a Dockerfile. Docker deployments
has the order in which a project's kind is decided.
Frameworks
framework | Found by | Serves |
|---|---|---|
vite, vite-react, vite-vue, vite-svelte, vite-solid, vite-preact | vite, and the framework's Vite plugin | dist, or build.outDir |
astro | astro | dist, or outDir; a Worker with @astrojs/cloudflare |
nextjs | next | out with output: 'export'; a Worker with @opennextjs/cloudflare and a wrangler.jsonc |
sveltekit | @sveltejs/kit | build with adapter-static; a Worker with adapter-cloudflare |
nuxt | nuxt | .output/public, from nuxi generate |
react-router, remix | @react-router/dev, @remix-run/dev | build/client with ssr: false |
gatsby | gatsby | public |
docusaurus | @docusaurus/core | build |
eleventy | @11ty/eleventy | _site |
angular | @angular/core and angular.json | dist/<project>/browser |
create-react-app | react-scripts | build |
hugo | hugo.toml, or Hugo's config.toml | public |
jekyll | _config.yml and a Gemfile | _site |
mdbook | book.toml | book |
What deploys has
each one's build command. Your build-command and output-dir win over
what is detected.
It runs g1t-runner detect, found or downloaded as g1t/deploy finds it.