@proveanything/smartlinks 1.3.34 → 1.3.37

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.
@@ -20,6 +20,24 @@ export declare namespace product {
20
20
  /**
21
21
  * Create a new product for a collection (admin only).
22
22
  * The `data` payload follows the same shape as ProductResponse minus `id` and `collectionId`.
23
+ *
24
+ * **Hero Image Auto-Fetch:**
25
+ * You can pass `heroImage` as either:
26
+ * - A full asset object: `{ url: '...', thumbnails: {...} }`
27
+ * - A string URL: The system automatically fetches and stores the image
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // Using a URL - auto-fetched and stored
32
+ * const product = await product.create(collectionId, {
33
+ * name: 'Wine Bottle',
34
+ * description: 'Premium red wine',
35
+ * heroImage: 'https://example.com/wine.jpg', // Auto-fetched!
36
+ * tags: {},
37
+ * data: {}
38
+ * });
39
+ * ```
40
+ *
23
41
  * @param collectionId – Identifier of the parent collection
24
42
  * @param data – Product creation data (see ProductCreateRequest)
25
43
  * @returns Promise resolving to a ProductResponse object
@@ -29,6 +47,20 @@ export declare namespace product {
29
47
  /**
30
48
  * Update a product for a collection (admin only).
31
49
  * The `data` payload is a partial of ProductResponse minus `id` and `collectionId`.
50
+ *
51
+ * **Hero Image Auto-Fetch:**
52
+ * You can pass `heroImage` as either:
53
+ * - A full asset object: `{ url: '...', thumbnails: {...} }`
54
+ * - A string URL: The system automatically fetches and stores the image
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * // Update with new URL - auto-fetched and stored
59
+ * const product = await product.update(collectionId, productId, {
60
+ * heroImage: 'https://example.com/new-wine.jpg' // Auto-fetched!
61
+ * });
62
+ * ```
63
+ *
32
64
  * @param collectionId – Identifier of the parent collection
33
65
  * @param productId – Identifier of the product
34
66
  * @param data – Product update data (see ProductUpdateRequest)
@@ -32,6 +32,24 @@ export var product;
32
32
  /**
33
33
  * Create a new product for a collection (admin only).
34
34
  * The `data` payload follows the same shape as ProductResponse minus `id` and `collectionId`.
35
+ *
36
+ * **Hero Image Auto-Fetch:**
37
+ * You can pass `heroImage` as either:
38
+ * - A full asset object: `{ url: '...', thumbnails: {...} }`
39
+ * - A string URL: The system automatically fetches and stores the image
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * // Using a URL - auto-fetched and stored
44
+ * const product = await product.create(collectionId, {
45
+ * name: 'Wine Bottle',
46
+ * description: 'Premium red wine',
47
+ * heroImage: 'https://example.com/wine.jpg', // Auto-fetched!
48
+ * tags: {},
49
+ * data: {}
50
+ * });
51
+ * ```
52
+ *
35
53
  * @param collectionId – Identifier of the parent collection
36
54
  * @param data – Product creation data (see ProductCreateRequest)
37
55
  * @returns Promise resolving to a ProductResponse object
@@ -45,6 +63,20 @@ export var product;
45
63
  /**
46
64
  * Update a product for a collection (admin only).
47
65
  * The `data` payload is a partial of ProductResponse minus `id` and `collectionId`.
66
+ *
67
+ * **Hero Image Auto-Fetch:**
68
+ * You can pass `heroImage` as either:
69
+ * - A full asset object: `{ url: '...', thumbnails: {...} }`
70
+ * - A string URL: The system automatically fetches and stores the image
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * // Update with new URL - auto-fetched and stored
75
+ * const product = await product.update(collectionId, productId, {
76
+ * heroImage: 'https://example.com/new-wine.jpg' // Auto-fetched!
77
+ * });
78
+ * ```
79
+ *
48
80
  * @param collectionId – Identifier of the parent collection
49
81
  * @param productId – Identifier of the product
50
82
  * @param data – Product update data (see ProductUpdateRequest)
@@ -20,10 +20,27 @@ export declare namespace proof {
20
20
  */
21
21
  function update(collectionId: string, productId: string, proofId: string, values: ProofUpdateRequest): Promise<ProofResponse>;
22
22
  /**
23
- * Claim a proof for a product.
24
- * PUT /public/collection/:collectionId/product/:productId/proof/:proofId
23
+ * Claim a proof for a product using a proof ID (serial number, NFC tag, etc.).
24
+ * PUT /public/collection/:collectionId/product/:productId/proof/:proofId/claim
25
25
  */
26
26
  function claim(collectionId: string, productId: string, proofId: string, values: ProofClaimRequest): Promise<ProofResponse>;
27
+ /**
28
+ * Claim a product without providing a proof ID.
29
+ * System auto-generates a unique serial number on-demand.
30
+ * Requires allowAutoGenerateClaims to be enabled on the collection or product.
31
+ * PUT /public/collection/:collectionId/product/:productId/proof/claim
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const proof = await proof.claimProduct(
36
+ * 'beauty-brand',
37
+ * 'moisturizer-pro',
38
+ * { purchaseDate: '2026-02-17', store: 'Target' }
39
+ * );
40
+ * console.log('Auto-generated ID:', proof.id);
41
+ * ```
42
+ */
43
+ function claimProduct(collectionId: string, productId: string, values?: ProofClaimRequest): Promise<ProofResponse>;
27
44
  /**
28
45
  * Delete a proof for a product (admin only).
29
46
  * DELETE /admin/collection/:collectionId/product/:productId/proof/:proofId
package/dist/api/proof.js CHANGED
@@ -42,14 +42,35 @@ export var proof;
42
42
  }
43
43
  proof.update = update;
44
44
  /**
45
- * Claim a proof for a product.
46
- * PUT /public/collection/:collectionId/product/:productId/proof/:proofId
45
+ * Claim a proof for a product using a proof ID (serial number, NFC tag, etc.).
46
+ * PUT /public/collection/:collectionId/product/:productId/proof/:proofId/claim
47
47
  */
48
48
  async function claim(collectionId, productId, proofId, values) {
49
49
  const path = `/public/collection/${encodeURIComponent(collectionId)}/product/${encodeURIComponent(productId)}/proof/${encodeURIComponent(proofId)}/claim`;
50
50
  return put(path, values);
51
51
  }
52
52
  proof.claim = claim;
53
+ /**
54
+ * Claim a product without providing a proof ID.
55
+ * System auto-generates a unique serial number on-demand.
56
+ * Requires allowAutoGenerateClaims to be enabled on the collection or product.
57
+ * PUT /public/collection/:collectionId/product/:productId/proof/claim
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const proof = await proof.claimProduct(
62
+ * 'beauty-brand',
63
+ * 'moisturizer-pro',
64
+ * { purchaseDate: '2026-02-17', store: 'Target' }
65
+ * );
66
+ * console.log('Auto-generated ID:', proof.id);
67
+ * ```
68
+ */
69
+ async function claimProduct(collectionId, productId, values) {
70
+ const path = `/public/collection/${encodeURIComponent(collectionId)}/product/${encodeURIComponent(productId)}/proof/claim`;
71
+ return put(path, values || {});
72
+ }
73
+ proof.claimProduct = claimProduct;
53
74
  /**
54
75
  * Delete a proof for a product (admin only).
55
76
  * DELETE /admin/collection/:collectionId/product/:productId/proof/:proofId
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.3.34 | Generated: 2026-02-16T09:46:01.466Z
3
+ Version: 1.3.37 | Generated: 2026-02-17T14:15:30.216Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -16,6 +16,8 @@ For detailed guides on specific features:
16
16
  - **[Liquid Templates](liquid-templates.md)** - Dynamic templating for content generation
17
17
  - **[Theme System](theme.system.md)** - Theme configuration and customization
18
18
  - **[Theme Defaults](theme-defaults.md)** - Default theme values and presets
19
+ - **[Proof Claiming Methods](proof-claiming-methods.md)** - All methods for claiming/registering product ownership (NFC tags, serial numbers, auto-generated claims)
20
+ - **[App Data Storage](app-data-storage.md)** - User-specific and collection-scoped app data storage
19
21
 
20
22
  ## API Namespaces
21
23
 
@@ -1503,6 +1505,7 @@ interface Collection {
1503
1505
  shortId: string, // The shortId of this collection
1504
1506
  dark?: boolean // if dark mode is enabled for this collection
1505
1507
  portalUrl?: string // URL for the collection's portal (if applicable)
1508
+ allowAutoGenerateClaims?: boolean
1506
1509
  }
1507
1510
  ```
1508
1511
 
@@ -3363,6 +3366,10 @@ interface Product {
3363
3366
  description: string
3364
3367
  gtin?: string
3365
3368
  type?: string
3369
+ * Hero image asset object.
3370
+ * When creating/updating, you can pass either:
3371
+ * - A full asset object with url and thumbnails
3372
+ * - A string URL - the system will automatically fetch and store the image
3366
3373
  heroImage: {
3367
3374
  url: string
3368
3375
  thumbnails: {
@@ -3377,14 +3384,19 @@ interface Product {
3377
3384
  data: {
3378
3385
  [key: string]: any
3379
3386
  } // Flexible key/value data map
3387
+ admin?: {
3388
+ allowAutoGenerateClaims?: boolean
3389
+ lastSerialId?: number
3390
+ [key: string]: any
3391
+ }
3380
3392
  }
3381
3393
  ```
3382
3394
 
3383
3395
  **ProductResponse** = `Product`
3384
3396
 
3385
- **ProductCreateRequest** = `Omit<Product, 'id' | 'collectionId'>`
3397
+ **ProductCreateRequest** = `Omit<Product, 'id' | 'collectionId'> & {`
3386
3398
 
3387
- **ProductUpdateRequest** = `Partial<Omit<Product, 'id' | 'collectionId'>>`
3399
+ **ProductUpdateRequest** = `Partial<Omit<Product, 'id' | 'collectionId'>> & {`
3388
3400
 
3389
3401
  ### proof
3390
3402
 
@@ -3772,16 +3784,27 @@ interface TemplateRenderSourceResponse {
3772
3784
  **AppConfigOptions** (type)
3773
3785
  ```typescript
3774
3786
  type AppConfigOptions = {
3787
+ /** The app ID */
3775
3788
  appId: string
3789
+
3790
+ /** Collection ID (required for most operations) */
3776
3791
  collectionId?: string
3792
+ /** Product ID (optional - for product-scoped config) */
3777
3793
  productId?: string
3794
+ /** Variant ID (optional - for variant-scoped config) */
3778
3795
  variantId?: string
3796
+ /** Batch ID (optional - for batch-scoped config) */
3779
3797
  batchId?: string
3798
+
3799
+ /** Item ID - required for getDataItem/deleteDataItem */
3780
3800
  itemId?: string
3781
- user?: boolean
3782
- userData?: boolean
3801
+
3802
+ /** Use admin endpoints instead of public */
3783
3803
  admin?: boolean
3804
+
3805
+ /** Configuration object for setConfig */
3784
3806
  config?: any
3807
+ /** Data object for setDataItem */
3785
3808
  data?: any
3786
3809
  }
