@proveanything/smartlinks 2.0.36 → 2.0.38

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/openapi.yaml CHANGED
@@ -1347,7 +1347,7 @@ paths:
1347
1347
  get:
1348
1348
  tags:
1349
1349
  - sessions
1350
- summary: AI usage / cost report for a collection, grouped by any of model/serviceTier/appId/feature/mode over an optional date window.
1350
+ summary: AI usage for a collection (daily totals), grouped by any of model/appId/feature/mode/surface/provider/day over an optional date window (YYYY-MM-DD).
1351
1351
  operationId: sessions_usage
1352
1352
  security:
1353
1353
  - bearerAuth: []
@@ -16327,17 +16327,37 @@ components:
16327
16327
  to:
16328
16328
  type: string
16329
16329
  totals:
16330
- type: object
16331
- additionalProperties: true
16330
+ $ref: "#/components/schemas/AiUsageTotals"
16332
16331
  groups:
16333
16332
  type: array
16334
16333
  items:
16335
- type: object
16336
- additionalProperties: true
16334
+ $ref: "#/components/schemas/AiUsageTotals"
16337
16335
  required:
16338
16336
  - groupBy
16339
16337
  - totals
16340
16338
  - groups
16339
+ AiUsageTotals:
16340
+ type: object
16341
+ properties:
16342
+ promptTokens:
16343
+ type: number
16344
+ outputTokens:
16345
+ type: number
16346
+ cachedTokens:
16347
+ type: number
16348
+ totalTokens:
16349
+ type: number
16350
+ requests:
16351
+ type: number
16352
+ images:
16353
+ type: number
16354
+ required:
16355
+ - promptTokens
16356
+ - outputTokens
16357
+ - cachedTokens
16358
+ - totalTokens
16359
+ - requests
16360
+ - images
16341
16361
  VoiceSessionRequest:
16342
16362
  type: object
16343
16363
  properties:
@@ -19439,6 +19459,10 @@ components:
19439
19459
  $ref: "#/components/schemas/AppManifestExecutor"
19440
19460
  functions:
19441
19461
  $ref: "#/components/schemas/AppManifestFunctions"
19462
+ data:
19463
+ $ref: "#/components/schemas/AppDataDeclaration"
19464
+ headless:
19465
+ $ref: "#/components/schemas/AppHeadlessDeclaration"
19442
19466
  required:
19443
19467
  - name
19444
19468
  - version
@@ -25135,6 +25159,161 @@ components:
25135
25159
  type: boolean
25136
25160
  FacetValueDefinition:
25137
25161
  $ref: "#/components/schemas/FacetValue"
