Skip to content

Releases: fells-code/seamless-cli

v0.17.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 20:29
952c09e

Minor Changes

  • 2bcfa33: Scaffold from seamless-templates v0.15.0, the release that carries the Expo starter.

    0.16.0 taught init the mobile template kind but left the registry pin on v0.14.0, which has
    no such kind, so the question was never asked and --mobile=expo was refused as an unknown option.
    With the pin on v0.15.0 the registry lists the starter as expo (alias mobile, beta): init
    offers it after the backend, --mobile scaffolds it at mobile/ with EXPO_PUBLIC_API_URL filled
    from the manifest, and the success output says how to start it. The starter is a complete Expo
    Router app on @seamless-auth/react-native 0.1.0 (email code, sign-in link, passkeys, a
    protected call to the companion API), and its tools/associations/ generator writes the files
    native passkeys need. --yes still scaffolds without it.

    The same release moves the API starters to @seamless-auth/express 0.16.0 and
    @seamless-auth/fastify 0.7.0 and passes authServerUrl and audience into requireAuth, so a
    scaffolded API accepts the auth API's access token from the native app alongside browser cookies,
    and its /auth mount answers a bearer client with tokens in the body. The conformance harness's
    adapters take the same ^0.16.0 and ^0.7.0. The starters also keep their SSL options when
    DATABASE_URL carries sslmode (templates 0.15.0's patch note). The web starters stay on
    @seamless-auth/react 0.12.0, and the auth API and admin dashboard pins do not move.

v0.16.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 16:00
f536315

Minor Changes

  • b9529c6: seamless init learns the mobile template kind.

    seamless-templates gains a third kind next to web and api, starting with an Expo (React
    Native) starter. The CLI treated an unknown kind as if it were not there: the alias resolver
    skipped it, the prompts never offered it, and verify filtered it out without a word.

    A mobile starter is optional. init asks "Mobile app" after the backend, defaulting to none;
    --mobile=<id|alias> (or the bare alias, --mobile / --expo) includes one; --yes scaffolds
    without, since a native app brings prerequisites (an associated domain for passkeys) an
    unattended run should not opt into; and a registry that predates the kind offers nothing, so
    there is no question to ask. A chosen starter lands at mobile/ with its .env filled from the
    manifest, is recorded as services.mobile in seamless.config.json, is checked by seamless check only when recorded, and is called out in the success output with how to start it and the
    Android emulator host. verify announces the mobile templates it cannot drive instead of
    filtering them silently. Template copying skips .expo, ios, and android.

    The templates registry pin moves to the release that carries the starter in a follow-up.

Patch Changes

  • 4bbf7ac: seamless verify --local packs @seamless-auth/client alongside @seamless-auth/react
    when the React SDK checkout is an npm workspace.

    The client SDK repo is becoming a workspace that publishes a framework-agnostic
    @seamless-auth/client next to @seamless-auth/react, and the react tarball depends on
    the client one. Packing only the root of such a checkout would produce the private root
    package, and installing the react tarball alone would go to the registry for a client
    version that is not published yet. The harness now reads workspaces from the checkout's
    package.json, packs both packages when it finds one, and the react image installs every
    tarball in one npm install so the dependency resolves from the sibling file. A checkout
    that predates the workspace is packed as before. The version line reported for
    @seamless-auth/react reads the react package's own manifest in a workspace.

v0.15.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 01:21
49917f7

Minor Changes

  • c99c759: Move the scaffold onto auth API v0.13.1, admin dashboard v0.7.0, and seamless-templates v0.14.0.

    v0.13.0 instruments the auth path. Every auth_events row now carries a deployment id, a device
    class folded from the user agent, the subject's mail provider (a provider name, never the domain),
    an owner flag, and the attempt the row belongs to (the ephemeral token's new jti). GET /internal/metrics/funnel reports time to registration, time to login and passkey adoption, and
    GET /internal/metrics/sign-ins reports sign-in outcomes per method, device class, mail provider
    and owner flag, with where attempts stop. The same release ships dashboard v0.7.0 inside the API
    image, which is what that dashboard release needs: its Overview gains a Passwordless Funnel section
    and a Sign-in Outcomes section that read those two routes. v0.13.1 is the same server on a
    release image that applies Debian security updates at build time, since v0.13.0 never published an
    image (its scan failed on a base-image pcre2 finding).

    The admin dashboard pin moves with it, so the standalone console (--admin=image and
    --admin=source) serves the same release the API image serves at /console. Against an older API
    the two new Overview sections report themselves unavailable in place and the rest of the screen is
    unaffected.

    Templates v0.14.0 carries @seamless-auth/express 0.15.0 and @seamless-auth/fastify 0.6.0
    in the API starters, and the conformance harness's adapters take the same ^0.15.0 and ^0.6.0.
    Those adapters forward the browser's user agent to the API as x-seamless-client-user-agent
    beside the client address they already forward, and pass the sign-ins route through. The adapter is
    the only client the API sees, so a project on the older adapters has every audit row recorded as the
    adapter's own user agent and its breakdown by device reads unknown; the other dimensions do not
    depend on it. Nothing else in the starters moves: the manifest contract and the registry are
    byte-identical to v0.13.0, and the React starters stay on @seamless-auth/react 0.12.0, since
    the token claim the API added is one the client never reads.

v0.14.0

Choose a tag to compare

@github-actions github-actions released this 09 Sep 00:26
daf7a12

Minor Changes

  • af41ba4: Move the scaffold onto auth API v0.12.0, admin dashboard v0.6.0, and seamless-templates v0.13.0.

    v0.11.0 puts passkey enrollment behind an access session. It is a breaking change to the wire
    contract: /webAuthn/register/start and /webAuthn/register/finish used to accept the ephemeral
    token the API mints from an email address alone, so anyone who knew an address could enroll a
    credential against that account and sign in as its owner. Both routes read the access session now,
    and enrollment no longer issues a session of its own, answering 200 with the credential instead.
    The same release declares and validates the window on GET /admin/users, and adds organization
    deletion along with a paged, searchable admin organization list. v0.12.0 ships dashboard v0.6.0
    inside the API image, which is what that dashboard release needs: it pages and searches organizations
    on the server, gains a remove action, takes a date range on Overview and Security, and grows an
    Authenticator Policy section.

    The admin dashboard pin moves with it, so the standalone console (--admin=image and
    --admin=source) serves the same release the API image serves at /console.

    The enrollment change has no safe release order, so every side of it moves here at once. Templates
    v0.13.0 carries @seamless-auth/react 0.12.0, @seamless-auth/express 0.14.0 and
    @seamless-auth/fastify 0.5.0 in the starters, and the conformance harness's adapters take the
    same ^0.14.0 and ^0.5.0. The adapters forward the access session the API now requires; an older
    one sends what this API refuses, so a scaffold pinned to either half alone would answer 401 at
    enrollment. No shipped flow loses a step, because registration proves an address with an email OTP
    and verifying it issues the session before the passkey screen appears.

    The adapters also proxy DELETE /admin/organizations/:organizationId, and forward the query string
    on GET /admin/users and GET /internal/auth-events/login-stats, which both dropped it, so the
    dashboard's user search and its login statistics range now reach the API as sent.

  • 206e3cd: Move the scaffold onto the current Seamless ecosystem: auth API v0.10.0, admin dashboard v0.5.0,
    and seamless-templates v0.12.0.

    Three releases of auth API work land together. v0.8.0 gives WebAuthn challenges their own store
    with a five-minute expiry and one-time use, so a registration and a login can be outstanding at once
    instead of clobbering each other, and it adds AUTHENTICATOR_POLICY, which decides attachment, user
    verification, attestation, and whether a synced passkey may enrol. v0.9.0 puts the lockout policy
    and the per-IP and per-identity limiters on TOTP step-up, which had none of the three, and stops
    running refresh tokens through bcrypt. v0.10.0 drops the sessions.refreshTokenHash column the
    previous release stopped writing.

    A scaffold's compose file is built from the pinned release's .env.example, so a new project picks up
    AUTHENTICATOR_POLICY along with SESSION_IDLE_TTL, MAX_CONCURRENT_SESSIONS and a commented
    TRUST_PROXY, and REFRESH_TOKEN_TTL moves from 1h to 1d.

    The admin dashboard bump keeps the standalone console (--admin=image and --admin=source) in step
    with the one the API image now serves at /console, since v0.10.0 embeds dashboard v0.5.0 itself.
    That release names the acting administrator separately from the subject in the events table, and
    collects identity proofing before preparing a device replacement, which is what the API already
    records and requires.

    Templates v0.12.0 moves the starters onto @seamless-auth/react 0.11.0, @seamless-auth/express
    0.13.0 and @seamless-auth/fastify 0.4.0. All three are 0.x minors, so the caret ranges the
    starters carried could never have resolved to them and a scaffolded project stayed on the older
    versions however long ago they were pinned. It also carries per-application auth cookie names read
    from AUTH_COOKIE_PREFIX, so two Seamless apps on one host stop overwriting each other's session. The
    manifest contract is unchanged, so nothing in init moves with it.

    The conformance harness's adapters follow the same SDKs the starters now install:
    @seamless-auth/express ^0.13.0 and @seamless-auth/fastify ^0.4.0. Both stop repeating the
    access and refresh tokens in the body of the response that sets them as httpOnly cookies, and both
    forward a magic link's redirectUri to the API.

  • ec85b59: Match the list windows the auth API now enforces, and let org list page.

    The API validates the window on its admin list routes: limit is 1 to 100 and
    offset is 0 or more. The CLI checked both flags against one range with a floor
    of zero, which was right for --offset and wrong for --limit, so
    users list --limit 0 and users list --limit 500 were sent and came back as a
    400 naming neither the flag nor the bound. Each flag is checked against its own
    range now, and the message says which one was wrong and what it accepts.

    --limit 0 is therefore an error rather than a request for nothing. Asking the
    server for zero rows and reporting "No users." said there were none when the CLI
    had not looked, which is worse than saying the flag is out of range.

    org list gains --limit, --offset and --search. It sent no window at all,
    so once the API started defaulting to 50 it printed the first 50 organizations
    and then a count of every organization, claiming rows it had not shown. It now
    reports where the page sits, the way users list already did, and --search
    matches the name and slug server-side.

v0.13.0

Choose a tag to compare

@github-actions github-actions released this 07 Sep 21:46
a6dc50f

Minor Changes

  • 63ff4ff: Add seamless check --strict, which exits non-zero when a check fails.

    check is what you would reach for in a health-check script or a CI gate, and it always
    exited 0: an empty directory, a stack that is down, and a fully healthy project were
    indistinguishable to anything reading the exit status.

    --strict exits 1 if any check failed, reporting how many. Without it the exit status is
    unchanged, because this output has been parsed by scripts since before the flag existed.

    Every check still runs either way. A gate that stops at the first problem hides the rest,
    and the whole picture is the reason to run check at all.

Patch Changes

  • 79aa298: Clean dist before building, so a stale artifact cannot be packed.

    build was a bare tsc, which overwrites but never removes. A file deleted or renamed
    in src left its old output behind, and prepublishOnly runs the same script, so a local
    publish could ship something no longer in the source tree. The clean script already
    existed and is now wired in.

  • cfed9e6: Correct the documentation that had drifted from the rest of the ecosystem.

    • seamless check and seamless verify now have README sections. Verify is half of
      what the CLI does and had none.
    • The auth server's local-development steps named a script that does not exist
      (db:migrate); the auth API spells it migrate:up, and the Docker path runs it for
      you at container start.
    • init --profile was documented as selecting a profile. It has been accepted and
      ignored since managed connect moved to the portal session, so the help now says so.
    • The generated project layout listed a README.md the CLI does not write, and omitted
      seamless.config.json, admin/, and which pieces a managed project skips.
    • "No redirects or third-party auth providers" predated OAuth sign-in, which the CLI has
      configured since the provider prompts shipped.
    • The included-projects list now names all four repositories the CLI scaffolds from and
      conformance-tests against, including seamless-auth-server and seamless-auth-react.
    • config set help was missing session_idle_ttl from the string-typed keys.
  • d039e18: Add --json to seamless whoami and seamless sessions list.

    config get/roles, users list/credentials, and org list/get/members list all had it;
    these two, both natural scripting targets, did not, so reading an identity or a session id
    from a script meant parsing formatted output.

    Both print machine-readable output and nothing else: an empty session list is [] rather
    than "No active sessions.", and whoami --json reports a missing sub or email as
    null instead of the (unknown) the table shows.

  • 723d581: Point a managed scaffold at the instance URL the portal computes.

    init composed the scaffolded backend's AUTH_SERVER_URL from application.domain, a
    stored column the portal superseded. It goes stale when a trial is upgraded and its tenant
    moves zones, and mvp and business instances are served at domain/<infraId> rather than at
    domain. Either way the scaffold pointed at a URL that does not answer, and the failure
    surfaced as an SDK error in the developer's app rather than as anything the CLI said.

    resolveAppInstanceUrl already existed for exactly this, and apps and the application
    picker already used it; the two scaffold paths did not. They do now.

    The connectable-application filter asked for domain too, so an application the portal
    computed an instanceUrl for but whose domain column was never populated was filtered
    out and never offered. It now asks the same question the scaffold does.

  • e1d3687: Write the signing key id a managed instance actually publishes.

    A managed scaffold hardcoded JWKS_KID=dev-main. Managed instances pin their kid per tier
    (trialkey1 for trials, paidkey1 for paid), so the value was never the instance's own.
    Nothing verifies against it, adapters resolve the key from the token header through the
    remote JWKS, but they do warn on boot while it is the dev default, so every managed
    scaffold produced an app that reported itself misconfigured.

    init now reads the kid from the instance's /.well-known/jwks.json. If the instance
    cannot be reached it keeps the old default, says so, and explains that nothing breaks
    except the warning.

  • 976081b: Say what could not be reached when a scaffold's network read fails.

    seamless init makes three remote reads: the template registry, the templates archive, and
    the auth server's .env.example. Each of them handles a non-ok HTTP response with a message
    naming the status and the URL, but a connection-level failure (offline, DNS, TLS, no route)
    rejects with a bare TypeError: fetch failed that propagated untouched to the top-level
    handler. The whole output was "Error: fetch failed", which named neither the host nor which
    of the three reads had failed.

    The three call sites now go through a shared helper that turns that rejection into a message
    naming the URL, what the CLI wanted from it, and the network as the likely cause, in the
    style login already uses for an unreachable instance. Non-ok responses keep the messages
    they had, and the original error is preserved as the thrown error's cause.

  • 4418970: Recognize the addresses a local dev instance actually answers on.

    isLocalInstanceUrl accepted only localhost, 127.0.0.1, ::1 and .localhost
    subdomains. It gates two things: whether plaintext http is allowed for an instance URL,
    and whether --local OTP delivery is permitted. A dev instance is commonly reached at
    none of those, a container bound to 0.0.0.0, a LAN address from a phone on the same
    network, or an mDNS .local name, and each was rejected as if it were production, forcing
    https onto a box with no certificate.

    Now also treated as local: the whole 127.0.0.0/8 loopback range, 0.0.0.0 and ::, the
    private IPv4 ranges (10/8, 172.16/12, 192.168/16), link-local (169.254/16 and
    fe80::/10), IPv6 unique-local (fc00::/7), and .local names. Ranges are matched by
    octet rather than by prefix, so 172.15, 172.32 and 1.10.0.1 stay public.

  • f4ccb30: Stop writing AUTH_MODE into scaffolded projects.

    The scaffold set AUTH_MODE=server in the auth server env and on the admin console
    container, but nothing reads it: not the auth API, not the admin dashboard (its
    entrypoint takes only API_URL), and not the web or api templates. It was config that
    looked meaningful and meant nothing.

  • 8e5c0f7: Remove code nothing calls.

    • src/utils/writeEnv.ts, an unused duplicate of core/env.ts's writeEnv that still
      emitted unquoted values, the bug fixed in the real one.
    • buildJWKSConfig in the docker generator, which had no callers and was the only user of
      core/jwks.ts, so that module went with it.
    • generateKid in core/secrets.ts. generateSecret beside it stays; it is widely used.
    • setupDockerAuth in the auth generator, unreachable because generateAuthServer is only
      ever called with "local". It also wrote a compose file mounting pgdata at
      /var/lib/postgresql/data, which the pinned postgres:18 ignores, so it had gone stale
      as well as unreachable.

    With the unreachable branch gone, generateAuthServer no longer needs a mode, and its
    context: any and mode: "local" | "docker" | Symbol parameters become a plain root: string.

  • 74ae06c: Stop printing Error: undefined when something other than an Error is thrown.

    The top-level handler in index.ts and the catch blocks in whoami and sessions all
    read .message off the thrown value, which throw does not guarantee exists. A rejected
    promise carrying a string, a parsed response body, or undefined printed nothing useful,
    naming neither the failure nor the fact that something unexpected came back.

    A new errorMessage renders any thrown value: an Error's message (or its name when the
    message is empty), a thrown string as it is, a message field off a thrown object, and
    otherwise the object's shape or a labelled primitive. A thrown object is scrubbed first,
    since it arrives from a rejected request as often as from our own code.

v0.12.1

Choose a tag to compare

@github-actions github-actions released this 04 Sep 13:22
926b111

Patch Changes

  • 2acea63: Stop reading a 401 from /login as "no such account", and stop claiming an account
    exists when the instance will not say.

    POST /login no longer answers 401. An identifier with no usable account, which used
    to cover unknown, unverified, and no-permitted-method, now gets 200 and a decoy pre-auth
    token so the response cannot be used to test whether an account exists. Two branches in
    completeLogin read that 401 and are now unreachable: the "not verified yet" message
    and "No account was found for X". Both are removed, because there is no longer an answer
    for them to read.

    The messages that surrounded them were making a claim the CLI can no longer support. "A
    code was sent to X" is now "If an account exists for X, a code is on its way", and "This
    account cannot use email otp login" is now phrased as what the instance offered, since
    that method list comes back for an unknown identifier too.

    An unknown identifier therefore runs the ordinary flow and fails at the code step. That is
    the intended behaviour and not something the CLI can shortcut, so the final error now says
    so: it names the identifier and points at registering, instead of "Could not verify a
    code" with no explanation of the likeliest reason.

    423 is now reported on its own terms, with how long to wait when the instance says.
    Previously it fell through to "Login request failed (423)". It is also the one answer left
    that does imply an account exists, which is a deliberate and documented tradeoff on the
    API side.

    Adds verify/harness/api/loginEnumeration.spec.ts to the conformance matrix, pinning the
    guarantee against a running instance: an unknown identifier gets the same status and the
    same fields as a registered one, the same identifier keeps the same subject and the same
    method list across attempts, the OTP send reports success and sends nothing, the verify
    fails the way a wrong code fails, and a credential id that cannot exist is refused
    identically for both.

    The loginMethods assertion is the one worth reading. It is deliberately not equality
    between one account and one decoy: that list is filtered by what an account can do, and a
    decoy's capabilities are derived per identifier, so any two can legitimately differ. What
    must hold is that a real account's list is one a decoy can also produce, which is what
    makes a narrow list stop being proof of existence. The spec asserts that over a sample.

  • c3c9d57: Give seamless verify a build cache in CI, and stop paying for provenance attestations
    nothing reads.

    The conformance job spends nearly all of its time building Docker images, and none of it
    running tests. On the run that prompted this, Run seamless verify was 28m02s and the
    tests inside it took 23.7 seconds. Every image is rebuilt from scratch on every run,
    because CI has no Docker layer cache, and the host-side npm caches do nothing for a build
    that happens inside Docker.

    seamless verify now layers an extra compose file over the base one when
    SEAMLESS_VERIFY_COMPOSE_OVERRIDE is set. CI points it at verify/docker-compose.cache.yml,
    which attaches a type=gha build cache scoped per service, and per web template for the
    react image since each template is different source. Nothing changes for a local run: the
    variable is unset, the base compose file is used as it always was, and type=gha would be
    an error outside Actions anyway.

    The Dockerfiles were already ordered for this. Each installs dependencies from a lockfile
    before copying source, so a source change leaves the expensive layer intact and only a
    lockfile change invalidates it.

    Also sets BUILDX_NO_DEFAULT_ATTESTATIONS in the workflow. The images are thrown away when
    the job ends, so the provenance attestation buys nothing, and on that same run
    resolving provenance for metadata file took 301s by itself.

  • 20f8e66: Follow the React SDK's passkey enrollment through the removal of its naming step.

    @seamless-auth/react used to open a "Name This Device" modal after "Register Passkey" was
    pressed, and the harness typed into it before the WebAuthn ceremony would start. That view is
    gone from the SDK, so registerWithPasskey waited 30 seconds for a placeholder that no longer
    renders and then timed out, failing react/passkeyRegister.spec.ts and react/passkeyLogin.spec.ts
    (which registers before it signs back in).

    The helper now stops at the button, which is where the ceremony begins. This tracks the SDK
    release that drops the modal, so a --local run against an older React checkout, or a published
    run before that release lands on npm, will fail on the modal this no longer dismisses.

v0.11.0

Choose a tag to compare

@github-actions github-actions released this 02 Aug 14:52
12e2206

Minor Changes

  • 3ef3b68: Add seamless apps, so a portal account can see what it owns without opening the dashboard.
    apps list prints name, plan, status, and instance URL; apps get <id> adds the console URL,
    region, owners, trial expiry, and whether a service token has been issued (masked, never the live
    value). Both take --json and both require a portal session.

    Applications are now read through the portal's instanceUrl, which is derived from the service
    plan, rather than the stored domain column that goes stale when a trial is upgraded. Applications
    that have not finished provisioning are listed instead of being silently dropped. init is
    unchanged: it still reads domain and still considers only applications that have one.

    apps list shows the infra id as the reference (falling back to the id before provisioning), and apps get accepts an id, a name, or an infra id.

  • 9d089c7: Move the scaffold onto the current Seamless ecosystem: auth API v0.7.1, admin dashboard v0.4.0,
    and seamless-templates v0.8.1 (which carries @seamless-auth/react ^0.8.0 in both React
    starters, @seamless-auth/express ^0.12.0 in the Express starter, and @seamless-auth/fastify
    ^0.3.1 in the Fastify starter).

    A scaffolded project can now finish registration without a passkey. Registration used to end on a
    screen with a single control, leaving anyone who did not want a passkey, or whose device could not
    make one, with no way forward. The starters offer a skip when the instance has another login method
    enabled, and say so plainly when it does not. That reads from GET /system-config/public, a new
    unauthenticated route on the auth server that returns the configured login methods, so the sign-in
    screens can offer what an instance actually has enabled instead of a hardcoded guess. The API, the
    adapters, and the web templates all had to move together for it to work, which is why this bumps
    them as a set.

    Registration against a scaffolded Fastify API used to fail with a 500 and
    TypeError: option maxAge is invalid: 300. The auth server sent the registration response's ttl
    as the string "300", and the Fastify adapter handed it to a cookie library that requires an
    integer. The Express starter never showed this, because its adapter multiplies the value into
    milliseconds and so coerced the string on the way past. It is fixed from both ends:
    @seamless-auth/core 0.12.1 parses the lifetime before it reaches an adapter and rejects anything
    that is not a positive whole number of seconds, and auth API v0.7.1 sends the value as a number.

    seamless init now offers Fastify as a backend, listed as "Fastify (beta)" beside Express. It
    serves the same surface as the Express starter on the same environment contract, including the
    admin console at /console behind SERVE_ADMIN_CONSOLE. Two boot-time fixes land with it: an empty
    PORT= in .env now falls back to 3000 rather than binding a random free port, and pino-pretty
    moves to a runtime dependency so an install without dev dependencies boots. Both Express and Fastify
    starters ship .env.example secret placeholders long enough to clear the adapter's 32 character
    minimum, so the documented cp .env.example .env && npm run dev path boots. A project from
    seamless init was already unaffected, because the CLI fills COOKIE_SIGNING_KEY itself.

    Both React starters gain a protected /session route that shows the issued claims, roles,
    organization context, step-up freshness, and registered passkeys, so the first authenticated screen
    reads as an app rather than a JSON.stringify dump. Missing configuration now stops a scaffolded
    project with a message naming the variable instead of surfacing later as a 500, and the Express
    starter reports every configuration problem at once.

    The auth API drops the admin bootstrap invite flow in favor of the OWNER_EMAIL grant the CLI
    already writes, so the generated .env no longer carries SEAMLESS_BOOTSTRAP_ENABLED,
    SEAMLESS_BOOTSTRAP_SECRET, or SEAMLESS_AUTH_DEBUG_SECRETS. AVAILABLE_ROLES now offers
    admin:read and admin:write alongside bare admin, and assigning a role the instance does not
    list is rejected rather than silently doing nothing. Postgres TLS is configurable through DB_SSL,
    DB_SSL_CA, and DB_SSL_REJECT_UNAUTHORIZED, and DB_URI is accepted as a DATABASE_URL alias.

    The conformance harness adapter moves to @seamless-auth/express ^0.12.0, which is also what
    proxies the new public system-config route. The breaking change in 0.11.0 splits error into
    errorCode and errorBody on the handler result types, which only affects code importing handlers
    from @seamless-auth/core directly; the adapter uses createSeamlessAuthServer, so it needed no
    source change.

  • 4917717: Make seamless init template flags discoverable, predictable, and safe to get wrong.

    Add seamless templates list [--json], which prints every starter init can scaffold with its id,
    kind, framework, selecting flags, and status. It reads the same registry init does (so
    SEAMLESS_TEMPLATES_DIR and SEAMLESS_TEMPLATES_REF apply) and needs no login, so the available
    templates no longer have to be looked up in the source.

    Every template now answers to --<id> as well as its shorter --<alias>, so seamless init --react-vite works alongside --basic, and the api starters (--express, --fastify) have a flag
    for the first time. The "unknown option" error lists both spellings and points at
    seamless templates list.

    Template flags are also resolved before init creates a directory or asks whether to write into one
    that is not empty. An unrecognized or conflicting flag now fails immediately instead of surfacing
    only after the overwrite confirmation.

  • 6e107cb: init now offers the managed path instead of assuming it. A portal session used to make managed the
    default silently, with --local as the only escape and no way to learn you needed it until after the
    template prompts. When your account has a provisioned application, init asks whether to connect it
    or scaffold a local stack, with managed leading.

    Whether managed is even possible is resolved before the first prompt. An account with nothing to
    connect no longer answers two prompts and then fails: it says why and continues to a local scaffold.
    That message now distinguishes "no applications yet" from "still provisioning", which the old
    NoApplicationsError got wrong for anyone mid-provision.

    A directory that already has files is no longer forced down the integrate path. init asks whether
    to connect it to a managed application or scaffold in place. Scaffolding into a non-empty directory
    was previously impossible, so a stray README or .git was enough to block a local project, and
    every route that now reaches it confirms first: starter files overwrite anything with the same name,
    and the confirmation defaults to no.

    An unreachable control plane asks before scaffolding a local stack rather than degrading silently.

    --local and --app <id> skip the new prompts, and --app without a session still fails rather
    than falling back.

  • 490391d: Add a non-interactive seamless init. --yes (-y) answers every question with the option the
    prompt marks as recommended, so a scaffold runs from CI, a Dockerfile, or a script with no terminal
    attached:

    seamless init my-app --local --yes --email=you@example.com

    Each question also gets its own flag, honored with or without --yes: --web=<id|alias> and
    --api=<id|alias> choose the starters, --email=<address> sets the owner who becomes the admin,
    --auth=<docker|local> picks how the auth server runs, and --admin=<api|image|source|none> picks
    where the admin console is hosted. Unspecified values fall back to the recommended option, except
    the owner email, which has no safe default and is taken from --email or the portal session.

    --yes deliberately stops rather than guessing in three places. Choosing between a managed
    application and a local stack needs --app <id> or --local. Scaffolding into a directory that is
    not empty needs --force, since starter files overwrite anything with the same name. Rotating a
    managed application's existing service token needs --force too, because it breaks whatever is
    already deployed on the old one.

  • cc13a6b: Connecting a project to a managed application now wires up its bundled database. init reads the
    application's database and writes DATABASE_URL into api/.env as
    postgres://USER:PASSWORD@host:port/db?sslmode=require.

    The user and password stay as literal placeholders. The control plane only returns them for
    ?reveal=true, which this CLI never asks for, so a live database credential never reaches the
    developer's disk or terminal: they copy those from the dashboard. Anything printed as a connection
    string has its userinfo masked regardless.

    An application whose database is still provisioning produces a warning rather than a failure, and the
    database is read before the service token is rotated so a missing one is never reported against a
    project whose old token has already been invalidated. Running init inside an existing project adds
    DATABASE_URL only when there is not one already, so a working connection string is never replaced
    by a placeholder.

    This needs the templates release that teaches the express starter to read DATABASE_URL and
    negotiate TLS. Until SEAMLESS_TEMPLATES_REF is bumped to it, the value is computed but the pinned
    starter does not declare the placeholder, so nothing is written.

  • 15b487a: init now asks for your email and writes it to the scaffolded auth server as OWNER_EMAIL. The auth
    server grants the admin role at account creation to a signup matching that address, so the local...

Read more

v0.10.2

Choose a tag to compare

@github-actions github-actions released this 26 Jul 20:27
0641d13

Patch Changes

  • 5c71d8c: Fix the released conformance smoke (released-smoke): bump the harness adapter's
    @seamless-auth/express pin from ^0.8.0 to ^0.9.0. The published 0.8.0 still
    served the OTP/magic-link generate routes as GET, while the harness flows and
    @seamless-auth/react 0.5.0 both POST them, so every adapter (and downstream
    react) flow failed with generate-email-otp -> 404. 0.9.0 serves them as POST,
    matching what the source (--local) conformance already builds.

v0.10.1

Choose a tag to compare

@github-actions github-actions released this 26 Jul 01:16
185a129

Patch Changes

  • 166afdd: Bump the pinned Seamless component versions the CLI pulls to their latest
    published tags: auth-api v0.3.0 → v0.4.0, admin dashboard v0.1.0 →
    v0.3.0, and the templates ref v0.3.0 → v0.4.0.

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 25 Jul 23:18
d9d6479

Minor Changes

  • 46ed8dd: Let adopters choose how the admin console is hosted during seamless init.

    The old "Include Admin Dashboard?" / image-vs-source prompts are replaced by a
    single question with four options:

    • Served by your API at /console (recommended default) — the app backend
      proxies the console via the SDK's createSeamlessConsoleProxy, so it loads
      from the API's own origin. The scaffold sets SERVE_ADMIN_CONSOLE=true on the
      API, SERVE_ADMIN_DASHBOARD=true on the auth server, and adds the API origin
      to the auth server's ORIGINS so console passkey ceremonies verify. No
      separate admin container.
    • Separate container — official image or cloned source, as before, on
      http://localhost:5174.
    • None — no console is scaffolded.

    Each choice pre-configures the auth-server env, the app-backend env, the Docker
    Compose services, seamless.config.json, the success output, and seamless check accordingly. Pins the auth API image to v0.3.0 and the templates to
    v0.3.0 (which env-gate the console proxy).

  • e612a10: Enable email_otp in the scaffolded auth server's default login methods.

    The auth server's own default (passkey,magic_link) has no method the CLI can
    drive without a browser authenticator, so seamless login could not sign in to
    a freshly scaffolded local stack. buildAuthEnv now appends email_otp to
    LOGIN_METHODS (composing with the OAuth method when providers are configured),
    so email-OTP login works out of the box.

  • 7fbaff0: Enable ALLOW_UNCREDENTIALED_DELIVERY_SECRETS=true in the scaffolded auth server env.

    Companion to the email_otp default: with it set, seamless login --local
    reads the OTP straight from the auth server's response instead of needing a mail
    provider, so signing in to a freshly scaffolded local stack works end to end.
    It's a dev-only escape hatch — the auth server ignores it under a production
    NODE_ENV, and the scaffold runs as development.

Patch Changes

  • 2e27156: Fix seamless bootstrap-admin to target the app API instead of the login profile's auth server.

    The bootstrap invite route (/auth/internal/bootstrap/admin-invite) and its
    delivery are exposed by the app API (the SeamlessAuth server adapter), not the
    auth server directly — the auth server does not serve that path. Previously
    bootstrap-admin fell back to the active profile's instanceUrl, so once a
    profile pointed at the auth server (as seamless login and the admin commands
    require), bootstrap requests 404'd.

    bootstrap-admin now resolves its target independently of any profile:
    --api-url <url> → SEAMLESS_API_URL → the local default http://localhost:3000.
    The --profile flag is removed from this command (it no longer affects the
    target; the bootstrap secret is still resolved from the local project).

  • 3dbdc61: Reconcile documentation with actual behavior.

    • README: correct the Node requirement (24, per .nvmrc/engines, not 18);
      update bootstrap-admin docs to the --api-url → SEAMLESS_API_URL →
      http://localhost:3000 resolution (the removed --profile flag and
      auth-server-profile wording are gone).
    • AGENTS.md: drop the npm run typecheck/lint/format:check commands that
      don't exist (there is no lint/format tooling yet); note the --filter=<flow>
      (= form) for verify; list the instance-management commands; remove the stale
      top-level templates/ reference (templates live in the seamless-templates
      monorepo).
    • package.json: drop the dead templates entry from files.

    Closes #94.

  • e81a07d: Make seamless check managed-aware and resilient to partial config.

    checkCompose dereferenced config.docker.composeFile, which is null for
    managed projects, so seamless check crashed with a TypeError on any managed
    scaffold. check now branches on services.auth.mode === "managed": it validates
    the remote instance's /health/status and skips the Docker/compose/container
    checks (which don't apply remotely). It also wraps JSON.parse and guards missing
    service entries so a malformed or partial seamless.config.json prints a friendly
    message instead of a stack trace. The local console health check is derived from
    services.admin.mode (image/source → :5174, api → :3000/console, none/hosted →
    skipped).

    Closes #78.

  • c4a0f93: Fix the conformance adapter flows to match the SDK's POST OTP/magic-link routes.

    @seamless-auth/express now serves OTP generate routes (and /magic-link) over
    POST, but the harness adapter flows still called them with GET, so every adapter
    spec failed at generate-email-otp -> 404 once the stack came up. The adapter
    flows now POST /auth/otp/generate-email-otp, /auth/otp/generate-login-email-otp,
    and /auth/magic-link.

    Closes #111.

  • 545aafc: Disable auth rate limits in the conformance stack.

    The conformance suite drives many OTP/registration/magic-link flows from a single
    IP and trips auth-api's dedicated per-IP limiters (which RATE_LIMIT doesn't
    tune), so the adapter layer failed with 429s once the stack came up. The verify
    compose now sets DISABLE_AUTH_RATE_LIMITS=true on the auth-api service — a
    dev-only flag (ignored under NODE_ENV=production) added in seamless-auth-api.

    Requires seamless-auth-api with DISABLE_AUTH_RATE_LIMITS support; conformance
    builds it from source, so no release is needed.

  • f7e5b5d: Fix the conformance stack and surface container logs on failure.

    auth-api 0.3.0 requires FRONTEND_URL at startup (a required system config), which
    the verify compose never set — so the auth-api container exited on boot and every
    conformance run (here and in sibling repos calling the reusable workflow) aborted
    with a bare "docker failed" before any layer ran. verify/docker-compose.verify.yml
    now sets FRONTEND_URL, and seamless verify dumps recent container logs on a
    setup failure so a container that exits on startup is diagnosable instead of hidden.

    Closes #107.

  • 54f1f02: Quote generated .env values that a dotenv parser would otherwise misread.

    writeEnv wrote bare KEY=value, so a value containing #, whitespace, quotes,
    a backslash, or a newline (e.g. a managed API_SERVICE_TOKEN or a pasted OAuth
    secret) produced a .env that dotenv truncates or mis-parses. Values that need
    it are now double-quoted and escaped, and parseEnv/parseEnvString unquote on
    read so the CLI round-trips its own output. Simple values (tokens, URLs, hex
    secrets) are still written bare.

    Closes #81.

  • 943d13d: Harden the managed init flow.

    • Explicit managed intent no longer silently scaffolds local. When --app is
      given but there is no usable session (expired or control plane unreachable),
      init now fails with an actionable message instead of quietly scaffolding a
      self-hosted project and ignoring the flag. Without --app, a missing session or
      an unreachable control plane falls back to local with a clear warning (rather
      than aborting on transient network errors, as it previously did for non-reauth
      failures). Closes #79.
    • Service-token rotation is now recoverable. Rotation invalidates the app's
      previous token, so it runs after templates are copied (the likeliest failure
      point), and every step after it is guarded: if scaffolding fails post-rotation,
      the freshly issued token is printed so a deployed app can be re-wired instead of
      left bricked. The same guard covers integrateExistingProject. Closes #80.
  • 9eaaf0e: Fix the conformance adapter crash: the dev service token was too short.

    seamless verify defaulted API_SERVICE_TOKEN to a 24-char constant, which the
    adapter reuses as its cookie secret; a newer @seamless-auth/express rejects a
    cookieSecret shorter than 32, so the adapter container exited and conformance
    failed after the stack came up. The dev service token and bootstrap secret
    defaults are now >=32 characters.

    Closes #109.