3787
3810
  ```
@@ -3937,18 +3960,25 @@ Post a chat message to the AI (admin or public)
3937
3960
  ### appConfiguration
3938
3961
 
3939
3962
  **getConfig**(opts: AppConfigOptions) → `Promise<any>`
3963
+ Get app configuration for a collection/product scope. ```typescript const config = await appConfiguration.getConfig({ appId: 'warranty-portal', collectionId: 'my-collection' }); ```
3940
3964
 
3941
3965
  **setConfig**(opts: AppConfigOptions) → `Promise<any>`
3966
+ Set app configuration for a collection/product scope. Requires admin authentication. ```typescript await appConfiguration.setConfig({ appId: 'warranty-portal', collectionId: 'my-collection', admin: true, config: { warrantyPeriod: 24, supportEmail: 'support@example.com' } }); ```
3942
3967
 
3943
3968
  **deleteConfig**(opts: AppConfigOptions) → `Promise<void>`
3969
+ Delete app configuration for a collection/product scope. Requires admin authentication. ```typescript await appConfiguration.deleteConfig({ appId: 'warranty-portal', collectionId: 'my-collection', admin: true }); ```
3944
3970
 
3945
3971
  **getData**(opts: AppConfigOptions) → `Promise<any[]>`
3972
+ Get all data items for an app within a scope. ```typescript const items = await appConfiguration.getData({ appId: 'product-docs', collectionId: 'my-collection', productId: 'product-123' }); ```
3946
3973
 
3947
3974
  **getDataItem**(opts: AppConfigOptions) → `Promise<any>`
3975
+ Get a single data item by ID within a scope. ```typescript const item = await appConfiguration.getDataItem({ appId: 'product-docs', collectionId: 'my-collection', productId: 'product-123', itemId: 'manual-1' }); ```
3948
3976
 
3949
3977
  **setDataItem**(opts: AppConfigOptions) → `Promise<any>`
3978
+ Set/create a data item within a scope. Requires admin authentication. ```typescript await appConfiguration.setDataItem({ appId: 'product-docs', collectionId: 'my-collection', productId: 'product-123', admin: true, data: { id: 'manual-1', title: 'User Manual', url: 'https://...' } }); ```
3950
3979
 
3951
3980
  **deleteDataItem**(opts: AppConfigOptions) → `Promise<void>`
3981
+ Delete a data item by ID within a scope. Requires admin authentication. ```typescript await appConfiguration.deleteDataItem({ appId: 'product-docs', collectionId: 'my-collection', productId: 'product-123', admin: true, itemId: 'manual-1' }); ```
3952
3982
 
3953
3983
  **getWidgets**(collectionId: string,
3954
3984
  options?: GetCollectionWidgetsOptions) → `Promise<CollectionWidgetsResponse>`
@@ -4778,12 +4808,12 @@ List all Product Items for a Collection.
4778
4808
 
4779
4809
  **create**(collectionId: string,
4780
4810
  data: ProductCreateRequest) → `Promise<ProductResponse>`
4781
- Create a new product for a collection (admin only). The `data` payload follows the same shape as ProductResponse minus `id` and `collectionId`.
4811
+ Create a new product for a collection (admin only). The `data` payload follows the same shape as ProductResponse minus `id` and `collectionId`. **Hero Image Auto-Fetch:** You can pass `heroImage` as either: - A full asset object: `{ url: '...', thumbnails: {...} }` - A string URL: The system automatically fetches and stores the image ```typescript // Using a URL - auto-fetched and stored const product = await product.create(collectionId, { name: 'Wine Bottle', description: 'Premium red wine', heroImage: 'https://example.com/wine.jpg', // Auto-fetched! tags: {}, data: {} }); ```
4782
4812
 
