Documentation
¶
Overview ¶
Package pack implements Līdza packs: a directory under packs/ with a manifest, a Rust crate compiled to WASM, and a generated Go wrapper that exposes each capability as a typed method backed by the engine.
Index ¶
- Constants
- Variables
- func Build(ctx context.Context, root string, m *Manifest, out io.Writer) error
- func BuildStale(ctx context.Context, root string, names []string, out io.Writer) error
- func Generate(root, module, appDir string, names []string, s *schema.Schema) ([]string, error)
- func GeneratePackGo(m *Manifest, module string) string
- func GeneratePacksGo(pkg, module string, names []string) string
- func IsOfficialGo(entry string) bool
- func NeedsBuild(root string, m *Manifest) bool
- func SyncFragments(root string, packs []string) ([]string, error)
- type Capability
- type Manifest
- type Official
- type Problem
- type Rust
- type SQLCSync
- type Setting
Constants ¶
const Dir = "packs"
Dir is where an app keeps its packs, relative to the project root.
const ManifestFile = "pack.lidza.json"
ManifestFile is the manifest name inside a pack directory.
const OfficialPrefix = "lidza/"
OfficialPrefix marks a Go pack imported from the framework in lidza.json ("lidza/db"). Official Rust packs are copied into the app as local packs, so they carry no prefix.
const PacksFile = "packs.go"
PacksFile is the generated registry in the app's package (the root's package main, or lidza.json's appDir).
const QueriesDir = "db/queries"
QueriesDir holds the SQL files sqlc compiles.
const SQLCFile = "sqlc.yaml"
SQLCFile is the sqlc configuration `lidza pack add db` writes.
const SQLCInstall = "CGO_ENABLED=1 go install github.com/sqlc-dev/sqlc/cmd/sqlc@" + SQLCVersion
SQLCInstall is the command that installs SQLCVersion. sqlc's Postgres parser is C, so it builds with cgo.
const SQLCVersion = "v1.31.1"
SQLCVersion is the sqlc release the framework supports: install.sh installs it, the generated Dockerfile builds it, lidza build names it.
Variables ¶
var Officials = []Official{ { Name: "db", Description: "Postgres: bounded pgx pool from DATABASE_URL, migrations from db/migrations, typed queries with sqlc.", Env: []string{ "# lidza/db. lidza install writes this machine's address: the Postgres socket", "# (/var/run/postgresql on Linux, /tmp on macOS) or 127.0.0.1:5432.", "DATABASE_URL=postgres:///app_dev?host=/var/run/postgresql", "DB_MAX_CONNS=10", "# DB_MIGRATE=true # apply db/migrations at start", }, Notes: []string{ "set DATABASE_URL in .env; `lidza db migrate` applies db/migrations", "write SQL in db/queries/*.sql; `lidza gen` turns it into Go (db/queries/gen) with sqlc", "in a handler: queries.New(db.From(ctx)).YourQuery(ctx, ...)", }, Production: []Setting{{Name: "DATABASE_URL", Why: "the production Postgres"}}, }, { Name: "realtime", Description: "WebSocket topics at GET /api/v1/realtime; handlers publish JSON; a Valkey bus fans out across nodes.", Env: []string{ "# lidza/realtime", "# REALTIME_BUS_URL=redis://127.0.0.1:6379 # required with more than one node", "REALTIME_MAX_CONNS=10000", }, Notes: []string{ "register the endpoint in routes.go behind auth.Require(): r.Handle(\"GET /api/v1/realtime\", realtime.Handler(realtime.Authorize(fn))); without Authorize no topic can be subscribed, realtime.AllowAll opens them all", "publish from a handler: realtime.From(ctx).Publish(ctx, \"topic\", value)", "browser: new WebSocket(`ws://${location.host}/api/v1/realtime?topics=topic`)", }, }, { Name: "cache", Description: "Cache on Valkey or Redis with TTL and read-through Remember; CACHE_URL=memory for tests.", Env: []string{ "# lidza/cache", "CACHE_URL=redis://127.0.0.1:6379", "# CACHE_URL=memory # bounded in-process cache for one node or tests", }, Notes: []string{ "cache.Remember(ctx, cache.From(ctx), \"key\", ttl, load) caches a computed value", "cache.From(ctx).Invalidate(ctx, \"prefix:\") after writes", "shared counters (a rate limit across nodes): n, err := cache.From(ctx).Incr(ctx, \"rate:\"+ip, 1, time.Minute)", }, Production: []Setting{{Name: "CACHE_URL", Why: "a Valkey or Redis address (memory holds one node's cache only)", Dev: []string{"memory"}}}, }, { Name: "auth", Description: "Sessions and tokens: argon2id passwords, short-lived JWT access tokens, refresh sessions in Postgres, cookies or bearer, auth.Require middleware.", Env: []string{ "# lidza/auth (needs lidza/db). AUTH_SECRET is generated on the first start and kept in the database.", "# AUTH_ACCESS_TTL=15m # app setting: lidza settings set AUTH_ACCESS_TTL=15m", "# AUTH_REFRESH_TTL=720h # app setting", "# AUTH_COOKIE_SECURE=true # behind TLS", "# AUTH_LOGIN_RPS=1 # credential attempts per second per client (auth.Throttle)", "# AUTH_LOGIN_BURST=5", "# AUTH_SIGNIN_RPS=1 # sign-in attempts per second per client (auth.ThrottleSignIn); unset: AUTH_LOGIN_RPS", "# AUTH_SIGNIN_BURST=5 # unset: AUTH_LOGIN_BURST", "# AUTH_MIN_PASSWORD=10 # auth.ValidatePassword floor", "# AUTH_TOKEN_TTL=1h # verification and reset links", "# AUTH_OWNER_CLAIM=true # public deploys: the first admin claims with a one-time token (config/owner-claim/token), not by signing in first", "# AUTH_PROVIDERS=google,github # sign-in providers for auth.Mount; ids and secrets in the credentials", "# AUTH_CONNECT=github # external accounts users connect (auth.Connection); AUTH_CONNECT_GITHUB_CLIENT_ID and _CLIENT_SECRET in the credentials, _SCOPES optional", }, Notes: []string{ "sign-in: auth.Mount(r, auth.Options{}) in routes.go serves register, login, logout, session, verification, reset and the AUTH_PROVIDERS sign-ins on the pack's own tables (recipe \"Add sign-in\"); or keep your own users table and call auth.From(ctx).Login after auth.CheckPassword", "login: tokens, err := auth.From(ctx).Login(ctx, userID, claims); for browsers add auth.From(ctx).Cookies(tokens) with req.SetCookie", "protect routes: g := r.Group(\"/api/v1/notes\", auth.Require()); auth.CurrentUser(ctx) inside; auth.Optional() where visitors are served too", "throttle the credential routes: router.Route(r, \"POST /api/v1/auth/register\", register, auth.Throttle()), and sign-in with its own limit: router.Route(r, \"POST /api/v1/auth/login\", login, auth.ThrottleSignIn()); check passwords with auth.From(ctx).ValidatePassword(pw, email)", "email verification and password reset: auth.From(ctx).IssueToken(ctx, auth.PurposeVerifyEmail, email, 0) and ConsumeToken; the app sends the link", "external accounts: AUTH_CONNECT=github (or Options.Connectors with auth.OAuth2Connect); the user goes to /api/v1/auth/connect/github/start, the server calls the API with auth.From(ctx).Connection(ctx, owner, \"github\") and its Client(); tokens sealed in auth_connection, never in the browser (recipe \"Connect an external account\")", "roles and permissions per team: var roles = auth.Roles{\"admin\": {\"*\"}, \"editor\": {\"posts.*\"}, \"viewer\": {\"posts.read\"}}; roles.Grant(ctx, subject, team, \"editor\"); guard routes with roles.Require(\"posts.write\", func(r *http.Request) string { return r.PathValue(\"team\") }), or roles.Check(ctx, team, perm) in a handler; checked on every request (recipe \"Roles and permissions\")", "working code: lidza snippet routes, lidza snippet auth-handlers", "run `lidza gen` and `lidza db migrate`: the auth_session table comes from schema.lidza", }, Production: []Setting{{Name: "AUTH_SECRET", Why: "a random secret of 32 bytes or more, signing sessions"}}, }, { Name: "jobs", Description: "Background jobs on Postgres: bounded workers per node, retries with backoff, delayed and recurring runs, takeover of jobs whose node died, release of running jobs at shutdown.", Env: []string{ "# lidza/jobs (needs lidza/db)", "JOBS_WORKERS=4", "JOBS_MAX_ATTEMPTS=5", "# JOBS_DRAIN=1s # at shutdown, running jobs may finish this long, then go back to pending", }, Notes: []string{ "register handlers in OnStart: jobs.FromServices(s).Handle(\"email\", func(ctx, payload) error {...})", "enqueue from a handler: jobs.From(ctx).Enqueue(ctx, \"email\", payload, jobs.RunAt(t))", "recurring: jobs.FromServices(s).Schedule(\"digest\", jobs.Weekly(time.Monday, \"09:00\", \"Europe/Tirane\"), nil) in OnStart; also jobs.Every(15*time.Minute), jobs.Daily(\"06:30\", zone)", "run `lidza gen` and `lidza db migrate`: the job and job_schedule tables come from schema.lidza", }, }, { Name: "i18n", Description: "Localization: catalogs in locales/<lang>.json embedded in the binary, locale per request, numbers, currency and dates.", Env: []string{"# lidza/i18n", "I18N_DEFAULT=en"}, Notes: []string{ "messages: i18n.From(ctx).T(ctx, \"greeting\", name); add locales/<lang>.json files", "pages (react, svelte): t('key') from src/i18n.ts; npm run build prerenders each page per locale and the binary serves the visitor's", "catalog for other clients: r.Handle(\"GET /api/v1/i18n/{lang}\", i18n.Handler())", }, }, { Name: "analytics", Description: "Opt-in error reporting and product events: server panics and 500s, frontend errors and named events stored in Postgres, optional OTLP export.", Env: []string{ "# lidza/analytics (needs lidza/db)", "# ANALYTICS_OTLP_URL=http://127.0.0.1:4318/v1/logs # export errors to a collector (Sentry, Grafana, GlitchTip accept OTLP)", "ANALYTICS_RETENTION=720h", "# VITE_ANALYTICS=1 # turn on the frontend reporter (react template)", }, Notes: []string{ "register the endpoint in routes.go: r.Handle(\"POST /api/v1/analytics/{kind}\", analytics.Handler())", "server errors are captured automatically (panics, 500s); events: analytics.From(ctx).Track(ctx, \"signup\", props)", "frontend: set VITE_ANALYTICS=1 in .env; src/analytics.ts reports errors and pageviews, track(name, props) for events", "run `lidza gen` and `lidza db migrate`: the app_error and app_event tables come from schema.lidza", "agents: the MCP tool lidza_errors lists recent errors", }, }, { Name: "audit", Description: "A durable audit log: who did what to which resource, when and how it went, recorded from routes and jobs with the signed-in user as the actor, secrets redacted, paginated, pruned after a retention.", Env: []string{ "# lidza/audit (needs lidza/db; lidza/auth for user actors)", "AUDIT_RETENTION=8760h # records older than this are pruned daily; 0 keeps them", }, Notes: []string{ "record: audit.From(ctx).Record(ctx, audit.Event{Action: \"post.publish\", Resource: \"post/\" + id}); RecordTx(ctx, tx, e) inside the change's transaction", "jobs and startup steps: audit.System(ctx, \"nightly-export\") names the actor", "read: audit.From(ctx).List(ctx, audit.Query{Scope: team, Limit: 50}), then Query.Cursor = page.Next", "run `lidza gen` and `lidza db migrate`: the audit_event table comes from schema.lidza", }, }, { Name: "billing", Description: "Subscriptions on Stripe: the app's plans in code, Checkout and the customer portal, subscriptions synced from Stripe's signed webhooks, feature checks without calling Stripe.", Env: []string{ "# lidza/billing (needs lidza/db; the keys are app settings)", "# lidza settings set STRIPE_SECRET_KEY=sk_test_... STRIPE_WEBHOOK_SECRET=whsec_...", }, Notes: []string{ "plans in code: var plans = billing.Plans{\"pro\": {Name: \"Pro\", Price: \"price_...\", Features: []string{\"exports\"}}}", "routes: plans.Mount(r, billing.Options{}) serves /api/v1/billing, /checkout, /portal and Stripe's /webhook", "check: plans.Has(ctx, owner, \"exports\") or plans.Require(ctx, owner, \"exports\") (402)", "in Stripe: a webhook endpoint at /api/v1/billing/webhook for checkout.session.completed and customer.subscription.*", "run `lidza gen` and `lidza db migrate`: billing_customer and billing_subscription come from schema.lidza", }, Production: []Setting{{Name: "STRIPE_SECRET_KEY", Why: "Stripe's live secret key (sk_live_...)", Dev: []string{}}, {Name: "STRIPE_WEBHOOK_SECRET", Why: "the signing secret of the live webhook endpoint"}, {Name: "APP_URL", Why: "where Checkout and the portal send customers back"}}, }, { Name: "hooks", Description: "Outbound webhooks: events sent to the URLs an app's users subscribe, signed (Standard Webhooks), delivered through the jobs pack with retries over about eleven hours, a delivery log with replay, failing endpoints disabled, internal addresses refused.", Env: []string{ "# lidza/hooks (needs lidza/db and lidza/jobs, and the master key for endpoint secrets)", "# HOOKS_ALLOW_PRIVATE=true # development only: endpoints on localhost and private networks", "HOOKS_TIMEOUT=10s", "HOOKS_DISABLE_AFTER=20 # deliveries in a row that failed every attempt before an endpoint is disabled", "HOOKS_MAX_ENDPOINTS=20 # per owner", "HOOKS_RETENTION=720h # deliveries kept; 0 keeps them", }, Notes: []string{ "send: hooks.From(ctx).Send(ctx, owner, \"order.paid\", order); SendTx(ctx, tx, ...) inside the change's transaction", "routes for users to manage their endpoints: hooks.Mount(r, hooks.Options{}) (owner: the workspace, else the user)", "receivers verify with webhook.Standard(\"THEIR_SECRET\", handler) (pkg/webhook) or any Standard Webhooks library", "run `lidza gen` and `lidza db migrate`: hook_endpoint and hook_delivery come from schema.lidza", }, Production: []Setting{{Name: "HOOKS_ALLOW_PRIVATE", Why: "must be off in production: endpoints may not reach internal addresses", Dev: []string{"true", "1"}, Optional: true}}, }, { Name: "mail", Description: "Transactional email behind one Send: Mailgun, SendGrid, Postmark, Resend or SMTP over plain HTTP, log and outbox providers for development and tests, templates in mail/, an outbox table with the db pack, background delivery with retries through the jobs pack.", Env: []string{ "# lidza/mail (list lidza/db and lidza/jobs before it for the outbox and background delivery) (app settings: set them here, or keep them in the app with the admin pages or lidza settings set NAME=value)", "# MAIL_PROVIDER=log # log | outbox | smtp | mailgun | sendgrid | postmark | resend", "# MAIL_FROM=\"App <app@example.com>\" # development default: dev@localhost", "# APP_URL=https://app.example.com # where links in emails point; development default: http:// plus LIDZA_ADDR", "# MAIL_API_KEY= # mailgun, sendgrid, postmark, resend", "# MAIL_DOMAIN=example.com # mailgun", "# MAIL_BASE_URL=https://api.eu.mailgun.net # a provider's regional API", "# MAIL_SMTP_URL=smtp://user:pass@smtp.example.com:587 # or smtps://...:465", "# MAIL_MAX_ATTEMPTS=5 # delivery retries through the jobs pack", }, Notes: []string{ "send: mail.From(ctx).Send(ctx, mail.Message{To: email, Subject: \"Verify your email\", Template: \"verify\", Data: data})", "templates: mail/<name>.txt.tmpl and mail/<name>.html.tmpl (Go templates over Data); or set Text and HTML on the message", "tests: MAIL_PROVIDER=outbox in .env.test, then mail.From(ctx).Outbox(ctx, 10) has the messages; agents: the MCP tool lidza_mail", "never import a vendor SDK (lidza check L006): the pack speaks each API directly", "run `lidza gen` and `lidza db migrate`: the mail_message table comes from schema.lidza", }, Production: []Setting{{Name: "MAIL_PROVIDER", Why: "smtp, mailgun, sendgrid, postmark or resend, with its key", Dev: []string{"log", "outbox"}}, {Name: "MAIL_FROM", Why: "the sender address"}, {Name: "APP_URL", Why: "the public address links in emails point to"}}, }, { Name: "llm", Description: "Language models behind one Chat, Stream, Embed, Generate and Run: Anthropic, OpenAI, Google and Ollama spoken directly over HTTP, a fake provider for tests, structured output from schema types, the app's tools offered to the model, embeddings from the chat provider or another, retries, and token usage per call (chats and embeddings, by label) in llm_usage with the db pack.", Env: []string{ "# lidza/llm (app settings: set them here, or keep them in the app with the admin pages or lidza settings set NAME=value)", "# LLM_PROVIDER=fake # fake | ollama | anthropic | openai | google | compatible", "# LLM_MODEL= # the provider's default when empty (claude-sonnet-5-5, gpt-6-luna, gemini-3.8-flash, llama3.2)", "# LLM_API_KEY= # anthropic, openai, google (a secret: lidza settings set)", "# LLM_BASE_URL= # a proxy or region; Ollama elsewhere than http://127.0.0.1:11434; required for compatible", "# LLM_MAX_TOKENS=4096 # reply bound; LLM_TIMEOUT=60s per attempt; LLM_MAX_ATTEMPTS=3 on 429 and 5xx", "# EMBED_PROVIDER= # Embed's provider: empty uses LLM_PROVIDER (anthropic cannot embed) | openai | google | ollama | compatible | none | fake", "# EMBED_MODEL= # text-embedding-3-small, gemini-embedding-001, nomic-embed-text (LLM_EMBED_MODEL is read when empty)", "# EMBED_API_KEY= # openai, google (a secret: lidza settings set); empty reuses LLM_API_KEY when EMBED_PROVIDER is LLM_PROVIDER", "# EMBED_BASE_URL= # as LLM_BASE_URL, for the embeddings provider", }, Notes: []string{ "chat: llm.From(ctx).Chat(ctx, llm.Request{System: \"...\", Messages: []llm.Message{{Role: llm.User, Content: text}}}) returns Text and Usage; Stream delivers the text as it arrives", "structured: out, err := llm.Generate[schema.NoteTags](ctx, llm.From(ctx), req) sends the type's JSON Schema and validates the reply", "tools: llm.From(ctx).Run(ctx, req, tools()) offers the app's lidza.Tool values to the model and runs the calls it makes", "tests: LLM_PROVIDER=fake in .env.test; llm.From(srv.Context()).Fake().Reply(\"...\") or .ReplyJSON(v) scripts the next reply", "embeddings: llm.From(ctx).Embeddings(ctx, llm.EmbedRequest{Texts: texts, Label: \"post.index\"}) returns Vectors and Usage (Embed(ctx, texts) is the unlabelled form); with an anthropic chat set EMBED_PROVIDER, and EMBED_PROVIDER=none makes Embed return llm.ErrNoEmbeddings", "usage: with the db pack every call, chat or embedding, is a row in llm_usage (set Request.Label or EmbedRequest.Label to the feature name); llm.From(ctx).Usage(ctx, since) reports it, the MCP tool lidza_llm_usage too; run `lidza gen` and `lidza db migrate` for the table", "never import a vendor SDK (lidza check L007): the pack speaks each API directly", }, Production: []Setting{{Name: "LLM_PROVIDER", Why: "anthropic, openai, google, ollama or compatible, with its key", Dev: []string{"fake"}}, {Name: "EMBED_PROVIDER", Why: "openai, google, ollama or compatible with EMBED_API_KEY, none, or unset for the chat provider", Dev: []string{"fake"}, Optional: true}}, }, { Name: "storage", Description: "Files behind one Put, Get, Stat, List, Delete and presigned URLs: any S3-compatible service (AWS S3, MinIO, Cloudflare R2, Backblaze B2, Wasabi, Spaces) spoken directly with Signature V4, and a local directory for development and tests.", Env: []string{ "# lidza/storage (app settings: set them here, or keep them in the app with the admin pages or lidza settings set NAME=value)", "# STORAGE_PROVIDER=local # local | s3 | r2 | spaces | b2 | gcs | minio", "# STORAGE_DIR=storage # local: where the files go", "# STORAGE_BUCKET= # s3", "# STORAGE_ENDPOINT=https://s3.amazonaws.com # or https://<account>.r2.cloudflarestorage.com, http://127.0.0.1:9000 (MinIO)", "# STORAGE_REGION=us-east-1", "# STORAGE_ACCESS_KEY= # keep both keys in the app: lidza settings set STORAGE_ACCESS_KEY=... STORAGE_SECRET_KEY=...", "# STORAGE_PUBLIC_URL= # a CDN or public bucket; URL(key) returns it plus the key", "# STORAGE_PREFIX= # a folder every key goes under, for a bucket several apps share", "# STORAGE_MAX_SIZE=104857600 # one Put, bytes", }, Notes: []string{ "store: obj, err := storage.From(ctx).Put(ctx, \"avatars/\"+id+\".png\", r, storage.PutOptions{}) (content type detected); Get, Stat, List, Delete", "uploads through the API: router.Route(g, \"PUT /api/v1/posts/{id}/image\", uploadImage, router.UploadLimit(10<<20)) with In = router.File; Put(ctx, key, req.Body.Body, storage.PutOptions{ContentType: req.Body.ContentType}); the client has api.uploadImage({ id }, file, { onProgress })", "browsers: PresignGet(ctx, key, ttl) for a private object, PresignPut for a direct upload, URL(key) with STORAGE_PUBLIC_URL; or mount storage.Handler(\"/api/v1/files/\") behind auth.Require()", "tests: STORAGE_PROVIDER=local and STORAGE_DIR under a temporary directory; nothing leaves the machine", "never import a vendor SDK (lidza check L008) and never write files to the local disk (os.WriteFile, L009): the pack keeps them; agents: the MCP tool lidza_storage lists what is stored", }, Production: []Setting{{Name: "STORAGE_PROVIDER", Why: "s3 or another object store (local needs one node with a lasting disk)", Dev: []string{"local"}}}, }, { Name: "media", Description: "Image processing in Rust: dimensions and format, resize (fit inside or cover and crop) with format conversion.", Rust: true, Notes: []string{ "capabilities take image bytes as base64 (schema type bytes)", "a square avatar: media.From(ctx).ImageResize(ctx, schema.ImageResizeInput{Data: b, Width: &n, Height: &n, Fit: &cover})", "HEIC, AVIF and TIFF fail with engine.ErrorCode(err) == \"unsupported_format\": keep the original file", }, }, { Name: "geo", Description: "Geospatial in Rust: haversine distance, nearest neighbours (R-tree), bounding boxes.", Rust: true, }, }
Officials lists the packs `lidza pack add` knows.
Functions ¶
func Build ¶
Build compiles the crate to wasm32-wasip1 in release mode and copies the module to packs/<name>/<name>.wasm. Output goes to out with a prefix.
func BuildStale ¶
BuildStale builds every enabled pack whose module is missing or stale.
func Generate ¶
Generate writes packs.go into appDir (relative to root; empty is the root's package main) and, for every enabled pack, pack.go and the crate's schema.rs (the app schema as serde types). It returns the files it changed, relative to root.
func GeneratePackGo ¶
GeneratePackGo renders packs/<name>/pack.go: the pack type, its lifecycle (compile, pool, register) and one typed method per capability.
func GeneratePacksGo ¶
GeneratePacksGo renders the app's packs.go, in package pkg, from the enabled pack names.
func IsOfficialGo ¶
IsOfficialGo reports whether a lidza.json entry is an imported Go pack.
func NeedsBuild ¶
NeedsBuild reports whether the pack's WASM is missing or older than its crate sources.
func SyncFragments ¶
SyncFragments appends to schema.lidza every model, type or enum of the enabled official packs' schema fragments that the app does not declare yet: a pack upgraded to a newer framework version may bring a table (the auth pack's auth_token, for instance), and `lidza gen` picks it up without a second `lidza pack add`. It returns the names it added.
Types ¶
type Capability ¶
type Capability struct {
// Name is the WASM export and, exported, the Go method.
Name string `json:"name"`
Description string `json:"description"`
// Input and Output are type names from schema.lidza.
Input string `json:"input"`
Output string `json:"output"`
// Rules are instructions for the agent using the capability.
Rules string `json:"rules,omitempty"`
}
Capability is one exported function: JSON in, JSON out, typed by schema.lidza types on both sides.
type Manifest ¶
type Manifest struct {
// Name is the pack's identifier: the directory, the Go package, the
// crate and the WASM file name.
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
Rust Rust `json:"rust"`
Capabilities []Capability `json:"capabilities"`
// Path is the manifest's location, relative to the project root.
Path string `json:"-"`
}
Manifest is pack.lidza.json.
func List ¶
List returns the manifests of the local packs lidza.json enables, in order; official Go packs have none.
func Scaffold ¶
Scaffold creates packs/<name> with a manifest, a crate holding the ABI and one example capability (reverse), and the schema types the example needs. The caller adds the name to lidza.json and runs the generators.
type Official ¶
type Official struct {
Name string
Description string
// Rust packs are source (manifest, crate, schema fragment) copied into
// packs/<name> and built there; Go packs are imported.
Rust bool
// Env are lines appended to .env.example.
Env []string
// Notes are printed after adding.
Notes []string
// Production are the settings a deployment needs; lidza ship names
// the ones the credentials do not hold.
Production []Setting
}
Official describes a pack the framework ships.
func Add ¶
Add installs an official pack into the app and returns the lidza.json entry to enable it. Go packs need no files beyond .env.example lines and, for db, the sqlc configuration; Rust packs are copied into packs/<name> and their schema fragment appended to schema.lidza.
func FindOfficial ¶
FindOfficial returns the official pack called name.
type Problem ¶
type Problem struct {
Message string
}
Problem is one validation finding, located in the manifest.
type Rust ¶
type Rust struct {
// Dir is the crate directory inside the pack, default "rust".
Dir string `json:"dir,omitempty"`
// MemoryMB caps each WASM instance's memory, default 64.
MemoryMB int `json:"memory_mb,omitempty"`
// Instances is the pool size, default 4.
Instances int `json:"instances,omitempty"`
// TimeoutMS bounds each call, default 5000.
TimeoutMS int `json:"timeout_ms,omitempty"`
// Uninterruptible drops the per-loop deadline checks: loops run
// several times faster, and a call that overruns the timeout keeps
// its instance busy until it returns (the caller still gets the
// error at the deadline, and the instance is replaced afterwards).
// Set it for capabilities whose loops are bounded by their input.
Uninterruptible bool `json:"uninterruptible,omitempty"`
}
Rust locates and bounds the crate.
type SQLCSync ¶
type SQLCSync struct {
// Changed is true when sqlc.yaml was written.
Changed bool
// Added is true when the file had no Go names before: made by a
// release that left sqlc on its default, so the names of
// db/queries/gen change (Url becomes URL).
Added bool
// Note explains why the file was left alone, "" otherwise.
Note string
}
SQLCSync says what SyncSQLCNames did.
func SyncSQLCNames ¶
SyncSQLCNames writes the schema's initialisms and the renames sqlc needs for plurals (schema.SQLCNames) into the go options of root's sqlc.yaml, so db/queries/gen names a column as schema/ names the field: URL, ProviderID, TagIDs. A file without sqlc.yaml is left alone, and so are the names of one that sets initialisms or rename itself. While a model has a decimal field, the go options' overrides also map numeric to decimal.Decimal, the type schema/ uses (syncSQLCTypes).
type Setting ¶
type Setting struct {
Name string
// Why says what it is, for the operator.
Why string
// Dev are values that only suit development and tests (the log
// mailer, the fake model); a deployment set to one is flagged too.
Dev []string
// Optional settings are not flagged when missing, only when set to
// a Dev value (EMBED_PROVIDER, which defaults to the chat provider).
Optional bool
}
Setting is one setting a pack needs in production.