theme_extension

package
v0.0.0-...-1d1a5ee Latest Latest
Warning

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

Go to latest
Published: Jul 23, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package te holds the te (theme-extension) leg's business logic: project config (the extension_id truth source), store-openapi calls, and the theme-app/-wrapped scaffold.

Index

Constants

View Source
const (
	// StorePublicationsPath is the store-openapi (2020-07) publications endpoint
	// (te deploy → store-visible). PartnerPublicationsPath is the partner-openapi
	// one (te release → app-visible). Same body, different base+token.
	// Note: publications lives at 2024-07; the 2025-06 partner-openapi has
	// /connection but not /publications (404).
	StorePublicationsPath   = "/openapi/2020-07/theme-extensions/publications"
	PartnerPublicationsPath = "/openapi/2024-07/theme-extensions/publications"
)

Variables

View Source
var ErrThemeAppMissing = errors.New("theme-app is missing or not a directory")

ErrThemeAppMissing marks the only user-fixable ZipThemeApp failure: there is no theme-app/ directory under the project root. Callers branch with errors.Is — this case is validation, everything else (perms, read errors, zip writes) is internal.

Functions

func CompareVersions

func CompareVersions(a, b string) int

CompareVersions returns -1, 0, or 1 as a<b, a==b, a>b, comparing dot-separated numeric segments left-to-right. A missing or unparseable segment counts as 0 (deliberate: the comparison stays total) — callers that need a confirmed ordering must pre-validate both sides with ValidVersionFormat.

func CreateDevDocFile

func CreateDevDocFile(ctx context.Context, store *client.Client, extensionID, fileType, location, content string) *output.ExitError

CreateDevDocFile pushes a newly-added file (POST dev-doc {type,location,content}).

func DeleteDevDocFile

func DeleteDevDocFile(ctx context.Context, store *client.Client, extensionID, fileType, location string) *output.ExitError

DeleteDevDocFile removes a file (DELETE dev-doc?type=&location=). v1 sends the target as query params (no body) on delete.

func DevDocTarget

func DevDocTarget(relSlash string) (fileType, location string)

DevDocTarget maps a forward-slash relative path under theme-app/ to the (type, location) the dev-doc endpoint expects, replicating v1 getFileInfo: type = the immediate parent directory name, location = the base file name.

func LatestVersion

func LatestVersion(vers []map[string]any) string

LatestVersion returns the "version" of the newest entry — index 0, since the versions API returns newest-first. Empty when the list is empty or the field is missing/non-string.

func ListExtensions

func ListExtensions(ctx context.Context, store *client.Client) ([]map[string]any, *output.ExitError)

ListExtensions GETs /theme-extensions (store-token) — the store's private theme-extension list. Also the recovery path: a lost config can find its extension_id back here by title/name.

func ListVersions

func ListVersions(ctx context.Context, store *client.Client, extensionID string) ([]map[string]any, *output.ExitError)

ListVersions GETs /theme-extensions/{id}/versions (store-token).

func Publish

func Publish(ctx context.Context, c *client.Client, path, extensionID, versionID string) *output.ExitError

Publish POSTs {extension_id, version_id, type:"enable"} to a publications endpoint. The CALLER supplies the path AND a client already pointed at the right base with the right token (store for deploy, partner for release) — this function is base/token-agnostic so the two commands cannot diverge.

func PushDevDoctree

func PushDevDoctree(ctx context.Context, store *client.Client, extensionID, resourceURL string, pollInterval time.Duration, maxRetry int) *output.ExitError

PushDevDoctree pushes the full dev tree (PATCH /theme-extensions/{id}/dev-doctree) — a dev-state push, not a formal version (no version explosion via POST /version-tasks). resourceURL is the OSS url of the freshly zipped theme-app/.

The push is async: the PATCH response carries {task_id}. We poll that task to completion at GET /version-tasks/{id} (state 1 = done, 2 = failed) — the same task-status endpoint v1's serve polls. Polling at that path does not mint a formal version (that requires a POST to /version-tasks). pollInterval/maxRetry bound the wait. A response without task_id is treated as a synchronous 2xx success (defensive; live data always carries one).

func Register

func Register(ctx context.Context, store *client.Client, root, name, resourceURL, version, description string, pollInterval time.Duration, maxRetry int) (app.UpsertResult, *output.ExitError)

