Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
b1d8e3f7ab
|
1
.gitea/CODEOWNERS
Normal file
1
.gitea/CODEOWNERS
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* @go/CoreDevelopers @go/Agents
|
||||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -5,6 +5,29 @@ All notable changes to this module will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.0.0] - 2026-05-12
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- `authClient *auth.Client` cached in `OnInit` — the Auth client is now initialised once
|
||||||
|
during startup and reused in `HealthCheck`, eliminating a per-probe `app.Auth(ctx)` call.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Go directive bumped from 1.25 to 1.26
|
||||||
|
- `health`, `launcher`, and `logz` dependencies bumped to v1.0.1
|
||||||
|
- `xerrors v1.0.1` added — all error returns now use structured `xerrors.Err` instead of
|
||||||
|
`fmt.Errorf`; `OnInit` returns `ErrInvalidInput` for missing `ProjectID` and
|
||||||
|
`ErrInternal` for SDK initialisation failures; `HealthCheck` returns `ErrInternal` when
|
||||||
|
called before `OnInit`
|
||||||
|
|
||||||
|
### Stabilization
|
||||||
|
|
||||||
|
- API committed as stable. `Config`, `Provider`, `Component`, and `New` are unchanged
|
||||||
|
from v0.9.0.
|
||||||
|
|
||||||
|
[1.0.0]: https://code.nochebuena.dev/go/firebase/compare/v0.9.0...v1.0.0
|
||||||
|
|
||||||
## [0.9.0] - 2026-03-18
|
## [0.9.0] - 2026-03-18
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
6
COMMIT.md
Normal file
6
COMMIT.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
feat(firebase)!: promote to v1.0.0 — cache auth.Client, adopt xerrors, bump deps to v1
|
||||||
|
|
||||||
|
Cache auth.Client in OnInit (eliminates per-probe app.Auth call in HealthCheck).
|
||||||
|
Replace all fmt.Errorf with xerrors structured errors (ErrInvalidInput / ErrInternal).
|
||||||
|
Bump health/launcher/logz to v1.0.1, add xerrors v1.0.1, Go directive to 1.26.
|
||||||
|
API committed as stable.
|
||||||
55
RELEASE.md
Normal file
55
RELEASE.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# v1.0.0
|
||||||
|
|
||||||
|
> `code.nochebuena.dev/go/firebase`
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`firebase` manages the lifecycle of a `firebase.google.com/go/v4` App: validates
|
||||||
|
configuration at init time, initialises the SDK App, exposes the native `*firebase.App`
|
||||||
|
to consumers, and performs health checks by probing the Firebase Auth service.
|
||||||
|
|
||||||
|
v1.0.0 caches the `auth.Client` inside the component (eliminating per-probe allocation),
|
||||||
|
adopts `xerrors` for all structured error returns, bumps all micro-lib dependencies to v1,
|
||||||
|
and commits the API as stable.
|
||||||
|
|
||||||
|
## What Changed Since v0.9.0
|
||||||
|
|
||||||
|
### Auth client cached in `OnInit`
|
||||||
|
|
||||||
|
`OnInit` now calls `app.Auth(context.Background())` once and stores the result on the
|
||||||
|
component. `HealthCheck` uses the cached client directly — no per-probe `app.Auth(ctx)`
|
||||||
|
call.
|
||||||
|
|
||||||
|
### Structured errors via `xerrors`
|
||||||
|
|
||||||
|
All `fmt.Errorf` calls replaced with `xerrors`:
|
||||||
|
|
||||||
|
| Situation | Code |
|
||||||
|
|-----------|------|
|
||||||
|
| `ProjectID` empty | `ErrInvalidInput` |
|
||||||
|
| `fb.NewApp` fails | `ErrInternal` (wraps SDK error) |
|
||||||
|
| `app.Auth` fails | `ErrInternal` (wraps SDK error) |
|
||||||
|
| `HealthCheck` before `OnInit` | `ErrInternal` |
|
||||||
|
|
||||||
|
### Dependency updates
|
||||||
|
|
||||||
|
- `health`, `launcher`, `logz` bumped from `v0.9.x` to `v1.0.1`
|
||||||
|
- `xerrors v1.0.1` added as direct dependency
|
||||||
|
- Go directive bumped from `1.25` to `1.26`
|
||||||
|
|
||||||
|
## Full API (stable)
|
||||||
|
|
||||||
|
- `Config` — `ProjectID string` (`FIREBASE_PROJECT_ID`, required)
|
||||||
|
- `Provider` — `App() *fb.App`
|
||||||
|
- `Component` — embeds `launcher.Component` + `health.Checkable` + `Provider`
|
||||||
|
- `New(logger, cfg) Component`
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
go get code.nochebuena.dev/go/firebase@v1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
See [CHANGELOG.md](CHANGELOG.md#100---2026-05-12).
|
||||||
22
firebase.go
22
firebase.go
@@ -2,7 +2,6 @@ package firebase
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
fb "firebase.google.com/go/v4"
|
fb "firebase.google.com/go/v4"
|
||||||
"firebase.google.com/go/v4/auth"
|
"firebase.google.com/go/v4/auth"
|
||||||
@@ -10,6 +9,7 @@ import (
|
|||||||
"code.nochebuena.dev/go/health"
|
"code.nochebuena.dev/go/health"
|
||||||
"code.nochebuena.dev/go/launcher"
|
"code.nochebuena.dev/go/launcher"
|
||||||
"code.nochebuena.dev/go/logz"
|
"code.nochebuena.dev/go/logz"
|
||||||
|
"code.nochebuena.dev/go/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provider is the minimal interface for consumers that only need the firebase App.
|
// Provider is the minimal interface for consumers that only need the firebase App.
|
||||||
@@ -34,6 +34,7 @@ type firebaseComponent struct {
|
|||||||
cfg Config
|
cfg Config
|
||||||
logger logz.Logger
|
logger logz.Logger
|
||||||
app *fb.App
|
app *fb.App
|
||||||
|
authClient *auth.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a firebase Component. Call lc.Append(fb) to manage its lifecycle.
|
// New returns a firebase Component. Call lc.Append(fb) to manage its lifecycle.
|
||||||
@@ -43,7 +44,7 @@ func New(logger logz.Logger, cfg Config) Component {
|
|||||||
|
|
||||||
func (f *firebaseComponent) OnInit() error {
|
func (f *firebaseComponent) OnInit() error {
|
||||||
if f.cfg.ProjectID == "" {
|
if f.cfg.ProjectID == "" {
|
||||||
return fmt.Errorf("firebase: ProjectID is required")
|
return xerrors.New(xerrors.ErrInvalidInput, "firebase: ProjectID is required")
|
||||||
}
|
}
|
||||||
f.logger.Info("firebase: initializing app", "project_id", f.cfg.ProjectID)
|
f.logger.Info("firebase: initializing app", "project_id", f.cfg.ProjectID)
|
||||||
app, err := fb.NewApp(context.Background(), &fb.Config{
|
app, err := fb.NewApp(context.Background(), &fb.Config{
|
||||||
@@ -51,9 +52,14 @@ func (f *firebaseComponent) OnInit() error {
|
|||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.logger.Error("firebase: failed to create app", err)
|
f.logger.Error("firebase: failed to create app", err)
|
||||||
return fmt.Errorf("firebase: create app: %w", err)
|
return xerrors.Wrap(xerrors.ErrInternal, "firebase: create app", err)
|
||||||
}
|
}
|
||||||
f.app = app
|
f.app = app
|
||||||
|
authClient, err := app.Auth(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Wrap(xerrors.ErrInternal, "firebase: get auth client", err)
|
||||||
|
}
|
||||||
|
f.authClient = authClient
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,14 +76,10 @@ func (f *firebaseComponent) OnStop() error {
|
|||||||
func (f *firebaseComponent) App() *fb.App { return f.app }
|
func (f *firebaseComponent) App() *fb.App { return f.app }
|
||||||
|
|
||||||
func (f *firebaseComponent) HealthCheck(ctx context.Context) error {
|
func (f *firebaseComponent) HealthCheck(ctx context.Context) error {
|
||||||
if f.app == nil {
|
if f.authClient == nil {
|
||||||
return fmt.Errorf("firebase: app not initialized")
|
return xerrors.New(xerrors.ErrInternal, "firebase: app not initialized")
|
||||||
}
|
}
|
||||||
authClient, err := f.app.Auth(ctx)
|
_, err := f.authClient.GetUser(ctx, "health-probe-non-existent")
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("firebase: get auth client: %w", err)
|
|
||||||
}
|
|
||||||
_, err = authClient.GetUser(ctx, "health-probe-non-existent")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if auth.IsUserNotFound(err) {
|
if auth.IsUserNotFound(err) {
|
||||||
return nil // expected: probe of non-existent UID succeeded
|
return nil // expected: probe of non-existent UID succeeded
|
||||||
|
|||||||
9
go.mod
9
go.mod
@@ -1,11 +1,11 @@
|
|||||||
module code.nochebuena.dev/go/firebase
|
module code.nochebuena.dev/go/firebase
|
||||||
|
|
||||||
go 1.25
|
go 1.26
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.nochebuena.dev/go/health v0.9.0
|
code.nochebuena.dev/go/health v1.0.1
|
||||||
code.nochebuena.dev/go/launcher v0.9.0
|
code.nochebuena.dev/go/launcher v1.0.1
|
||||||
code.nochebuena.dev/go/logz v0.9.0
|
code.nochebuena.dev/go/logz v1.0.1
|
||||||
firebase.google.com/go/v4 v4.15.0
|
firebase.google.com/go/v4 v4.15.0
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,6 +17,7 @@ require (
|
|||||||
cloud.google.com/go/iam v1.1.7 // indirect
|
cloud.google.com/go/iam v1.1.7 // indirect
|
||||||
cloud.google.com/go/longrunning v0.5.5 // indirect
|
cloud.google.com/go/longrunning v0.5.5 // indirect
|
||||||
cloud.google.com/go/storage v1.40.0 // indirect
|
cloud.google.com/go/storage v1.40.0 // indirect
|
||||||
|
code.nochebuena.dev/go/xerrors v1.0.1 // indirect
|
||||||
github.com/MicahParks/keyfunc v1.9.0 // indirect
|
github.com/MicahParks/keyfunc v1.9.0 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/go-logr/logr v1.4.1 // indirect
|
github.com/go-logr/logr v1.4.1 // indirect
|
||||||
|
|||||||
14
go.sum
14
go.sum
@@ -13,12 +13,14 @@ cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMI
|
|||||||
cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s=
|
cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s=
|
||||||
cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw=
|
cloud.google.com/go/storage v1.40.0 h1:VEpDQV5CJxFmJ6ueWNsKxcr1QAYOXEgxDa+sBbJahPw=
|
||||||
cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g=
|
cloud.google.com/go/storage v1.40.0/go.mod h1:Rrj7/hKlG87BLqDJYtwR0fbPld8uJPbQ2ucUMY7Ir0g=
|
||||||
code.nochebuena.dev/go/health v0.9.0 h1:x0UKjC7CHAE3AgwyFzCyjmGJIjoLBBxeOHxXuqpbKwI=
|
code.nochebuena.dev/go/health v1.0.1 h1:FwB1sDa9oZBPgIi3kNMUjTVRKQ/Yn77WvlrwNtgFlws=
|
||||||
code.nochebuena.dev/go/health v0.9.0/go.mod h1:f3IsNtU60JSn5yXmBBh9XOvr5pRyEah5+wS4tjDQZso=
|
code.nochebuena.dev/go/health v1.0.1/go.mod h1:sy/HVT+E+k2rEuqmW9Q8QX0QnotAQxPHXSexYs7GNMg=
|
||||||
code.nochebuena.dev/go/launcher v0.9.0 h1:dJHonA9Xm03AQKK0919FJaQn9ZKHZ+RZfB9yxjnx3TA=
|
code.nochebuena.dev/go/launcher v1.0.1 h1:hbPV8jNtyxfchrT7igzz3M2tKGI3bm8uWkHBXRvSPgg=
|
||||||
code.nochebuena.dev/go/launcher v0.9.0/go.mod h1:IBtntmbnyddukjEhxlc7Ysdzz9nZsnd9+8FzAIHt77g=
|
code.nochebuena.dev/go/launcher v1.0.1/go.mod h1:1KwndVuqm31JN9Dpl9YvOmlogPlKKzoDMo9aRFkYwmM=
|
||||||
code.nochebuena.dev/go/logz v0.9.0 h1:wfV7vtI4V/8ED7Hm31Fbql7Y5iOGrlHN4X8Z5ajTZZE=
|
code.nochebuena.dev/go/logz v1.0.1 h1:kK9aZo19L208CwCr2D/dbSOMaOv62cXsigMSsdFu+8Y=
|
||||||
code.nochebuena.dev/go/logz v0.9.0/go.mod h1:qODhSbKb+tWE7rdhHLcKweiP5CgwIaWoZxadCT3bQV8=
|
code.nochebuena.dev/go/logz v1.0.1/go.mod h1:YNpNm03fURm2v0ySh/477z9AJhtfRcd9rFOW6fFqgNM=
|
||||||
|
code.nochebuena.dev/go/xerrors v1.0.1 h1:fgXoabY/ZwxAzaM1sKFf3sbL7ZHWyDxItB/rdbnl0mo=
|
||||||
|
code.nochebuena.dev/go/xerrors v1.0.1/go.mod h1:03MMVfrhaf4XmTMgMrEUFCmuZPGHUCKDitiQvwCuwvY=
|
||||||
firebase.google.com/go/v4 v4.15.0 h1:k27M+cHbyN1YpBI2Cf4NSjeHnnYRB9ldXwpqA5KikN0=
|
firebase.google.com/go/v4 v4.15.0 h1:k27M+cHbyN1YpBI2Cf4NSjeHnnYRB9ldXwpqA5KikN0=
|
||||||
firebase.google.com/go/v4 v4.15.0/go.mod h1:S/4MJqVZn1robtXkHhpRUbwOC4gdYtgsiMMJQ4x+xmQ=
|
firebase.google.com/go/v4 v4.15.0/go.mod h1:S/4MJqVZn1robtXkHhpRUbwOC4gdYtgsiMMJQ4x+xmQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
|||||||
Reference in New Issue
Block a user