25162
+ AppDataField:
25163
+ type: object
25164
+ properties:
25165
+ type:
25166
+ $ref: "#/components/schemas/AppDataFieldType"
25167
+ label:
25168
+ type: string
25169
+ description:
25170
+ type: string
25171
+ required:
25172
+ type: boolean
25173
+ localized:
25174
+ type: boolean
25175
+ zone:
25176
+ type: string
25177
+ enum:
25178
+ - data
25179
+ - owner
25180
+ - admin
25181
+ public:
25182
+ type: boolean
25183
+ to:
25184
+ type: string
25185
+ options:
25186
+ type: array
25187
+ items:
25188
+ type: string
25189
+ required:
25190
+ - type
25191
+ AppDataType:
25192
+ type: object
25193
+ properties:
25194
+ description:
25195
+ type: string
25196
+ storage:
25197
+ $ref: "#/components/schemas/AppDataStorage"
25198
+ visibility:
25199
+ type: string
25200
+ enum:
25201
+ - public
25202
+ - owner
25203
+ - admin
25204
+ anchors:
25205
+ type: array
25206
+ items:
25207
+ type: string
25208
+ enum:
25209
+ - product
25210
+ - variant
25211
+ - batch
25212
+ - proof
25213
+ - contact
25214
+ fields:
25215
+ type: object
25216
+ additionalProperties:
25217
+ $ref: "#/components/schemas/AppDataField"
25218
+ listing:
25219
+ type: object
25220
+ additionalProperties: true
25221
+ examples:
25222
+ type: array
25223
+ items:
25224
+ type: object
25225
+ additionalProperties: true
25226
+ read:
25227
+ type: object
25228
+ additionalProperties: true
25229
+ since:
25230
+ type: string
25231
+ required:
25232
+ - description
25233
+ - storage
25234
+ - fields
25235
+ AppDataDeclaration:
25236
+ type: object
25237
+ properties:
25238
+ schemaVersion:
25239
+ type: string
25240
+ types:
25241
+ type: object
25242
+ additionalProperties:
25243
+ $ref: "#/components/schemas/AppDataType"
25244
+ required:
25245
+ - schemaVersion
25246
+ - types
25247
+ AppHeadlessDeclaration:
25248
+ type: object
25249
+ properties:
25250
+ purpose:
25251
+ type: string
25252
+ categories:
25253
+ type: array
25254
+ items:
25255
+ $ref: "#/components/schemas/HeadlessCategory"
25256
+ primaryTypes:
25257
+ type: array
25258
+ items:
25259
+ type: string
25260
+ editedIn:
25261
+ type: object
25262
+ additionalProperties: true
25263
+ render:
25264
+ type: object
25265
+ additionalProperties: true
25266
+ required:
25267
+ - purpose
25268
+ - categories
25269
+ - primaryTypes
25270
+ - editedIn
25271
+ AppDataFieldType:
25272
+ type: string
25273
+ enum:
25274
+ - string
25275
+ - text
25276
+ - richtext
25277
+ - markdown
25278
+ - number
25279
+ - boolean
25280
+ - date
25281
+ - datetime
25282
+ - enum
25283
+ - url
25284
+ - image
25285
+ - file
25286
+ - ref
25287
+ - "string[]"
25288
+ - "ref[]"
25289
+ - json
25290
+ AppDataStorage:
25291
+ type: object
25292
+ additionalProperties: true
25293
+ HeadlessCategory:
25294
+ type: string
25295
+ enum:
25296
+ - faq
25297
+ - media
25298
+ - pages
25299
+ - articles
25300
+ - catalog
25301
+ - events
25302
+ - locations
25303
+ - people
25304
+ - reviews
25305
+ - documents
25306
+ - forms
25307
+ - other
25308
+ HeadlessSeoHelper:
25309
+ type: string
25310
+ enum:
25311
+ - faqPage
25312
+ - product
25313
+ - article
25314
+ - breadcrumbs
25315
+ - organization
25316
+ - localBusiness
25138
25317
  CachedData:
25139
25318
  type: object
25140
25319
  properties:
