origin

package
v0.16.1 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

Documentation

Overview

Package origin is the single owner of "this workspace's origin clients".

Production code constructs a *jira.Client only through Client (the workspace's origin) or Connected (a candidate site/email/token, used when verifying a credential the user just typed). The wiki client is Wiki — the same split (standalone in-process handler vs connected site). jira.New stays exported for tests that stand up httptest servers; a gate test fails if production files grow a new direct call.

Index

Constants

View Source
const AdvertiseRel = "serve-origin.json"

AdvertiseRel is the profile-relative runtime file a standalone serve writes so other processes can find the persist owner. Connected workspaces never write it.

View Source
const DefaultProjectKey = "STD"

DefaultProjectKey is the project seeded into a new standalone origin so create/createmeta have somewhere to file. Issuetap also creates a project on first write if a caller names another key.

View Source
const DefaultSpaceKey = "LOC"

DefaultSpaceKey is the wiki space seeded into a new standalone origin so page create has somewhere to file. Short and obviously local — not a display name, and not a site-specific key.

View Source
const PersistRel = "origin/issuetap.yaml"

PersistRel is the workspace-relative path of the issuetap write-through snapshot. The file is the origin; the SQLite mirror remains a disposable cache filled by sync.

View Source
const ProbePath = "/api/v1/issues/sync/progress/"

ProbePath and probeTimeout match cmd/gadak/port_fallback.go. Origin cannot import cmd, so the values and the header contract (X-Gadak, X-Gadak-Profile) are copied here including the 700ms bound — a longer timeout would stall every CLI write when no serve is up. Exported so the desktop app's origin-only listener (GDK-340) can serve exactly the path the probe hits.

View Source
const RESTPrefix = "/api/v1/origin"

RESTPrefix is the serve passthrough root. A client request to /rest/api/3/issue is sent to <serve> + RESTPrefix + /rest/api/3/issue.

Variables

View Source
var ErrWorkspaceBusy = errors.New("origin: another process is using this workspace (persist is locked); write through its serve, or close it and retry")

ErrWorkspaceBusy means another process holds the persist lock for this workspace and did not advertise a routable origin. Embedding anyway would open a second graph over the same file (GDK-343: last Close wins, silent loss), so the caller gets this instead.

Functions

func AdvertisePath

func AdvertisePath(dir string) string

AdvertisePath is the absolute runtime-file path inside a profile directory.

func Client

func Client(cfg *config.Config) (*jira.Client, error)

Client is the single owner of "this workspace's Jira client". A connected workspace gets the same jira.New(site, email, token) as before. A standalone workspace gets a client whose Transport is the in-process issuetap handler, unless a live `gadak serve` for this profile advertised itself — then Transport is that serve's origin passthrough so persist has one owner. BaseURL stays empty so stored browse links are /browse/KEY rather than a fake https origin a person might click.

func Close

func Close() error

Close flushes every live standalone origin and drops the sessions. Safe to call more than once. The process owner (cmd/gadak main) calls this on the way out so the last PersistDebounce window is not lost.

In-flight constructors are waited on (they publish, then this snapshots) so Close never closes a half-built Embedded. There is no permanent closed flag: Client after Close must open a new session (persist is the origin; the process is allowed to come back).

func Connected

func Connected(site, email, token string) *jira.Client

Connected builds a client for an explicit site/email/token — verifying a credential the user just typed, not "this workspace's origin".

func DefaultConfluenceConfig

func DefaultConfluenceConfig() *config.ConfluenceConfig

DefaultConfluenceConfig is what initStandalone writes so the wiki sync pass is on and scoped to the seeded space. Presence of the block is the on switch (internal/sync/confluence.go).

func Describe

func Describe(cfg *config.Config) (kind, origin string)

Describe answers doctor: which kind of workspace, and where the origin is. Connected reports "jira" — "jira+linear" when the Linear source is on (no hostname or key either way; doctor is safe to paste). Standalone reports the persist path.

func ForgetLive

func ForgetLive()

ForgetLive drops cached embedded sessions without closing them. Tests use this to simulate a second process: the serve handler still holds the graph, but Client no longer finds it in this process.

func Linear added in v0.16.1

func Linear(cfg *config.Config) (*linear.Client, error)

Linear is the single owner of "this workspace's Linear client" — the same role Wiki plays for Confluence (GDK-258: a third source beside the Jira client, never a facade behind its Transport). There is no standalone variant: issuetap has no Linear surface, and the block carries its own credential rather than the Atlassian one.

func OwnerStatus

func OwnerStatus(cfg *config.Config) string

OwnerStatus is the doctor line: "serve pid=… addr=…" or "embedded (no live serve)". Empty when the workspace is not standalone.

func PersistPath

func PersistPath(dir string) string

PersistPath is the absolute issuetap snapshot path inside a profile directory.

func RemoveAdvertise

func RemoveAdvertise(dir string) error

RemoveAdvertise deletes the runtime file. Missing is not an error — crash leftover is the other path, and the next probe treats a dead file as "no live serve".

func SessionInFlight

func SessionInFlight() int64

SessionInFlight is how many standaloneSession constructions are running outside mu. Same shape as store.WriteBusyRetries: a cheap accessor, no logs.

func SessionsConstructed

func SessionsConstructed() uint64

SessionsConstructed is how many times constructStandalone ran. Tests use a delta to prove a routed Client did not open a second persist graph.

func SessionsDiscarded

func SessionsDiscarded() uint64

SessionsDiscarded is how many constructed sessions lost the publish race and were closed. Same shape as store.WriteBusyRetries.

func SetInProcess

func SetInProcess(v bool)

SetInProcess marks this process as the persist owner (`gadak serve` on a standalone workspace). Client and Wiki then always use the embedded session and never proxy to the advertise file — that would loop back onto this same listener.

func StandaloneHandler

func StandaloneHandler(cfg *config.Config) (http.Handler, error)

StandaloneHandler is the in-process issuetap HTTP surface for this workspace. Serve's origin passthrough uses it so CLI writes land on the same graph the UI already holds. Always embeds — never routes — so the serve process cannot proxy to itself through this entry.

func TransportIsEmbedded

func TransportIsEmbedded(rt http.RoundTripper) bool

TransportIsEmbedded reports whether c talks to an in-process issuetap handler. Tests use this instead of naming the unexported type.

func TransportIsServe

func TransportIsServe(rt http.RoundTripper) bool

TransportIsServe reports whether c talks to a live serve passthrough.

func Wiki

func Wiki(cfg *config.Config) (*confluence.Client, error)

Wiki is the single owner of "this workspace's Confluence client". A connected workspace gets confluence.New(site, email, token). A standalone workspace shares the in-process issuetap handler with Client.

func WriteAdvertise

func WriteAdvertise(dir, addr string) error

WriteAdvertise publishes the final listen address of a standalone serve. Atomic write (temp + rename) at 0600, same as config.Save.

Types

type Advertise struct {
	Addr      string `json:"addr"`
	PID       int    `json:"pid"`
	StartedAt string `json:"startedAt"`
}

Advertise is the JSON document in AdvertiseRel.

type GadakProbe added in v0.16.1

type GadakProbe struct {
	IsGadak bool
	Profile string
}

GadakProbe classifies a loopback GET to the progress endpoint. Exported so cmd/gadak's port fallback uses this single copy (GDK-423). Guards: 700ms context, no Origin header, X-Gadak required, profile from X-Gadak-Profile.

func ProbeGadakOnPort added in v0.16.1

func ProbeGadakOnPort(port string, timeout time.Duration) GadakProbe

type Writer added in v0.16.1

type Writer interface {
	CreateMeta(ctx context.Context, projects []string) ([]jira.CreateMetaProject, error)
	CreateIssue(ctx context.Context, fields map[string]any) (string, error)
	EditMeta(ctx context.Context, key string) (map[string]jira.FieldMeta, error)
	UpdateFields(ctx context.Context, key string, fields map[string]any) error
	EditIssue(ctx context.Context, key string, fields, update map[string]any) error
	Transitions(ctx context.Context, key string) ([]jira.Transition, error)
	Transition(ctx context.Context, key, transitionID string) error
	AddComment(ctx context.Context, key string, adf json.RawMessage) (jira.Comment, error)
	SetAssignee(ctx context.Context, key, accountID string) error
	SearchUsers(ctx context.Context, query string) ([]jira.User, error)
	PriorityCatalog(ctx context.Context) ([]jira.NamedID, error)
	Upload(ctx context.Context, key, filename string, file io.Reader) ([]jira.Attachment, error)
	MediaRef(ctx context.Context, attachmentID string) (mediaID, filename string, err error)
}

Writer is the write surface of an origin: exactly the verbs the server and CLI call when writing through. Jira (connected) and standalone (issuetap speaks the Jira API) both satisfy it via *jira.Client; a Linear adapter implements the same verbs over GraphQL (GDK-358).

The vocabulary is deliberately Jira-shaped — including the types — because two of the three origins already speak it natively. Capability negotiation stays EditMeta/CreateMeta: an origin that cannot edit a field omits it there, and the existing UI already turns fields on and off from that answer. An unsupported verb returns an honest error, never a silent no-op.

func WriterFor added in v0.16.1

func WriterFor(cfg *config.Config, source string) (Writer, error)

WriterFor picks the write path for one issue's source — the caller reads it from the mirror (store.KeySource), because a key's shape cannot tell a Linear "MID-5" from a Jira "MID-5". Jira and standalone rows share the Jira client; "linear" routes to the GraphQL adapter (GDK-361). An empty source (a key the mirror does not know yet, or a create) routes to the default origin.

Jump to

Keyboard shortcuts

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