me3-protocol 2.6.0 → 2.8.0
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.d.ts +42 -0
- package/dist/index.js +147 -3
- package/package.json +1 -1
- package/schema.json +108 -0
package/dist/index.d.ts
CHANGED
|
@@ -25,6 +25,28 @@ export interface Me3Post {
|
|
|
25
25
|
publishedAt?: string;
|
|
26
26
|
/** Short excerpt for archive/listing (optional) */
|
|
27
27
|
excerpt?: string;
|
|
28
|
+
/** ISO timestamp when post was sent to newsletter subscribers (optional) */
|
|
29
|
+
emailedAt?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface Me3Product {
|
|
32
|
+
/** URL-friendly identifier */
|
|
33
|
+
slug: string;
|
|
34
|
+
/** Product name */
|
|
35
|
+
title: string;
|
|
36
|
+
/** Path to markdown file (relative to me.json) */
|
|
37
|
+
file: string;
|
|
38
|
+
/** Product price in cents (e.g., 2999 for $29.99) */
|
|
39
|
+
price: number;
|
|
40
|
+
/** Currency code */
|
|
41
|
+
currency: "USD" | "GBP" | "EUR";
|
|
42
|
+
/** Product images (URLs) */
|
|
43
|
+
images?: string[];
|
|
44
|
+
/** Whether product is available for purchase */
|
|
45
|
+
available?: boolean;
|
|
46
|
+
/** ISO publish date (optional) */
|
|
47
|
+
publishedAt?: string;
|
|
48
|
+
/** Short excerpt for listings (optional) */
|
|
49
|
+
excerpt?: string;
|
|
28
50
|
}
|
|
29
51
|
export interface Me3Links {
|
|
30
52
|
website?: string;
|
|
@@ -128,6 +150,8 @@ export interface Me3IntentBook {
|
|
|
128
150
|
description?: string;
|
|
129
151
|
/** Meeting duration in minutes */
|
|
130
152
|
duration?: number;
|
|
153
|
+
/** Buffer time between meetings in minutes (default: 0) */
|
|
154
|
+
bufferTime?: number;
|
|
131
155
|
/** Booking provider (e.g., "cal.com", "calendly") - for external providers */
|
|
132
156
|
provider?: string;
|
|
133
157
|
/** Direct booking URL - for external booking systems */
|
|
@@ -137,6 +161,20 @@ export interface Me3IntentBook {
|
|
|
137
161
|
/** Pricing configuration for paid meetings (optional) */
|
|
138
162
|
pricing?: Me3BookingPricing;
|
|
139
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Shop intent.
|
|
166
|
+
* Declares that the person sells products via a simple shop.
|
|
167
|
+
*/
|
|
168
|
+
export interface Me3IntentShop {
|
|
169
|
+
/** Whether shop is enabled */
|
|
170
|
+
enabled: boolean;
|
|
171
|
+
/** Shop title/name */
|
|
172
|
+
title?: string;
|
|
173
|
+
/** Shop description */
|
|
174
|
+
description?: string;
|
|
175
|
+
/** Shop currency */
|
|
176
|
+
currency: "USD" | "GBP" | "EUR";
|
|
177
|
+
}
|
|
140
178
|
/**
|
|
141
179
|
* Intents object - declares what actions visitors/agents can take.
|
|
142
180
|
* This is the machine-readable API contract for interacting with a person.
|
|
@@ -146,6 +184,8 @@ export interface Me3Intents {
|
|
|
146
184
|
subscribe?: Me3IntentSubscribe;
|
|
147
185
|
/** Meeting booking */
|
|
148
186
|
book?: Me3IntentBook;
|
|
187
|
+
/** Shop intent */
|
|
188
|
+
shop?: Me3IntentShop;
|
|
149
189
|
}
|
|
150
190
|
export interface Me3Profile {
|
|
151
191
|
/** Protocol version */
|
|
@@ -170,6 +210,8 @@ export interface Me3Profile {
|
|
|
170
210
|
pages?: Me3Page[];
|
|
171
211
|
/** Blog posts (markdown) */
|
|
172
212
|
posts?: Me3Post[];
|
|
213
|
+
/** Products (markdown) */
|
|
214
|
+
products?: Me3Product[];
|
|
173
215
|
/**
|
|
174
216
|
* Custom footer configuration.
|
|
175
217
|
* - `undefined`: default footer behavior (renderer-defined)
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,7 @@ const MAX_FOOTER_LINK_TEXT_LENGTH = 60;
|
|
|
24
24
|
const MAX_INTENT_TITLE_LENGTH = 100;
|
|
25
25
|
const MAX_INTENT_DESCRIPTION_LENGTH = 300;
|
|
26
26
|
const VALID_FREQUENCIES = ["daily", "weekly", "monthly", "irregular"];
|
|
27
|
+
const VALID_CURRENCIES = ["USD", "GBP", "EUR"];
|
|
27
28
|
/**
|
|
28
29
|
* Validate a me3 profile object
|
|
29
30
|
*/
|
|
@@ -323,6 +324,97 @@ function validateProfile(data) {
|
|
|
323
324
|
message: "Post excerpt must be a string",
|
|
324
325
|
});
|
|
325
326
|
}
|
|
327
|
+
if (post.emailedAt !== undefined &&
|
|
328
|
+
typeof post.emailedAt !== "string") {
|
|
329
|
+
errors.push({
|
|
330
|
+
field: `posts[${index}].emailedAt`,
|
|
331
|
+
message: "Post emailedAt must be a string",
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// Products (optional)
|
|
338
|
+
if (profile.products !== undefined) {
|
|
339
|
+
const products = profile.products;
|
|
340
|
+
if (!Array.isArray(products)) {
|
|
341
|
+
errors.push({ field: "products", message: "Products must be an array" });
|
|
342
|
+
}
|
|
343
|
+
else {
|
|
344
|
+
products.forEach((product, index) => {
|
|
345
|
+
if (!product || typeof product !== "object") {
|
|
346
|
+
errors.push({
|
|
347
|
+
field: `products[${index}]`,
|
|
348
|
+
message: "Product must be an object",
|
|
349
|
+
});
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (!product.slug || typeof product.slug !== "string") {
|
|
353
|
+
errors.push({
|
|
354
|
+
field: `products[${index}].slug`,
|
|
355
|
+
message: "Product slug is required",
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
if (!product.title || typeof product.title !== "string") {
|
|
359
|
+
errors.push({
|
|
360
|
+
field: `products[${index}].title`,
|
|
361
|
+
message: "Product title is required",
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
if (!product.file || typeof product.file !== "string") {
|
|
365
|
+
errors.push({
|
|
366
|
+
field: `products[${index}].file`,
|
|
367
|
+
message: "Product file is required",
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
if (typeof product.price !== "number") {
|
|
371
|
+
errors.push({
|
|
372
|
+
field: `products[${index}].price`,
|
|
373
|
+
message: "Product price must be a number (in cents)",
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
if (typeof product.currency !== "string" ||
|
|
377
|
+
!VALID_CURRENCIES.includes(product.currency)) {
|
|
378
|
+
errors.push({
|
|
379
|
+
field: `products[${index}].currency`,
|
|
380
|
+
message: `Product currency must be one of: ${VALID_CURRENCIES.join(", ")}`,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
if (product.available !== undefined &&
|
|
384
|
+
typeof product.available !== "boolean") {
|
|
385
|
+
errors.push({
|
|
386
|
+
field: `products[${index}].available`,
|
|
387
|
+
message: "Product available must be a boolean",
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
if (product.images !== undefined) {
|
|
391
|
+
if (!Array.isArray(product.images)) {
|
|
392
|
+
errors.push({
|
|
393
|
+
field: `products[${index}].images`,
|
|
394
|
+
message: "Product images must be an array of strings",
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
else if (product.images.some((img) => typeof img !== "string")) {
|
|
398
|
+
errors.push({
|
|
399
|
+
field: `products[${index}].images`,
|
|
400
|
+
message: "Product images must be an array of strings",
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (product.publishedAt !== undefined &&
|
|
405
|
+
typeof product.publishedAt !== "string") {
|
|
406
|
+
errors.push({
|
|
407
|
+
field: `products[${index}].publishedAt`,
|
|
408
|
+
message: "Product publishedAt must be a string",
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
if (product.excerpt !== undefined &&
|
|
412
|
+
typeof product.excerpt !== "string") {
|
|
413
|
+
errors.push({
|
|
414
|
+
field: `products[${index}].excerpt`,
|
|
415
|
+
message: "Product excerpt must be a string",
|
|
416
|
+
});
|
|
417
|
+
}
|
|
326
418
|
});
|
|
327
419
|
}
|
|
328
420
|
}
|
|
@@ -563,12 +655,11 @@ function validateProfile(data) {
|
|
|
563
655
|
message: "Suggested amount must be at least $5",
|
|
564
656
|
});
|
|
565
657
|
}
|
|
566
|
-
const validCurrencies = ["USD", "GBP", "EUR"];
|
|
567
658
|
if (typeof pricing.currency !== "string" ||
|
|
568
|
-
!
|
|
659
|
+
!VALID_CURRENCIES.includes(pricing.currency)) {
|
|
569
660
|
errors.push({
|
|
570
661
|
field: "intents.book.pricing.currency",
|
|
571
|
-
message: `Currency must be one of: ${
|
|
662
|
+
message: `Currency must be one of: ${VALID_CURRENCIES.join(", ")}`,
|
|
572
663
|
});
|
|
573
664
|
}
|
|
574
665
|
if (pricing.minimumAmount !== 5) {
|
|
@@ -588,6 +679,59 @@ function validateProfile(data) {
|
|
|
588
679
|
}
|
|
589
680
|
}
|
|
590
681
|
}
|
|
682
|
+
// Validate shop intent
|
|
683
|
+
if (intents.shop !== undefined) {
|
|
684
|
+
if (typeof intents.shop !== "object" || intents.shop === null) {
|
|
685
|
+
errors.push({
|
|
686
|
+
field: "intents.shop",
|
|
687
|
+
message: "Shop intent must be an object",
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
const shop = intents.shop;
|
|
692
|
+
if (typeof shop.enabled !== "boolean") {
|
|
693
|
+
errors.push({
|
|
694
|
+
field: "intents.shop.enabled",
|
|
695
|
+
message: "Shop enabled must be a boolean",
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
if (shop.title !== undefined) {
|
|
699
|
+
if (typeof shop.title !== "string") {
|
|
700
|
+
errors.push({
|
|
701
|
+
field: "intents.shop.title",
|
|
702
|
+
message: "Shop title must be a string",
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
else if (shop.title.length > MAX_INTENT_TITLE_LENGTH) {
|
|
706
|
+
errors.push({
|
|
707
|
+
field: "intents.shop.title",
|
|
708
|
+
message: `Shop title must be ${MAX_INTENT_TITLE_LENGTH} characters or less`,
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (shop.description !== undefined) {
|
|
713
|
+
if (typeof shop.description !== "string") {
|
|
714
|
+
errors.push({
|
|
715
|
+
field: "intents.shop.description",
|
|
716
|
+
message: "Shop description must be a string",
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
else if (shop.description.length > MAX_INTENT_DESCRIPTION_LENGTH) {
|
|
720
|
+
errors.push({
|
|
721
|
+
field: "intents.shop.description",
|
|
722
|
+
message: `Shop description must be ${MAX_INTENT_DESCRIPTION_LENGTH} characters or less`,
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
if (typeof shop.currency !== "string" ||
|
|
727
|
+
!VALID_CURRENCIES.includes(shop.currency)) {
|
|
728
|
+
errors.push({
|
|
729
|
+
field: "intents.shop.currency",
|
|
730
|
+
message: `Shop currency must be one of: ${VALID_CURRENCIES.join(", ")}`,
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
591
735
|
}
|
|
592
736
|
}
|
|
593
737
|
if (errors.length > 0) {
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -177,6 +177,10 @@
|
|
|
177
177
|
"$ref": "#/definitions/Me3BookingAvailability",
|
|
178
178
|
"description": "Availability windows - for native me3 booking"
|
|
179
179
|
},
|
|
180
|
+
"bufferTime": {
|
|
181
|
+
"description": "Buffer time between meetings in minutes (default: 0)",
|
|
182
|
+
"type": "number"
|
|
183
|
+
},
|
|
180
184
|
"description": {
|
|
181
185
|
"description": "What the meeting is about",
|
|
182
186
|
"type": "string"
|
|
@@ -211,6 +215,38 @@
|
|
|
211
215
|
],
|
|
212
216
|
"type": "object"
|
|
213
217
|
},
|
|
218
|
+
"Me3IntentShop": {
|
|
219
|
+
"additionalProperties": false,
|
|
220
|
+
"description": "Shop intent. Declares that the person sells products via a simple shop.",
|
|
221
|
+
"properties": {
|
|
222
|
+
"currency": {
|
|
223
|
+
"description": "Shop currency",
|
|
224
|
+
"enum": [
|
|
225
|
+
"USD",
|
|
226
|
+
"GBP",
|
|
227
|
+
"EUR"
|
|
228
|
+
],
|
|
229
|
+
"type": "string"
|
|
230
|
+
},
|
|
231
|
+
"description": {
|
|
232
|
+
"description": "Shop description",
|
|
233
|
+
"type": "string"
|
|
234
|
+
},
|
|
235
|
+
"enabled": {
|
|
236
|
+
"description": "Whether shop is enabled",
|
|
237
|
+
"type": "boolean"
|
|
238
|
+
},
|
|
239
|
+
"title": {
|
|
240
|
+
"description": "Shop title/name",
|
|
241
|
+
"type": "string"
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
"required": [
|
|
245
|
+
"enabled",
|
|
246
|
+
"currency"
|
|
247
|
+
],
|
|
248
|
+
"type": "object"
|
|
249
|
+
},
|
|
214
250
|
"Me3IntentSubscribe": {
|
|
215
251
|
"additionalProperties": false,
|
|
216
252
|
"description": "Newsletter subscription intent. When enabled, the site accepts email subscriptions via POST /api/subscribe",
|
|
@@ -251,6 +287,10 @@
|
|
|
251
287
|
"$ref": "#/definitions/Me3IntentBook",
|
|
252
288
|
"description": "Meeting booking"
|
|
253
289
|
},
|
|
290
|
+
"shop": {
|
|
291
|
+
"$ref": "#/definitions/Me3IntentShop",
|
|
292
|
+
"description": "Shop intent"
|
|
293
|
+
},
|
|
254
294
|
"subscribe": {
|
|
255
295
|
"$ref": "#/definitions/Me3IntentSubscribe",
|
|
256
296
|
"description": "Newsletter subscription"
|
|
@@ -329,6 +369,10 @@
|
|
|
329
369
|
"Me3Post": {
|
|
330
370
|
"additionalProperties": false,
|
|
331
371
|
"properties": {
|
|
372
|
+
"emailedAt": {
|
|
373
|
+
"description": "ISO timestamp when post was sent to newsletter subscribers (optional)",
|
|
374
|
+
"type": "string"
|
|
375
|
+
},
|
|
332
376
|
"excerpt": {
|
|
333
377
|
"description": "Short excerpt for archive/listing (optional)",
|
|
334
378
|
"type": "string"
|
|
@@ -357,6 +401,63 @@
|
|
|
357
401
|
],
|
|
358
402
|
"type": "object"
|
|
359
403
|
},
|
|
404
|
+
"Me3Product": {
|
|
405
|
+
"additionalProperties": false,
|
|
406
|
+
"properties": {
|
|
407
|
+
"available": {
|
|
408
|
+
"description": "Whether product is available for purchase",
|
|
409
|
+
"type": "boolean"
|
|
410
|
+
},
|
|
411
|
+
"currency": {
|
|
412
|
+
"description": "Currency code",
|
|
413
|
+
"enum": [
|
|
414
|
+
"USD",
|
|
415
|
+
"GBP",
|
|
416
|
+
"EUR"
|
|
417
|
+
],
|
|
418
|
+
"type": "string"
|
|
419
|
+
},
|
|
420
|
+
"excerpt": {
|
|
421
|
+
"description": "Short excerpt for listings (optional)",
|
|
422
|
+
"type": "string"
|
|
423
|
+
},
|
|
424
|
+
"file": {
|
|
425
|
+
"description": "Path to markdown file (relative to me.json)",
|
|
426
|
+
"type": "string"
|
|
427
|
+
},
|
|
428
|
+
"images": {
|
|
429
|
+
"description": "Product images (URLs)",
|
|
430
|
+
"items": {
|
|
431
|
+
"type": "string"
|
|
432
|
+
},
|
|
433
|
+
"type": "array"
|
|
434
|
+
},
|
|
435
|
+
"price": {
|
|
436
|
+
"description": "Product price in cents (e.g., 2999 for $29.99)",
|
|
437
|
+
"type": "number"
|
|
438
|
+
},
|
|
439
|
+
"publishedAt": {
|
|
440
|
+
"description": "ISO publish date (optional)",
|
|
441
|
+
"type": "string"
|
|
442
|
+
},
|
|
443
|
+
"slug": {
|
|
444
|
+
"description": "URL-friendly identifier",
|
|
445
|
+
"type": "string"
|
|
446
|
+
},
|
|
447
|
+
"title": {
|
|
448
|
+
"description": "Product name",
|
|
449
|
+
"type": "string"
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
"required": [
|
|
453
|
+
"slug",
|
|
454
|
+
"title",
|
|
455
|
+
"file",
|
|
456
|
+
"price",
|
|
457
|
+
"currency"
|
|
458
|
+
],
|
|
459
|
+
"type": "object"
|
|
460
|
+
},
|
|
360
461
|
"Me3Profile": {
|
|
361
462
|
"additionalProperties": false,
|
|
362
463
|
"properties": {
|
|
@@ -425,6 +526,13 @@
|
|
|
425
526
|
},
|
|
426
527
|
"type": "array"
|
|
427
528
|
},
|
|
529
|
+
"products": {
|
|
530
|
+
"description": "Products (markdown)",
|
|
531
|
+
"items": {
|
|
532
|
+
"$ref": "#/definitions/Me3Product"
|
|
533
|
+
},
|
|
534
|
+
"type": "array"
|
|
535
|
+
},
|
|
428
536
|
"verification": {
|
|
429
537
|
"$ref": "#/definitions/Me3Verification",
|
|
430
538
|
"description": "Human verification status (populated from account, not editable per-site)"
|