package/dist/seo.d.ts ADDED
@@ -0,0 +1,85 @@
1
+ export interface SeoHead {
2
+ title?: string;
3
+ description?: string;
4
+ /** Absolute image URL for link previews (og:image / twitter:image). */
5
+ image?: string;
6
+ /** Absolute canonical URL. Usually leave unset: the platform sends the site's canonical address. */
7
+ canonical?: string;
8
+ /** Keep this page out of search engines. */
9
+ noindex?: boolean;
10
+ /** og:type — 'website' (default), 'article' or 'product'. */
11
+ type?: 'website' | 'article' | 'product';
12
+ /** The site's name (og:site_name). */
13
+ siteName?: string;
14
+ }
15
+ /** Set this route's head tags. Call on every route change; unset fields are removed (if we added them). */
16
+ export declare function head(h: SeoHead): void;
17
+ /**
18
+ * Place a JSON-LD structured-data block in <head>. `id` names the block, so calling again replaces it
19
+ * (e.g. per route); pass null to remove it. `<` is escaped so data can't close the script tag.
20
+ */
21
+ export declare function jsonLd(id: string, data: object | object[] | null): void;
22
+ type Obj = Record<string, any>;
23
+ export interface ProductSchemaOptions {
24
+ /** The page's absolute URL. */
25
+ url?: string;
26
+ /** Brand name (defaults to none). */
27
+ brand?: string;
28
+ /** An offer, when the product is sold: price as a number or string, ISO currency, availability. */
29
+ offer?: {
30
+ price: number | string;
31
+ currency: string;
32
+ availability?: 'InStock' | 'OutOfStock' | 'PreOrder';
33
+ url?: string;
34
+ };
35
+ /** Aggregate rating, when the site shows one. */
36
+ rating?: {
37
+ value: number;
38
+ count: number;
39
+ };
40
+ }
41
+ export declare const schema: {
42
+ /** schema.org Product from a SmartLinks product. */
43
+ product(product: Obj, opts?: ProductSchemaOptions): Obj;
44
+ /** schema.org FAQPage — answer-shaped content AI search can cite, and FAQ rich results. */
45
+ faqPage(items: Array<{
46
+ question: string;
47
+ answer: string;
48
+ }>): Obj;
49
+ /** schema.org Organization from a collection (the brand behind the site). */
50
+ organization(collection: Obj, opts?: {
51
+ url?: string;
52
+ sameAs?: string[];
53
+ }): Obj;
54
+ /** schema.org LocalBusiness — for a business with a place (shop, restaurant, studio). */
55
+ localBusiness(collection: Obj, opts?: {
56
+ url?: string;
57
+ telephone?: string;
58
+ address?: {
59
+ street?: string;
60
+ locality?: string;
61
+ region?: string;
62
+ postalCode?: string;
63
+ country?: string;
64
+ };
65
+ openingHours?: string[];
66
+ type?: string;
67
+ }): Obj;
68
+ /** schema.org BreadcrumbList from a trail of { name, url } (home first). */
69
+ breadcrumbs(trail: Array<{
70
+ name: string;
71
+ url: string;
72
+ }>): Obj;
73
+ /** schema.org Article (a blog post, news item, guide). Dates as ISO strings. */
74
+ article(a: {
75
+ headline: string;
76
+ description?: string;
77
+ image?: string;
78
+ url?: string;
79
+ datePublished?: string;
80
+ dateModified?: string;
81
+ author?: string;
82
+ publisher?: string;
83
+ }): Obj;
84
+ };
85
+ export {};
package/dist/seo.js ADDED
@@ -0,0 +1,172 @@
1
+ // =============================================================================
2
+ // SEO + GEO helpers for apps served as websites (framework-agnostic).
3
+ // =============================================================================
4
+ // seo.head() per-route <title>, description, Open Graph / Twitter tags, canonical, robots
5
+ // seo.jsonLd() place a structured-data block (replaces the previous one with the same id)
6
+ // seo.schema.* schema.org builders from platform data (Product, FAQPage, Organization, …)
7
+ //
8
+ // They write plain DOM, so whatever pre-renders the page (the platform's renderer, a crawler that runs
9
+ // JavaScript) captures them. In SSR / no-document environments they're no-ops; the builders are pure.
10
+ // =============================================================================
11
+ const MARK = 'data-sl-seo';
12
+ function doc() {
13
+ return typeof document !== 'undefined' && document && document.head ? document : null;
14
+ }
15
+ function setMeta(d, attr, key, content) {
16
+ let el = d.head.querySelector(`meta[${attr}="${key}"]`);
17
+ if (content === undefined || content === null || content === '') {
18
+ if (el && el.getAttribute(MARK) !== null)
19
+ el.remove();
20
+ return;
21
+ }
22
+ if (!el) {
23
+ el = d.createElement('meta');
24
+ el.setAttribute(attr, key);
25
+ el.setAttribute(MARK, '');
26
+ d.head.appendChild(el);
27
+ }
28
+ el.setAttribute('content', content);
29
+ }
30
+ /** Set this route's head tags. Call on every route change; unset fields are removed (if we added them). */
31
+ export function head(h) {
32
+ const d = doc();
33
+ if (!d)
34
+ return;
35
+ if (h.title)
36
+ d.title = h.title;
37
+ setMeta(d, 'name', 'description', h.description);
38
+ setMeta(d, 'property', 'og:title', h.title);
39
+ setMeta(d, 'property', 'og:description', h.description);
40
+ setMeta(d, 'property', 'og:image', h.image);
41
+ setMeta(d, 'property', 'og:type', h.type || 'website');
42
+ setMeta(d, 'property', 'og:site_name', h.siteName);
43
+ setMeta(d, 'name', 'twitter:card', h.image ? 'summary_large_image' : 'summary');
44
+ setMeta(d, 'name', 'twitter:title', h.title);
45
+ setMeta(d, 'name', 'twitter:description', h.description);
46
+ setMeta(d, 'name', 'twitter:image', h.image);
47
+ setMeta(d, 'name', 'robots', h.noindex ? 'noindex, nofollow' : undefined);
48
+ let link = d.head.querySelector('link[rel="canonical"]');
49
+ if (h.canonical) {
50
+ if (!link) {
51
+ link = d.createElement('link');
52
+ link.setAttribute('rel', 'canonical');
53
+ link.setAttribute(MARK, '');
54
+ d.head.appendChild(link);
55
+ }
56
+ link.setAttribute('href', h.canonical);
57
+ }
58
+ else if (link && link.getAttribute(MARK) !== null) {
59
+ link.remove();
60
+ }
61
+ }
62
+ /**
63
+ * Place a JSON-LD structured-data block in <head>. `id` names the block, so calling again replaces it
64
+ * (e.g. per route); pass null to remove it. `<` is escaped so data can't close the script tag.
65
+ */
66
+ export function jsonLd(id, data) {
67
+ const d = doc();
68
+ if (!d)
69
+ return;
70
+ const sel = `script[type="application/ld+json"][${MARK}="${id}"]`;
71
+ let el = d.head.querySelector(sel);
72
+ if (data === null) {
73
+ if (el)
74
+ el.remove();
75
+ return;
76
+ }
77
+ if (!el) {
78
+ el = d.createElement('script');
79
+ el.setAttribute('type', 'application/ld+json');
80
+ el.setAttribute(MARK, id);
81
+ d.head.appendChild(el);
82
+ }
83
+ el.textContent = JSON.stringify(data).replace(/</g, '\\u003c');
84
+ }
85
+ const CTX = 'https://schema.org';
86
+ /** Drop undefined / null / empty values so the output stays valid and small. */
87
+ function clean(o) {
88
+ for (const k of Object.keys(o)) {
89
+ const v = o[k];
90
+ if (v === undefined || v === null || v === '' || (Array.isArray(v) && v.length === 0))
91
+ delete o[k];
92
+ }
93
+ return o;
94
+ }
95
+ const imageOf = (x) => { var _a, _b, _c; return ((_a = x === null || x === void 0 ? void 0 : x.heroImage) === null || _a === void 0 ? void 0 : _a.url) || ((_b = x === null || x === void 0 ? void 0 : x.logoImage) === null || _b === void 0 ? void 0 : _b.url) || ((_c = x === null || x === void 0 ? void 0 : x.image) === null || _c === void 0 ? void 0 : _c.url) || (typeof (x === null || x === void 0 ? void 0 : x.image) === 'string' ? x.image : undefined); };
96
+ export const schema = {
97
+ /** schema.org Product from a SmartLinks product. */
98
+ product(product, opts = {}) {
99
+ const images = [imageOf(product), ...(product.additionalImages || []).map((i) => i === null || i === void 0 ? void 0 : i.url)].filter(Boolean);
100
+ return clean({
101
+ '@context': CTX,
102
+ '@type': 'Product',
103
+ name: product.name,
104
+ description: product.description || undefined,
105
+ image: images.length > 1 ? images : images[0],
106
+ sku: product.sku || undefined,
107
+ gtin: product.gtin || product.ownGtin || undefined,
108
+ url: opts.url,
109
+ brand: opts.brand ? { '@type': 'Brand', name: opts.brand } : undefined,
110
+ offers: opts.offer ? clean({
111
+ '@type': 'Offer',
112
+ price: String(opts.offer.price),
113
+ priceCurrency: opts.offer.currency,
114
+ availability: opts.offer.availability ? `${CTX}/${opts.offer.availability}` : undefined,
115
+ url: opts.offer.url || opts.url,
116
+ }) : undefined,
117
+ aggregateRating: opts.rating ? { '@type': 'AggregateRating', ratingValue: opts.rating.value, reviewCount: opts.rating.count } : undefined,
118
+ });
119
+ },
120
+ /** schema.org FAQPage — answer-shaped content AI search can cite, and FAQ rich results. */
121
+ faqPage(items) {
122
+ return {
123
+ '@context': CTX,
124
+ '@type': 'FAQPage',
125
+ mainEntity: items.filter((i) => i && i.question && i.answer).map((i) => ({
126
+ '@type': 'Question',
127
+ name: i.question,
128
+ acceptedAnswer: { '@type': 'Answer', text: i.answer },
129
+ })),
130
+ };
131
+ },
132
+ /** schema.org Organization from a collection (the brand behind the site). */
133
+ organization(collection, opts = {}) {
134
+ return clean({
135
+ '@context': CTX,
136
+ '@type': 'Organization',
137
+ name: collection.title || collection.name,
138
+ description: collection.description || undefined,
139
+ logo: imageOf(collection),
140
+ url: opts.url || (collection.hubCustomDomain ? `https://${collection.hubCustomDomain}` : collection.siteHost ? `https://${collection.siteHost}` : undefined),
141
+ sameAs: opts.sameAs,
142
+ });
143
+ },
144
+ /** schema.org LocalBusiness — for a business with a place (shop, restaurant, studio). */
145
+ localBusiness(collection, opts = {}) {
146
+ const a = opts.address;
147
+ return clean(Object.assign(Object.assign({}, schema.organization(collection, { url: opts.url })), { '@type': opts.type || 'LocalBusiness', telephone: opts.telephone, address: a ? clean({ '@type': 'PostalAddress', streetAddress: a.street, addressLocality: a.locality, addressRegion: a.region, postalCode: a.postalCode, addressCountry: a.country }) : undefined, openingHours: opts.openingHours }));
148
+ },
149
+ /** schema.org BreadcrumbList from a trail of { name, url } (home first). */
150
+ breadcrumbs(trail) {
151
+ return {
152
+ '@context': CTX,
153
+ '@type': 'BreadcrumbList',
154
+ itemListElement: trail.map((t, i) => ({ '@type': 'ListItem', position: i + 1, name: t.name, item: t.url })),
155
+ };
156
+ },
157
+ /** schema.org Article (a blog post, news item, guide). Dates as ISO strings. */
158
+ article(a) {
159
+ return clean({
160
+ '@context': CTX,
161
+ '@type': 'Article',
162
+ headline: a.headline,
163
+ description: a.description,
164
+ image: a.image,
165
+ url: a.url,
166
+ datePublished: a.datePublished,
167
+ dateModified: a.dateModified || a.datePublished,
168
+ author: a.author ? { '@type': 'Person', name: a.author } : undefined,
169
+ publisher: a.publisher ? { '@type': 'Organization', name: a.publisher } : undefined,
170
+ });
171
+ },
172
+ };
package/dist/site.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ declare global {
2
+ var __SL_READY__: boolean | undefined;
3
+ }
4
+ /**
5
+ * Tell the platform this page has finished rendering its content (data loaded, head tags set). The
6
+ * platform's page renderer takes its snapshot for search engines and AI crawlers at this point;
7
+ * without it, it waits for the network to go idle (capped). Call once per page, after your data
8
+ * renders. Harmless anywhere else.
9
+ */
10
+ export declare function ready(): void;
package/dist/site.js ADDED
@@ -0,0 +1,18 @@
1
+ // =============================================================================
2
+ // site — for apps served as websites.
3
+ // =============================================================================
4
+ /**
5
+ * Tell the platform this page has finished rendering its content (data loaded, head tags set). The
6
+ * platform's page renderer takes its snapshot for search engines and AI crawlers at this point;
7
+ * without it, it waits for the network to go idle (capped). Call once per page, after your data
8
+ * renders. Harmless anywhere else.
9
+ */
10
+ export function ready() {
11
+ if (typeof globalThis === 'undefined')
12
+ return;
13
+ globalThis.__SL_READY__ = true;
14
+ const w = typeof window !== 'undefined' ? window : null;
15
+ if (w && typeof w.dispatchEvent === 'function' && typeof w.CustomEvent === 'function') {
16
+ w.dispatchEvent(new w.CustomEvent('smartlinks:ready'));
17
+ }
18
+ }
@@ -412,25 +412,22 @@ export interface AiSessionCreate {
412
412
  /** Seed items (e.g. a system/instruction turn). */
413
413
  items?: ResponseInputItem[];
414
414
  }
