A Transparent and Verifiable Way to Sync the AT Protocol's PLC Directory
1package plc
2
3import (
4 "time"
5
6 "github.com/goccy/go-json"
7)
8
9// PLCOperation represents a single operation from the PLC directory
10type PLCOperation struct {
11 DID string `json:"did"`
12 Operation json.RawMessage `json:"operation"` // Lazy
13 CID string `json:"cid"`
14 Nullified interface{} `json:"nullified,omitempty"`
15 CreatedAt time.Time `json:"createdAt"`
16
17 RawJSON []byte `json:"-"`
18 ParsedOperation map[string]interface{} `json:"-"` // Pre-parsed cache
19}
20
21// IsNullified checks if this operation has been nullified
22func (op *PLCOperation) IsNullified() bool {
23 if op.Nullified == nil {
24 return false
25 }
26
27 switch v := op.Nullified.(type) {
28 case bool:
29 return v
30 case string:
31 return v != ""
32 default:
33 return false
34 }
35}
36
37// GetNullifyingCID returns the CID that nullified this operation
38func (op *PLCOperation) GetNullifyingCID() string {
39 if s, ok := op.Nullified.(string); ok {
40 return s
41 }
42 return ""
43}
44
45// DIDDocument represents a DID document from PLC
46type DIDDocument struct {
47 Context []string `json:"@context"`
48 ID string `json:"id"`
49 AlsoKnownAs []string `json:"alsoKnownAs"`
50 VerificationMethod []VerificationMethod `json:"verificationMethod"`
51 Service []Service `json:"service"`
52}
53
54// VerificationMethod represents a verification method in a DID document
55type VerificationMethod struct {
56 ID string `json:"id"`
57 Type string `json:"type"`
58 Controller string `json:"controller"`
59 PublicKeyMultibase string `json:"publicKeyMultibase"`
60}
61
62// Service represents a service endpoint in a DID document
63type Service struct {
64 ID string `json:"id"`
65 Type string `json:"type"`
66 ServiceEndpoint string `json:"serviceEndpoint"`
67}
68
69// ExportOptions contains options for exporting PLC operations
70type ExportOptions struct {
71 Count int // Number of operations to fetch
72 After string // ISO 8601 datetime string to start after
73}
74
75// DIDHistoryEntry represents a single operation in DID history
76type DIDHistoryEntry struct {
77 Operation PLCOperation `json:"operation"`
78 PLCBundle string `json:"plc_bundle,omitempty"`
79}
80
81// DIDHistory represents the full history of a DID
82type DIDHistory struct {
83 DID string `json:"did"`
84 Current *PLCOperation `json:"current"`
85 Operations []DIDHistoryEntry `json:"operations"`
86}
87
88// EndpointInfo contains extracted endpoint information from an operation
89type EndpointInfo struct {
90 Type string // "pds", "labeler", etc.
91 Endpoint string
92}
93
94// GetOperationData parses Operation into map (with caching)
95func (op *PLCOperation) GetOperationData() (map[string]interface{}, error) {
96 // Return cached if already parsed
97 if op.ParsedOperation != nil {
98 return op.ParsedOperation, nil
99 }
100
101 // Parse on first call
102 if len(op.Operation) == 0 {
103 return nil, nil
104 }
105
106 var data map[string]interface{}
107 if err := json.UnmarshalNoEscape(op.Operation, &data); err != nil {
108 return nil, err
109 }
110
111 // Cache it
112 op.ParsedOperation = data
113
114 return data, nil
115}
116
117// GetOperationMap is an alias for compatibility
118func (op *PLCOperation) GetOperationMap() (map[string]interface{}, error) {
119 return op.GetOperationData()
120}