4783
4813
  **update**(collectionId: string,
4784
4814
  productId: string,
4785
4815
  data: ProductUpdateRequest) → `Promise<ProductResponse>`
4786
- Update a product for a collection (admin only). The `data` payload is a partial of ProductResponse minus `id` and `collectionId`.
4816
+ Update a product for a collection (admin only). The `data` payload is a partial of ProductResponse minus `id` and `collectionId`. **Hero Image Auto-Fetch:** You can pass `heroImage` as either: - A full asset object: `{ url: '...', thumbnails: {...} }` - A string URL: The system automatically fetches and stores the image ```typescript // Update with new URL - auto-fetched and stored const product = await product.update(collectionId, productId, { heroImage: 'https://example.com/new-wine.jpg' // Auto-fetched! }); ```
4787
4817
 
4788
4818
  **remove**(collectionId: string,
4789
4819
  productId: string) → `Promise<void>`
@@ -4828,7 +4858,12 @@ Update a proof for a product (admin only). PUT /admin/collection/:collectionId/p
4828
4858
  productId: string,
4829
4859
  proofId: string,
4830
4860
  values: ProofClaimRequest) → `Promise<ProofResponse>`
4831
- Claim a proof for a product. PUT /public/collection/:collectionId/product/:productId/proof/:proofId
4861
+ Claim a proof for a product using a proof ID (serial number, NFC tag, etc.). PUT /public/collection/:collectionId/product/:productId/proof/:proofId/claim
4862
+
4863
+ **claimProduct**(collectionId: string,
4864
+ productId: string,
4865
+ values?: ProofClaimRequest) → `Promise<ProofResponse>`
4866
+ Claim a product without providing a proof ID. System auto-generates a unique serial number on-demand. Requires allowAutoGenerateClaims to be enabled on the collection or product. PUT /public/collection/:collectionId/product/:productId/proof/claim ```typescript const proof = await proof.claimProduct( 'beauty-brand', 'moisturizer-pro', { purchaseDate: '2026-02-17', store: 'Target' } ); console.log('Auto-generated ID:', proof.id); ```
4832
4867
 