415
- /** Per-collection AI usage/cost report. `costUnits` are OPAQUE internal units, never provider currency. */
415
+ /** Per-collection AI usage report (daily totals). Usage only — requests, tokens, images; no cost figures. */
416
416
  export interface AiUsageReport {
417
417
  groupBy: string[];
418
418
  from?: string | null;
419
419
  to?: string | null;
420
- totals: {
421
- promptTokens: number;
422
- outputTokens: number;
423
- totalTokens: number;
424
- requests: number;
425
- costUnits: number;
426
- };
427
- groups: Array<Record<string, any> & {
428
- promptTokens: number;
429
- outputTokens: number;
430
- totalTokens: number;
431
- requests: number;
432
- costUnits: number;
433
- }>;
420
+ totals: AiUsageTotals;
421
+ groups: Array<Record<string, any> & AiUsageTotals>;
422
+ }
423
+ /** Summed usage for a report group (or the whole window). */
424
+ export interface AiUsageTotals {
425
+ promptTokens: number;
426
+ outputTokens: number;
427
+ cachedTokens: number;
428
+ totalTokens: number;
429
+ requests: number;
430
+ images: number;
434
431
  }
435
432
  /** Voice session request */
436
433
  export interface VoiceSessionRequest {
@@ -1,5 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
+ import type { AppDataDeclaration, AppHeadlessDeclaration } from './headless.js';
3
4
  /**
4
5
  * A bundle (widget or container) as returned by the collection widgets endpoint.
5
6
  *
@@ -662,6 +663,16 @@ export interface AppManifest {
662
663
  * @see AppManifestFunctions
663
664
  */
664
665
  functions?: AppManifestFunctions;
666
+ /**
667
+ * The app's public data model: its data types, how each is stored, fields, examples and read
668
+ * recipes. Required for `headless`. @see AppDataDeclaration · docs/headless-providers.md
669
+ */
670
+ data?: AppDataDeclaration;
671
+ /**
672
+ * Opt-in: other sites and apps may install this app and use its content (a headless content
673
+ * provider). Validated by `smartlinks-headless`. @see AppHeadlessDeclaration
674
+ */
675
+ headless?: AppHeadlessDeclaration;
665
676
  [key: string]: any;
666
677
  }
