Help us shape the future of Go! Take the 2026 Go Developer Survey

pgstore

package
v0.2.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 31 Imported by: 0

Documentation

Overview

Package pgstore is the server's Postgres persistence: every server replica shares its state, so no process owns the database.

Index

Constants

View Source
const DefaultRetention = 7 * 24 * time.Hour
View Source
const MinimumServerVersion = 180000

MinimumServerVersion is PostgreSQL 18; migrations may use its features.

View Source
const Schema = "diffx"

Schema holds every diffx table, so the server can share a database.

Variables

View Source
var ErrExpired = reviewdata.ErrExpired
View Source
var ErrInvalidURL = errors.New("invalid Postgres connection string")

ErrInvalidURL never carries the connection string, which holds credentials.

View Source
var ErrNUL = review.Error(400, "text values must not contain NUL")

ErrNUL rejects text Postgres cannot store. JSON-decoded requests are valid UTF-8, so NUL is the only unrepresentable text; previews are bytea and may hold it.

View Source
var ErrNotFound = reviewdata.ErrNotFound
View Source
var ErrSubmissionConflict = reviewdata.ErrSubmissionConflict

Functions

func Config

func Config(url string) (*pgxpool.Config, error)

Config parses a connection string and pins diffx's session settings. Pool sizing comes from URL parameters such as pool_max_conns.

func MigrationDigest

func MigrationDigest() (string, error)

MigrationDigest identifies the embedded migrations, so test harnesses can reuse a database migrated by this exact schema.

Types

type GitHubStore

type GitHubStore struct {
	// contains filtered or unexported fields
}

func (*GitHubStore) ClaimRefresh

func (s *GitHubStore) ClaimRefresh(ctx context.Context, token string, now, leaseUntil int64) (githubsync.Lease, error)

func (*GitHubStore) CompleteRefresh

func (s *GitHubStore) CompleteRefresh(ctx context.Context, lease githubsync.Lease, state, head string, admissions []githubsync.Admission, now int64) error

func (*GitHubStore) Connection

func (s *GitHubStore) Connection(ctx context.Context, ownerID string) (githubsync.Connection, error)

func (*GitHubStore) Connections

func (s *GitHubStore) Connections(ctx context.Context) ([]githubsync.Connection, error)

func (*GitHubStore) DeleteConnection

func (s *GitHubStore) DeleteConnection(ctx context.Context, ownerID string) error

Follows cascade with their connection.

func (*GitHubStore) DeleteFollow

func (s *GitHubStore) DeleteFollow(ctx context.Context, ownerID string, repositoryID int64) error

func (*GitHubStore) Follows

func (s *GitHubStore) Follows(ctx context.Context, ownerID string) ([]githubsync.Follow, error)

func (*GitHubStore) KnownOpen

func (s *GitHubStore) KnownOpen(ctx context.Context, repositoryID int64) ([]int, error)

func (*GitHubStore) Leased

func (s *GitHubStore) Leased(ctx context.Context, repositoryID int64, number int, token string, now int64) (githubsync.Lease, []byte, error)

func (*GitHubStore) LoseInstallation

func (s *GitHubStore) LoseInstallation(ctx context.Context, installationID int64, repositoryIDs []int64) error

func (*GitHubStore) PullRequestHead

func (s *GitHubStore) PullRequestHead(ctx context.Context, repositoryID int64, number int) (string, bool, error)

func (*GitHubStore) PutConnection

func (s *GitHubStore) PutConnection(ctx context.Context, c githubsync.Connection) error

func (*GitHubStore) PutFollow

func (s *GitHubStore) PutFollow(ctx context.Context, f githubsync.Follow) error

func (*GitHubStore) PutOAuthState

func (s *GitHubStore) PutOAuthState(ctx context.Context, hash, ownerID string, expiresAt int64) error

func (*GitHubStore) ReconcileAlone

func (s *GitHubStore) ReconcileAlone(ctx context.Context, reconcile func(context.Context) error) (bool, error)

ReconcileAlone runs reconcile unless another replica's reconcile holds the lock, reporting whether it ran. The session lock lives on a dedicated connection, so no transaction spans reconciliation's GitHub calls; a lost connection releases it early, which permits only a coalesced, harmless second reconcile.

func (*GitHubStore) RecordDelivery

