@01.software/cli 0.10.3 → 0.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +256 -36
- package/dist/index.js.map +1 -1
- package/dist/mcp/{chunk-VSMPWKVX.js → chunk-2EPYMNHW.js} +256 -221
- package/dist/mcp/chunk-2EPYMNHW.js.map +1 -0
- package/dist/mcp/http.js +1 -1
- package/dist/mcp/stdio.js +1 -1
- package/dist/mcp/vercel.js +255 -220
- package/package.json +2 -2
- package/dist/mcp/chunk-VSMPWKVX.js.map +0 -1
|
@@ -1103,7 +1103,7 @@ async function swallow(promise) {
|
|
|
1103
1103
|
import { z as z3 } from "zod";
|
|
1104
1104
|
|
|
1105
1105
|
// src/lib/client.ts
|
|
1106
|
-
import { createServerClient } from "@01.software/sdk";
|
|
1106
|
+
import { createServerClient } from "@01.software/sdk/server";
|
|
1107
1107
|
var MISSING_HTTP_AUTH_CONTEXT_ERROR2 = "MCP HTTP requests require a validated OAuth tenant context before tool execution.";
|
|
1108
1108
|
var HTTP_OAUTH_SDK_CLIENT_ERROR = "MCP HTTP OAuth requests cannot use SDK-backed tools. Use reviewed Console service endpoints for OAuth transport.";
|
|
1109
1109
|
function getClient() {
|
|
@@ -1936,18 +1936,22 @@ async function productDetail({
|
|
|
1936
1936
|
// src/tools/product-upsert.ts
|
|
1937
1937
|
import { z as z23 } from "zod";
|
|
1938
1938
|
var optionValueSchema = z23.object({
|
|
1939
|
-
id: z23.string().optional().describe("
|
|
1939
|
+
id: z23.string().optional().describe("Stable existing option-value ID for rename-safe updates"),
|
|
1940
1940
|
value: z23.string().describe("Display label (e.g. Black, S)"),
|
|
1941
|
-
slug: z23.string().optional().describe(
|
|
1941
|
+
slug: z23.string().optional().describe(
|
|
1942
|
+
"Optional compatibility value token. The server generates one from value on create when omitted; not canonical identity."
|
|
1943
|
+
),
|
|
1942
1944
|
swatchColor: z23.string().nullable().optional(),
|
|
1943
1945
|
thumbnail: z23.string().nullable().optional(),
|
|
1944
1946
|
images: z23.array(z23.string()).optional(),
|
|
1945
1947
|
metadata: z23.unknown().optional()
|
|
1946
1948
|
});
|
|
1947
1949
|
var optionSchema = z23.object({
|
|
1948
|
-
id: z23.string().optional().describe("
|
|
1950
|
+
id: z23.string().optional().describe("Stable existing option ID for rename-safe updates"),
|
|
1949
1951
|
title: z23.string().describe("Option name (e.g. Color, Size)"),
|
|
1950
|
-
slug: z23.string().optional().describe(
|
|
1952
|
+
slug: z23.string().optional().describe(
|
|
1953
|
+
"Optional compatibility option token. The server generates one from title on create when omitted; not canonical identity."
|
|
1954
|
+
),
|
|
1951
1955
|
values: z23.array(optionValueSchema).describe("Allowed option values")
|
|
1952
1956
|
});
|
|
1953
1957
|
var variantOptionValueSchema = z23.object({
|
|
@@ -1961,7 +1965,7 @@ var variantSchema = z23.object({
|
|
|
1961
1965
|
z23.record(z23.string(), z23.union([z23.string(), variantOptionValueSchema])),
|
|
1962
1966
|
z23.array(z23.string())
|
|
1963
1967
|
]).optional().describe(
|
|
1964
|
-
"Option-value selection. Prefer
|
|
1968
|
+
"Option-value selection. Prefer stable option-value IDs, either as an array or object values using { valueId }. Slug maps and exact { OptionTitle: ValueLabel } maps remain compatibility-only and fail when labels are ambiguous."
|
|
1965
1969
|
),
|
|
1966
1970
|
sku: z23.string().nullable().optional(),
|
|
1967
1971
|
title: z23.string().nullable().optional(),
|
|
@@ -1983,10 +1987,10 @@ var schema23 = {
|
|
|
1983
1987
|
"Product fields. Include `id` to update an existing product; omit for create (then `title` is required)."
|
|
1984
1988
|
),
|
|
1985
1989
|
options: z23.array(optionSchema).optional().describe(
|
|
1986
|
-
"Option definitions.
|
|
1990
|
+
"Option definitions. Include stable option/value IDs when updating or renaming existing rows. Slugs are optional compatibility metadata generated from title/value on create when omitted; omitted options on an existing product are deleted (with their values)."
|
|
1987
1991
|
),
|
|
1988
1992
|
variants: z23.array(variantSchema).optional().describe(
|
|
1989
|
-
"Variant rows. Prefer
|
|
1993
|
+
"Variant rows. Prefer stable option-value IDs in optionValues. Slug/title maps are compatibility inputs. Omitted variants on an existing product are deleted, unless referenced by an active cart or non-terminal order \u2014 those are soft-deactivated (isActive: false)."
|
|
1990
1994
|
)
|
|
1991
1995
|
};
|
|
1992
1996
|
var metadata23 = {
|
|
@@ -2287,14 +2291,16 @@ var recipes = {
|
|
|
2287
2291
|
recommendedSurface: "react-query",
|
|
2288
2292
|
runtime: "browser",
|
|
2289
2293
|
code: `import { createClient } from '@01.software/sdk'
|
|
2294
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
2290
2295
|
|
|
2291
2296
|
const client = createClient({
|
|
2292
2297
|
publishableKey: process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY!,
|
|
2293
2298
|
})
|
|
2299
|
+
const query = createQueryHooks(client)
|
|
2294
2300
|
|
|
2295
2301
|
// React Query hook \u2014 handles caching and background updates
|
|
2296
2302
|
function ProductList() {
|
|
2297
|
-
const { data, isLoading, error } =
|
|
2303
|
+
const { data, isLoading, error } = query.useQuery({
|
|
2298
2304
|
collection: 'products',
|
|
2299
2305
|
options: {
|
|
2300
2306
|
where: { status: { equals: 'published' } },
|
|
@@ -2326,7 +2332,7 @@ function ProductList() {
|
|
|
2326
2332
|
title: "Fetch collection list (server)",
|
|
2327
2333
|
recommendedSurface: "query-builder",
|
|
2328
2334
|
runtime: "server",
|
|
2329
|
-
code: `import { createServerClient } from '@01.software/sdk'
|
|
2335
|
+
code: `import { createServerClient } from '@01.software/sdk/server'
|
|
2330
2336
|
|
|
2331
2337
|
const client = createServerClient({
|
|
2332
2338
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -2359,13 +2365,15 @@ const result = await client.collections.from('products').find({
|
|
|
2359
2365
|
recommendedSurface: "react-query",
|
|
2360
2366
|
runtime: "browser",
|
|
2361
2367
|
code: `import { createClient } from '@01.software/sdk'
|
|
2368
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
2362
2369
|
|
|
2363
2370
|
const client = createClient({
|
|
2364
2371
|
publishableKey: process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY!,
|
|
2365
2372
|
})
|
|
2373
|
+
const query = createQueryHooks(client)
|
|
2366
2374
|
|
|
2367
2375
|
function ProductDetail({ id }: { id: string }) {
|
|
2368
|
-
const { data, isLoading } =
|
|
2376
|
+
const { data, isLoading } = query.useQueryById({
|
|
2369
2377
|
collection: 'products',
|
|
2370
2378
|
id,
|
|
2371
2379
|
})
|
|
@@ -2385,7 +2393,7 @@ function ProductDetail({ id }: { id: string }) {
|
|
|
2385
2393
|
title: "Fetch single item by ID (server)",
|
|
2386
2394
|
recommendedSurface: "query-builder",
|
|
2387
2395
|
runtime: "server",
|
|
2388
|
-
code: `import { createServerClient } from '@01.software/sdk'
|
|
2396
|
+
code: `import { createServerClient } from '@01.software/sdk/server'
|
|
2389
2397
|
|
|
2390
2398
|
const client = createServerClient({
|
|
2391
2399
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -2408,7 +2416,7 @@ console.log(product.title)`,
|
|
|
2408
2416
|
title: "Create a new item (server only)",
|
|
2409
2417
|
recommendedSurface: "server-api",
|
|
2410
2418
|
runtime: "server",
|
|
2411
|
-
code: `import { createServerClient } from '@01.software/sdk'
|
|
2419
|
+
code: `import { createServerClient } from '@01.software/sdk/server'
|
|
2412
2420
|
|
|
2413
2421
|
const client = createServerClient({
|
|
2414
2422
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -2437,7 +2445,7 @@ const result = await client.collections.from('products').create({
|
|
|
2437
2445
|
title: "Update an existing item (server only)",
|
|
2438
2446
|
recommendedSurface: "server-api",
|
|
2439
2447
|
runtime: "server",
|
|
2440
|
-
code: `import { createServerClient } from '@01.software/sdk'
|
|
2448
|
+
code: `import { createServerClient } from '@01.software/sdk/server'
|
|
2441
2449
|
|
|
2442
2450
|
const client = createServerClient({
|
|
2443
2451
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -2466,7 +2474,7 @@ const result = await client.collections.from('products').update('product-id', {
|
|
|
2466
2474
|
title: "Delete an item (server only)",
|
|
2467
2475
|
recommendedSurface: "server-api",
|
|
2468
2476
|
runtime: "server",
|
|
2469
|
-
code: `import { createServerClient } from '@01.software/sdk'
|
|
2477
|
+
code: `import { createServerClient } from '@01.software/sdk/server'
|
|
2470
2478
|
|
|
2471
2479
|
const client = createServerClient({
|
|
2472
2480
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -2491,10 +2499,12 @@ console.log('Deleted:', deleted.title)`,
|
|
|
2491
2499
|
recommendedSurface: "react-query",
|
|
2492
2500
|
runtime: "browser",
|
|
2493
2501
|
code: `import { createClient } from '@01.software/sdk'
|
|
2502
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
2494
2503
|
|
|
2495
2504
|
const client = createClient({
|
|
2496
2505
|
publishableKey: process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY!,
|
|
2497
2506
|
})
|
|
2507
|
+
const query = createQueryHooks(client)
|
|
2498
2508
|
|
|
2499
2509
|
function InfiniteProductList() {
|
|
2500
2510
|
const {
|
|
@@ -2503,7 +2513,7 @@ function InfiniteProductList() {
|
|
|
2503
2513
|
hasNextPage,
|
|
2504
2514
|
isFetchingNextPage,
|
|
2505
2515
|
isLoading,
|
|
2506
|
-
} =
|
|
2516
|
+
} = query.useInfiniteQuery({
|
|
2507
2517
|
collection: 'products',
|
|
2508
2518
|
options: { where: { status: { equals: 'published' } } },
|
|
2509
2519
|
pageSize: 20,
|
|
@@ -2538,7 +2548,8 @@ function InfiniteProductList() {
|
|
|
2538
2548
|
title: "SSR data prefetching (server)",
|
|
2539
2549
|
recommendedSurface: "react-query",
|
|
2540
2550
|
runtime: "server",
|
|
2541
|
-
code: `import { createServerClient } from '@01.software/sdk'
|
|
2551
|
+
code: `import { createServerClient } from '@01.software/sdk/server'
|
|
2552
|
+
import { createServerQueryHooks, getQueryClient } from '@01.software/sdk/query'
|
|
2542
2553
|
import { dehydrate, HydrationBoundary } from '@tanstack/react-query'
|
|
2543
2554
|
|
|
2544
2555
|
// In a Next.js Server Component or getServerSideProps:
|
|
@@ -2546,27 +2557,29 @@ const client = createServerClient({
|
|
|
2546
2557
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
2547
2558
|
secretKey: process.env.SOFTWARE_SECRET_KEY!,
|
|
2548
2559
|
})
|
|
2560
|
+
const queryClient = getQueryClient()
|
|
2561
|
+
const serverQuery = createServerQueryHooks(client, queryClient)
|
|
2549
2562
|
|
|
2550
2563
|
// Prefetch list \u2014 client hydrates instantly without a loading state
|
|
2551
|
-
await
|
|
2564
|
+
await serverQuery.prefetchQuery({
|
|
2552
2565
|
collection: 'products',
|
|
2553
2566
|
options: { limit: 20 },
|
|
2554
2567
|
})
|
|
2555
2568
|
|
|
2556
2569
|
// Prefetch single item
|
|
2557
|
-
await
|
|
2570
|
+
await serverQuery.prefetchQueryById({
|
|
2558
2571
|
collection: 'products',
|
|
2559
2572
|
id: 'product-id',
|
|
2560
2573
|
})
|
|
2561
2574
|
|
|
2562
2575
|
// Prefetch infinite list
|
|
2563
|
-
await
|
|
2576
|
+
await serverQuery.prefetchInfiniteQuery({
|
|
2564
2577
|
collection: 'products',
|
|
2565
2578
|
pageSize: 20,
|
|
2566
2579
|
})
|
|
2567
2580
|
|
|
2568
2581
|
// Dehydrate and pass to client
|
|
2569
|
-
const state = dehydrate(
|
|
2582
|
+
const state = dehydrate(queryClient)
|
|
2570
2583
|
|
|
2571
2584
|
export default function Page() {
|
|
2572
2585
|
return (
|
|
@@ -2636,7 +2649,7 @@ await client.customer.resetPassword(token, 'newPassword123')`,
|
|
|
2636
2649
|
title: "File upload pattern (server)",
|
|
2637
2650
|
recommendedSurface: "server-api",
|
|
2638
2651
|
runtime: "server",
|
|
2639
|
-
code: `import { createServerClient } from '@01.software/sdk'
|
|
2652
|
+
code: `import { createServerClient } from '@01.software/sdk/server'
|
|
2640
2653
|
|
|
2641
2654
|
const client = createServerClient({
|
|
2642
2655
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -2667,7 +2680,7 @@ const result = await client.collections.from('images').create(formData as unknow
|
|
|
2667
2680
|
title: "Bulk update/delete (server only)",
|
|
2668
2681
|
recommendedSurface: "server-api",
|
|
2669
2682
|
runtime: "server",
|
|
2670
|
-
code: `import { createServerClient } from '@01.software/sdk'
|
|
2683
|
+
code: `import { createServerClient } from '@01.software/sdk/server'
|
|
2671
2684
|
|
|
2672
2685
|
const client = createServerClient({
|
|
2673
2686
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -2819,15 +2832,15 @@ var docIndex = [
|
|
|
2819
2832
|
},
|
|
2820
2833
|
{
|
|
2821
2834
|
title: "Query Builder \u2014 Metadata Generation",
|
|
2822
|
-
keywords: ["metadata", "
|
|
2823
|
-
summary: "
|
|
2835
|
+
keywords: ["metadata", "generateMetadata", "extractSeo", "next.js metadata", "seo", "open graph", "query builder"],
|
|
2836
|
+
summary: "Use @01.software/sdk/metadata helpers with fetched documents to generate Metadata-shaped SEO objects without pulling Next.js into the root SDK entry.",
|
|
2824
2837
|
resourceUri: "docs://sdk/query-builder"
|
|
2825
2838
|
},
|
|
2826
2839
|
// React Query Hooks
|
|
2827
2840
|
{
|
|
2828
2841
|
title: "React Query \u2014 useQuery()",
|
|
2829
2842
|
keywords: ["useQuery", "react query", "hook", "list", "fetch", "collection", "cache", "react"],
|
|
2830
|
-
summary: "client.
|
|
2843
|
+
summary: "createQueryHooks(client).useQuery({ collection, options }) \u2014 fetches a list with caching and background updates. Use inside a React component.",
|
|
2831
2844
|
resourceUri: "docs://sdk/react-query"
|
|
2832
2845
|
},
|
|
2833
2846
|
{
|
|
@@ -2839,7 +2852,7 @@ var docIndex = [
|
|
|
2839
2852
|
{
|
|
2840
2853
|
title: "React Query \u2014 useInfiniteQuery()",
|
|
2841
2854
|
keywords: ["useInfiniteQuery", "useSuspenseInfiniteQuery", "infinite scroll", "load more", "pagination", "react query", "hook"],
|
|
2842
|
-
summary: "client.
|
|
2855
|
+
summary: "createQueryHooks(client).useInfiniteQuery({ collection, options, pageSize }) \u2014 infinite scrolling. data.pages is an array of pages; flatten with flatMap for all docs.",
|
|
2843
2856
|
resourceUri: "docs://sdk/react-query"
|
|
2844
2857
|
},
|
|
2845
2858
|
{
|
|
@@ -2858,7 +2871,7 @@ var docIndex = [
|
|
|
2858
2871
|
{
|
|
2859
2872
|
title: "Cache Invalidation and Manual Cache Management",
|
|
2860
2873
|
keywords: ["invalidateQueries", "getQueryData", "setQueryData", "cache", "invalidate", "optimistic update", "react query"],
|
|
2861
|
-
summary: "
|
|
2874
|
+
summary: "query.invalidateQueries(collection, type) triggers refetch. getQueryData/setQueryData allow manual optimistic updates.",
|
|
2862
2875
|
resourceUri: "docs://sdk/react-query"
|
|
2863
2876
|
},
|
|
2864
2877
|
// Filtering
|
|
@@ -3009,23 +3022,25 @@ var AUTH_GUIDES = {
|
|
|
3009
3022
|
title: "Browser Client Setup",
|
|
3010
3023
|
envVars: ["NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY"],
|
|
3011
3024
|
code: `import { createClient } from '@01.software/sdk'
|
|
3025
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
3012
3026
|
|
|
3013
3027
|
const client = createClient({
|
|
3014
3028
|
publishableKey: process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY!
|
|
3015
3029
|
})
|
|
3030
|
+
const query = createQueryHooks(client)
|
|
3016
3031
|
|
|
3017
3032
|
// Read-only operations + React Query hooks + Customer Auth
|
|
3018
|
-
const { data } =
|
|
3033
|
+
const { data } = query.useQuery({ collection: 'products' })`,
|
|
3019
3034
|
notes: [
|
|
3020
3035
|
"Client is read-only \u2014 no create/update/delete operations",
|
|
3021
3036
|
"publishableKey is safe to expose in browser (prefixed with NEXT_PUBLIC_)",
|
|
3022
|
-
"
|
|
3037
|
+
"Use createQueryHooks(client) for React Query hooks and client.customer for Customer Auth"
|
|
3023
3038
|
]
|
|
3024
3039
|
},
|
|
3025
3040
|
"server-client": {
|
|
3026
3041
|
title: "Server Client Setup",
|
|
3027
3042
|
envVars: ["SOFTWARE_PUBLISHABLE_KEY", "SOFTWARE_SECRET_KEY"],
|
|
3028
|
-
code: `import { createServerClient } from '@01.software/sdk'
|
|
3043
|
+
code: `import { createServerClient } from '@01.software/sdk/server'
|
|
3029
3044
|
|
|
3030
3045
|
const client = createServerClient({
|
|
3031
3046
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -3038,7 +3053,7 @@ const result = await client.collections.from('products').create({ title: 'New Pr
|
|
|
3038
3053
|
"ServerClient has full CRUD access and must run only in trusted server code",
|
|
3039
3054
|
"Store server credentials in environment variables and rotate them from the Console",
|
|
3040
3055
|
"Use in API routes, server actions, or backend services only",
|
|
3041
|
-
"
|
|
3056
|
+
"Use createServerClient in API routes, server actions, or backend services; keep React Query hooks for browser-safe reads and server prefetching"
|
|
3042
3057
|
]
|
|
3043
3058
|
},
|
|
3044
3059
|
"customer-auth": {
|
|
@@ -3176,37 +3191,35 @@ function generatePattern(collection, operation, surface) {
|
|
|
3176
3191
|
);
|
|
3177
3192
|
}
|
|
3178
3193
|
const parts2 = [];
|
|
3179
|
-
if (operation === "read") {
|
|
3194
|
+
if (operation === "read" || operation === "full-crud") {
|
|
3180
3195
|
parts2.push(
|
|
3181
3196
|
`import { createClient } from '@01.software/sdk'`,
|
|
3182
|
-
|
|
3183
|
-
`const client = createClient({`,
|
|
3184
|
-
` publishableKey: process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY!`,
|
|
3185
|
-
`})`,
|
|
3186
|
-
``
|
|
3197
|
+
`import { createQueryHooks } from '@01.software/sdk/query'`
|
|
3187
3198
|
);
|
|
3188
|
-
}
|
|
3199
|
+
}
|
|
3200
|
+
if (operation === "write" || operation === "full-crud") {
|
|
3201
|
+
parts2.push(`import { createServerClient } from '@01.software/sdk/server'`);
|
|
3202
|
+
}
|
|
3203
|
+
parts2.push(``);
|
|
3204
|
+
if (operation === "read" || operation === "full-crud") {
|
|
3189
3205
|
parts2.push(
|
|
3190
|
-
`
|
|
3191
|
-
|
|
3192
|
-
`// Mutation hooks require ServerClient`,
|
|
3193
|
-
`const client = createServerClient({`,
|
|
3194
|
-
` publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,`,
|
|
3195
|
-
` secretKey: process.env.SOFTWARE_SECRET_KEY!`,
|
|
3206
|
+
`const client = createClient({`,
|
|
3207
|
+
` publishableKey: process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY!`,
|
|
3196
3208
|
`})`,
|
|
3209
|
+
`const query = createQueryHooks(client)`,
|
|
3197
3210
|
``
|
|
3198
3211
|
);
|
|
3199
3212
|
}
|
|
3200
3213
|
if (operation === "read" || operation === "full-crud") {
|
|
3201
3214
|
parts2.push(
|
|
3202
3215
|
`// List query`,
|
|
3203
|
-
`const { data, isLoading } =
|
|
3216
|
+
`const { data, isLoading } = query.useQuery({`,
|
|
3204
3217
|
` collection: '${collection}',`,
|
|
3205
3218
|
` options: { limit: 10 }`,
|
|
3206
3219
|
`})`,
|
|
3207
3220
|
``,
|
|
3208
3221
|
`// Single item`,
|
|
3209
|
-
`const { data: item } =
|
|
3222
|
+
`const { data: item } = query.useQueryById({`,
|
|
3210
3223
|
` collection: '${collection}',`,
|
|
3211
3224
|
` id: itemId`,
|
|
3212
3225
|
`})`
|
|
@@ -3215,31 +3228,28 @@ function generatePattern(collection, operation, surface) {
|
|
|
3215
3228
|
if (operation === "write" || operation === "full-crud") {
|
|
3216
3229
|
parts2.push(
|
|
3217
3230
|
``,
|
|
3218
|
-
`//
|
|
3219
|
-
`const
|
|
3220
|
-
`
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
`const { mutate: update } = client.query.useUpdate({ collection: '${collection}' })`,
|
|
3224
|
-
`update({ id: itemId, data: { title: 'Updated' } })`,
|
|
3231
|
+
`// Writes belong in a server action or API route, not a client component.`,
|
|
3232
|
+
`const server = createServerClient({`,
|
|
3233
|
+
` publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,`,
|
|
3234
|
+
` secretKey: process.env.SOFTWARE_SECRET_KEY!`,
|
|
3235
|
+
`})`,
|
|
3225
3236
|
``,
|
|
3226
|
-
|
|
3227
|
-
`
|
|
3228
|
-
`remove(itemId)`
|
|
3237
|
+
`await server.collections.from('${collection}').create({ title: 'New Item' })`,
|
|
3238
|
+
`await server.collections.from('${collection}').update(itemId, { title: 'Updated' })`,
|
|
3239
|
+
`await server.collections.from('${collection}').remove(itemId)`
|
|
3229
3240
|
);
|
|
3230
3241
|
}
|
|
3231
3242
|
return {
|
|
3232
3243
|
code: parts2.join("\n"),
|
|
3233
3244
|
notes: [
|
|
3234
|
-
"React Query hooks provide automatic caching and background updates",
|
|
3235
|
-
"
|
|
3236
|
-
operation === "write" || operation === "full-crud" ? "Mutation hooks (useCreate, useUpdate, useRemove) require ServerClient with SOFTWARE_PUBLISHABLE_KEY + SOFTWARE_SECRET_KEY" : "Read hooks work in browser components"
|
|
3245
|
+
"React Query hooks provide automatic caching and background updates for browser-safe reads",
|
|
3246
|
+
operation === "write" || operation === "full-crud" ? "Writes require trusted server code with SOFTWARE_PUBLISHABLE_KEY + SOFTWARE_SECRET_KEY; invalidate browser caches after the server action returns" : "Read hooks work in browser components"
|
|
3237
3247
|
]
|
|
3238
3248
|
};
|
|
3239
3249
|
}
|
|
3240
3250
|
if (surface === "server-api") {
|
|
3241
3251
|
const parts2 = [
|
|
3242
|
-
`import { createServerClient } from '@01.software/sdk'`,
|
|
3252
|
+
`import { createServerClient } from '@01.software/sdk/server'`,
|
|
3243
3253
|
``,
|
|
3244
3254
|
`const client = createServerClient({`,
|
|
3245
3255
|
` publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,`,
|
|
@@ -3406,8 +3416,12 @@ const result = await client.collections.from('products').find({
|
|
|
3406
3416
|
})
|
|
3407
3417
|
|
|
3408
3418
|
// Use React hooks
|
|
3419
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
3420
|
+
|
|
3421
|
+
const query = createQueryHooks(client)
|
|
3422
|
+
|
|
3409
3423
|
function ProductList() {
|
|
3410
|
-
const { data, isLoading } =
|
|
3424
|
+
const { data, isLoading } = query.useQuery({
|
|
3411
3425
|
collection: 'products',
|
|
3412
3426
|
options: { limit: 10 }
|
|
3413
3427
|
})
|
|
@@ -3424,7 +3438,7 @@ function ProductList() {
|
|
|
3424
3438
|
}
|
|
3425
3439
|
\`\`\`
|
|
3426
3440
|
|
|
3427
|
-
### React Query Hooks (
|
|
3441
|
+
### React Query Hooks (@01.software/sdk/query)
|
|
3428
3442
|
|
|
3429
3443
|
| Hook | Description |
|
|
3430
3444
|
|------|-------------|
|
|
@@ -3459,13 +3473,17 @@ await client.collections.from('products').remove('id')
|
|
|
3459
3473
|
// count() returns { totalDocs }
|
|
3460
3474
|
const { totalDocs } = await client.collections.from('products').count()
|
|
3461
3475
|
|
|
3462
|
-
// Metadata - generate
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
const
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3476
|
+
// Metadata - generate Metadata-shaped SEO objects from fetched documents
|
|
3477
|
+
import { extractSeo, generateMetadata } from '@01.software/sdk/metadata'
|
|
3478
|
+
|
|
3479
|
+
const productResult = await client.collections.from('products').find({
|
|
3480
|
+
where: { slug: { equals: 'my-product' } },
|
|
3481
|
+
limit: 1,
|
|
3482
|
+
depth: 1,
|
|
3483
|
+
})
|
|
3484
|
+
const productMeta = productResult.docs[0]
|
|
3485
|
+
? generateMetadata(extractSeo(productResult.docs[0]), { siteName: 'My Store' })
|
|
3486
|
+
: null
|
|
3469
3487
|
\`\`\`
|
|
3470
3488
|
|
|
3471
3489
|
### Filtering (Payload Query Syntax)
|
|
@@ -3488,7 +3506,7 @@ For ecommerce collections, use \`products.listing.*\` for browse/search pricing
|
|
|
3488
3506
|
### Server Client (Server-side)
|
|
3489
3507
|
|
|
3490
3508
|
\`\`\`typescript
|
|
3491
|
-
import { createServerClient } from '@01.software/sdk'
|
|
3509
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
3492
3510
|
|
|
3493
3511
|
const client = createServerClient({
|
|
3494
3512
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -3508,7 +3526,7 @@ if (!product) return notFound()
|
|
|
3508
3526
|
// product: { product, variants, options, brand, categories, tags, images, videos, listing }
|
|
3509
3527
|
\`\`\`
|
|
3510
3528
|
|
|
3511
|
-
For React: \`const { data } = client.
|
|
3529
|
+
For React: \`const { data } = createQueryHooks(client).useProductDetailBySlug(slug)\`.
|
|
3512
3530
|
|
|
3513
3531
|
### Product listing (grouped)
|
|
3514
3532
|
|
|
@@ -3563,7 +3581,8 @@ ${filters}
|
|
|
3563
3581
|
### ${operation === "find" ? "Query" : operation === "create" ? "Create" : operation === "update" ? "Update" : "Delete"} Example
|
|
3564
3582
|
|
|
3565
3583
|
\`\`\`typescript
|
|
3566
|
-
import { createClient
|
|
3584
|
+
import { createClient } from '@01.software/sdk'
|
|
3585
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
3567
3586
|
|
|
3568
3587
|
// Client (read-only public collections)
|
|
3569
3588
|
const client = createClient({
|
|
@@ -3584,14 +3603,18 @@ const result = await ${readClientName}.collections.from('${collection}').find(${
|
|
|
3584
3603
|
// result.docs - array of items
|
|
3585
3604
|
// result.totalDocs, result.page, result.totalPages, result.hasNextPage, ...
|
|
3586
3605
|
|
|
3587
|
-
${isPublicCollection ? `// Using React
|
|
3588
|
-
|
|
3606
|
+
${isPublicCollection ? `// Using React Query hooks
|
|
3607
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
3608
|
+
|
|
3609
|
+
const query = createQueryHooks(client)
|
|
3610
|
+
|
|
3611
|
+
const { data, isLoading, error } = query.useQuery({
|
|
3589
3612
|
collection: '${collection}',
|
|
3590
3613
|
options: { limit: 10 }
|
|
3591
3614
|
})
|
|
3592
3615
|
|
|
3593
3616
|
// With Suspense
|
|
3594
|
-
const { data } =
|
|
3617
|
+
const { data } = query.useSuspenseQuery({
|
|
3595
3618
|
collection: '${collection}',
|
|
3596
3619
|
options: { limit: 10 }
|
|
3597
3620
|
})` : `// React hooks are browser/public only and do not support '${collection}'.`}` : operation === "create" ? `// Create ${collection} item (ServerClient only)
|
|
@@ -3660,7 +3683,7 @@ var SCENARIOS = {
|
|
|
3660
3683
|
|
|
3661
3684
|
### Code Example (ServerClient)
|
|
3662
3685
|
\`\`\`typescript
|
|
3663
|
-
import { createServerClient } from '@01.software/sdk'
|
|
3686
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
3664
3687
|
|
|
3665
3688
|
const client = createServerClient({
|
|
3666
3689
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -3885,7 +3908,6 @@ customer-addresses
|
|
|
3885
3908
|
### Optional Collections
|
|
3886
3909
|
|
|
3887
3910
|
- customer-groups \u2014 Console/server-scoped segmentation for VIP coupons and campaigns. Use \`createServerClient().collections.from('customer-groups')\`.
|
|
3888
|
-
- customer-profile-lists \u2014 Public profile display/ranking lists for storefronts. Browser reads may use \`client.collections.from('customer-profile-lists')\`.
|
|
3889
3911
|
|
|
3890
3912
|
### Config
|
|
3891
3913
|
|
|
@@ -4026,7 +4048,9 @@ comments, reactions, bookmarks, reports, community-bans
|
|
|
4026
4048
|
|
|
4027
4049
|
### Optional Collections
|
|
4028
4050
|
|
|
4029
|
-
post-categories, customer-profile-lists
|
|
4051
|
+
post-categories, customer-profile-lists
|
|
4052
|
+
|
|
4053
|
+
- \`customer-profile-lists\` is Community-owned public profile curation. It composes \`customer-profiles\`, so effective Community access also requires Customers.`
|
|
4030
4054
|
};
|
|
4031
4055
|
function featureSetupGuide({
|
|
4032
4056
|
feature
|
|
@@ -4139,12 +4163,7 @@ var COLLECTIONS_BY_CATEGORY = {
|
|
|
4139
4163
|
"shipping-policies",
|
|
4140
4164
|
"shipping-zones"
|
|
4141
4165
|
],
|
|
4142
|
-
Customers: [
|
|
4143
|
-
"customers",
|
|
4144
|
-
"customer-profiles",
|
|
4145
|
-
"customer-profile-lists",
|
|
4146
|
-
"customer-addresses"
|
|
4147
|
-
],
|
|
4166
|
+
Customers: ["customers", "customer-profiles", "customer-addresses"],
|
|
4148
4167
|
Carts: ["carts", "cart-items"],
|
|
4149
4168
|
Discounts: ["discounts"],
|
|
4150
4169
|
Documents: ["documents", "document-categories", "document-types"],
|
|
@@ -4160,7 +4179,8 @@ var COLLECTIONS_BY_CATEGORY = {
|
|
|
4160
4179
|
"reactions",
|
|
4161
4180
|
"reaction-types",
|
|
4162
4181
|
"bookmarks",
|
|
4163
|
-
"post-categories"
|
|
4182
|
+
"post-categories",
|
|
4183
|
+
"customer-profile-lists"
|
|
4164
4184
|
],
|
|
4165
4185
|
Playlists: [
|
|
4166
4186
|
"playlists",
|
|
@@ -4270,6 +4290,22 @@ yarn add @01.software/sdk
|
|
|
4270
4290
|
pnpm add @01.software/sdk
|
|
4271
4291
|
\`\`\`
|
|
4272
4292
|
|
|
4293
|
+
## Optional peers
|
|
4294
|
+
|
|
4295
|
+
You do not need extra packages for the root SDK entry. Install peer
|
|
4296
|
+
dependencies only when you import a feature sub-path:
|
|
4297
|
+
|
|
4298
|
+
- \`@01.software/sdk/query\` -> \`@tanstack/react-query\`, \`react\`, \`react-dom\`
|
|
4299
|
+
- \`@01.software/sdk/realtime\` -> \`@tanstack/react-query\`
|
|
4300
|
+
- \`@01.software/sdk/analytics/react\` -> \`react\`, \`react-dom\`
|
|
4301
|
+
- \`@01.software/sdk/ui/rich-text\` -> \`@payloadcms/richtext-lexical\`
|
|
4302
|
+
- \`@01.software/sdk/ui/form\` -> none
|
|
4303
|
+
- \`@01.software/sdk/ui/code-block\` -> \`shiki\`, \`hast-util-to-jsx-runtime\`
|
|
4304
|
+
- \`@01.software/sdk/ui/canvas\` -> \`@tanstack/react-query\`, \`@xyflow/react\`, \`quickjs-emscripten\`, \`postcss\`, \`sucrase\`
|
|
4305
|
+
- \`@01.software/sdk/ui/canvas/server\` -> none
|
|
4306
|
+
- \`@01.software/sdk/ui/video\` -> \`@mux/mux-player-react\`
|
|
4307
|
+
- \`@01.software/sdk/ui/image\` -> none
|
|
4308
|
+
|
|
4273
4309
|
## Basic Usage
|
|
4274
4310
|
|
|
4275
4311
|
\`\`\`typescript
|
|
@@ -4307,7 +4343,7 @@ Comprehensive guides to master the 01.software SDK.
|
|
|
4307
4343
|
|
|
4308
4344
|
## Data Fetching
|
|
4309
4345
|
|
|
4310
|
-
Use the Query Builder or React Query hooks to fetch data efficiently.
|
|
4346
|
+
Use the Query Builder or opt-in React Query hooks to fetch data efficiently.
|
|
4311
4347
|
|
|
4312
4348
|
### Query Builder
|
|
4313
4349
|
\`\`\`typescript
|
|
@@ -4335,7 +4371,10 @@ const { totalDocs } = await client.collections.from('products').count()
|
|
|
4335
4371
|
|
|
4336
4372
|
### React Query Hook
|
|
4337
4373
|
\`\`\`typescript
|
|
4338
|
-
|
|
4374
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
4375
|
+
|
|
4376
|
+
const query = createQueryHooks(client)
|
|
4377
|
+
const { data, isLoading, error } = query.useQuery({
|
|
4339
4378
|
collection: 'products',
|
|
4340
4379
|
options: {
|
|
4341
4380
|
where: { status: { equals: 'published' } },
|
|
@@ -4346,7 +4385,7 @@ const { data, isLoading, error } = client.query.useQuery({
|
|
|
4346
4385
|
|
|
4347
4386
|
### Suspense Mode
|
|
4348
4387
|
\`\`\`typescript
|
|
4349
|
-
const { data } =
|
|
4388
|
+
const { data } = query.useSuspenseQuery({
|
|
4350
4389
|
collection: 'products',
|
|
4351
4390
|
options: { limit: 10 }
|
|
4352
4391
|
})
|
|
@@ -4355,7 +4394,7 @@ const { data } = client.query.useSuspenseQuery({
|
|
|
4355
4394
|
### Infinite Scroll
|
|
4356
4395
|
\`\`\`typescript
|
|
4357
4396
|
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
|
|
4358
|
-
|
|
4397
|
+
query.useInfiniteQuery({
|
|
4359
4398
|
collection: 'products',
|
|
4360
4399
|
pageSize: 20
|
|
4361
4400
|
})
|
|
@@ -4402,19 +4441,18 @@ const result = await serverClient.from('products').removeMany(
|
|
|
4402
4441
|
)
|
|
4403
4442
|
\`\`\`
|
|
4404
4443
|
|
|
4405
|
-
###
|
|
4444
|
+
### Server Mutations
|
|
4406
4445
|
\`\`\`typescript
|
|
4407
|
-
|
|
4408
|
-
const { mutate: create } = client.query.useCreate({ collection: 'products' })
|
|
4409
|
-
create({ title: 'New', status: 'draft' })
|
|
4446
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
4410
4447
|
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4448
|
+
const server = createServerClient({
|
|
4449
|
+
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
4450
|
+
secretKey: process.env.SOFTWARE_SECRET_KEY!,
|
|
4451
|
+
})
|
|
4414
4452
|
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
remove('product-id')
|
|
4453
|
+
await server.collections.from('products').create({ title: 'New', status: 'draft' })
|
|
4454
|
+
await server.collections.from('products').update('product-id', { title: 'Updated' })
|
|
4455
|
+
await server.collections.from('products').remove('product-id')
|
|
4418
4456
|
\`\`\`
|
|
4419
4457
|
|
|
4420
4458
|
## Caching Strategies
|
|
@@ -4424,17 +4462,17 @@ The SDK uses React Query for caching and background updates.
|
|
|
4424
4462
|
### SSR Prefetching
|
|
4425
4463
|
\`\`\`typescript
|
|
4426
4464
|
// Prefetch in server component for instant client hydration
|
|
4427
|
-
await
|
|
4465
|
+
await query.prefetchQuery({
|
|
4428
4466
|
collection: 'products',
|
|
4429
4467
|
options: { limit: 10 }
|
|
4430
4468
|
})
|
|
4431
4469
|
|
|
4432
|
-
await
|
|
4470
|
+
await query.prefetchQueryById({
|
|
4433
4471
|
collection: 'products',
|
|
4434
4472
|
id: 'product-id'
|
|
4435
4473
|
})
|
|
4436
4474
|
|
|
4437
|
-
await
|
|
4475
|
+
await query.prefetchInfiniteQuery({
|
|
4438
4476
|
collection: 'products',
|
|
4439
4477
|
pageSize: 20
|
|
4440
4478
|
})
|
|
@@ -4443,19 +4481,19 @@ await client.query.prefetchInfiniteQuery({
|
|
|
4443
4481
|
### Cache Invalidation
|
|
4444
4482
|
\`\`\`typescript
|
|
4445
4483
|
// Invalidate list cache for a collection
|
|
4446
|
-
|
|
4484
|
+
query.invalidateQueries('products', 'list')
|
|
4447
4485
|
|
|
4448
4486
|
// Invalidate all caches for a collection
|
|
4449
|
-
|
|
4487
|
+
query.invalidateQueries('products')
|
|
4450
4488
|
\`\`\`
|
|
4451
4489
|
|
|
4452
4490
|
### Manual Cache Management
|
|
4453
4491
|
\`\`\`typescript
|
|
4454
4492
|
// Read cached data
|
|
4455
|
-
const cached =
|
|
4493
|
+
const cached = query.getQueryData('products', 'list')
|
|
4456
4494
|
|
|
4457
4495
|
// Write to cache (optimistic updates)
|
|
4458
|
-
|
|
4496
|
+
query.setQueryData('products', 'list', newData)
|
|
4459
4497
|
\`\`\`
|
|
4460
4498
|
|
|
4461
4499
|
## Error Handling
|
|
@@ -4533,7 +4571,7 @@ const client = createClient({
|
|
|
4533
4571
|
For server-side operations (full CRUD)
|
|
4534
4572
|
|
|
4535
4573
|
\`\`\`typescript
|
|
4536
|
-
import { createServerClient } from '@01.software/sdk'
|
|
4574
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
4537
4575
|
|
|
4538
4576
|
const client = createServerClient({
|
|
4539
4577
|
publishableKey: string,
|
|
@@ -4612,13 +4650,19 @@ const result = await client.collections.from('collection').removeMany(where)
|
|
|
4612
4650
|
// Returns PayloadFindResponse with deleted docs
|
|
4613
4651
|
\`\`\`
|
|
4614
4652
|
|
|
4615
|
-
## React Query Hooks (
|
|
4653
|
+
## React Query Hooks (\`@01.software/sdk/query\`)
|
|
4654
|
+
|
|
4655
|
+
\`\`\`typescript
|
|
4656
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
4657
|
+
|
|
4658
|
+
const query = createQueryHooks(client)
|
|
4659
|
+
\`\`\`
|
|
4616
4660
|
|
|
4617
4661
|
### useQuery()
|
|
4618
4662
|
Query a collection list.
|
|
4619
4663
|
|
|
4620
4664
|
\`\`\`typescript
|
|
4621
|
-
const { data, isLoading, error } =
|
|
4665
|
+
const { data, isLoading, error } = query.useQuery({
|
|
4622
4666
|
collection: 'products',
|
|
4623
4667
|
options: { limit: 10, where: { status: { equals: 'published' } } }
|
|
4624
4668
|
})
|
|
@@ -4628,7 +4672,7 @@ const { data, isLoading, error } = client.query.useQuery({
|
|
|
4628
4672
|
Suspense mode list query.
|
|
4629
4673
|
|
|
4630
4674
|
\`\`\`typescript
|
|
4631
|
-
const { data } =
|
|
4675
|
+
const { data } = query.useSuspenseQuery({
|
|
4632
4676
|
collection: 'products',
|
|
4633
4677
|
options: { limit: 10 }
|
|
4634
4678
|
})
|
|
@@ -4638,7 +4682,7 @@ const { data } = client.query.useSuspenseQuery({
|
|
|
4638
4682
|
Get a single item by ID.
|
|
4639
4683
|
|
|
4640
4684
|
\`\`\`typescript
|
|
4641
|
-
const { data } =
|
|
4685
|
+
const { data } = query.useQueryById({
|
|
4642
4686
|
collection: 'products',
|
|
4643
4687
|
id: 'product-id'
|
|
4644
4688
|
})
|
|
@@ -4648,7 +4692,7 @@ const { data } = client.query.useQueryById({
|
|
|
4648
4692
|
Suspense mode single item query.
|
|
4649
4693
|
|
|
4650
4694
|
\`\`\`typescript
|
|
4651
|
-
const { data } =
|
|
4695
|
+
const { data } = query.useSuspenseQueryById({
|
|
4652
4696
|
collection: 'products',
|
|
4653
4697
|
id: 'product-id'
|
|
4654
4698
|
})
|
|
@@ -4658,7 +4702,7 @@ const { data } = client.query.useSuspenseQueryById({
|
|
|
4658
4702
|
Infinite scroll.
|
|
4659
4703
|
|
|
4660
4704
|
\`\`\`typescript
|
|
4661
|
-
const { data, fetchNextPage, hasNextPage } =
|
|
4705
|
+
const { data, fetchNextPage, hasNextPage } = query.useInfiniteQuery({
|
|
4662
4706
|
collection: 'products',
|
|
4663
4707
|
options: { limit: 20 },
|
|
4664
4708
|
pageSize: 20
|
|
@@ -4669,52 +4713,43 @@ const { data, fetchNextPage, hasNextPage } = client.query.useInfiniteQuery({
|
|
|
4669
4713
|
Suspense mode infinite scroll.
|
|
4670
4714
|
|
|
4671
4715
|
\`\`\`typescript
|
|
4672
|
-
const { data, fetchNextPage } =
|
|
4716
|
+
const { data, fetchNextPage } = query.useSuspenseInfiniteQuery({
|
|
4673
4717
|
collection: 'products',
|
|
4674
4718
|
pageSize: 20
|
|
4675
4719
|
})
|
|
4676
4720
|
\`\`\`
|
|
4677
4721
|
|
|
4678
|
-
##
|
|
4679
|
-
|
|
4680
|
-
### useCreate()
|
|
4681
|
-
Create a document with automatic cache invalidation.
|
|
4682
|
-
|
|
4683
|
-
\`\`\`typescript
|
|
4684
|
-
const { mutate } = client.query.useCreate({ collection: 'products' })
|
|
4685
|
-
mutate({ title: 'New Product', status: 'draft' })
|
|
4686
|
-
\`\`\`
|
|
4722
|
+
## Server Mutations
|
|
4687
4723
|
|
|
4688
|
-
|
|
4689
|
-
Update a document with automatic cache invalidation.
|
|
4724
|
+
Writes require trusted server code with \`createServerClient\`; do not run server credentials in React client components.
|
|
4690
4725
|
|
|
4691
4726
|
\`\`\`typescript
|
|
4692
|
-
|
|
4693
|
-
mutate({ id: 'product-id', data: { title: 'Updated' } })
|
|
4694
|
-
\`\`\`
|
|
4727
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
4695
4728
|
|
|
4696
|
-
|
|
4697
|
-
|
|
4729
|
+
const server = createServerClient({
|
|
4730
|
+
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
4731
|
+
secretKey: process.env.SOFTWARE_SECRET_KEY!,
|
|
4732
|
+
})
|
|
4698
4733
|
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4734
|
+
await server.collections.from('products').create({ title: 'New Product', status: 'draft' })
|
|
4735
|
+
await server.collections.from('products').update('product-id', { title: 'Updated' })
|
|
4736
|
+
await server.collections.from('products').remove('product-id')
|
|
4702
4737
|
\`\`\`
|
|
4703
4738
|
|
|
4704
4739
|
## Cache Utilities
|
|
4705
4740
|
|
|
4706
4741
|
\`\`\`typescript
|
|
4707
4742
|
// Invalidate cache
|
|
4708
|
-
|
|
4743
|
+
query.invalidateQueries('products', 'list')
|
|
4709
4744
|
|
|
4710
4745
|
// SSR prefetch
|
|
4711
|
-
await
|
|
4712
|
-
await
|
|
4713
|
-
await
|
|
4746
|
+
await query.prefetchQuery({ collection: 'products', options: { limit: 10 } })
|
|
4747
|
+
await query.prefetchQueryById({ collection: 'products', id: 'id' })
|
|
4748
|
+
await query.prefetchInfiniteQuery({ collection: 'products', pageSize: 20 })
|
|
4714
4749
|
|
|
4715
4750
|
// Get/set cached data
|
|
4716
|
-
const cached =
|
|
4717
|
-
|
|
4751
|
+
const cached = query.getQueryData('products', 'list')
|
|
4752
|
+
query.setQueryData('products', 'list', newData)
|
|
4718
4753
|
\`\`\`
|
|
4719
4754
|
|
|
4720
4755
|
For ecommerce reads, prefer \`products.listing.*\` for card/search pricing and keep authoritative sellable pricing on \`product-variants.price\`.
|
|
@@ -4961,7 +4996,7 @@ const result3 = await client.collections.from('products').find({ sort: '-isFeatu
|
|
|
4961
4996
|
## Full Example
|
|
4962
4997
|
|
|
4963
4998
|
\`\`\`typescript
|
|
4964
|
-
import { createServerClient } from '@01.software/sdk'
|
|
4999
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
4965
5000
|
|
|
4966
5001
|
const serverClient = createServerClient({
|
|
4967
5002
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -4989,14 +5024,22 @@ console.log(result.hasNextPage) // true
|
|
|
4989
5024
|
var metadata43 = {
|
|
4990
5025
|
name: "docs-react-query",
|
|
4991
5026
|
title: "React Query Hooks",
|
|
4992
|
-
description: "01.software SDK React Query hooks reference (
|
|
5027
|
+
description: "01.software SDK React Query hooks reference (@01.software/sdk/query)"
|
|
4993
5028
|
};
|
|
4994
5029
|
function handler13() {
|
|
4995
5030
|
return `# React Query Hooks
|
|
4996
5031
|
|
|
4997
|
-
React Query hooks are
|
|
5032
|
+
React Query hooks are opt-in through \`@01.software/sdk/query\`. They provide automatic caching, background refetching, and cache invalidation without making root \`createClient\` consumers install React Query.
|
|
4998
5033
|
|
|
4999
|
-
|
|
5034
|
+
Install \`@tanstack/react-query\` and React peers only when importing this sub-path.
|
|
5035
|
+
|
|
5036
|
+
\`\`\`typescript
|
|
5037
|
+
import { createClient } from '@01.software/sdk'
|
|
5038
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
5039
|
+
|
|
5040
|
+
const client = createClient({ publishableKey })
|
|
5041
|
+
const query = createQueryHooks(client)
|
|
5042
|
+
\`\`\`
|
|
5000
5043
|
|
|
5001
5044
|
## Query Hooks
|
|
5002
5045
|
|
|
@@ -5004,7 +5047,7 @@ React Query hooks are available on the browser-side \`Client\` via \`client.quer
|
|
|
5004
5047
|
Query a collection list with automatic caching.
|
|
5005
5048
|
|
|
5006
5049
|
\`\`\`typescript
|
|
5007
|
-
const { data, isLoading, error } =
|
|
5050
|
+
const { data, isLoading, error } = query.useQuery({
|
|
5008
5051
|
collection: 'products',
|
|
5009
5052
|
options: {
|
|
5010
5053
|
where: { status: { equals: 'published' } },
|
|
@@ -5022,7 +5065,7 @@ Suspense-mode list query. Throws a promise while loading (use with React Suspens
|
|
|
5022
5065
|
|
|
5023
5066
|
\`\`\`typescript
|
|
5024
5067
|
// Inside a Suspense boundary
|
|
5025
|
-
const { data } =
|
|
5068
|
+
const { data } = query.useSuspenseQuery({
|
|
5026
5069
|
collection: 'products',
|
|
5027
5070
|
options: { limit: 10 },
|
|
5028
5071
|
})
|
|
@@ -5033,7 +5076,7 @@ const { data } = client.query.useSuspenseQuery({
|
|
|
5033
5076
|
Get a single document by ID.
|
|
5034
5077
|
|
|
5035
5078
|
\`\`\`typescript
|
|
5036
|
-
const { data, isLoading } =
|
|
5079
|
+
const { data, isLoading } = query.useQueryById({
|
|
5037
5080
|
collection: 'products',
|
|
5038
5081
|
id: 'product-id',
|
|
5039
5082
|
})
|
|
@@ -5044,7 +5087,7 @@ const { data, isLoading } = client.query.useQueryById({
|
|
|
5044
5087
|
Suspense-mode single document query.
|
|
5045
5088
|
|
|
5046
5089
|
\`\`\`typescript
|
|
5047
|
-
const { data } =
|
|
5090
|
+
const { data } = query.useSuspenseQueryById({
|
|
5048
5091
|
collection: 'products',
|
|
5049
5092
|
id: 'product-id',
|
|
5050
5093
|
})
|
|
@@ -5060,7 +5103,7 @@ const {
|
|
|
5060
5103
|
fetchNextPage,
|
|
5061
5104
|
hasNextPage,
|
|
5062
5105
|
isFetchingNextPage,
|
|
5063
|
-
} =
|
|
5106
|
+
} = query.useInfiniteQuery({
|
|
5064
5107
|
collection: 'products',
|
|
5065
5108
|
options: {
|
|
5066
5109
|
where: { status: { equals: 'published' } },
|
|
@@ -5076,55 +5119,33 @@ const {
|
|
|
5076
5119
|
Suspense-mode infinite scroll.
|
|
5077
5120
|
|
|
5078
5121
|
\`\`\`typescript
|
|
5079
|
-
const { data, fetchNextPage, hasNextPage } =
|
|
5122
|
+
const { data, fetchNextPage, hasNextPage } = query.useSuspenseInfiniteQuery({
|
|
5080
5123
|
collection: 'products',
|
|
5081
5124
|
pageSize: 20,
|
|
5082
5125
|
})
|
|
5083
5126
|
\`\`\`
|
|
5084
5127
|
|
|
5085
|
-
##
|
|
5086
|
-
|
|
5087
|
-
Mutation hooks automatically invalidate relevant cache keys after success.
|
|
5128
|
+
## Writes
|
|
5088
5129
|
|
|
5089
|
-
|
|
5090
|
-
Create a document and invalidate list cache.
|
|
5130
|
+
Keep writes in trusted server code. Use a server action, API route, or backend service with \`createServerClient\`, then invalidate browser React Query caches after the action completes.
|
|
5091
5131
|
|
|
5092
5132
|
\`\`\`typescript
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
})
|
|
5096
|
-
|
|
5097
|
-
// Fire and forget
|
|
5098
|
-
mutate({ title: 'New Product', status: 'draft' })
|
|
5099
|
-
|
|
5100
|
-
// Await result
|
|
5101
|
-
const result = await mutateAsync({ title: 'New Product', status: 'draft' })
|
|
5102
|
-
// result.doc - created document
|
|
5103
|
-
\`\`\`
|
|
5104
|
-
|
|
5105
|
-
For ecommerce reads, price-oriented product cards should consume \`products.listing.minPrice/maxPrice\`. Authoritative sellable pricing still lives on \`product-variants.price\`.
|
|
5133
|
+
// app/products/actions.ts
|
|
5134
|
+
'use server'
|
|
5106
5135
|
|
|
5107
|
-
|
|
5108
|
-
Update a document and invalidate list + detail cache.
|
|
5136
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
5109
5137
|
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5138
|
+
const server = createServerClient({
|
|
5139
|
+
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
5140
|
+
secretKey: process.env.SOFTWARE_SECRET_KEY!,
|
|
5113
5141
|
})
|
|
5114
5142
|
|
|
5115
|
-
|
|
5143
|
+
export async function createProduct(data: { title: string; status: 'draft' | 'published' }) {
|
|
5144
|
+
return server.collections.from('products').create(data)
|
|
5145
|
+
}
|
|
5116
5146
|
\`\`\`
|
|
5117
5147
|
|
|
5118
|
-
|
|
5119
|
-
Remove a document and invalidate list cache.
|
|
5120
|
-
|
|
5121
|
-
\`\`\`typescript
|
|
5122
|
-
const { mutate, mutateAsync } = client.query.useRemove({
|
|
5123
|
-
collection: 'products',
|
|
5124
|
-
})
|
|
5125
|
-
|
|
5126
|
-
mutate('product-id')
|
|
5127
|
-
\`\`\`
|
|
5148
|
+
For ecommerce reads, price-oriented product cards should consume \`products.listing.minPrice/maxPrice\`. Authoritative sellable pricing still lives on \`product-variants.price\`.
|
|
5128
5149
|
|
|
5129
5150
|
## Cache Utilities
|
|
5130
5151
|
|
|
@@ -5133,10 +5154,10 @@ Manually invalidate cached queries for a collection.
|
|
|
5133
5154
|
|
|
5134
5155
|
\`\`\`typescript
|
|
5135
5156
|
// Invalidate all list queries for a collection
|
|
5136
|
-
|
|
5157
|
+
query.invalidateQueries('products', 'list')
|
|
5137
5158
|
|
|
5138
5159
|
// Invalidate all queries for a collection (list + detail)
|
|
5139
|
-
|
|
5160
|
+
query.invalidateQueries('products')
|
|
5140
5161
|
\`\`\`
|
|
5141
5162
|
|
|
5142
5163
|
### getQueryData() / setQueryData()
|
|
@@ -5144,10 +5165,10 @@ Read and write the React Query cache directly.
|
|
|
5144
5165
|
|
|
5145
5166
|
\`\`\`typescript
|
|
5146
5167
|
// Read cached data
|
|
5147
|
-
const cached =
|
|
5168
|
+
const cached = query.getQueryData('products', 'list')
|
|
5148
5169
|
|
|
5149
5170
|
// Write to cache (useful for optimistic updates)
|
|
5150
|
-
|
|
5171
|
+
query.setQueryData('products', 'list', newData)
|
|
5151
5172
|
\`\`\`
|
|
5152
5173
|
|
|
5153
5174
|
## SSR Prefetching
|
|
@@ -5157,34 +5178,37 @@ Prefetch data in server components for instant hydration on the client.
|
|
|
5157
5178
|
\`\`\`typescript
|
|
5158
5179
|
// app/products/page.tsx (Next.js App Router Server Component)
|
|
5159
5180
|
import { HydrationBoundary, dehydrate } from '@tanstack/react-query'
|
|
5160
|
-
import { createServerClient } from '@01.software/sdk'
|
|
5181
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
5182
|
+
import { createServerQueryHooks, getQueryClient } from '@01.software/sdk/query'
|
|
5161
5183
|
|
|
5162
5184
|
export default async function ProductsPage() {
|
|
5163
5185
|
const serverClient = createServerClient({
|
|
5164
5186
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
5165
5187
|
secretKey: process.env.SOFTWARE_SECRET_KEY!,
|
|
5166
5188
|
})
|
|
5189
|
+
const queryClient = getQueryClient()
|
|
5190
|
+
const serverQuery = createServerQueryHooks(serverClient, queryClient)
|
|
5167
5191
|
|
|
5168
5192
|
// Prefetch list
|
|
5169
|
-
await
|
|
5193
|
+
await serverQuery.prefetchQuery({
|
|
5170
5194
|
collection: 'products',
|
|
5171
5195
|
options: { limit: 20, where: { status: { equals: 'published' } } },
|
|
5172
5196
|
})
|
|
5173
5197
|
|
|
5174
5198
|
// Prefetch single item
|
|
5175
|
-
await
|
|
5199
|
+
await serverQuery.prefetchQueryById({
|
|
5176
5200
|
collection: 'products',
|
|
5177
5201
|
id: 'product-id',
|
|
5178
5202
|
})
|
|
5179
5203
|
|
|
5180
5204
|
// Prefetch infinite query
|
|
5181
|
-
await
|
|
5205
|
+
await serverQuery.prefetchInfiniteQuery({
|
|
5182
5206
|
collection: 'products',
|
|
5183
5207
|
pageSize: 20,
|
|
5184
5208
|
})
|
|
5185
5209
|
|
|
5186
5210
|
return (
|
|
5187
|
-
<HydrationBoundary state={dehydrate(
|
|
5211
|
+
<HydrationBoundary state={dehydrate(queryClient)}>
|
|
5188
5212
|
<ProductList />
|
|
5189
5213
|
</HydrationBoundary>
|
|
5190
5214
|
)
|
|
@@ -5197,13 +5221,15 @@ export default async function ProductsPage() {
|
|
|
5197
5221
|
'use client'
|
|
5198
5222
|
|
|
5199
5223
|
import { createClient } from '@01.software/sdk'
|
|
5224
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
5200
5225
|
|
|
5201
5226
|
const client = createClient({
|
|
5202
5227
|
publishableKey: process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY!,
|
|
5203
5228
|
})
|
|
5229
|
+
const query = createQueryHooks(client)
|
|
5204
5230
|
|
|
5205
5231
|
export function ProductList() {
|
|
5206
|
-
const { data, isLoading, error } =
|
|
5232
|
+
const { data, isLoading, error } = query.useQuery({
|
|
5207
5233
|
collection: 'products',
|
|
5208
5234
|
options: {
|
|
5209
5235
|
where: { status: { equals: 'published' } },
|
|
@@ -5212,20 +5238,13 @@ export function ProductList() {
|
|
|
5212
5238
|
},
|
|
5213
5239
|
})
|
|
5214
5240
|
|
|
5215
|
-
const { mutate: removeProduct } = client.query.useRemove({
|
|
5216
|
-
collection: 'products',
|
|
5217
|
-
})
|
|
5218
|
-
|
|
5219
5241
|
if (isLoading) return <div>Loading...</div>
|
|
5220
5242
|
if (error) return <div>Error: {error.message}</div>
|
|
5221
5243
|
|
|
5222
5244
|
return (
|
|
5223
5245
|
<ul>
|
|
5224
5246
|
{data?.docs.map((product) => (
|
|
5225
|
-
<li key={product.id}>
|
|
5226
|
-
{product.title}
|
|
5227
|
-
<button onClick={() => removeProduct(product.id)}>Delete</button>
|
|
5228
|
-
</li>
|
|
5247
|
+
<li key={product.id}>{product.title}</li>
|
|
5229
5248
|
))}
|
|
5230
5249
|
</ul>
|
|
5231
5250
|
)
|
|
@@ -5245,7 +5264,7 @@ function handler14() {
|
|
|
5245
5264
|
Server-side operations are available via \`client.commerce\` on \`ServerClient\`. Use \`createServerClient\` with both \`publishableKey\` and \`secretKey\`.
|
|
5246
5265
|
|
|
5247
5266
|
\`\`\`typescript
|
|
5248
|
-
import { createServerClient } from '@01.software/sdk'
|
|
5267
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
5249
5268
|
|
|
5250
5269
|
const client = createServerClient({
|
|
5251
5270
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -5694,9 +5713,9 @@ The SDK provides two client types for different execution environments.
|
|
|
5694
5713
|
| Read (\`find\`, \`findById\`, \`count\`) | Yes | Yes |
|
|
5695
5714
|
| Write (\`create\`, \`update\`, \`remove\`) | No | Yes |
|
|
5696
5715
|
| Bulk (\`updateMany\`, \`removeMany\`) | No | Yes |
|
|
5697
|
-
| React Query hooks (
|
|
5716
|
+
| React Query hooks (\`@01.software/sdk/query\`) | Yes | Yes (SSR prefetch) |
|
|
5698
5717
|
| Customer auth (\`client.customer\`) | Yes | No |
|
|
5699
|
-
|
|
|
5718
|
+
| Commerce/server APIs (\`server.commerce\`, server CRUD) | No | Yes |
|
|
5700
5719
|
|
|
5701
5720
|
## Client (createClient)
|
|
5702
5721
|
|
|
@@ -5704,16 +5723,18 @@ Use in browser code, React client components, and anywhere the secret key must n
|
|
|
5704
5723
|
|
|
5705
5724
|
\`\`\`typescript
|
|
5706
5725
|
import { createClient } from '@01.software/sdk'
|
|
5726
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
5707
5727
|
|
|
5708
5728
|
const client = createClient({
|
|
5709
5729
|
publishableKey: process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY!,
|
|
5710
5730
|
})
|
|
5731
|
+
const query = createQueryHooks(client)
|
|
5711
5732
|
|
|
5712
5733
|
// Read data
|
|
5713
5734
|
const products = await client.collections.from('products').find({ limit: 10 })
|
|
5714
5735
|
|
|
5715
5736
|
// React Query hooks
|
|
5716
|
-
const { data } =
|
|
5737
|
+
const { data } = query.useQuery({ collection: 'products' })
|
|
5717
5738
|
|
|
5718
5739
|
// Customer auth
|
|
5719
5740
|
await client.customer.login({ email, password })
|
|
@@ -5726,7 +5747,7 @@ await client.customer.login({ email, password })
|
|
|
5726
5747
|
Use in server components, API routes, server actions, and background jobs. Has full CRUD access.
|
|
5727
5748
|
|
|
5728
5749
|
\`\`\`typescript
|
|
5729
|
-
import { createServerClient } from '@01.software/sdk'
|
|
5750
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
5730
5751
|
|
|
5731
5752
|
const client = createServerClient({
|
|
5732
5753
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -5747,11 +5768,14 @@ await client.collections.from('product-variants').create({
|
|
|
5747
5768
|
})
|
|
5748
5769
|
await client.collections.from('products').remove('product-id')
|
|
5749
5770
|
|
|
5750
|
-
//
|
|
5771
|
+
// Commerce API (orders, carts, etc.)
|
|
5751
5772
|
await client.commerce.orders.create({ ... })
|
|
5752
5773
|
await client.commerce.orders.checkout({ ... })
|
|
5753
5774
|
\`\`\`
|
|
5754
5775
|
|
|
5776
|
+
Server-only code must import \`createServerClient\` from the \`/server\`
|
|
5777
|
+
sub-path.
|
|
5778
|
+
|
|
5755
5779
|
**Environment variables**:
|
|
5756
5780
|
- \`SOFTWARE_PUBLISHABLE_KEY\` \u2014 publishable key (no NEXT_PUBLIC prefix, server-only)
|
|
5757
5781
|
- \`SOFTWARE_SECRET_KEY\` \u2014 server credential
|
|
@@ -5781,7 +5805,7 @@ deploying again.
|
|
|
5781
5805
|
|
|
5782
5806
|
\`\`\`typescript
|
|
5783
5807
|
// lib/sdk.ts \u2014 server-only module
|
|
5784
|
-
import { createServerClient } from '@01.software/sdk'
|
|
5808
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
5785
5809
|
|
|
5786
5810
|
export function getServerClient() {
|
|
5787
5811
|
return createServerClient({
|
|
@@ -5794,10 +5818,12 @@ export function getServerClient() {
|
|
|
5794
5818
|
\`\`\`typescript
|
|
5795
5819
|
// lib/sdk-client.ts \u2014 browser-safe module
|
|
5796
5820
|
import { createClient } from '@01.software/sdk'
|
|
5821
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
5797
5822
|
|
|
5798
5823
|
export const browserClient = createClient({
|
|
5799
5824
|
publishableKey: process.env.NEXT_PUBLIC_SOFTWARE_PUBLISHABLE_KEY!,
|
|
5800
5825
|
})
|
|
5826
|
+
export const browserQuery = createQueryHooks(browserClient)
|
|
5801
5827
|
\`\`\`
|
|
5802
5828
|
|
|
5803
5829
|
\`\`\`typescript
|
|
@@ -5814,10 +5840,10 @@ export default async function ProductsPage() {
|
|
|
5814
5840
|
\`\`\`typescript
|
|
5815
5841
|
// components/product-list.tsx \u2014 Client Component
|
|
5816
5842
|
'use client'
|
|
5817
|
-
import {
|
|
5843
|
+
import { browserQuery } from '@/lib/sdk-client'
|
|
5818
5844
|
|
|
5819
5845
|
export function ProductList() {
|
|
5820
|
-
const { data } =
|
|
5846
|
+
const { data } = browserQuery.useQuery({ collection: 'products' })
|
|
5821
5847
|
return <ul>{data?.docs.map(p => <li key={p.id}>{p.title}</li>)}</ul>
|
|
5822
5848
|
}
|
|
5823
5849
|
\`\`\`
|
|
@@ -5848,7 +5874,7 @@ Upload files using the \`images\` collection (tenant-scoped, unified image store
|
|
|
5848
5874
|
Use \`ServerClient\` with \`FormData\` to upload images server-side.
|
|
5849
5875
|
|
|
5850
5876
|
\`\`\`typescript
|
|
5851
|
-
import { createServerClient } from '@01.software/sdk'
|
|
5877
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
5852
5878
|
|
|
5853
5879
|
const client = createServerClient({
|
|
5854
5880
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -5871,7 +5897,7 @@ async function uploadImage(file: File) {
|
|
|
5871
5897
|
\`\`\`typescript
|
|
5872
5898
|
// app/api/upload/route.ts
|
|
5873
5899
|
import { NextRequest, NextResponse } from 'next/server'
|
|
5874
|
-
import { createServerClient } from '@01.software/sdk'
|
|
5900
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
5875
5901
|
|
|
5876
5902
|
const client = createServerClient({
|
|
5877
5903
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -5901,7 +5927,7 @@ export async function POST(req: NextRequest) {
|
|
|
5901
5927
|
// actions/upload.ts
|
|
5902
5928
|
'use server'
|
|
5903
5929
|
|
|
5904
|
-
import { createServerClient } from '@01.software/sdk'
|
|
5930
|
+
import { createServerClient } from '@01.software/sdk/server'
|
|
5905
5931
|
|
|
5906
5932
|
const client = createServerClient({
|
|
5907
5933
|
publishableKey: process.env.SOFTWARE_PUBLISHABLE_KEY!,
|
|
@@ -6124,29 +6150,38 @@ const client = createClient({
|
|
|
6124
6150
|
const detail = await client.commerce.product.detail({ slug: 'my-product' })
|
|
6125
6151
|
if (!detail) return notFound()
|
|
6126
6152
|
const selection = resolveProductSelection(detail, {
|
|
6127
|
-
search: '?opt.color=black
|
|
6153
|
+
search: '?opt.option-color=color-black',
|
|
6128
6154
|
})
|
|
6129
6155
|
// selection.selectedVariant, selection.price, selection.stock, selection.media
|
|
6130
6156
|
\`\`\`
|
|
6131
6157
|
|
|
6132
6158
|
## URL round-trip
|
|
6133
6159
|
|
|
6134
|
-
Use the SDK codec for
|
|
6160
|
+
Use the SDK codec for canonical selection URLs. Complete selections use
|
|
6161
|
+
\`variant=<variantId>\`; partial selections use
|
|
6162
|
+
\`opt.<optionId>=<valueId>\`. Older
|
|
6163
|
+
\`opt.<optionSlug>=<valueSlug>\` URLs still decode during Stage 1, but slugs are
|
|
6164
|
+
compatibility metadata rather than canonical identity.
|
|
6135
6165
|
|
|
6136
6166
|
\`\`\`typescript
|
|
6137
6167
|
import { createProductSelectionCodec } from '@01.software/sdk'
|
|
6138
6168
|
|
|
6139
6169
|
const codec = createProductSelectionCodec(detail)
|
|
6140
|
-
const selection = codec.parse('?opt.color=black')
|
|
6141
|
-
const
|
|
6170
|
+
const selection = codec.parse('?opt.option-color=color-black')
|
|
6171
|
+
const selectionQuery = codec.stringify(selection)
|
|
6142
6172
|
\`\`\`
|
|
6143
6173
|
|
|
6144
|
-
|
|
6174
|
+
Use IDs from \`detail.options[].id\` and \`detail.options[].values[].id\` when building new selection links. Slugs remain useful for display and older inbound URLs, but new outbound URLs should use the codec output.
|
|
6175
|
+
|
|
6176
|
+
Value-slug-only URLs such as \`?black\` or \`?color=black\` are rejected because option titles and values are not stable identifiers.
|
|
6145
6177
|
|
|
6146
6178
|
## React Query hook variant
|
|
6147
6179
|
|
|
6148
6180
|
\`\`\`typescript
|
|
6149
|
-
|
|
6181
|
+
import { createQueryHooks } from '@01.software/sdk/query'
|
|
6182
|
+
|
|
6183
|
+
const query = createQueryHooks(client)
|
|
6184
|
+
const { data: detail, isLoading } = query.useProductDetailBySlug(slug)
|
|
6150
6185
|
\`\`\`
|
|
6151
6186
|
|
|
6152
6187
|
Cache invalidates automatically when any of 10 detail-relevant collections is mutated through SDK mutation hooks.
|
|
@@ -6540,4 +6575,4 @@ export {
|
|
|
6540
6575
|
flushMcpTelemetrySummary,
|
|
6541
6576
|
createServer
|
|
6542
6577
|
};
|
|
6543
|
-
//# sourceMappingURL=chunk-
|
|
6578
|
+
//# sourceMappingURL=chunk-2EPYMNHW.js.map
|