667
678
  /**
@@ -1,2 +1 @@
1
- // src/types/appManifest.ts
2
1
  export {};
@@ -48,7 +48,7 @@ export interface Collection {
48
48
  hubCustomDomain?: string;
49
49
  /**
50
50
  * The collection's SITE HOST on the tenant domain — computed by the server, never stored:
51
- * `<hubName>.smartlinks.host` when a name is claimed, else the default `c-<shortId>.smartlinks.host`.
51
+ * `<hubName>.smartlinks.host` when a name is claimed, else the default `c-<collectionId>.smartlinks.host`.
52
52
  * Hub serves it, and app functions are reachable under it at `https://<siteHost>/_fn/…`
53
53
  * (see SL.functions.siteUrl).
54
54
  */
@@ -0,0 +1,96 @@
1
+ /** Field value types. Keep this set small: generated editors, typed reads and sites rely on it. */
2
+ export type AppDataFieldType = 'string' | 'text' | 'richtext' | 'markdown' | 'number' | 'boolean' | 'date' | 'datetime' | 'enum' | 'url' | 'image' | 'file' | 'ref' | 'string[]' | 'ref[]' | 'json';
3
+ export interface AppDataField {
4
+ type: AppDataFieldType;
5
+ label?: string;
6
+ description?: string;
7
+ required?: boolean;
8
+ /** Translated per language (string / text / richtext / markdown only). */
9
+ localized?: boolean;
10
+ /**
11
+ * The JSONB zone it lives in (app objects): `data` (default), `owner`, or `admin`. Only `data`
12
+ * can be public; `admin` is never readable on public endpoints.
13
+ */
14
+ zone?: 'data' | 'owner' | 'admin';
15
+ /** Readable by anonymous visitors (when the item's visibility is public). */
16
+ public?: boolean;
17
+ /** For `ref` / `ref[]`: the declared type id, or 'product' | 'contact' | 'proof'. */
18
+ to?: string;
19
+ /** For `enum`: the allowed values. */
20
+ options?: string[];
21
+ }
22
+ /** How a type's items are stored. */
23
+ export type AppDataStorage =
24
+ /** App records (`SL.app.records`), filtered by recordType. The usual home for content. */
25
+ {
26
+ kind: 'record';
27
+ recordType: string;
28
+ }
29
+ /** App cases (`SL.app.cases`) — requests that get resolved. */
30
+ | {
31
+ kind: 'case';
32
+ category?: string;
33
+ }
34
+ /** App threads (`SL.app.threads`) — discussions, Q&A, reviews. */
35
+ | {
36
+ kind: 'thread';
37
+ slug?: string;
38
+ }
39
+ /** App configuration (`SL.appConfiguration.getConfig` / data items) — settings, small lists. */
40
+ | {
41
+ kind: 'config';
42
+ key?: string;
43
+ };
44
+ export interface AppDataType {
45
+ /** What one item is, in a sentence. */
46
+ description: string;
47
+ storage: AppDataStorage;
48
+ /** The visibility items normally have (app objects): public, owner or admin. Default public. */
49
+ visibility?: 'public' | 'owner' | 'admin';
50
+ /** What an item can be attached to (app objects' anchor columns). */
51
+ anchors?: Array<'product' | 'variant' | 'batch' | 'proof' | 'contact'>;
52
+ fields: Record<string, AppDataField>;
53
+ /** How a site normally lists them. */
54
+ listing?: {
55
+ sort?: string[];
56
+ filters?: string[];
57
+ };
58
+ /** Real-shaped sample items (the `data` zone's JSON). At least one for a headless type. */
59
+ examples?: Array<Record<string, unknown>>;
60
+ /** SDK recipes a site uses. If omitted, the checker prints the standard ones for the storage. */
61
+ read?: {
62
+ list?: string;
63
+ get?: string;
64
+ notes?: string;
65
+ };
66
+ /** The app version that introduced this type. */
67
+ since?: string;
68
+ }
69
+ export interface AppDataDeclaration {
70
+ /** Semver of the data contract itself (not the app's version). Major = breaking. */
71
+ schemaVersion: string;
72
+ types: Record<string, AppDataType>;
73
+ }
74
+ /** What kind of content a provider supplies — how site builders find it. */
75
+ export type HeadlessCategory = 'faq' | 'media' | 'pages' | 'articles' | 'catalog' | 'events' | 'locations' | 'people' | 'reviews' | 'documents' | 'forms' | 'other';
76
+ export declare const HEADLESS_CATEGORIES: readonly HeadlessCategory[];
77
+ /** SEO structured-data helpers a site should use with this content (`SL.seo.schema.*`). */
78
+ export type HeadlessSeoHelper = 'faqPage' | 'product' | 'article' | 'breadcrumbs' | 'organization' | 'localBusiness';
79
+ export interface AppHeadlessDeclaration {
80
+ /** What content this app holds, and when a site should use it rather than build its own. */
81
+ purpose: string;
82
+ categories: HeadlessCategory[];
83
+ /** The `data` types a site renders (the rest are supporting types, e.g. categories). */
84
+ primaryTypes: string[];
85
+ /** Where the business edits the content — the app's admin inside SmartLinks. Sites never build an editor for it. */
86
+ editedIn: {
87
+ label: string;
88
+ adminPath?: string;
89
+ notes?: string;
90
+ };
91
+ /** How a site should present it. */
92
+ render?: {
93
+ guidance?: string;
94
+ seo?: HeadlessSeoHelper[];
95
+ };
96
+ }