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 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
- !validCurrencies.includes(pricing.currency)) {
659
+ !VALID_CURRENCIES.includes(pricing.currency)) {
569
660
  errors.push({
570
661
  field: "intents.book.pricing.currency",
571
- message: `Currency must be one of: ${validCurrencies.join(", ")}`,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "me3-protocol",
3
- "version": "2.6.0",
3
+ "version": "2.8.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
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)"