this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

basic starter label SDK (#960)

Similar to Jaz's
https://github.com/bluesky-social/indigo/blob/main/util/labels/labels.go

This one has helpers for signing/verifying. It defines a new/separate
label type directly, instead of using the lexgen stuff... labels are
sort of protocol-layer, not lexicon-layer? but there are helpers to
convert.

A follow-up would be getting functionality in `goat` to help subscribe
label streams, query and verify individually, etc.

authored by

Whyrusleeping and committed by
GitHub
a4e0cc37 e772f3c9

+740
+503
atproto/label/cbor_gen.go
··· 1 + // Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. 2 + 3 + package label 4 + 5 + import ( 6 + "fmt" 7 + "io" 8 + "math" 9 + "sort" 10 + 11 + cid "github.com/ipfs/go-cid" 12 + cbg "github.com/whyrusleeping/cbor-gen" 13 + xerrors "golang.org/x/xerrors" 14 + ) 15 + 16 + var _ = xerrors.Errorf 17 + var _ = cid.Undef 18 + var _ = math.E 19 + var _ = sort.Sort 20 + 21 + func (t *Label) MarshalCBOR(w io.Writer) error { 22 + if t == nil { 23 + _, err := w.Write(cbg.CborNull) 24 + return err 25 + } 26 + 27 + cw := cbg.NewCborWriter(w) 28 + fieldCount := 9 29 + 30 + if t.CID == nil { 31 + fieldCount-- 32 + } 33 + 34 + if t.ExpiresAt == nil { 35 + fieldCount-- 36 + } 37 + 38 + if t.Negated == nil { 39 + fieldCount-- 40 + } 41 + 42 + if t.Sig == nil { 43 + fieldCount-- 44 + } 45 + 46 + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 47 + return err 48 + } 49 + 50 + // t.CID (string) (string) 51 + if t.CID != nil { 52 + 53 + if len("cid") > 1000000 { 54 + return xerrors.Errorf("Value in field \"cid\" was too long") 55 + } 56 + 57 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("cid"))); err != nil { 58 + return err 59 + } 60 + if _, err := cw.WriteString(string("cid")); err != nil { 61 + return err 62 + } 63 + 64 + if t.CID == nil { 65 + if _, err := cw.Write(cbg.CborNull); err != nil { 66 + return err 67 + } 68 + } else { 69 + if len(*t.CID) > 1000000 { 70 + return xerrors.Errorf("Value in field t.CID was too long") 71 + } 72 + 73 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.CID))); err != nil { 74 + return err 75 + } 76 + if _, err := cw.WriteString(string(*t.CID)); err != nil { 77 + return err 78 + } 79 + } 80 + } 81 + 82 + // t.CreatedAt (string) (string) 83 + if len("cts") > 1000000 { 84 + return xerrors.Errorf("Value in field \"cts\" was too long") 85 + } 86 + 87 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("cts"))); err != nil { 88 + return err 89 + } 90 + if _, err := cw.WriteString(string("cts")); err != nil { 91 + return err 92 + } 93 + 94 + if len(t.CreatedAt) > 1000000 { 95 + return xerrors.Errorf("Value in field t.CreatedAt was too long") 96 + } 97 + 98 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.CreatedAt))); err != nil { 99 + return err 100 + } 101 + if _, err := cw.WriteString(string(t.CreatedAt)); err != nil { 102 + return err 103 + } 104 + 105 + // t.ExpiresAt (string) (string) 106 + if t.ExpiresAt != nil { 107 + 108 + if len("exp") > 1000000 { 109 + return xerrors.Errorf("Value in field \"exp\" was too long") 110 + } 111 + 112 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("exp"))); err != nil { 113 + return err 114 + } 115 + if _, err := cw.WriteString(string("exp")); err != nil { 116 + return err 117 + } 118 + 119 + if t.ExpiresAt == nil { 120 + if _, err := cw.Write(cbg.CborNull); err != nil { 121 + return err 122 + } 123 + } else { 124 + if len(*t.ExpiresAt) > 1000000 { 125 + return xerrors.Errorf("Value in field t.ExpiresAt was too long") 126 + } 127 + 128 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.ExpiresAt))); err != nil { 129 + return err 130 + } 131 + if _, err := cw.WriteString(string(*t.ExpiresAt)); err != nil { 132 + return err 133 + } 134 + } 135 + } 136 + 137 + // t.Negated (bool) (bool) 138 + if t.Negated != nil { 139 + 140 + if len("neg") > 1000000 { 141 + return xerrors.Errorf("Value in field \"neg\" was too long") 142 + } 143 + 144 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("neg"))); err != nil { 145 + return err 146 + } 147 + if _, err := cw.WriteString(string("neg")); err != nil { 148 + return err 149 + } 150 + 151 + if t.Negated == nil { 152 + if _, err := cw.Write(cbg.CborNull); err != nil { 153 + return err 154 + } 155 + } else { 156 + if err := cbg.WriteBool(w, *t.Negated); err != nil { 157 + return err 158 + } 159 + } 160 + } 161 + 162 + // t.Sig ([]uint8) (slice) 163 + if t.Sig != nil { 164 + 165 + if len("sig") > 1000000 { 166 + return xerrors.Errorf("Value in field \"sig\" was too long") 167 + } 168 + 169 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("sig"))); err != nil { 170 + return err 171 + } 172 + if _, err := cw.WriteString(string("sig")); err != nil { 173 + return err 174 + } 175 + 176 + if len(t.Sig) > 2097152 { 177 + return xerrors.Errorf("Byte array in field t.Sig was too long") 178 + } 179 + 180 + if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Sig))); err != nil { 181 + return err 182 + } 183 + 184 + if _, err := cw.Write(t.Sig); err != nil { 185 + return err 186 + } 187 + 188 + } 189 + 190 + // t.SourceDID (string) (string) 191 + if len("src") > 1000000 { 192 + return xerrors.Errorf("Value in field \"src\" was too long") 193 + } 194 + 195 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("src"))); err != nil { 196 + return err 197 + } 198 + if _, err := cw.WriteString(string("src")); err != nil { 199 + return err 200 + } 201 + 202 + if len(t.SourceDID) > 1000000 { 203 + return xerrors.Errorf("Value in field t.SourceDID was too long") 204 + } 205 + 206 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.SourceDID))); err != nil { 207 + return err 208 + } 209 + if _, err := cw.WriteString(string(t.SourceDID)); err != nil { 210 + return err 211 + } 212 + 213 + // t.URI (string) (string) 214 + if len("uri") > 1000000 { 215 + return xerrors.Errorf("Value in field \"uri\" was too long") 216 + } 217 + 218 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("uri"))); err != nil { 219 + return err 220 + } 221 + if _, err := cw.WriteString(string("uri")); err != nil { 222 + return err 223 + } 224 + 225 + if len(t.URI) > 1000000 { 226 + return xerrors.Errorf("Value in field t.URI was too long") 227 + } 228 + 229 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.URI))); err != nil { 230 + return err 231 + } 232 + if _, err := cw.WriteString(string(t.URI)); err != nil { 233 + return err 234 + } 235 + 236 + // t.Val (string) (string) 237 + if len("val") > 1000000 { 238 + return xerrors.Errorf("Value in field \"val\" was too long") 239 + } 240 + 241 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("val"))); err != nil { 242 + return err 243 + } 244 + if _, err := cw.WriteString(string("val")); err != nil { 245 + return err 246 + } 247 + 248 + if len(t.Val) > 1000000 { 249 + return xerrors.Errorf("Value in field t.Val was too long") 250 + } 251 + 252 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Val))); err != nil { 253 + return err 254 + } 255 + if _, err := cw.WriteString(string(t.Val)); err != nil { 256 + return err 257 + } 258 + 259 + // t.Version (int64) (int64) 260 + if len("ver") > 1000000 { 261 + return xerrors.Errorf("Value in field \"ver\" was too long") 262 + } 263 + 264 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("ver"))); err != nil { 265 + return err 266 + } 267 + if _, err := cw.WriteString(string("ver")); err != nil { 268 + return err 269 + } 270 + 271 + if t.Version >= 0 { 272 + if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Version)); err != nil { 273 + return err 274 + } 275 + } else { 276 + if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.Version-1)); err != nil { 277 + return err 278 + } 279 + } 280 + 281 + return nil 282 + } 283 + 284 + func (t *Label) UnmarshalCBOR(r io.Reader) (err error) { 285 + *t = Label{} 286 + 287 + cr := cbg.NewCborReader(r) 288 + 289 + maj, extra, err := cr.ReadHeader() 290 + if err != nil { 291 + return err 292 + } 293 + defer func() { 294 + if err == io.EOF { 295 + err = io.ErrUnexpectedEOF 296 + } 297 + }() 298 + 299 + if maj != cbg.MajMap { 300 + return fmt.Errorf("cbor input should be of type map") 301 + } 302 + 303 + if extra > cbg.MaxLength { 304 + return fmt.Errorf("Label: map struct too large (%d)", extra) 305 + } 306 + 307 + n := extra 308 + 309 + nameBuf := make([]byte, 3) 310 + for i := uint64(0); i < n; i++ { 311 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000) 312 + if err != nil { 313 + return err 314 + } 315 + 316 + if !ok { 317 + // Field doesn't exist on this type, so ignore it 318 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 319 + return err 320 + } 321 + continue 322 + } 323 + 324 + switch string(nameBuf[:nameLen]) { 325 + // t.CID (string) (string) 326 + case "cid": 327 + 328 + { 329 + b, err := cr.ReadByte() 330 + if err != nil { 331 + return err 332 + } 333 + if b != cbg.CborNull[0] { 334 + if err := cr.UnreadByte(); err != nil { 335 + return err 336 + } 337 + 338 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 339 + if err != nil { 340 + return err 341 + } 342 + 343 + t.CID = (*string)(&sval) 344 + } 345 + } 346 + // t.CreatedAt (string) (string) 347 + case "cts": 348 + 349 + { 350 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 351 + if err != nil { 352 + return err 353 + } 354 + 355 + t.CreatedAt = string(sval) 356 + } 357 + // t.ExpiresAt (string) (string) 358 + case "exp": 359 + 360 + { 361 + b, err := cr.ReadByte() 362 + if err != nil { 363 + return err 364 + } 365 + if b != cbg.CborNull[0] { 366 + if err := cr.UnreadByte(); err != nil { 367 + return err 368 + } 369 + 370 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 371 + if err != nil { 372 + return err 373 + } 374 + 375 + t.ExpiresAt = (*string)(&sval) 376 + } 377 + } 378 + // t.Negated (bool) (bool) 379 + case "neg": 380 + 381 + { 382 + b, err := cr.ReadByte() 383 + if err != nil { 384 + return err 385 + } 386 + if b != cbg.CborNull[0] { 387 + if err := cr.UnreadByte(); err != nil { 388 + return err 389 + } 390 + 391 + maj, extra, err = cr.ReadHeader() 392 + if err != nil { 393 + return err 394 + } 395 + if maj != cbg.MajOther { 396 + return fmt.Errorf("booleans must be major type 7") 397 + } 398 + 399 + var val bool 400 + switch extra { 401 + case 20: 402 + val = false 403 + case 21: 404 + val = true 405 + default: 406 + return fmt.Errorf("booleans are either major type 7, value 20 or 21 (got %d)", extra) 407 + } 408 + t.Negated = &val 409 + } 410 + } 411 + // t.Sig ([]uint8) (slice) 412 + case "sig": 413 + 414 + maj, extra, err = cr.ReadHeader() 415 + if err != nil { 416 + return err 417 + } 418 + 419 + if extra > 2097152 { 420 + return fmt.Errorf("t.Sig: byte array too large (%d)", extra) 421 + } 422 + if maj != cbg.MajByteString { 423 + return fmt.Errorf("expected byte array") 424 + } 425 + 426 + if extra > 0 { 427 + t.Sig = make([]uint8, extra) 428 + } 429 + 430 + if _, err := io.ReadFull(cr, t.Sig); err != nil { 431 + return err 432 + } 433 + 434 + // t.SourceDID (string) (string) 435 + case "src": 436 + 437 + { 438 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 439 + if err != nil { 440 + return err 441 + } 442 + 443 + t.SourceDID = string(sval) 444 + } 445 + // t.URI (string) (string) 446 + case "uri": 447 + 448 + { 449 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 450 + if err != nil { 451 + return err 452 + } 453 + 454 + t.URI = string(sval) 455 + } 456 + // t.Val (string) (string) 457 + case "val": 458 + 459 + { 460 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 461 + if err != nil { 462 + return err 463 + } 464 + 465 + t.Val = string(sval) 466 + } 467 + // t.Version (int64) (int64) 468 + case "ver": 469 + { 470 + maj, extra, err := cr.ReadHeader() 471 + if err != nil { 472 + return err 473 + } 474 + var extraI int64 475 + switch maj { 476 + case cbg.MajUnsignedInt: 477 + extraI = int64(extra) 478 + if extraI < 0 { 479 + return fmt.Errorf("int64 positive overflow") 480 + } 481 + case cbg.MajNegativeInt: 482 + extraI = int64(extra) 483 + if extraI < 0 { 484 + return fmt.Errorf("int64 negative overflow") 485 + } 486 + extraI = -1 - extraI 487 + default: 488 + return fmt.Errorf("wrong type for int64 field: %d", maj) 489 + } 490 + 491 + t.Version = int64(extraI) 492 + } 493 + 494 + default: 495 + // Field doesn't exist on this type, so ignore it 496 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 497 + return err 498 + } 499 + } 500 + } 501 + 502 + return nil 503 + }
+141
atproto/label/label.go
··· 1 + package label 2 + 3 + import ( 4 + "bytes" 5 + "fmt" 6 + 7 + comatproto "github.com/bluesky-social/indigo/api/atproto" 8 + "github.com/bluesky-social/indigo/atproto/crypto" 9 + "github.com/bluesky-social/indigo/atproto/syntax" 10 + "github.com/bluesky-social/indigo/atproto/data" 11 + ) 12 + 13 + // version of the label data fromat implemented by this package 14 + const ATPROTO_LABEL_VERSION int64 = 1 15 + 16 + type Label struct { 17 + CID *string `json:"cid,omitempty" cborgen:"cid,omitempty"` 18 + CreatedAt string `json:"cts" cborgen:"cts"` 19 + ExpiresAt *string `json:"exp,omitempty" cborgen:"exp,omitempty"` 20 + Negated *bool `json:"neg,omitempty" cborgen:"neg,omitempty"` 21 + SourceDID string `json:"src" cborgen:"src"` 22 + URI string `json:"uri" cborgen:"uri"` 23 + Val string `json:"val" cborgen:"val"` 24 + Version int64 `json:"ver" cborgen:"ver"` 25 + Sig data.Bytes `json:"sig,omitempty" cborgen:"sig,omitempty"` 26 + } 27 + 28 + // does basic checks on syntax and structure 29 + func (l *Label) VerifySyntax() error { 30 + if l.Version != ATPROTO_LABEL_VERSION { 31 + return fmt.Errorf("unsupported label version: %d", l.Version) 32 + } 33 + if len(l.Val) == 0 { 34 + return fmt.Errorf("empty label value") 35 + } 36 + if l.CID != nil { 37 + _, err := syntax.ParseCID(*l.CID) 38 + if err != nil { 39 + return fmt.Errorf("invalid label: %w", err) 40 + } 41 + } 42 + _, err := syntax.ParseDatetime(l.CreatedAt) 43 + if err != nil { 44 + return fmt.Errorf("invalid label: %w", err) 45 + } 46 + if l.ExpiresAt != nil { 47 + _, err := syntax.ParseDatetime(*l.ExpiresAt) 48 + if err != nil { 49 + return fmt.Errorf("invalid label: %w", err) 50 + } 51 + } 52 + _, err = syntax.ParseDID(l.SourceDID) 53 + if err != nil { 54 + return fmt.Errorf("invalid label: %w", err) 55 + } 56 + _, err = syntax.ParseURI(l.URI) 57 + if err != nil { 58 + return fmt.Errorf("invalid label: %w", err) 59 + } 60 + return nil 61 + } 62 + 63 + func (l *Label) UnsignedBytes() ([]byte, error) { 64 + buf := new(bytes.Buffer) 65 + if l.Sig == nil { 66 + if err := l.MarshalCBOR(buf); err != nil { 67 + return nil, err 68 + } 69 + return buf.Bytes(), nil 70 + } 71 + unsigned := Label{ 72 + CID: l.CID, 73 + CreatedAt: l.CreatedAt, 74 + ExpiresAt: l.ExpiresAt, 75 + Negated: l.Negated, 76 + SourceDID: l.SourceDID, 77 + URI: l.URI, 78 + Val: l.Val, 79 + Version: l.Version, 80 + } 81 + if err := unsigned.MarshalCBOR(buf); err != nil { 82 + return nil, err 83 + } 84 + return buf.Bytes(), nil 85 + } 86 + 87 + // Signs the commit, storing the signature in the `Sig` field 88 + func (l *Label) Sign(privkey crypto.PrivateKey) error { 89 + b, err := l.UnsignedBytes() 90 + if err != nil { 91 + return err 92 + } 93 + sig, err := privkey.HashAndSign(b) 94 + if err != nil { 95 + return err 96 + } 97 + l.Sig = sig 98 + return nil 99 + } 100 + 101 + // Verifies `Sig` field using the provided key. Returns `nil` if signature is valid. 102 + func (l *Label) VerifySignature(pubkey crypto.PublicKey) error { 103 + if l.Sig == nil { 104 + return fmt.Errorf("can not verify unsigned commit") 105 + } 106 + b, err := l.UnsignedBytes() 107 + if err != nil { 108 + return err 109 + } 110 + return pubkey.HashAndVerify(b, l.Sig) 111 + } 112 + 113 + func (l *Label) ToLexicon() comatproto.LabelDefs_Label { 114 + return comatproto.LabelDefs_Label{ 115 + Cid: l.CID, 116 + Cts: l.CreatedAt, 117 + Exp: l.ExpiresAt, 118 + Sig: []byte(l.Sig), 119 + Src: l.SourceDID, 120 + Uri: l.URI, 121 + Val: l.Val, 122 + Ver: &l.Version, 123 + } 124 + } 125 + 126 + func FromLexicon(l *comatproto.LabelDefs_Label) Label { 127 + var v int64 = 0 128 + if l.Ver != nil { 129 + v = *l.Ver 130 + } 131 + return Label{ 132 + CID: l.Cid, 133 + CreatedAt: l.Cts, 134 + ExpiresAt: l.Exp, 135 + Sig: []byte(l.Sig), 136 + SourceDID: l.Src, 137 + URI: l.Uri, 138 + Val: l.Val, 139 + Version: v, 140 + } 141 + }
+91
atproto/label/label_test.go
··· 1 + package label 2 + 3 + import ( 4 + "encoding/json" 5 + "testing" 6 + 7 + "github.com/bluesky-social/indigo/atproto/crypto" 8 + 9 + "github.com/stretchr/testify/assert" 10 + ) 11 + 12 + func TestVerifyLabel(t *testing.T) { 13 + assert := assert.New(t) 14 + 15 + pubkeyStr := "zQ3shcnfWLQN1bY4d2patsEAYFzy4xp1zdckEvHsV7S4ocTnC" 16 + pubkey, err := crypto.ParsePublicMultibase(pubkeyStr) 17 + if err != nil { 18 + t.Fatal(err) 19 + } 20 + 21 + labelJSON := []byte(`{ 22 + "ver": 1, 23 + "src": "did:plc:n3timvoib5nau7gvwd6cshap", 24 + "uri": "did:plc:44ybard66vv44zksje25o7dz", 25 + "val": "bladerunner", 26 + "cts": "2024-10-23T17:51:19.128Z", 27 + "sig": { 28 + "$bytes": "uCRNA5mTzh078T5xZtkvLEt/O+z0gsKM3aqRI/lVAB8ZtbMnznwS/JwHopZE40JhNNDj80z8gsDLAp/hWqG5Pg" 29 + } 30 + }`) 31 + 32 + var l Label 33 + if err := json.Unmarshal(labelJSON, &l); err != nil { 34 + t.Fatal(err) 35 + } 36 + 37 + assert.NoError(l.VerifySyntax()) 38 + assert.NoError(l.VerifySignature(pubkey)) 39 + 40 + // check that signature fails after mutation 41 + l.Val = "wrong" 42 + assert.NoError(l.VerifySyntax()) 43 + assert.Error(l.VerifySignature(pubkey)) 44 + 45 + // version check 46 + l.Version = 0 47 + assert.Error(l.VerifySyntax()) 48 + } 49 + 50 + func TestParseLabel(t *testing.T) { 51 + assert := assert.New(t) 52 + 53 + unsignedJSON := []byte(`{ 54 + "cts": "2024-10-23T17:51:19.128Z", 55 + "src": "did:plc:n3timvoib5nau7gvwd6cshap", 56 + "uri": "did:plc:44ybard66vv44zksje25o7dz", 57 + "val": "bladerunner", 58 + "ver": 1 59 + }`) 60 + 61 + var l Label 62 + if err := json.Unmarshal(unsignedJSON, &l); err != nil { 63 + t.Fatal(err) 64 + } 65 + assert.NoError(l.VerifySyntax()) 66 + } 67 + 68 + func TestSignLabel(t *testing.T) { 69 + assert := assert.New(t) 70 + 71 + l := Label{ 72 + Version: ATPROTO_LABEL_VERSION, 73 + CreatedAt: "2024-10-23T17:51:19.128Z", 74 + URI: "at://did:plc:ewvi7nxzyoun6zhxrhs64oiz/app.bsky.actor.profile/self", 75 + Val: "good", 76 + SourceDID: "did:plc:ewvi7nxzyoun6zhxrhs64oiz", 77 + } 78 + 79 + priv, err := crypto.GeneratePrivateKeyK256() 80 + if err != nil { 81 + t.Fatal(err) 82 + } 83 + 84 + pub, err := priv.PublicKey() 85 + if err != nil { 86 + t.Fatal(err) 87 + } 88 + 89 + assert.NoError(l.Sign(priv)) 90 + assert.NoError(l.VerifySignature(pub)) 91 + }
+5
gen/main.go
··· 10 10 "github.com/bluesky-social/indigo/atproto/data" 11 11 atrepo "github.com/bluesky-social/indigo/atproto/repo" 12 12 atmst "github.com/bluesky-social/indigo/atproto/repo/mst" 13 + "github.com/bluesky-social/indigo/atproto/label" 13 14 "github.com/bluesky-social/indigo/events" 14 15 lexutil "github.com/bluesky-social/indigo/lex/util" 15 16 "github.com/bluesky-social/indigo/mst" ··· 129 130 } 130 131 131 132 if err := genCfg.WriteMapEncodersToFile("atproto/repo/mst/cbor_gen.go", "mst", atmst.NodeData{}, atmst.EntryData{}); err != nil { 133 + panic(err) 134 + } 135 + 136 + if err := genCfg.WriteMapEncodersToFile("atproto/label/cbor_gen.go", "label", label.Label{}); err != nil { 132 137 panic(err) 133 138 } 134 139 }