func (s *GitHubStore) RecordDelivery(ctx context.Context, id, event string, now int64) error

func (*GitHubStore) RecordLease

func (s *GitHubStore) RecordLease(ctx context.Context, lease githubsync.Lease, leased []byte, now int64) error

func (*GitHubStore) ReleaseRefresh

func (s *GitHubStore) ReleaseRefresh(ctx context.Context, lease githubsync.Lease, retryAt int64, detail string) error

func (*GitHubStore) RepositoryFollows

func (s *GitHubStore) RepositoryFollows(ctx context.Context, repositoryID int64) ([]githubsync.Follow, error)

func (*GitHubStore) RequestRefresh

func (s *GitHubStore) RequestRefresh(ctx context.Context, ref githubsync.PullRequestRef, retentionRun string, opened bool, now int64) error

func (*GitHubStore) RevokeUser

func (s *GitHubStore) RevokeUser(ctx context.Context, userID int64) error

func (*GitHubStore) SeenDelivery

func (s *GitHubStore) SeenDelivery(ctx context.Context, id string) (bool, error)

func (*GitHubStore) SetMuted

func (s *GitHubStore) SetMuted(ctx context.Context, ownerID string, repositoryID int64, muted bool) error

func (*GitHubStore) TakeOAuthState

func (s *GitHubStore) TakeOAuthState(ctx context.Context, hash string, now int64) (string, error)

type Listener

type Listener struct {
	// contains filtered or unexported fields
}

Listener holds one dedicated session that LISTENs on every channel. Pooled connections return to the pool between statements and cannot hold LISTEN; neither can a transaction-mode PgBouncer, so the database URL must reach Postgres directly or through a session-mode pooler.

func (*Listener) Close

func (listener *Listener) Close() error

Close releases the session of a listener whose Run never started or has returned; it must not run concurrently with Run.

func (*Listener) Run

func (listener *Listener) Run(ctx context.Context, deliver func(Notification)) error

Run delivers notifications until ctx ends, then closes the session. A lost session is logged and reopened with backoff; each reopening delivers Resync. deliver runs on Run's goroutine and must not block.

type Notification

type Notification struct {
	Kind      NotificationKind
	OwnerID   string
	ContextID string
}

Notification is a hint to query durable state, never a durable event.

type NotificationKind

type NotificationKind int

NotificationKind names what another (or this) replica committed.

const (
	// ContextChanged: an observation binding or deletion of OwnerID's ContextID committed.
	ContextChanged NotificationKind = iota + 1
	// AccountRemoved: account OwnerID was disabled or deleted.
	AccountRemoved
	// JobQueued: an ingestion job became claimable.
	JobQueued
	// SettingsChanged: an admin changed the app settings.
	SettingsChanged
	// Resync: the session was lost and re-established; notifications
	// committed meanwhile were not delivered, so consumers re-read durable state.
	Resync
)

type PushStore

type PushStore struct {
	// contains filtered or unexported fields
}

func (*PushStore) ClaimNotifications

func (s *PushStore) ClaimNotifications(ctx context.Context, now, leaseUntil int64, limit int) ([]pushservice.Claim, error)

ClaimNotifications shares one token across the claimed rows; each row's transitions are fenced separately.

func (*PushStore) DeleteSubscription

func (s *PushStore) DeleteSubscription(ctx context.Context, ownerID, id string) error

func (*PushStore) FinishNotification

func (s *PushStore) FinishNotification(ctx context.Context, claim pushservice.Claim, state string) error

func (*PushStore) PushKeys

func (s *PushStore) PushKeys(ctx context.Context, generated webpush.Keys, now int64) (webpush.Keys, error)

PushKeys reads in a separate statement: its snapshot sees keys a concurrent caller committed while the insert waited on the conflict.

func (*PushStore) PutSubscription

func (s *PushStore) PutSubscription(ctx context.Context, subscription pushservice.Subscription) (pushservice.Subscription, error)

func (*PushStore) RecordDelivery

func (s *PushStore) RecordDelivery(ctx context.Context, claim pushservice.Claim, subscriptionID string, accepted bool, now int64) error

RecordDelivery holds the claim's row until commit, so a reclaim waits and then sees the outcome; the first outcome per device stands.

func (*PushStore) RecordSuccess

func (s *PushStore) RecordSuccess(ctx context.Context, subscriptionID string, now int64) error