4833
4868
  **remove**(collectionId: string,
4834
4869
  productId: string,
@@ -4974,6 +5009,29 @@ Backward-compat: Public batch lookup (GET) with collectionId parameter (ignored)
4974
5009
  **renderSource**(collectionId: string,
4975
5010
  body: TemplateRenderSourceRequest) → `Promise<TemplateRenderSourceResponse>`
4976
5011
 
5012
+ ### userAppData
5013
+
5014
+ **getConfig**(appId: string) → `Promise<any>`
5015
+ Get user's config blob for an app. This is a single JSON object stored per user+app. ```typescript const config = await userAppData.getConfig('allergy-tracker'); // Returns: { allergies: ['peanuts'], notifications: true } ```
5016
+
5017
+ **setConfig**(appId: string, config: any) → `Promise<any>`
5018
+ Set user's config blob for an app. ```typescript await userAppData.setConfig('allergy-tracker', { allergies: ['peanuts', 'shellfish'], notifications: true }); ```
5019
+
5020
+ **deleteConfig**(appId: string) → `Promise<void>`
5021
+ Delete user's config blob for an app. ```typescript await userAppData.deleteConfig('allergy-tracker'); ```
5022
+
5023
+ **list**(appId: string) → `Promise<any[]>`
5024
+ List all user's data items for an app. Returns an array of objects, each with an `id` field. ```typescript const beds = await userAppData.list('garden-planner'); // Returns: [{ id: 'bed-1', name: 'Vegetables', ... }, { id: 'bed-2', ... }] ```
5025
+
5026
+ **get**(appId: string, itemId: string) → `Promise<any>`
5027
+ Get a specific user data item by ID. ```typescript const bed = await userAppData.get('garden-planner', 'bed-1'); // Returns: { id: 'bed-1', name: 'Vegetable Bed', plants: [...] } ```
5028
+
5029
+ **set**(appId: string, item: any) → `Promise<any>`
5030
+ Create or update a user data item. The item object must include an `id` field. ```typescript await userAppData.set('garden-planner', { id: 'bed-1', name: 'Vegetable Bed', plants: ['tomatoes', 'peppers'], location: { x: 10, y: 20 } }); ```
5031
+
5032
+ **remove**(appId: string, itemId: string) → `Promise<void>`
5033
+ Delete a user data item by ID. ```typescript await userAppData.remove('garden-planner', 'bed-1'); ```
5034
+
4977
5035
  ### variant
4978
5036
 
4979
5037
  **get**(collectionId: string,
@@ -0,0 +1,223 @@
1
+ # App Data Storage Guide
2
+
3
+ The SmartLinks platform provides two distinct types of data storage for apps:
4
+
5
+ ## 1. User-Specific Data (Global per User+App)
6
+
7
+ **Use the `userAppData` namespace for all user-specific data.**
8
+
9
+ User data is **shared across all collections** for a given user and app. This is perfect for storing user preferences, personal settings, and user-generated content that should persist regardless of which collection they're viewing.
10
+
11
+ ### Use Cases
12
+ - User allergies in an allergy tracking app
13
+ - Garden bed layouts in a garden planning app
14
+ - User preferences and settings
15
+ - Shopping lists, wishlists, favorites
16
+ - Personal notes and annotations
17
+
18
+ ### API Endpoints
19
+ ```
20
+ GET /public/auth/app/:appId - Get user's single config blob
21
+ POST /public/auth/app/:appId - Set user's single config blob
22
+ DELETE /public/auth/app/:appId - Delete user's config blob
23
+
24
+ GET /public/auth/app/:appId/data - Get all user's data items
25
+ GET /public/auth/app/:appId/data/:itemId - Get a specific user data item
26
+ POST /public/auth/app/:appId/data - Create/update a user data item
27
+ DELETE /public/auth/app/:appId/data/:itemId - Delete a user data item
28
+ ```
29
+
30
+ ### SDK Usage
31
+
32
+ #### Single Config Blob (Simple Key-Value)
33
+ ```typescript
34
+ import { userAppData } from '@proveanything/smartlinks';
35
+
36
+ // Get user's config
37
+ const config = await userAppData.getConfig('allergy-tracker');
38
+
39
+ // Save user's config
40
+ await userAppData.setConfig('allergy-tracker', {
41
+ allergies: ['peanuts', 'shellfish'],
42
+ notifications: true
43
+ });
44
+
45
+ // Delete user's config
46
+ await userAppData.deleteConfig('allergy-tracker');
47
+ ```
48
+
49
+ #### Multiple Keyed Data Items (Recommended)
50
+ ```typescript
51
+ // Get all user's garden beds
52
+ const beds = await userAppData.list('garden-planner');
53
+ // Returns: [{ id: 'bed-1', name: 'Vegetables', ... }, { id: 'bed-2', ... }]
54
+
55
+ // Get specific bed
56
+ const bed = await userAppData.get('garden-planner', 'bed-1');
57
+
58
+ // Save/update a bed
59
+ await userAppData.set('garden-planner', {
60
+ id: 'bed-1',
61
+ name: 'Vegetable Bed',
62
+ plants: ['tomatoes', 'peppers'],
63
+ location: { x: 10, y: 20 }
64
+ });
65
+
66
+ // Delete a bed
67
+ await userAppData.remove('garden-planner', 'bed-1');
68
+ ```
69
+
70
+ ### Important Notes
71
+ - ✅ **Clean, simple API** - Just pass the `appId` (no collection/product scoping)
72
+ - ✅ User data requires authentication (Bearer token)
73
+ - ✅ Data is automatically scoped to the authenticated user
74
+ - ✅ Impossible to accidentally scope to collections
75
+
76
+ ---
77
+
78
+ ## 2. Collection/Product-Scoped Data (Admin Configuration)
79
+
80
+ **Use the `appConfiguration` namespace for collection/product-scoped data.**
81
+
82
+ This data is scoped to specific collections, products, variants, or batches. It's typically configured by collection admins/owners and applies to all users viewing that collection/product.
83
+
84
+ ### Use Cases
85
+ - App-specific settings for a collection
86
+ - Product-level configuration
87
+ - Feature flags and toggles
88
+ - Theme and branding settings
89
+ - Public content that all users see
90
+
91
+ ### API Endpoints
92
+ ```
93
+ GET /public/collection/:collectionId/app/:appId
94
+ POST /admin/collection/:collectionId/app/:appId
95
+ DELETE /admin/collection/:collectionId/app/:appId
96
+
97
+ GET /public/collection/:collectionId/product/:productId/app/:appId/data
98
+ POST /admin/collection/:collectionId/product/:productId/app/:appId/data
99
+ ...
100
+ ```
101
+
102
+ ### SDK Usage
103
+
104
+ ```typescript
105
+ import { appConfiguration } from '@proveanything/smartlinks';
106
+
107
+ // Get collection-level app config
108
+ const collectionConfig = await appConfiguration.getConfig({
109
+ appId: 'warranty-portal',
110
+ collectionId: 'my-collection'
111
+ });
112
+
113
+ // Set collection-level config (requires admin auth)
114
+ await appConfiguration.setConfig({
115
+ appId: 'warranty-portal',
116
+ collectionId: 'my-collection',
117
+ admin: true,
118
+ config: {
119
+ warrantyPeriod: 24,
120
+ supportEmail: 'support@example.com'
121
+ }
122
+ });
123
+
124
+ // Get product-level data items
125
+ const items = await appConfiguration.getData({
126
+ appId: 'product-docs',
127
+ collectionId: 'my-collection',
128
+ productId: 'product-123'
129
+ });
130
+
131
+ // Set product-level data item (requires admin auth)
132
+ await appConfiguration.setDataItem({
133
+ appId: 'product-docs',
134
+ collectionId: 'my-collection',
135
+ productId: 'product-123',
136
+ admin: true,
137
+ data: {
138
+ id: 'manual-1',
139
+ title: 'User Manual',
140
+ url: 'https://...'
141
+ }
142
+ });
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Comparison Table
148
+
149
+ | Feature | User Data | Collection/Product Data |
150
+ |---------|-----------|------------------------|
151
+ | **Namespace** | `userAppData` | `appConfiguration` |
152
+ | **Scope** | User + App (global) | Collection/Product/Variant/Batch |
153
+ | **Set by** | Individual users | Collection admins/owners |
154
+ | **Shared across collections?** | ✅ Yes | ❌ No |
155
+ | **Requires auth?** | ✅ Yes (user token) | ✅ Yes (admin token for write) |
156
+ | **Function signature** | Simple: `set(appId, data)` | Options object: `setDataItem({ appId, collectionId, data })` |
157
+ | **Admin write required?** | ❌ No | ✅ Yes (for write operations) |
158
+
159
+ ---
160
+
161
+ ## Migration from Old SDK
162
+
163
+ ### Old SDK → New SDK
164
+
165
+ ```typescript
166
+ // OLD: Get user config
167
+ RemoteApi.get({ path: `public/auth/app/${appId}` })
168
+ // NEW:
169
+ userAppData.getConfig(appId)
170
+
171
+ // OLD: Set user config
172
+ RemoteApi.post({ path: `public/auth/app/${appId}`, data })
173
+ // NEW:
174
+ userAppData.setConfig(appId, data)
175
+
176
+ // OLD: Get user data items
177
+ RemoteApi.get({ path: `public/auth/app/${appId}/data` })
178
+ // NEW:
179
+ userAppData.list(appId)
180
+
181
+ // OLD: Get user data item
182
+ RemoteApi.get({ path: `public/auth/app/${appId}/data/${itemId}` })
183
+ // NEW:
184
+ userAppData.get(appId, itemId)
185
+
186
+ // OLD: Set user data item
187
+ RemoteApi.post({ path: `public/auth/app/${appId}/data`, data: item })
188
+ // NEW:
189
+ userAppData.set(appId, item)
190
+
191
+ // OLD: Delete user data item
192
+ RemoteApi.delete({ path: `public/auth/app/${appId}/data/${itemId}` })
193
+ // NEW:
194
+ userAppData.remove(appId, itemId)
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Complete API Reference
200
+
201
+ ### `userAppData` (User-Specific Data)
202
+
203
+ | Function | Signature | Description |
204
+ |----------|-----------|-------------|
205
+ | `getConfig` | `(appId: string) => Promise<any>` | Get user's config blob |
206
+ | `setConfig` | `(appId: string, config: any) => Promise<any>` | Set user's config blob |
207
+ | `deleteConfig` | `(appId: string) => Promise<void>` | Delete user's config blob |
208
+ | `list` | `(appId: string) => Promise<any[]>` | List all user's data items |
209
+ | `get` | `(appId: string, itemId: string) => Promise<any>` | Get specific data item |
210
+ | `set` | `(appId: string, item: any) => Promise<any>` | Create/update data item |
211
+ | `remove` | `(appId: string, itemId: string) => Promise<void>` | Delete data item |
212
+
213
+ ### `appConfiguration` (Collection/Product-Scoped Data)
214
+
215
+ | Function | Signature | Description |
216
+ |----------|-----------|-------------|
217
+ | `getConfig` | `(opts: AppConfigOptions) => Promise<any>` | Get config for scope |
218
+ | `setConfig` | `(opts: AppConfigOptions) => Promise<any>` | Set config for scope |
219
+ | `deleteConfig` | `(opts: AppConfigOptions) => Promise<void>` | Delete config for scope |
220
+ | `getData` | `(opts: AppConfigOptions) => Promise<any[]>` | List data items in scope |
221
+ | `getDataItem` | `(opts: AppConfigOptions) => Promise<any>` | Get specific data item |
222
+ | `setDataItem` | `(opts: AppConfigOptions) => Promise<any>` | Create/update data item |
223
+ | `deleteDataItem` | `(opts: AppConfigOptions) => Promise<void>` | Delete data item |