Register performs the no-connect registration for a te project: it reuses app.RegisterThemeExtension (PUT theme-extensions + version-tasks + poll) — the same store-openapi machinery app deploy's theme leg uses — then writes the resulting extension_id back to extension.config.json (truth source). create-vs-commit is decided by the config's existing extension_id, not a partner-context query (te is store-side, pre-connect). It never connects.

version is the per-build semver: `te serve` passes "" (create at 1.0.0 on a fresh extension, no bump on re-register); `te build` passes the user's --version, honored on both the create and commit path (v1 te accepts any valid semver even on the first build). resourceURL is the OSS url from a prior ossupload.Upload of the zipped theme-app/ directory.

func Scaffold

func Scaffold(destDir, name, themeType string) error

Scaffold materializes the bundled basic|embed te template into destDir and applies v1's initProj rewrite. It keeps the theme-app/ wrapper (zip root + dev-doc type=parentDirName carrier) and writes nothing outside destDir. The extension.config.json is written by the caller via WriteConfig.

func UpdateDevDocFile

func UpdateDevDocFile(ctx context.Context, store *client.Client, extensionID, fileType, location, content string) *output.ExitError

UpdateDevDocFile pushes a changed file (PATCH dev-doc {type,location,content}).

func UpsertDevDocFile

func UpsertDevDocFile(ctx context.Context, store *client.Client, extensionID, fileType, location, content string) *output.ExitError

UpsertDevDocFile ensures a dev-doc file holds content: PATCH it, and if the per-file doc doesn't exist yet, fall back to POST-create. The doc can be absent on an "update" for two reasons: (1) the initial bulk dev-doctree push does not seed the per-file dev-doc store, so the first per-file touch finds nothing; (2) atomic-save editors fire remove+create+chmod, which the fsnotify watcher coalesces to a chmod and delivers as "update".

func ValidVersionFormat

func ValidVersionFormat(v string) bool

ValidVersionFormat reports whether v is X.Y.Z (numeric segments only).

func VersionIDFor

func VersionIDFor(vers []map[string]any, v string) (string, bool)

VersionIDFor resolves a human semver value (e.g. "1.0.0") to its server version_id by scanning the version list. Versions are newest-first, so the first match wins (version values are unique per extension). Returns ok=false when no entry's "version" equals v or the match carries no "version_id".

func WriteConfig

func WriteConfig(root string, c Config) error

WriteConfig writes the config atomically (unique temp + rename) as v1-style extension.config.json — the only persistence of extension_id across processes.

func ZipThemeApp

func ZipThemeApp(root string) (string, error)

ZipThemeApp zips <root>/theme-app/ including the "theme-app/" wrapper directory as the entry prefix (e.g. "theme-app/blocks/x.liquid"), matching v1's compress. The backend's version-task / doctree parser requires this wrapper: it unzips and reads files under "theme-app/…" (e.g. theme-app/assets-manifest.json). A flattened zip (entries at the root) makes the parser build no doc — the version is created but doc-less, and a later `te release` fails with "version has no doc". Returns the zip path under <root>/.te-build/.

Types

type Config

type Config struct {
	ExtensionID string // extensionId — truth source
	ClientID    string // appId — the bound app's client_id (written by connect)
	PartnerID   string // partnerId — owning partner of the bound app (written by connect; lets release skip the partner lookup)
	Name        string // extensionName (basic) / extensionTitle (embed)
	Version     string // version — last-built semver (te build writeback); te deploy's default target
	Type        string // type: theme
	Subtype     string // subtype: basic | embed
}

Config is the te project's persisted state. extension_id is the single cross-process truth source for the binding chain (connect/deploy/release run in separate processes and cannot share memory). client_secret is never stored. On-disk JSON keys match v1 (see rawConfig); Type/Subtype are v2 additions.

func ReadConfig

func ReadConfig(root string) (Config, error)

ReadConfig loads extension.config.json from root. A missing file keeps its fs.ErrNotExist identity (callers branch with errors.Is — "not a te project"); a present-but-undecodable file is a distinct "malformed" error so callers never tell the user to re-register (which would orphan the extension_id the corrupt file still holds).

func RequireExtensionID

func RequireExtensionID(root string) (Config, *output.ExitError)

RequireExtensionID reads the config and returns a validation error when extension_id is absent — connect/deploy/release/versions must not silently fail. Missing file / empty id → hint to register; malformed file → the malformed message (not the register hint, see ReadConfig).

Jump to

Keyboard shortcuts

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