func (*PushStore) RetryNotification

func (s *PushStore) RetryNotification(ctx context.Context, claim pushservice.Claim, attempt int, availableAt int64) error

func (*PushStore) StreamID

func (s *PushStore) StreamID(ctx context.Context, ownerID, contextID string, now int64) (string, error)

func (*PushStore) Subscriptions

func (s *PushStore) Subscriptions(ctx context.Context, ownerID string) ([]pushservice.Subscription, error)

func (*PushStore) Undelivered

func (s *PushStore) Undelivered(ctx context.Context, notificationID string) ([]pushservice.Subscription, error)

type Queue

type Queue struct {
	// contains filtered or unexported fields
}

Queue is shared by every replica's worker: claims skip rows another worker holds, and each transition is fenced by its lease token in one statement.

func (*Queue) Accept

func (queue *Queue) Accept(ctx context.Context, owner string, request ingestion.Request) (ingestionqueue.Job, error)

func (*Queue) Claim

func (queue *Queue) Claim(ctx context.Context, duration time.Duration) (ingestionqueue.Delivery, error)

Claim decodes within the claiming transaction, so an undecodable payload leaves the job unclaimed.

func (*Queue) Complete

func (queue *Queue) Complete(ctx context.Context, delivery ingestionqueue.Delivery, id string) error

Complete succeeds again when an earlier acknowledgement of the same result committed.

func (*Queue) Fail

func (queue *Queue) Fail(ctx context.Context, delivery ingestionqueue.Delivery, detail string) error

func (*Queue) Get

func (queue *Queue) Get(ctx context.Context, owner, id string) (ingestionqueue.Job, error)

func (*Queue) Renew

func (queue *Queue) Renew(ctx context.Context, delivery ingestionqueue.Delivery, duration time.Duration) error

func (*Queue) Retry

func (queue *Queue) Retry(ctx context.Context, delivery ingestionqueue.Delivery, next time.Time, detail string) error

type SchemaError

type SchemaError struct {
	Version, Floor, Supported int64
}

SchemaError reports a database written by a release this binary cannot run against.

func (*SchemaError) Error

func (failure *SchemaError) Error() string

type Store

type Store struct {
	// contains filtered or unexported fields
}

func Open

func Open(ctx context.Context, url string, retention time.Duration) (*Store, error)

Open migrates the database to this binary's schema and returns a store. It refuses servers older than PostgreSQL 18 and schemas this binary cannot run against.

func OpenWaiting

func OpenWaiting(ctx context.Context, url string, retention time.Duration, patience time.Duration) (*Store, error)

OpenWaiting retries Open while the server is unreachable, so replicas may start before their database. Other failures, such as refused schemas or credentials, return immediately.

func (*Store) AcceptInvite

func (store *Store) AcceptInvite(ctx context.Context, inviteID string, account identityservice.Account, identity google.Identity, now time.Time) error

AcceptInvite uses the pending invite in the account's transaction, so two acceptances create one account.

func (*Store) AcceptPasswordInvite added in v0.2.4

func (store *Store) AcceptPasswordInvite(ctx context.Context, inviteID string, account identityservice.Account, passwordHash string, now time.Time, required identityservice.Settings) error

AcceptPasswordInvite uses the pending invite in the password account's transaction, so two acceptances create one account.

func (*Store) AccountPassword

func (store *Store) AccountPassword(ctx context.Context, email string) (identityservice.PasswordCredential, error)

func (*Store) AccountPasswordByID

func (store *Store) AccountPasswordByID(ctx context.Context, accountID string) (identityservice.PasswordCredential, error)

func (*Store) AccountSummaries

func (store *Store) AccountSummaries(ctx context.Context) ([]identityservice.AccountSummary, error)

func (*Store) AdminExists

func (store *Store) AdminExists(ctx context.Context) (bool, error)

func (*Store) AppSettings added in v0.2.4

func (store *Store) AppSettings(ctx context.Context) (identityservice.Settings, error)

func (*Store) ClearMarks

func (store *Store) ClearMarks(ctx context.Context, contextID string, scope review.DiffMode) error

func (*Store) Close

func (store *Store) Close() error

func (*Store) Comments

func (store *Store) Comments(ctx context.Context, contextID string) ([]review.ReviewComment, error)

