Show T5 products in the client's shop; keep float IDs and unknown paths off IMVU
CI / build (push) Successful in 34s

The shop's T5 filter (maturity_rating "t5") is answered from the hub's products, fetched so they can be
shown and tried on; buying T5 products adds them to the hub library, and product.php details for
community products are answered here.

The client sends some product IDs as floats ("2000000008.0"): product.php passed the worn community
product to IMVU that way. Every ID is now read either way, and products.Guard refuses any request to
IMVU that still names a local ID given out. T5DE_PROXY_DUMP logs request and response bodies.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
dhkatzandClaude Opus 5.5 committed 2026-10-30 01:15:16 -07:00
1 parent 6506c641f0
commit 2280ad6314
14 files changed
+785 -18

No files matched your search

+26
View File
@@ -15,6 +15,7 @@ import (
"io"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
@@ -491,3 +492,28 @@ func (c *Client) AccessToken(ctx context.Context) (string, error) {
err := c.Call(ctx, "POST", "/api/v1/access", nil, &out)
return out.Token, err
}
// Product is a product as the hub lists it (GET /api/v1/products).
type Product struct {
ID string `json:"id"`
Name string `json:"name"`
Creator string `json:"creator"`
Rating string `json:"rating"`
Latest int `json:"latest"`
Parent int64 `json:"parent"`
Image string `json:"image"`
Categories []Category `json:"categories"` // the parent's IMVU category path, top first
}
// Category is an IMVU shop category.
type Category struct {
ID int64 `json:"id"`
Name string `json:"name"`
}
// Products searches the hub's products (by name; all if query is empty), newest first.
func (c *Client) Products(ctx context.Context, query string) ([]Product, error) {
var out struct{ Products []Product }
err := c.Call(ctx, "GET", "/api/v1/products?limit=200&q="+url.QueryEscape(query), nil, &out)
return out.Products, err
}