From 8c41e41c9e2d2cd7d29f170fdcf4a99a2d90b02c Mon Sep 17 00:00:00 2001 From: Pascal Bleser Date: Thu, 23 Apr 2026 13:58:53 +0200 Subject: [PATCH] groupware: documentation changes after API generator updates for the use of template functions --- pkg/jmap/api_contact.go | 2 + pkg/jmap/integration_calendar_test.go | 4 - pkg/jmap/integration_contact_test.go | 2 +- pkg/jmap/integration_test.go | 8 + pkg/jmap/model.go | 6 +- pkg/jmap/model_examples.go | 164 +++++++++++++++- pkg/jmap/tools.go | 4 + services/groupware/package.json | 2 +- .../groupware/pkg/groupware/api_contacts.go | 1 - .../groupware/pkg/groupware/api_emails.go | 2 + .../groupware/pkg/groupware/api_events.go | 3 - services/groupware/pkg/groupware/objtypes.go | 13 +- services/groupware/pkg/groupware/templates.go | 81 ++++---- services/groupware/pnpm-lock.yaml | 182 +++++++++--------- 14 files changed, 334 insertions(+), 140 deletions(-) diff --git a/pkg/jmap/api_contact.go b/pkg/jmap/api_contact.go index f16bb4eb25..805e8ab66c 100644 --- a/pkg/jmap/api_contact.go +++ b/pkg/jmap/api_contact.go @@ -98,6 +98,7 @@ func (j *Client) QueryContactCards(accountIds []string, ) } +// @api:example create func (j *Client) CreateContactCard(accountId string, contact ContactCardChange, ctx Context) (*ContactCard, SessionState, State, Language, Error) { if contact.Version == nil { contact.Version = &DEFAULT_CONTACT_CARD_VERSION @@ -131,6 +132,7 @@ func (j *Client) DeleteContactCard(accountId string, destroyIds []string, ctx Co ) } +// @api:example update func (j *Client) UpdateContactCard(accountId string, id string, changes ContactCardChange, ctx Context) (ContactCard, SessionState, State, Language, Error) { return update(j, "UpdateContactCard", ContactCardType, func(update map[string]PatchObject) ContactCardSetCommand { diff --git a/pkg/jmap/integration_calendar_test.go b/pkg/jmap/integration_calendar_test.go index 3ed6b9ea0b..1c4bf56a13 100644 --- a/pkg/jmap/integration_calendar_test.go +++ b/pkg/jmap/integration_calendar_test.go @@ -756,7 +756,3 @@ var Categories = []string{ func pickCategories() map[string]bool { return toBoolMap(pickRandoms(Categories...)) } - -func ptr[T any](t T) *T { - return &t -} diff --git a/pkg/jmap/integration_contact_test.go b/pkg/jmap/integration_contact_test.go index 9879dadd95..1b4fb7c81e 100644 --- a/pkg/jmap/integration_contact_test.go +++ b/pkg/jmap/integration_contact_test.go @@ -335,7 +335,7 @@ func (s *StalwartTest) fillContacts( //NOSONAR card := ContactCardChange{ Type: jscontact.ContactCardType, Version: ptr(jscontact.JSContactVersion_1_0), - AddressBookIds: toBoolMap([]string{addressbookId}), + AddressBookIds: toBoolPtrMap([]string{addressbookId}), ProdId: &productName, Language: &language, Kind: ptr(jscontact.ContactCardKindIndividual), diff --git a/pkg/jmap/integration_test.go b/pkg/jmap/integration_test.go index 2bc0b2b5aa..4cb647e042 100644 --- a/pkg/jmap/integration_test.go +++ b/pkg/jmap/integration_test.go @@ -1055,6 +1055,14 @@ func toBoolMap[K comparable](s []K) map[K]bool { return m } +func toBoolPtrMap[K comparable](s []K) map[K]*bool { + m := make(map[K]*bool, len(s)) + for _, e := range s { + m[e] = ptr(true) + } + return m +} + func toBoolMapS[K comparable](s ...K) map[K]bool { m := make(map[K]bool, len(s)) for _, e := range s { diff --git a/pkg/jmap/model.go b/pkg/jmap/model.go index a454bb9008..f1c539c0fc 100644 --- a/pkg/jmap/model.go +++ b/pkg/jmap/model.go @@ -4829,7 +4829,7 @@ type ContactCardChange struct { // The value for each key in the object MUST be true. // // This is a JMAP extension and not part of [RFC9553]. - AddressBookIds map[string]bool `json:"addressBookIds,omitempty"` + AddressBookIds map[string]*bool `json:"addressBookIds,omitempty"` // The JSContact type of the Card object: the value MUST be "Card". Type jscontact.TypeOfContactCard `json:"@type,omitempty"` @@ -4837,7 +4837,7 @@ type ContactCardChange struct { // The JSContact version of this Card. // // The value MUST be one of the IANA-registered JSContact Version values for the version property. - Version *jscontact.JSContactVersion `json:"version,omitzero"` + Version *jscontact.JSContactVersion `json:"version,omitempty"` // The kind of the entity the Card represents (default: `individual`). // @@ -4868,7 +4868,7 @@ type ContactCardChange struct { // // A group Card without the members property can be considered an abstract grouping or one whose members // are known empirically (e.g., `IETF Participants`). - Members map[string]bool `json:"members,omitempty"` + Members map[string]*bool `json:"members,omitempty"` // The identifier for the product that created the Card. // diff --git a/pkg/jmap/model_examples.go b/pkg/jmap/model_examples.go index 9adb6e3641..7dcf2b4b70 100644 --- a/pkg/jmap/model_examples.go +++ b/pkg/jmap/model_examples.go @@ -726,6 +726,11 @@ func (e Exemplar) MailboxGetResponse() MailboxGetResponse { } } +func (e Exemplar) MailboxChange() MailboxChange { + a, _, _ := e.MailboxInbox() + return copyTo[MailboxChange](a) +} + func (e Exemplar) MailboxChanges() MailboxChanges { a, _, _ := e.MailboxInbox() return MailboxChanges{ @@ -739,7 +744,7 @@ func (e Exemplar) UploadedBlob() UploadedBlob { return UploadedBlob{ BlobId: "eisoochohl9iekohf5ramaiqu4oucaegheith7otae0xeeg7zuexia4ohjut", Size: 12762, - Type: "image/png", + Type: "image/png", //NOSONAR } } @@ -898,6 +903,12 @@ func (e Exemplar) AddressBook() AddressBook { } } +func (e Exemplar) AddressBookChange() AddressBookChange { + return AddressBookChange{ + Description: ptr("A different name"), + } +} + func (e Exemplar) OtherAddressBook() (AddressBook, string, string) { return AddressBook{ Id: "aemaeWun6Fei", @@ -1400,7 +1411,7 @@ func (e Exemplar) DesignContactCard() (ContactCard, string, string) { Created: created, Updated: updated, Language: "en-GB", - ProdId: "OpenCloud Groupware 1.0", + ProdId: "OpenCloud Groupware 1.0", //NOSONAR Name: &c.Name{ Type: c.NameType, Components: []c.NameComponent{ @@ -1557,6 +1568,123 @@ func (e Exemplar) DesignContactCard() (ContactCard, string, string) { }, "Another Contact Card", "other" } +func (e Exemplar) IndividualContactCard() (ContactCard, string, string) { + return ContactCard{ + Kind: c.ContactCardKindIndividual, + AddressBookIds: map[string]bool{ + "c34c2bb4-4e8e-4579-b35d-6f6739a11146": true, + }, + Language: "de-DE", + ProdId: "OpenCloud Groupware 1.0", + RelatedTo: map[string]c.Relation{ + "urn:uid:ca9d2a62-e068-43b6-a470-46506976d505": { + Type: c.RelationType, + Relation: map[c.Relationship]bool{ + c.RelationContact: true, + }, + }, + }, + Name: &c.Name{ + Type: c.NameType, + Components: []c.NameComponent{ + {Value: "Roberta", Kind: c.NameComponentKindGiven}, + {Value: " ", Kind: c.NameComponentKindSeparator}, + {Value: "Draper", Kind: c.NameComponentKindSurname}, + }, + IsOrdered: true, + }, + Nicknames: map[string]c.Nickname{ + "a": { + Type: c.NicknameType, + Name: "Bobby", + Contexts: map[c.NicknameContext]bool{ + c.NicknameContextWork: true, + c.NicknameContextPrivate: true, + }, + Pref: 1, + }, + }, + Organizations: map[string]c.Organization{ + "o": { + Type: c.OrganizationType, + Name: "Martian Marine Corps", + Units: []c.OrgUnit{ + {Name: "Special Forces"}, + }, + Contexts: map[c.OrganizationContext]bool{ + c.OrganizationContextWork: true, + }, + }, + }, + SpeakToAs: &c.SpeakToAs{ + Type: c.SpeakToAsType, + GrammaticalGender: c.GrammaticalGenderFeminine, + Pronouns: map[string]c.Pronouns{ + "p": { + Type: c.PronounsType, + Pronouns: "she/her", + Contexts: map[c.PronounsContext]bool{ + c.PronounsContextWork: true, + }, + Pref: 1, + }, + }, + }, + Emails: map[string]c.EmailAddress{ + "e": { + Type: c.EmailAddressType, + Address: "gunny@mmc.mars.gov.example.com", + Contexts: map[c.EmailAddressContext]bool{ + c.EmailAddressContextWork: true, + }, + Pref: 1, + Label: "work", + }, + }, + OnlineServices: map[string]c.OnlineService{ + "s": { + Type: c.OnlineServiceType, + Service: "MarsNet", + Uri: "https://mars.example.com/@gunny", + User: "gunny", + Contexts: map[c.OnlineServiceContext]bool{ + c.OnlineServiceContextWork: true, + }, + Pref: 1, + }, + }, + Phones: map[string]c.Phone{ + "p": { + Type: c.PhoneType, + Number: "+1-555-123-4567", + Features: map[c.PhoneFeature]bool{ + c.PhoneFeatureVoice: true, + c.PhoneFeatureText: true, + }, + Contexts: map[c.PhoneContext]bool{ + c.PhoneContextWork: true, + }, + Pref: 1, + }, + }, + Media: map[string]c.Media{ + "m": { + Type: c.MediaType, + Kind: c.MediaKindLogo, + Uri: "https://static.wikia.nocookie.net/expanse/images/3/3a/Bobbie_S4_closeup.png/revision/latest?cb=20191206015449", + MediaType: "image/png", + Contexts: map[c.MediaContext]bool{ + c.MediaContextWork: true, + }, + }, + }, + Keywords: map[string]bool{ + "imaginary": true, + "test": true, + }, + }, "A ContactCard for an individual", "individual" +} + func (e Exemplar) ContactCard() ContactCard { created, _ := time.Parse(time.RFC3339, "2025-09-25T18:26:14.094725532+02:00") updated, _ := time.Parse(time.RFC3339, "2025-09-26T09:58:01+02:00") @@ -1854,6 +1982,25 @@ func (e Exemplar) ContactCard() ContactCard { } } +func (e Exemplar) ContactCardChangeForCreate() (ContactCardChange, string, string) { + a, _, _ := e.IndividualContactCard() + return copyTo[ContactCardChange](a), "A ContactCard to create", "create" +} + +func (e Exemplar) ContactCardChangeForUpdate() (ContactCardChange, string, string) { + return ContactCardChange{ + AddressBookIds: map[string]*bool{ + "c34c2bb4-4e8e-4579-b35d-6f6739a11146": nil, + "02b6977f-bb60-4511-949e-37f47a930382": boolPtr(true), + }, + Nicknames: map[string]c.Nickname{ + "a": { + Name: "Bobbie", + }, + }, + }, "Updates to a ContactCard", "update" +} + func (e Exemplar) ContactCardGetResponse() ContactCardGetResponse { a := e.ContactCard() b, _, _ := e.DesignContactCard() @@ -2127,3 +2274,16 @@ func (e Exemplar) Objects() Objects { EmailSubmissions: &emailSubmissions, } } + +func copyTo[B any, A any](a A) B { + if b, err := json.Marshal(a); err != nil { + panic(err) + } else { + var t B + if err := json.Unmarshal(b, &t); err != nil { + panic(err) + } else { + return t + } + } +} diff --git a/pkg/jmap/tools.go b/pkg/jmap/tools.go index 0f7e206772..a14fb8f831 100644 --- a/pkg/jmap/tools.go +++ b/pkg/jmap/tools.go @@ -393,6 +393,10 @@ func mapPairs[K comparable, L, R any](left map[K]L, right map[K]R) map[K]pair[L, return result } +func ptr[T any](t T) *T { + return &t +} + func strPtr(s string) *string { return &s } diff --git a/services/groupware/package.json b/services/groupware/package.json index f526f4ebd3..27a1a9bb3b 100644 --- a/services/groupware/package.json +++ b/services/groupware/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "@redocly/cli": "^2.25.3", + "@redocly/cli": "^2.29.1", "@types/js-yaml": "^4.0.9", "cheerio": "^1.2.0", "js-yaml": "^4.1.1", diff --git a/services/groupware/pkg/groupware/api_contacts.go b/services/groupware/pkg/groupware/api_contacts.go index 381f4d0240..d57f5b7a66 100644 --- a/services/groupware/pkg/groupware/api_contacts.go +++ b/services/groupware/pkg/groupware/api_contacts.go @@ -104,7 +104,6 @@ func (g *Groupware) GetContactById(w http.ResponseWriter, r *http.Request) { func (g *Groupware) GetAllContacts(w http.ResponseWriter, r *http.Request) { getallpaged(Contact, w, r, g, - g.jmap.GetContactCards, func(cid string) jmap.ContactCardFilterElement { return jmap.ContactCardFilterCondition{InAddressBook: cid} }, diff --git a/services/groupware/pkg/groupware/api_emails.go b/services/groupware/pkg/groupware/api_emails.go index 60b942d99f..1f5d70872c 100644 --- a/services/groupware/pkg/groupware/api_emails.go +++ b/services/groupware/pkg/groupware/api_emails.go @@ -1039,6 +1039,7 @@ func (g *Groupware) DeleteEmails(w http.ResponseWriter, r *http.Request) { deleteMany(Email, w, r, g, g.jmap.DeleteEmails) } +// Send an existing email. func (g *Groupware) SendEmail(w http.ResponseWriter, r *http.Request) { //NOSONAR g.respond(w, r, func(req Request) Response { l := req.logger.With() @@ -1156,6 +1157,7 @@ func relatedEmailsFilter(email jmap.Email, beacon time.Time, days uint) jmap.Ema return filter } +// Retrieve objects that are related to a given Email. func (g *Groupware) RelatedToEmail(w http.ResponseWriter, r *http.Request) { //NOSONAR g.respond(w, r, func(req Request) Response { l := req.logger.With() diff --git a/services/groupware/pkg/groupware/api_events.go b/services/groupware/pkg/groupware/api_events.go index 9e4931812d..e3c06bf694 100644 --- a/services/groupware/pkg/groupware/api_events.go +++ b/services/groupware/pkg/groupware/api_events.go @@ -60,8 +60,6 @@ func (g *Groupware) GetEventsInCalendar(w http.ResponseWriter, r *http.Request) }) } -//func query[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], SEARCHRESULTS jmap.SearchResults[T]]( //NOSONAR - func curryMapQuery[SRES jmap.SearchResults[T], T jmap.Foo, FILTER any, COMP any]( f func(accountIds []string, filter FILTER, sortBy []COMP, position int, limit uint, calculateTotal bool, ctx jmap.Context) (map[string]SRES, jmap.SessionState, jmap.State, jmap.Language, jmap.Error), ) func(req Request, accountId string, filter FILTER, sortBy []COMP, offset int, limit uint, ctx jmap.Context) (SRES, jmap.SessionState, jmap.State, jmap.Language, jmap.Error) { @@ -73,7 +71,6 @@ func curryMapQuery[SRES jmap.SearchResults[T], T jmap.Foo, FILTER any, COMP any] func (g *Groupware) GetAllEvents(w http.ResponseWriter, r *http.Request) { getallpaged(Event, w, r, g, - g.jmap.GetCalendarEvents, func(cid string) jmap.CalendarEventFilterElement { return jmap.CalendarEventFilterCondition{InCalendar: cid} }, diff --git a/services/groupware/pkg/groupware/objtypes.go b/services/groupware/pkg/groupware/objtypes.go index 010e880a4f..d2b2f8b9f6 100644 --- a/services/groupware/pkg/groupware/objtypes.go +++ b/services/groupware/pkg/groupware/objtypes.go @@ -6,6 +6,7 @@ import ( type ObjectType[T jmap.Foo, CH jmap.Change, CHS jmap.Changes[T]] struct { name string + plural string responseType ResponseObjectType uriParamName string containerUriParamName string @@ -16,6 +17,7 @@ type ObjectType[T jmap.Foo, CH jmap.Change, CHS jmap.Changes[T]] struct { var ( Blob = ObjectType[jmap.Blob, jmap.BlobChange, jmap.BlobChanges]{ name: "blob", + plural: "blobs", responseType: BlobResponseObjectType, uriParamName: UriParamBlobId, containerUriParamName: "", @@ -24,7 +26,8 @@ var ( } AddressBook = ObjectType[jmap.AddressBook, jmap.AddressBookChange, jmap.AddressBookChanges]{ - name: "address book", + name: "addressbook", + plural: "addressbooks", responseType: AddressBookResponseObjectType, uriParamName: UriParamAddressBookId, containerUriParamName: "", @@ -34,6 +37,7 @@ var ( Calendar = ObjectType[jmap.Calendar, jmap.CalendarChange, jmap.CalendarChanges]{ name: "calendar", + plural: "calendars", responseType: CalendarResponseObjectType, uriParamName: UriParamCalendarId, containerUriParamName: "", @@ -43,6 +47,7 @@ var ( Contact = ObjectType[jmap.ContactCard, jmap.ContactCardChange, jmap.ContactCardChanges]{ name: "contact", + plural: "contacts", responseType: ContactResponseObjectType, uriParamName: UriParamContactId, containerUriParamName: UriParamCalendarId, @@ -52,6 +57,7 @@ var ( Email = ObjectType[jmap.Email, jmap.EmailChange, jmap.EmailChanges]{ name: "email", + plural: "emails", responseType: EmailResponseObjectType, uriParamName: UriParamEmailId, containerUriParamName: UriParamMailboxId, @@ -61,6 +67,7 @@ var ( Event = ObjectType[jmap.CalendarEvent, jmap.CalendarEventChange, jmap.CalendarEventChanges]{ name: "event", + plural: "events", responseType: EventResponseObjectType, uriParamName: UriParamEventId, containerUriParamName: UriParamCalendarId, @@ -70,6 +77,7 @@ var ( Identity = ObjectType[jmap.Identity, jmap.IdentityChange, jmap.IdentityChanges]{ name: "identity", + plural: "identities", responseType: IdentityResponseObjectType, uriParamName: UriParamIdentityId, containerUriParamName: "", @@ -79,6 +87,7 @@ var ( Mailbox = ObjectType[jmap.Mailbox, jmap.MailboxChange, jmap.MailboxChanges]{ name: "mailbox", + plural: "mailboxes", responseType: MailboxResponseObjectType, uriParamName: UriParamMailboxId, containerUriParamName: "", @@ -88,6 +97,7 @@ var ( Quota = ObjectType[jmap.Quota, jmap.QuotaChange, jmap.QuotaChanges]{ name: "quota", + plural: "quotas", responseType: QuotaResponseObjectType, uriParamName: "", containerUriParamName: "", @@ -97,6 +107,7 @@ var ( VacationResponse = ObjectType[jmap.VacationResponse, jmap.VacationResponseChange, jmap.VacationResponseChanges]{ name: "vacation response", + plural: "vacation responses", responseType: VacationResponseResponseObjectType, uriParamName: "", containerUriParamName: "", diff --git a/services/groupware/pkg/groupware/templates.go b/services/groupware/pkg/groupware/templates.go index 6b3da5310a..8a38506f19 100644 --- a/services/groupware/pkg/groupware/templates.go +++ b/services/groupware/pkg/groupware/templates.go @@ -7,9 +7,9 @@ import ( "github.com/opencloud-eu/opencloud/pkg/log" ) -// Create a new {{.Name}} using the JSON payload in the body if the `{{.Method}}` operation. -// -// When successful, it returns a `200 OK` with the {{.ObjType}} that was just created in the response. +// Create a new {{.Name}} using the JSON payload in the body of the `{{.Verb}}` operation. +// @api:response 200:T returns the {{.Name}} that was just created +// @api:body CHANGE the {{.Name}} to create func create[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, @@ -47,6 +47,8 @@ func create[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( }) } +// Retrieve all the {{.Name}}. +// @api:response 200:RESP returns all the {{.Names}} func getall[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.GetResponse[T]]( //NOSONAR o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, @@ -74,11 +76,12 @@ func getall[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.G }) } -func getallpaged[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.GetResponse[T], FILTER any, COMP any, SEARCHRESULTS jmap.SearchResults[T]]( //NOSONAR +// Retrieve all the {{.Name}} with support for paging using the {{.QueryParam.QueryParamOffset.Name}} and {{.QueryParam.QueryParamLimit.Name}} query parameters. +// @api:response 200:SEARCHRESULTS returns the {{.Names}} within the requested range, as well as the total amount of {{.Names}} +func getallpaged[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], FILTER any, COMP any, SEARCHRESULTS jmap.SearchResults[T]]( //NOSONAR o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, g *Groupware, - getFunc func(accountId string, ids []string, ctx jmap.Context) (RESP, jmap.SessionState, jmap.State, jmap.Language, jmap.Error), filterFunc func(containerId string) FILTER, sortBy []COMP, queryFunc func(req Request, accountId string, filter FILTER, sortBy []COMP, offset int, limit uint, ctx jmap.Context) (SEARCHRESULTS, jmap.SessionState, jmap.State, jmap.Language, jmap.Error), @@ -90,13 +93,11 @@ func getallpaged[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP j } l := req.logger.With().Str(accountId, log.SafeString(accountId)) - search := false offset, ok, err := req.parseIntParam(QueryParamOffset, 0) if err != nil { return req.error(accountId, err) } if ok { - search = true l = l.Int(QueryParamOffset, offset) } @@ -105,42 +106,33 @@ func getallpaged[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP j return req.error(accountId, err) } if ok { - search = true l = l.Uint(QueryParamLimit, limit) } - if search { - containerId := "" - if o.containerUriParamName != "" { - var err *Error - containerId, err = req.PathParam(o.containerUriParamName) - if err != nil { - return req.error(accountId, err) - } - l = l.Str(o.containerUriParamName, log.SafeString(containerId)) + containerId := "" + if o.containerUriParamName != "" { + var err *Error + containerId, err = req.PathParam(o.containerUriParamName) + if err != nil { + return req.error(accountId, err) } - - filter := filterFunc(containerId) - - logger := log.From(l) - ctx := req.ctx.WithLogger(logger) - results, sessionState, state, lang, jerr := queryFunc(req, accountId, filter, sortBy, offset, limit, ctx) - if jerr != nil { - return req.jmapError(accountId, jerr, sessionState, lang) - } - return req.respond(accountId, results, sessionState, o.responseType, state, lang) - } else { - logger := log.From(l) - ctx := req.ctx.WithLogger(logger) - objs, sessionState, state, lang, jerr := getFunc(accountId, []string{}, ctx) - if jerr != nil { - return req.jmapError(accountId, jerr, sessionState, lang) - } - return req.respond(accountId, objs, sessionState, o.responseType, state, lang) + l = l.Str(o.containerUriParamName, log.SafeString(containerId)) } + + filter := filterFunc(containerId) + + logger := log.From(l) + ctx := req.ctx.WithLogger(logger) + results, sessionState, state, lang, jerr := queryFunc(req, accountId, filter, sortBy, offset, limit, ctx) + if jerr != nil { + return req.jmapError(accountId, jerr, sessionState, lang) + } + return req.respond(accountId, results, sessionState, o.responseType, state, lang) }) } +// Query all the {{.Name}} with support for paging using the {{.QueryParam.QueryParamOffset.Name}} and {{.QueryParam.QueryParamLimit.Name}} query parameters. +// @api:response 200:SEARCHRESULTS returns the {{.Names}} that match the filter, within the requested range, as well as the total amount of matches func query[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], SEARCHRESULTS jmap.SearchResults[T]]( //NOSONAR o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, @@ -193,6 +185,9 @@ func query[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], SEARCHRESULT }) } +// Retrieve a specific {{.Name}} referenced by its unique identifier as specified in the path parameter `{{.UriParamName}}` in the path `{{.Path}}` +// @api:response 200:T returns the {{.Name}} that matches the requested identifier, if it exists +// @api:response 404 when there is no {{.Name}} for the requested identifier func get[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.GetResponse[T]]( o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, @@ -235,6 +230,9 @@ func get[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.GetR }) } +// Retrieve a specific {{.Name}} referenced by its unique identifier as specified in the path parameter `{{.UriParamName}}` in the path `{{.Path}}` +// @api:response 200:T returns the {{.Name}} that matches the requested identifier, if it exists +// @api:response 404 when there is no {{.Name}} for the requested identifier func getFromMap[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jmap.GetResponse[T]]( o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, @@ -248,7 +246,6 @@ func getFromMap[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jm } l := req.logger.With().Str(accountId, log.SafeString(accountId)) id, err := req.PathParamDoc(o.uriParamName, "The unique identifier of the object to retrieve") - // TODO add id splitting if err != nil { return req.error(accountId, err) } @@ -278,6 +275,9 @@ func getFromMap[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T], RESP jm }) } +// Retrieve the changes that occured for {{.Name}}, optionally since an opaque state specified using the header `{{.HeaderParam.HeaderParamSince}}`, +// optionally bounded by the query parameter `{{.QueryParam.QueryParamMaxChanges}}`. +// @api:response 200:CHANGES returns the changes to {{.Names}}: created, updated, and identifiers of destroyed {{.Names}} func changes[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, @@ -315,6 +315,9 @@ func changes[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( }) } +// Delete a specific {{.Name}} referenced by its unique identifier as specified in the path parameter `{{.UriParamName}}` in the path `{{.Path}}` +// @api:response 204 when the referenced {{.Name}} has been deleted successfully +// @api:response 404 when there is no {{.Name}} for the requested identifier func delete[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSONAR o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, @@ -359,6 +362,10 @@ func delete[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSONAR }) } +// Delete several {{.Name}} objects referenced by their unique identifiers as specified as an array in the body, +// or using the query parameter `{{.QueryParam.QueryParamId}}`. +// @api:response 204 when the referenced {{.Names}} have all been deleted successfully +// @api:body ?[]string an array of identifiers of {{.Names}} to delete func deleteMany[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSONAR o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, @@ -434,6 +441,8 @@ func deleteMany[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( //NOSO }) } +// Modify the specified {{.Name}} referenced its unique identifier, changes to attributes being specified as a JSON map in the request body. +// @api:response 200:T the modified {{.Name}} func modify[T jmap.Foo, CHANGE jmap.Change, CHANGES jmap.Changes[T]]( o ObjectType[T, CHANGE, CHANGES], w http.ResponseWriter, r *http.Request, diff --git a/services/groupware/pnpm-lock.yaml b/services/groupware/pnpm-lock.yaml index 2cd76c7674..ac3e7d0a88 100644 --- a/services/groupware/pnpm-lock.yaml +++ b/services/groupware/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@redocly/cli': - specifier: ^2.25.3 - version: 2.25.3(@opentelemetry/api@1.9.1)(core-js@3.45.1) + specifier: ^2.29.1 + version: 2.29.1(@opentelemetry/api@1.9.1)(core-js@3.45.1) '@types/js-yaml': specifier: ^4.0.9 version: 4.0.9 @@ -83,6 +83,9 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} + '@nodable/entities@2.1.0': + resolution: {integrity: sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==} + '@opentelemetry/api-logs@0.202.0': resolution: {integrity: sha512-fTBjMqKCfotFWfLzaKyhjLvyEyq5vDKTTFfBmx21btv3gvy8Lq6N5Dh2OzqeuN4DjtpSvNT1uNVfg08eD2Rfxw==} engines: {node: '>=8.0.0'} @@ -194,27 +197,27 @@ packages: '@redocly/cli-otel@0.1.2': resolution: {integrity: sha512-Bg7BoO5t1x3lVK+KhA5aGPmeXpQmdf6WtTYHhelKJCsQ+tRMiJoFAQoKHoBHAoNxXrhlS3K9lKFLHGmtxsFQfA==} - '@redocly/cli@2.25.3': - resolution: {integrity: sha512-02wjApwJwGD+kGWRoiFVY0Hq960ydMAMHrK3AJH2LMiYNYcrzAr1FSbA3OSylvg2gx3w/r1r710B+iMz3KJKbw==} + '@redocly/cli@2.29.1': + resolution: {integrity: sha512-n85tU21emkYc1k7IZhOFqIrEQizvQuHzHMOwcMZ503XNhzf9OYLLQ8AEcQl1hjpUGtJWsMeSJbpuEwewgb4T0Q==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} hasBin: true '@redocly/config@0.22.0': resolution: {integrity: sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==} - '@redocly/config@0.45.0': - resolution: {integrity: sha512-V+wNusPQUaYV1c5s9iptfKQ2Ggno4bMeiyXdNILxqZS87gttwPfqlqHKHKFyz006voS3JsR295cbpx3GlsIxKg==} + '@redocly/config@0.48.1': + resolution: {integrity: sha512-vq8GM3e0KiglqkwE5Lb9XayrmZY4dHCs21BsvV92yAZN68f1N9cZUuwY1SwnztPbH06dn9uLzubBl/JNfImqfA==} - '@redocly/openapi-core@1.34.11': - resolution: {integrity: sha512-V09ayfnb5GyysmvARbt+voFZAjGcf7hSYxOYxSkCc4fbH/DTfq5YWoec8cflvmHHqyIFbqvmGKmYFzqhr9zxDg==} + '@redocly/openapi-core@1.34.12': + resolution: {integrity: sha512-b32XWsz6enN6K4bx8xWsqUaXTJR/DnYT3lL1CzDYzIYKw243NNlz6fexmr71q/U4HrEcMoJGBvwAfcxOb8ymQw==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} - '@redocly/openapi-core@2.25.3': - resolution: {integrity: sha512-GIu3Mdym5IDIPCvXTzMZ6TQw/+7sKd52PdysxNVe7zBk22ExSGnVE9UAk9BaLOzXT77PJWDUwaimBdJoPpxHMA==} + '@redocly/openapi-core@2.29.1': + resolution: {integrity: sha512-T9FeS2+lpXR9V/XHqiJ53uGjoF1Hs80nRA9ACEXpTLF9a4jzzSANO92/f9HKuQvl0bHgyaIbP5OsBgVU3EP1KQ==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} - '@redocly/respect-core@2.25.3': - resolution: {integrity: sha512-07m80JYdp7J7kH4D1Vqdpa2ZBFCv3QAwCoh2w9H3OjuT/rXQkBSkJQm1n70fzO/HuUf4azzULdp2XnsIpxP2qw==} + '@redocly/respect-core@2.29.1': + resolution: {integrity: sha512-TklpmSho4nSp2ySXWRUJlFQaHoN4BtSTTWabzQPetblAJ6KRVZtgFk6x8eD8KwWUaJj8c7ed4/KAIHOqTdNVxg==} engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'} '@tsconfig/node10@1.0.12': @@ -299,8 +302,8 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - brace-expansion@2.0.3: - resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} brace-expansion@5.0.5: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} @@ -399,8 +402,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.3.3: - resolution: {integrity: sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==} + dompurify@3.4.1: + resolution: {integrity: sha512-JahakDAIg1gyOm7dlgWSDjV4n7Ip2PKR55NIT6jrMfIgLFgWo81vdr1/QGqWtFNRqXP9UV71oVePtjqS2ebnPw==} domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -450,11 +453,11 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-builder@1.1.4: - resolution: {integrity: sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==} + fast-xml-builder@1.1.5: + resolution: {integrity: sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==} - fast-xml-parser@5.5.9: - resolution: {integrity: sha512-jldvxr1MC6rtiZKgrFnDSvT8xuH+eJqxqOBThUVjYrxssYTo1avZLGql5l0a0BAERR01CadYzZ83kVEkbyDg+g==} + fast-xml-parser@5.7.1: + resolution: {integrity: sha512-8Cc3f8GUGUULg34pBch/KGyPLglS+OFs05deyOlY7fL2MTagYPKrVQNmR1fLF/yJ9PH5ZSTd3YDF6pnmeZU+zA==} hasBin: true foreach@2.0.6: @@ -538,8 +541,8 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lru-cache@11.2.7: - resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==} + lru-cache@11.3.5: + resolution: {integrity: sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==} engines: {node: 20 || >=22} lunr@2.3.9: @@ -668,8 +671,8 @@ packages: path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - path-expression-matcher@1.2.0: - resolution: {integrity: sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==} + path-expression-matcher@1.5.0: + resolution: {integrity: sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==} engines: {node: '>=14.0.0'} path-scurry@2.0.2: @@ -708,8 +711,8 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - protobufjs@7.5.4: - resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + protobufjs@7.5.5: + resolution: {integrity: sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==} engines: {node: '>=12.0.0'} queue-microtask@1.2.3: @@ -718,10 +721,10 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + react-dom@19.2.5: + resolution: {integrity: sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==} peerDependencies: - react: ^19.2.4 + react: ^19.2.5 react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -731,8 +734,8 @@ packages: peerDependencies: react: ^18.0.0 || ^19.0.0 - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + react@19.2.5: + resolution: {integrity: sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==} engines: {node: '>=0.10.0'} readable-stream@3.6.2: @@ -827,8 +830,8 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strnum@2.2.2: - resolution: {integrity: sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==} + strnum@2.2.3: + resolution: {integrity: sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==} styled-components@6.3.9: resolution: {integrity: sha512-J72R4ltw0UBVUlEjTzI0gg2STOqlI9JBhQOL4Dxt7aJOnnSesy0qJDn4PYfMCafk9cWOaVg129Pesl5o+DIh0Q==} @@ -1018,6 +1021,8 @@ snapshots: '@noble/hashes@1.8.0': {} + '@nodable/entities@2.1.0': {} + '@opentelemetry/api-logs@0.202.0': dependencies: '@opentelemetry/api': 1.9.1 @@ -1057,7 +1062,7 @@ snapshots: '@opentelemetry/sdk-logs': 0.202.0(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-metrics': 2.0.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.0.1(@opentelemetry/api@1.9.1) - protobufjs: 7.5.4 + protobufjs: 7.5.5 '@opentelemetry/resources@2.0.1(@opentelemetry/api@1.9.1)': dependencies: @@ -1135,15 +1140,15 @@ snapshots: dependencies: ulid: 2.4.0 - '@redocly/cli@2.25.3(@opentelemetry/api@1.9.1)(core-js@3.45.1)': + '@redocly/cli@2.29.1(@opentelemetry/api@1.9.1)(core-js@3.45.1)': dependencies: '@opentelemetry/exporter-trace-otlp-http': 0.202.0(@opentelemetry/api@1.9.1) '@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.34.0 '@redocly/cli-otel': 0.1.2 - '@redocly/openapi-core': 2.25.3 - '@redocly/respect-core': 2.25.3 + '@redocly/openapi-core': 2.29.1 + '@redocly/respect-core': 2.29.1 abort-controller: 3.0.0 ajv: '@redocly/ajv@8.18.0' ajv-formats: 3.0.1(@redocly/ajv@8.18.0) @@ -1156,13 +1161,13 @@ snapshots: mobx: 6.15.0 picomatch: 4.0.4 pluralize: 8.0.0 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - redoc: 2.5.1(core-js@3.45.1)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + redoc: 2.5.1(core-js@3.45.1)(mobx@6.15.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.3.9(react-dom@19.2.5(react@19.2.5))(react@19.2.5)) semver: 7.7.4 set-cookie-parser: 2.7.2 simple-websocket: 9.1.0 - styled-components: 6.3.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + styled-components: 6.3.9(react-dom@19.2.5(react@19.2.5))(react@19.2.5) ulid: 3.0.2 undici: 6.24.0 yargs: 17.0.1 @@ -1177,11 +1182,11 @@ snapshots: '@redocly/config@0.22.0': {} - '@redocly/config@0.45.0': + '@redocly/config@0.48.1': dependencies: json-schema-to-ts: 2.7.2 - '@redocly/openapi-core@1.34.11': + '@redocly/openapi-core@1.34.12': dependencies: '@redocly/ajv': 8.11.2 '@redocly/config': 0.22.0 @@ -1195,10 +1200,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@redocly/openapi-core@2.25.3': + '@redocly/openapi-core@2.29.1': dependencies: '@redocly/ajv': 8.18.0 - '@redocly/config': 0.45.0 + '@redocly/config': 0.48.1 ajv: '@redocly/ajv@8.18.0' ajv-formats: 3.0.1(@redocly/ajv@8.18.0) colorette: 1.4.0 @@ -1208,12 +1213,12 @@ snapshots: pluralize: 8.0.0 yaml-ast-parser: 0.0.43 - '@redocly/respect-core@2.25.3': + '@redocly/respect-core@2.29.1': dependencies: '@faker-js/faker': 7.6.0 '@noble/hashes': 1.8.0 '@redocly/ajv': 8.18.0 - '@redocly/openapi-core': 2.25.3 + '@redocly/openapi-core': 2.29.1 ajv: '@redocly/ajv@8.18.0' better-ajv-errors: 1.2.0(@redocly/ajv@8.18.0) colorette: 2.0.20 @@ -1285,7 +1290,7 @@ snapshots: boolbase@1.0.0: {} - brace-expansion@2.0.3: + brace-expansion@2.1.0: dependencies: balanced-match: 1.0.2 @@ -1391,7 +1396,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.3.3: + dompurify@3.4.1: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -1430,15 +1435,16 @@ snapshots: fast-uri@3.1.0: {} - fast-xml-builder@1.1.4: + fast-xml-builder@1.1.5: dependencies: - path-expression-matcher: 1.2.0 + path-expression-matcher: 1.5.0 - fast-xml-parser@5.5.9: + fast-xml-parser@5.7.1: dependencies: - fast-xml-builder: 1.1.4 - path-expression-matcher: 1.2.0 - strnum: 2.2.2 + '@nodable/entities': 2.1.0 + fast-xml-builder: 1.1.5 + path-expression-matcher: 1.5.0 + strnum: 2.2.3 foreach@2.0.6: {} @@ -1517,7 +1523,7 @@ snapshots: dependencies: js-tokens: 4.0.0 - lru-cache@11.2.7: {} + lru-cache@11.3.5: {} lunr@2.3.9: {} @@ -1533,27 +1539,27 @@ snapshots: minimatch@5.1.9: dependencies: - brace-expansion: 2.0.3 + brace-expansion: 2.1.0 minimist@1.2.8: {} minipass@7.1.3: {} - mobx-react-lite@4.1.1(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + mobx-react-lite@4.1.1(mobx@6.15.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: mobx: 6.15.0 - react: 19.2.4 - use-sync-external-store: 1.6.0(react@19.2.4) + react: 19.2.5 + use-sync-external-store: 1.6.0(react@19.2.5) optionalDependencies: - react-dom: 19.2.4(react@19.2.4) + react-dom: 19.2.5(react@19.2.5) - mobx-react@9.2.0(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + mobx-react@9.2.0(mobx@6.15.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: mobx: 6.15.0 - mobx-react-lite: 4.1.1(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - react: 19.2.4 + mobx-react-lite: 4.1.1(mobx@6.15.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: 19.2.5 optionalDependencies: - react-dom: 19.2.4(react@19.2.4) + react-dom: 19.2.5(react@19.2.5) mobx@6.15.0: {} @@ -1615,7 +1621,7 @@ snapshots: openapi-sampler@1.7.2: dependencies: '@types/json-schema': 7.0.15 - fast-xml-parser: 5.5.9 + fast-xml-parser: 5.7.1 json-pointer: 0.6.2 outdent@0.8.0: {} @@ -1635,11 +1641,11 @@ snapshots: path-browserify@1.0.1: {} - path-expression-matcher@1.2.0: {} + path-expression-matcher@1.5.0: {} path-scurry@2.0.2: dependencies: - lru-cache: 11.2.7 + lru-cache: 11.3.5 minipass: 7.1.3 perfect-scrollbar@1.5.6: {} @@ -1670,7 +1676,7 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - protobufjs@7.5.4: + protobufjs@7.5.5: dependencies: '@protobufjs/aspromise': 1.1.2 '@protobufjs/base64': 1.1.2 @@ -1691,20 +1697,20 @@ snapshots: dependencies: safe-buffer: 5.2.1 - react-dom@19.2.4(react@19.2.4): + react-dom@19.2.5(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 scheduler: 0.27.0 react-is@16.13.1: {} - react-tabs@6.1.1(react@19.2.4): + react-tabs@6.1.1(react@19.2.5): dependencies: clsx: 2.1.1 prop-types: 15.8.1 - react: 19.2.4 + react: 19.2.5 - react@19.2.4: {} + react@19.2.5: {} readable-stream@3.6.2: dependencies: @@ -1712,32 +1718,32 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - redoc@2.5.1(core-js@3.45.1)(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styled-components@6.3.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4)): + redoc@2.5.1(core-js@3.45.1)(mobx@6.15.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(styled-components@6.3.9(react-dom@19.2.5(react@19.2.5))(react@19.2.5)): dependencies: - '@redocly/openapi-core': 1.34.11 + '@redocly/openapi-core': 1.34.12 classnames: 2.5.1 core-js: 3.45.1 decko: 1.2.0 - dompurify: 3.3.3 + dompurify: 3.4.1 eventemitter3: 5.0.4 json-pointer: 0.6.2 lunr: 2.3.9 mark.js: 8.11.1 marked: 4.3.0 mobx: 6.15.0 - mobx-react: 9.2.0(mobx@6.15.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + mobx-react: 9.2.0(mobx@6.15.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) openapi-sampler: 1.7.2 path-browserify: 1.0.1 perfect-scrollbar: 1.5.6 polished: 4.3.1 prismjs: 1.30.0 prop-types: 15.8.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-tabs: 6.1.1(react@19.2.4) + react: 19.2.5 + react-dom: 19.2.5(react@19.2.5) + react-tabs: 6.1.1(react@19.2.5) slugify: 1.4.7 stickyfill: 1.1.1 - styled-components: 6.3.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + styled-components: 6.3.9(react-dom@19.2.5(react@19.2.5))(react@19.2.5) swagger2openapi: 7.0.8 url-template: 2.0.8 transitivePeerDependencies: @@ -1823,9 +1829,9 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strnum@2.2.2: {} + strnum@2.2.3: {} - styled-components@6.3.9(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + styled-components@6.3.9(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: '@emotion/is-prop-valid': 1.4.0 '@emotion/unitless': 0.10.0 @@ -1833,12 +1839,12 @@ snapshots: css-to-react-native: 3.2.0 csstype: 3.2.3 postcss: 8.4.49 - react: 19.2.4 + react: 19.2.5 shallowequal: 1.1.0 stylis: 4.3.6 tslib: 2.8.1 optionalDependencies: - react-dom: 19.2.4(react@19.2.4) + react-dom: 19.2.5(react@19.2.5) stylis@4.3.6: {} @@ -1905,9 +1911,9 @@ snapshots: url-template@2.0.8: {} - use-sync-external-store@1.6.0(react@19.2.4): + use-sync-external-store@1.6.0(react@19.2.5): dependencies: - react: 19.2.4 + react: 19.2.5 util-deprecate@1.0.2: {}