Comments returns the stream's comments while the context is retained.

func (*Store) CompletePasswordReset added in v0.2.4

func (store *Store) CompletePasswordReset(ctx context.Context, tokenHash, expected, replacement string, now time.Time) error

CompletePasswordReset consumes the reset, replaces the password fenced on the verified hash and revokes browser sessions at one commit.

func (*Store) Context

func (store *Store) Context(ctx context.Context, ownerID, id string, now time.Time) (reviewdata.ContextInfo, error)

func (*Store) ContextBinding

func (store *Store) ContextBinding(ctx context.Context, ownerID, id string, now time.Time) (reviewdata.Binding, error)

func (*Store) ContextCount

func (store *Store) ContextCount(ctx context.Context, ownerID string, selection ingestion.Selection, now time.Time) (int, error)

func (*Store) Contexts

func (store *Store) Contexts(ctx context.Context, ownerID string, limit int, beforeTime int64, beforeID string, now time.Time) ([]reviewdata.ContextInfo, error)

Contexts uses a keyset cursor; concurrent submissions may move an item across pages.

func (*Store) CountAuthAttempt

func (store *Store) CountAuthAttempt(ctx context.Context, client string, now time.Time, window time.Duration) (int, error)

CountAuthAttempt records one authentication attempt by client and returns the attempts in its current window, shared by every replica. A window starts at the client's first attempt and ends after window. Starting a window also prunes ended ones, so the table holds only recently active clients.

func (*Store) CreateAccount

func (store *Store) CreateAccount(ctx context.Context, account identityservice.Account, passwordHash string, created time.Time, required identityservice.Settings) error

CreateAccount commits a member and its credential together. An empty hash never verifies, so such an account has no password sign-in.

func (*Store) CreateAdmin

func (store *Store) CreateAdmin(ctx context.Context, account identityservice.Account, passwordHash, setupHash string, now time.Time) error

CreateAdmin consumes the setup secret, so concurrent setups create one admin.

func (*Store) CreateGoogleAccount added in v0.2.4

func (store *Store) CreateGoogleAccount(ctx context.Context, account identityservice.Account, identity google.Identity, now time.Time, required identityservice.Settings) error

CreateGoogleAccount commits an account and its Google identity without an invite; a subject linked concurrently is ErrNotFound.

func (*Store) CreateGoogleAdmin added in v0.2.4

func (store *Store) CreateGoogleAdmin(ctx context.Context, account identityservice.Account, identity google.Identity, setupHash string, now time.Time) error

CreateGoogleAdmin is CreateAdmin for a new account with a Google identity.

func (*Store) CreateIdentityToken

func (store *Store) CreateIdentityToken(ctx context.Context, accountID string, token identityservice.Token, secretHash string) error

func (*Store) CreateInvite

func (store *Store) CreateInvite(ctx context.Context, invite identityservice.Invite, tokenHash string) error

CreateInvite replaces the email's pending invites, refusing an email an account already uses, in one transaction. The email lock orders it with other invitations and acceptances of the email.

func (*Store) CreateSession

func (store *Store) CreateSession(ctx context.Context, accountID, expected, secretHash, csrf string, expires time.Time) error

CreateSession issues only against the verified hash of an enabled account. The account lock precedes the check, so the check's snapshot includes any credential change that committed first, and later changes revoke the session.

func (*Store) DeleteAccount

func (store *Store) DeleteAccount(ctx context.Context, accountID string) error

DeleteAccount removes the owner row; foreign keys cascade to everything it owns. Queued jobs reference ingestion records without a cascade, so they go first; the owner lock keeps new records out until the delete commits.

func (*Store) DeleteComment

func (store *Store) DeleteComment(ctx context.Context, contextID, commentID string) (bool, error)

func (*Store) DeleteComments

func (store *Store) DeleteComments(ctx context.Context, contextID string, selected map[string]bool) (int, error)

func (*Store) DeleteContext

func (store *Store) DeleteContext(ctx context.Context, ownerID, id string) error

DeleteContext removes the context and every scope's snapshot. Review state survives while its stream has another observation. Stream heads intentionally survive so older observations remain stale. The deletion is announced on contextChannel.

func (*Store) DeleteIdentityToken

func (store *Store) DeleteIdentityToken(ctx context.Context, accountID, tokenID string) error

