@proveanything/smartlinks 1.3.25 → 1.3.27
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/README.md +48 -0
- package/dist/api/ai.d.ts +6 -380
- package/dist/api/ai.js +15 -15
- package/dist/api/index.d.ts +0 -1
- package/dist/docs/API_SUMMARY.md +2259 -2271
- package/dist/docs/utils.md +651 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/types/ai.d.ts +379 -0
- package/dist/types/ai.js +5 -0
- package/dist/types/collection.d.ts +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/conditions.d.ts +287 -0
- package/dist/utils/conditions.js +453 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/paths.d.ts +82 -0
- package/dist/utils/paths.js +164 -0
- package/docs/API_SUMMARY.md +2259 -2271
- package/docs/utils.md +651 -0
- package/package.json +1 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a portal path/URL based on the provided parameters.
|
|
3
|
+
*
|
|
4
|
+
* Pass in objects where available (collection, product, batch, etc.) and the function
|
|
5
|
+
* will extract the needed properties. You can also pass just IDs if you don't have the full objects.
|
|
6
|
+
*
|
|
7
|
+
* Supports multiple path formats:
|
|
8
|
+
* - Basic product: `/c/{shortId}/{productId}`
|
|
9
|
+
* - With proof: `/c/{shortId}/{productId}/{proofId}`
|
|
10
|
+
* - GTIN (own): `/01/{gtin}` - ownGtin is read from the product object
|
|
11
|
+
* - GTIN (not own): `/gc/{shortId}/01/{gtin}`
|
|
12
|
+
* - With batch: adds `/10/{batchId}` and optionally `?17={expiryDate}`
|
|
13
|
+
* - With variant: adds `/22/{variantId}`
|
|
14
|
+
*
|
|
15
|
+
* @param params - Path parameters
|
|
16
|
+
* @returns The built portal path or URL
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // Basic product path (pass objects)
|
|
21
|
+
* buildPortalPath({
|
|
22
|
+
* collection: myCollection,
|
|
23
|
+
* product: myProduct // reads ownGtin from product if present
|
|
24
|
+
* })
|
|
25
|
+
* // Returns: https://portal.smartlinks.io/c/abc123/prod1
|
|
26
|
+
*
|
|
27
|
+
* // GTIN path (ownGtin read from product)
|
|
28
|
+
* buildPortalPath({
|
|
29
|
+
* collection: myCollection,
|
|
30
|
+
* product: myProduct // if product.ownGtin is true, uses /01/ path
|
|
31
|
+
* })
|
|
32
|
+
* // Returns: https://portal.smartlinks.io/01/1234567890123
|
|
33
|
+
*
|
|
34
|
+
* // With batch object (includes expiry date)
|
|
35
|
+
* buildPortalPath({
|
|
36
|
+
* collection: myCollection,
|
|
37
|
+
* product: myProduct,
|
|
38
|
+
* batch: myBatch // extracts id and expiryDate
|
|
39
|
+
* })
|
|
40
|
+
* // Returns: /01/1234567890123/10/batch1?17=260630
|
|
41
|
+
*
|
|
42
|
+
* // Or just pass IDs
|
|
43
|
+
* buildPortalPath({
|
|
44
|
+
* collection: { shortId: 'abc123' },
|
|
45
|
+
* productId: 'prod1',
|
|
46
|
+
* batchId: 'batch1' // just the ID, no expiry
|
|
47
|
+
* })
|
|
48
|
+
* // Returns: /c/abc123/prod1
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export function buildPortalPath(params) {
|
|
52
|
+
const { collection, product, productId, batch, batchId, variant, proof, queryParams = {} } = params;
|
|
53
|
+
// Extract values from collection
|
|
54
|
+
const shortId = collection.shortId;
|
|
55
|
+
const baseUrl = 'portalUrl' in collection ? collection.portalUrl : undefined;
|
|
56
|
+
// Extract product values
|
|
57
|
+
let gtin;
|
|
58
|
+
let ownGtin;
|
|
59
|
+
let extractedProductId;
|
|
60
|
+
if (product) {
|
|
61
|
+
extractedProductId = product.id;
|
|
62
|
+
gtin = product.gtin;
|
|
63
|
+
// ownGtin is a critical product setting - only read from product, never override
|
|
64
|
+
ownGtin = 'ownGtin' in product ? product.ownGtin : undefined;
|
|
65
|
+
}
|
|
66
|
+
else if (productId) {
|
|
67
|
+
extractedProductId = productId;
|
|
68
|
+
}
|
|
69
|
+
// Extract batch values
|
|
70
|
+
let extractedBatchId;
|
|
71
|
+
let expiryDate;
|
|
72
|
+
if (batch) {
|
|
73
|
+
// Batch object - extract id and expiryDate
|
|
74
|
+
extractedBatchId = batch.id;
|
|
75
|
+
if (batch.expiryDate) {
|
|
76
|
+
// Handle Firebase timestamp or Date
|
|
77
|
+
if (typeof batch.expiryDate === 'object' && 'seconds' in batch.expiryDate) {
|
|
78
|
+
expiryDate = new Date(batch.expiryDate.seconds * 1000);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
expiryDate = batch.expiryDate;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else if (batchId) {
|
|
86
|
+
// Just batch ID string - no expiry date
|
|
87
|
+
extractedBatchId = batchId;
|
|
88
|
+
}
|
|
89
|
+
// Extract variant ID
|
|
90
|
+
const variantId = variant
|
|
91
|
+
? typeof variant === 'string'
|
|
92
|
+
? variant
|
|
93
|
+
: variant.id
|
|
94
|
+
: undefined;
|
|
95
|
+
// Extract proof ID
|
|
96
|
+
const proofId = proof
|
|
97
|
+
? typeof proof === 'string'
|
|
98
|
+
? proof
|
|
99
|
+
: proof.id
|
|
100
|
+
: undefined;
|
|
101
|
+
let pathname = '';
|
|
102
|
+
const searchParams = new URLSearchParams();
|
|
103
|
+
// Build pathname based on GTIN or product ID
|
|
104
|
+
if (gtin) {
|
|
105
|
+
// GS1 Digital Link format
|
|
106
|
+
if (ownGtin) {
|
|
107
|
+
pathname = `/01/${gtin}`;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
pathname = `/gc/${shortId}/01/${gtin}`;
|
|
111
|
+
}
|
|
112
|
+
// Add batch (GS1 AI 10)
|
|
113
|
+
if (extractedBatchId) {
|
|
114
|
+
pathname += `/10/${extractedBatchId}`;
|
|
115
|
+
// Add expiry date as query param (GS1 AI 17)
|
|
116
|
+
if (expiryDate) {
|
|
117
|
+
const dateStr = formatExpiryDate(expiryDate);
|
|
118
|
+
searchParams.append('17', dateStr);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Add variant (GS1 AI 22)
|
|
122
|
+
if (variantId) {
|
|
123
|
+
pathname += `/22/${variantId}`;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (extractedProductId) {
|
|
127
|
+
// Regular product path
|
|
128
|
+
pathname = `/c/${shortId}/${extractedProductId}`;
|
|
129
|
+
// Add proof to path
|
|
130
|
+
if (proofId) {
|
|
131
|
+
pathname += `/${proofId}`;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Add any additional query params
|
|
135
|
+
for (const [key, value] of Object.entries(queryParams)) {
|
|
136
|
+
searchParams.append(key, value);
|
|
137
|
+
}
|
|
138
|
+
// Build final URL
|
|
139
|
+
const queryString = searchParams.toString();
|
|
140
|
+
const fullPath = pathname + (queryString ? `?${queryString}` : '');
|
|
141
|
+
if (baseUrl) {
|
|
142
|
+
const cleanBaseUrl = baseUrl.replace(/\/$/, '');
|
|
143
|
+
return cleanBaseUrl + fullPath;
|
|
144
|
+
}
|
|
145
|
+
return fullPath;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Formats an expiry date to YYMMDD format.
|
|
149
|
+
* @internal
|
|
150
|
+
*/
|
|
151
|
+
function formatExpiryDate(date) {
|
|
152
|
+
if (typeof date === 'string') {
|
|
153
|
+
// Already in YYMMDD format
|
|
154
|
+
if (/^\d{6}$/.test(date)) {
|
|
155
|
+
return date;
|
|
156
|
+
}
|
|
157
|
+
// Try to parse as ISO date
|
|
158
|
+
date = new Date(date);
|
|
159
|
+
}
|
|
160
|
+
const year = date.getFullYear().toString().slice(-2);
|
|
161
|
+
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
162
|
+
const day = date.getDate().toString().padStart(2, '0');
|
|
163
|
+
return `${year}${month}${day}`;
|
|
164
|
+
}
|