func (*Store) DeleteMark

func (store *Store) DeleteMark(ctx context.Context, contextID string, scope review.DiffMode, fileID string) error

DeleteMark and ClearMarks remove only marks visible in this context.

func (*Store) DeleteSession

func (store *Store) DeleteSession(ctx context.Context, secretHash string) error

func (*Store) GitHub

func (store *Store) GitHub() *GitHubStore

GitHub adapts the store to the integration's storage contract.

func (*Store) GoogleAccount

func (store *Store) GoogleAccount(ctx context.Context, identity google.Identity, now time.Time) (identityservice.Account, bool, error)

func (*Store) IdentityAccounts

func (store *Store) IdentityAccounts(ctx context.Context) ([]identityservice.Account, error)

func (*Store) IdentityTokens

func (store *Store) IdentityTokens(ctx context.Context, accountID string) ([]identityservice.Token, error)

func (*Store) ImportComments

func (store *Store) ImportComments(ctx context.Context, contextID string, comments []review.ReviewComment) ([]review.ReviewComment, error)

func (*Store) IngestContext

func (store *Store) IngestContext(ctx context.Context, ownerID string, request ingestion.Request) (reviewdata.Binding, error)

IngestContext atomically commits an immutable observation and its retry identity, and announces the binding on contextChannel. Checkout paths are labels; this method never accesses a producer filesystem.

func (*Store) Invite

func (store *Store) Invite(ctx context.Context, id string) (identityservice.Invite, error)

func (*Store) Invites

func (store *Store) Invites(ctx context.Context) ([]identityservice.Invite, error)

func (*Store) Listen

func (store *Store) Listen(ctx context.Context) (*Listener, error)

Listen opens the listening session before returning, so a composition that serves afterwards misses no commit while the session lasts.

func (*Store) Marks

func (store *Store) Marks(ctx context.Context, contextID string, scope review.DiffMode) ([]review.ReviewMark, error)

Marks returns stream marks whose file patch is unchanged in this context, projected onto this context's snapshot.

func (*Store) ObservationCommitFileVersion

func (store *Store) ObservationCommitFileVersion(ctx context.Context, ownerID, contextID, oid, fileID string) (reviewdata.FileVersion, error)

ObservationCommitFileVersion reads only indexed identities of a commit's file.

func (*Store) ObservationCommitPatch

func (store *Store) ObservationCommitPatch(ctx context.Context, ownerID, contextID, oid, fileID, fileVersion string) (review.FilePatch, error)

func (*Store) ObservationCommitSnapshot

func (store *Store) ObservationCommitSnapshot(ctx context.Context, ownerID, contextID, oid string) (review.RepositoryDiff, error)

ObservationCommitSnapshot reads a captured commit's diff. Merge commits and commits outside the observation are not found.

func (*Store) ObservationCommits

func (store *Store) ObservationCommits(ctx context.Context, ownerID, contextID string) ([]review.CommitSummary, review.CommitRange, error)

ObservationCommits lists an unexpired observation's captured commits, oldest first, with the count of omitted older commits.

func (*Store) ObservationContexts

func (store *Store) ObservationContexts(ctx context.Context, ownerID string, limit int, beforeTime int64, beforeID string, filter ingestion.Filter) ([]reviewdata.ContextInfo, error)

ObservationContexts filters immutable observations using captured metadata.

func (*Store) ObservationFileVersion

func (store *Store) ObservationFileVersion(ctx context.Context, ownerID, contextID string, mode review.DiffMode, fileID string) (reviewdata.FileVersion, error)

ObservationFileVersion reads only indexed identities. Missing files retain the scope identity so callers can reject stale scope references before file errors.

func (*Store) ObservationPatch

func (store *Store) ObservationPatch(ctx context.Context, ownerID, contextID string, mode review.DiffMode, fileID, fileVersion string) (review.FilePatch, error)

func (*Store) ObservationSnapshot

func (store *Store) ObservationSnapshot(ctx context.Context, ownerID, contextID string, mode review.DiffMode) (review.RepositoryDiff, error)

func (*Store) PasswordReset added in v0.2.4

func (store *Store) PasswordReset(ctx context.Context, tokenHash string, now time.Time) (identityservice.PasswordCredential, error)

func (*Store) PendingAdminSetup added in v0.2.4

func (store *Store) PendingAdminSetup(ctx context.Context, setupHash string, now time.Time) (bool, error)

func (*Store) PendingInvite

func (store *Store) PendingInvite(ctx context.Context, tokenHash string, now time.Time) (identityservice.Invite, error)

func (*Store) Ping

func (store *Store) Ping(ctx context.Context) error

Ping reports whether the database accepts queries.

func (*Store) PromoteSetupAdmin added in v0.2.4

func (store *Store) PromoteSetupAdmin(ctx context.Context, accountID, setupHash string, now time.Time) error

PromoteSetupAdmin consumes the setup secret for an existing enabled account.

func (*Store) PruneExpired

func (store *Store) PruneExpired(now time.Time) error

PruneExpired removes expired observations with every scope and commit diff, ends streams without observations, and drops finished integration records. It returns without pruning while another replica's pass holds the prune lock; reads enforce expiry, so skipping only defers removal.

func (*Store) Push

func (store *Store) Push() *PushStore

Push adapts the store to the push service's storage contract.

func (*Store) PutAdminSetup

func (store *Store) PutAdminSetup(ctx context.Context, tokenHash string, expires time.Time) (bool, error)

func (*Store) PutAppSettings added in v0.2.4

func (store *Store) PutAppSettings(ctx context.Context, settings identityservice.Settings, actorID string, at time.Time) error

PutAppSettings notifies every replica in the transaction that commits the change.

func (*Store) PutComment

func (store *Store) PutComment(ctx context.Context, contextID string, comment review.ReviewComment) error

PutComment stores a comment in the context's stream review. New references must name this context's snapshot; an existing comment may keep the snapshot it was written against.

func (*Store) PutGoogleFlow

func (store *Store) PutGoogleFlow(ctx context.Context, stateHash string, flow identityservice.GoogleFlow) error

func (*Store) PutMark

func (store *Store) PutMark(ctx context.Context, contextID string, mark review.ReviewMark) error

func (*Store) PutPasswordReset added in v0.2.4

func (store *Store) PutPasswordReset(ctx context.Context, accountID, tokenHash string, expires time.Time) error

PutPasswordReset replaces the account's pending reset.

func (*Store) Queue

func (store *Store) Queue() *Queue

func (*Store) ReplaceComment

func (store *Store) ReplaceComment(ctx context.Context, contextID string, comment review.ReviewComment) (bool, error)

ReplaceComment updates an existing stream comment and reports false when it no longer exists, so an edit racing a delete cannot recreate the comment.

func (*Store) ReplacePassword

func (store *Store) ReplacePassword(ctx context.Context, accountID, expected, replacement string) error

ReplacePassword fences authentication against password changes/reset, and invalidates every browser session at the same commit. API tokens are independent.

func (*Store) ResolveIdentityToken

func (store *Store) ResolveIdentityToken(ctx context.Context, secretHash string, now time.Time) (identityservice.TokenIdentity, error)

ResolveIdentityToken authenticates and records the use in one statement.

func (*Store) ResolveSession

func (store *Store) ResolveSession(ctx context.Context, secretHash string, now time.Time) (identityservice.Session, error)

func (*Store) RevokeInvite

func (store *Store) RevokeInvite(ctx context.Context, id string, at time.Time) error

RevokeInvite revokes a pending invite; used, revoked or unknown invites are ErrNotFound.

func (*Store) SetAccountDisabled

func (store *Store) SetAccountDisabled(ctx context.Context, accountID string, disabled bool, at time.Time) error

SetAccountDisabled revokes every browser session and API token at the commit that disables the account; enabling restores sign-in, not those credentials.

func (*Store) SetAdmin added in v0.2.4

func (store *Store) SetAdmin(ctx context.Context, accountID string, admin bool) error

SetAdmin grants or removes the admin role; removing the last enabled admin is ErrLastAdmin.

func (*Store) StoredVersion

func (store *Store) StoredVersion(ctx context.Context, ownerID, diffID, versionID string, now time.Time) (review.RepositoryDiff, error)

func (*Store) TakeGoogleFlow

func (store *Store) TakeGoogleFlow(ctx context.Context, stateHash string, now time.Time) (identityservice.GoogleFlow, error)

TakeGoogleFlow deletes the flow as it reads it, so one callback consumes it.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL