@intelex-ia/sdk 0.1.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/README.md +207 -0
- package/dist/client.d.ts +89 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +87 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +91 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +84 -0
- package/dist/react.js.map +1 -0
- package/dist/types.d.ts +81 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# `@intelex-ia/sdk`
|
|
2
|
+
|
|
3
|
+
SDK pra consumir a **Content API IntelexIA** em sites headless (Next.js, Astro etc.). Multiplataforma Fase 2b.
|
|
4
|
+
|
|
5
|
+
> **O que você ganha:** `getArticles` / `getArticleBySlug` tipados, um `<ArticleJsonLd>` pra injetar o schema JSON-LD, e um `articleToMetadata` pra plugar no `generateMetadata` do Next.js App Router. Zero dependências (usa `fetch` global).
|
|
6
|
+
|
|
7
|
+
## Instalação
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @intelex-ia/sdk
|
|
11
|
+
# ou
|
|
12
|
+
npm install @intelex-ia/sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
> **Enquanto não publicamos no npm**, instale via tarball/git URL (peça pro time IntelexIA).
|
|
16
|
+
|
|
17
|
+
## Configuração
|
|
18
|
+
|
|
19
|
+
1. No painel da IntelexIA, **cadastre o site como "Headless (código)"** (vai pedir só domain + opcional revalidate URL/secret).
|
|
20
|
+
2. Abra o site na lista → seção **"Tokens de API (Content API)"** → **Gerar token**. Você recebe `itx_…` (mostrado uma única vez).
|
|
21
|
+
3. Coloque o token em `.env.local`:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
INTELEXIA_TOKEN=itx_seu_token_aqui
|
|
25
|
+
INTELEXIA_API_URL=https://api.innovarticles.intelexia.com.br # opcional, é o default
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Uso (Next.js App Router)
|
|
29
|
+
|
|
30
|
+
### Cliente — `lib/intelexia.ts`
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createClient } from "@intelex-ia/sdk";
|
|
34
|
+
|
|
35
|
+
export const intelexia = createClient({
|
|
36
|
+
token: process.env.INTELEXIA_TOKEN!,
|
|
37
|
+
// ISR: revalida a cada 60s (ou use webhook revalidate pra invalidar
|
|
38
|
+
// sob demanda — ver mais abaixo).
|
|
39
|
+
init: { next: { revalidate: 60, tags: ["intelexia-articles"] } },
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Listagem — `app/blog/page.tsx` (Server Component)
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { intelexia } from "@/lib/intelexia";
|
|
47
|
+
import Link from "next/link";
|
|
48
|
+
|
|
49
|
+
export default async function BlogIndex() {
|
|
50
|
+
const { items } = await intelexia.getArticles({ limit: 20 });
|
|
51
|
+
return (
|
|
52
|
+
<main>
|
|
53
|
+
<h1>Blog</h1>
|
|
54
|
+
<ul>
|
|
55
|
+
{items.map((a) => (
|
|
56
|
+
<li key={a.id}>
|
|
57
|
+
<Link href={`/blog/${a.slug}`}>{a.title}</Link>
|
|
58
|
+
{a.publishedAt && (
|
|
59
|
+
<time>{new Date(a.publishedAt).toLocaleDateString("pt-BR")}</time>
|
|
60
|
+
)}
|
|
61
|
+
</li>
|
|
62
|
+
))}
|
|
63
|
+
</ul>
|
|
64
|
+
</main>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Post — `app/blog/[slug]/page.tsx` (com SEO completo)
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { intelexia } from "@/lib/intelexia";
|
|
73
|
+
import { ArticleJsonLd, articleToMetadata } from "@intelex-ia/sdk/react";
|
|
74
|
+
import { IntelexiaApiError } from "@intelex-ia/sdk";
|
|
75
|
+
import { notFound } from "next/navigation";
|
|
76
|
+
|
|
77
|
+
async function fetchArticle(slug: string) {
|
|
78
|
+
try {
|
|
79
|
+
return await intelexia.getArticleBySlug(slug);
|
|
80
|
+
} catch (err) {
|
|
81
|
+
if (err instanceof IntelexiaApiError && err.status === 404) notFound();
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function generateMetadata({
|
|
87
|
+
params,
|
|
88
|
+
}: {
|
|
89
|
+
params: Promise<{ slug: string }>;
|
|
90
|
+
}) {
|
|
91
|
+
const { slug } = await params;
|
|
92
|
+
const { article } = await fetchArticle(slug);
|
|
93
|
+
return articleToMetadata(article); // → title, description, OG, Twitter, keywords
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export default async function PostPage({
|
|
97
|
+
params,
|
|
98
|
+
}: {
|
|
99
|
+
params: Promise<{ slug: string }>;
|
|
100
|
+
}) {
|
|
101
|
+
const { slug } = await params;
|
|
102
|
+
const { article } = await fetchArticle(slug);
|
|
103
|
+
return (
|
|
104
|
+
<article>
|
|
105
|
+
{/* Schema JSON-LD (Article/Breadcrumb/FAQ/HowTo/Org/Person) */}
|
|
106
|
+
<ArticleJsonLd article={article} />
|
|
107
|
+
|
|
108
|
+
<h1>{article.title}</h1>
|
|
109
|
+
{article.featuredImageUrl && (
|
|
110
|
+
<img src={article.featuredImageUrl} alt={article.title ?? ""} />
|
|
111
|
+
)}
|
|
112
|
+
<div
|
|
113
|
+
dangerouslySetInnerHTML={{ __html: article.contentHtml ?? "" }}
|
|
114
|
+
/>
|
|
115
|
+
</article>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Webhook de revalidate — `app/api/revalidate/route.ts`
|
|
121
|
+
|
|
122
|
+
Quando um artigo publica no painel, o worker IntelexIA faz um `POST` no seu endpoint de revalidate (configurado no cadastro do site). Implemente assim:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { NextResponse } from "next/server";
|
|
126
|
+
import { revalidatePath, revalidateTag } from "next/cache";
|
|
127
|
+
|
|
128
|
+
export async function POST(req: Request) {
|
|
129
|
+
// Autentica com o secret cadastrado no painel (header X ou body)
|
|
130
|
+
const headerSecret = req.headers.get("x-revalidate-secret");
|
|
131
|
+
const body = (await req.json().catch(() => ({}))) as {
|
|
132
|
+
secret?: string;
|
|
133
|
+
slug?: string | null;
|
|
134
|
+
domain?: string;
|
|
135
|
+
};
|
|
136
|
+
const got = headerSecret ?? body.secret ?? "";
|
|
137
|
+
if (!process.env.INTELEXIA_REVALIDATE_SECRET || got !== process.env.INTELEXIA_REVALIDATE_SECRET) {
|
|
138
|
+
return NextResponse.json({ ok: false, error: "unauthorized" }, { status: 401 });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Revalida a página do post (se veio slug) e o índice do blog.
|
|
142
|
+
if (body.slug) revalidatePath(`/blog/${body.slug}`);
|
|
143
|
+
revalidatePath("/blog");
|
|
144
|
+
revalidateTag("intelexia-articles");
|
|
145
|
+
|
|
146
|
+
return NextResponse.json({ ok: true, revalidated: { slug: body.slug ?? null } });
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
E no `.env.local`:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
INTELEXIA_REVALIDATE_SECRET=cole-o-mesmo-segredo-do-painel
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
> O worker envia o secret tanto em `x-revalidate-secret` quanto no body (`{ secret, slug, domain }`), tem timeout de 15s e é **fire-and-forget** (se o seu endpoint falhar, o artigo continua publicado e a ISR atualiza pelo `revalidate: 60`).
|
|
157
|
+
|
|
158
|
+
## API
|
|
159
|
+
|
|
160
|
+
### `createClient(config)`
|
|
161
|
+
|
|
162
|
+
| Opção | Tipo | Default |
|
|
163
|
+
| -------- | -------------------- | ------------------------------------------------- |
|
|
164
|
+
| `token` | `string` (obrig.) | — |
|
|
165
|
+
| `apiUrl` | `string` | `https://api.innovarticles.intelexia.com.br` |
|
|
166
|
+
| `fetch` | `typeof fetch` | `globalThis.fetch` |
|
|
167
|
+
| `init` | `RequestInit` | `undefined` (passe `{ next: { revalidate: N } }`) |
|
|
168
|
+
|
|
169
|
+
### `client.getArticles({ limit?, offset?, init? })`
|
|
170
|
+
|
|
171
|
+
Resposta: `{ ok, mode, lifecycle, count, items: ArticleListItem[] }`.
|
|
172
|
+
|
|
173
|
+
### `client.getArticleBySlug(slug, { init? })`
|
|
174
|
+
|
|
175
|
+
Resposta: `{ ok, mode, lifecycle, article: Article }`. **404 → joga `IntelexiaApiError`** (use `try/catch` + `notFound()`).
|
|
176
|
+
|
|
177
|
+
### `mode: "full" | "plain"`
|
|
178
|
+
|
|
179
|
+
- **`full`** (sites `active`/`paused`): inclui schema JSON-LD, metaTitle/Description, keyword(s), interlinking interno no `contentHtml`.
|
|
180
|
+
- **`plain`** (site `cancelled`): só conteúdo cru — schema/meta/keywords vêm `null`, interlinking removido. O `ArticleJsonLd` e o `articleToMetadata` lidam graciosamente (omitem o que não tem).
|
|
181
|
+
|
|
182
|
+
A decisão é **server-side e não-negociável** — o cliente não escolhe o modo.
|
|
183
|
+
|
|
184
|
+
### Helpers `/react`
|
|
185
|
+
|
|
186
|
+
- `<ArticleJsonLd article={article} />` — renderiza `<script type="application/ld+json">` com o `schemaJson`. No-op se ausente.
|
|
187
|
+
- `articleToMetadata(article)` → objeto compatível com o `Metadata` do Next.js App Router (title, description, keywords, openGraph, twitter, customMetaTags como `other`).
|
|
188
|
+
|
|
189
|
+
## Erros
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
import { IntelexiaApiError } from "@intelex-ia/sdk";
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
await intelexia.getArticleBySlug("post-inexistente");
|
|
196
|
+
} catch (err) {
|
|
197
|
+
if (err instanceof IntelexiaApiError) {
|
|
198
|
+
console.error(err.status, err.message); // 404, "Artigo não encontrado."
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Compatibilidade
|
|
204
|
+
|
|
205
|
+
- Node 18+ (fetch nativo), Edge Runtime, Browser.
|
|
206
|
+
- React 18+ (peer dep opcional — só pros helpers `/react`).
|
|
207
|
+
- TypeScript: tipos publicados no `dist`.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cliente HTTP do `@intelex-ia/sdk`. Zero dependências (usa fetch global).
|
|
3
|
+
* Compatível com Next.js App Router (Server Components): aceita `init`
|
|
4
|
+
* customizado (ex.: `{ next: { revalidate: 60 } }` pra ISR).
|
|
5
|
+
*/
|
|
6
|
+
import type { Article, ArticleListItem, Lifecycle, Mode } from "./types.js";
|
|
7
|
+
/** Configuração do cliente. */
|
|
8
|
+
export interface ClientConfig {
|
|
9
|
+
/**
|
|
10
|
+
* URL base da API IntelexIA. Default:
|
|
11
|
+
* `https://api.innovarticles.intelexia.com.br`.
|
|
12
|
+
*/
|
|
13
|
+
apiUrl?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Token `itx_…` gerado no painel (Sites → seção "Tokens de API"). É
|
|
16
|
+
* SITE-SCOPED: cada token só lê os artigos do site dono.
|
|
17
|
+
*/
|
|
18
|
+
token: string;
|
|
19
|
+
/**
|
|
20
|
+
* Função de fetch (opcional). Default: `globalThis.fetch`. Útil pra
|
|
21
|
+
* injetar mock em testes ou um fetch wrappado.
|
|
22
|
+
*/
|
|
23
|
+
fetch?: typeof fetch;
|
|
24
|
+
/**
|
|
25
|
+
* `RequestInit` aplicado em TODA chamada. Use pra:
|
|
26
|
+
* - Next.js App Router: `{ next: { revalidate: 60, tags: ["articles"] } }`
|
|
27
|
+
* - Astro: `{ cache: "force-cache" }`
|
|
28
|
+
* - Cancelar via AbortSignal global, etc.
|
|
29
|
+
*/
|
|
30
|
+
init?: RequestInit;
|
|
31
|
+
}
|
|
32
|
+
/** Resposta de GET /v1/articles. */
|
|
33
|
+
export interface ArticlesListResponse {
|
|
34
|
+
ok: true;
|
|
35
|
+
mode: Mode;
|
|
36
|
+
lifecycle: Lifecycle;
|
|
37
|
+
count: number;
|
|
38
|
+
items: ArticleListItem[];
|
|
39
|
+
}
|
|
40
|
+
/** Resposta de GET /v1/articles/:slug. */
|
|
41
|
+
export interface ArticleResponse {
|
|
42
|
+
ok: true;
|
|
43
|
+
mode: Mode;
|
|
44
|
+
lifecycle: Lifecycle;
|
|
45
|
+
article: Article;
|
|
46
|
+
}
|
|
47
|
+
/** Erro HTTP da Content API com status + mensagem. */
|
|
48
|
+
export declare class IntelexiaApiError extends Error {
|
|
49
|
+
readonly status: number;
|
|
50
|
+
readonly path?: string | undefined;
|
|
51
|
+
constructor(status: number, message: string, path?: string | undefined);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Cria uma instância do cliente. O retorno tem os métodos `getArticles` e
|
|
55
|
+
* `getArticleBySlug`. Idempotente — pode ser instanciado uma vez por process
|
|
56
|
+
* (Node/Edge) e reusado.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createClient(config: ClientConfig): {
|
|
59
|
+
/**
|
|
60
|
+
* Lista os artigos publicados do site (mais recentes primeiro).
|
|
61
|
+
* Em sites cancelados, retorna a versão "plain" (sem metaTitle/Description).
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* const { items } = await client.getArticles({ limit: 10 });
|
|
65
|
+
*/
|
|
66
|
+
getArticles(opts?: {
|
|
67
|
+
limit?: number;
|
|
68
|
+
offset?: number;
|
|
69
|
+
/** Override do `init` desta chamada específica. */
|
|
70
|
+
init?: RequestInit;
|
|
71
|
+
}): Promise<ArticlesListResponse>;
|
|
72
|
+
/**
|
|
73
|
+
* Busca um artigo publicado pelo slug. 404 vira `IntelexiaApiError`.
|
|
74
|
+
* Em sites cancelados, retorna a versão "plain" (sem schema/meta/keywords).
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* try {
|
|
78
|
+
* const { article, mode } = await client.getArticleBySlug("meu-post");
|
|
79
|
+
* } catch (err) {
|
|
80
|
+
* if (err instanceof IntelexiaApiError && err.status === 404) notFound();
|
|
81
|
+
* }
|
|
82
|
+
*/
|
|
83
|
+
getArticleBySlug(slug: string, opts?: {
|
|
84
|
+
init?: RequestInit;
|
|
85
|
+
}): Promise<ArticleResponse>;
|
|
86
|
+
};
|
|
87
|
+
/** Tipo do retorno de `createClient` (útil pra passar adiante). */
|
|
88
|
+
export type IntelexiaClient = ReturnType<typeof createClient>;
|
|
89
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,SAAS,EACT,IAAI,EACL,MAAM,YAAY,CAAC;AAEpB,+BAA+B;AAC/B,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED,oCAAoC;AACpC,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,0CAA0C;AAC1C,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,sDAAsD;AACtD,qBAAa,iBAAkB,SAAQ,KAAK;aAExB,MAAM,EAAE,MAAM;aAEd,IAAI,CAAC,EAAE,MAAM;gBAFb,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM,EACC,IAAI,CAAC,EAAE,MAAM,YAAA;CAKhC;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY;IAwC7C;;;;;;OAMG;uBACsB;QACvB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,mDAAmD;QACnD,IAAI,CAAC,EAAE,WAAW,CAAC;KACpB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAWjC;;;;;;;;;;OAUG;2BAEK,MAAM,SACL;QAAE,IAAI,CAAC,EAAE,WAAW,CAAA;KAAE,GAC5B,OAAO,CAAC,eAAe,CAAC;EAK9B;AAED,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** Erro HTTP da Content API com status + mensagem. */
|
|
2
|
+
export class IntelexiaApiError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
path;
|
|
5
|
+
constructor(status, message, path) {
|
|
6
|
+
super(`[IntelexiaApi ${status}${path ? ` ${path}` : ""}] ${message}`);
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.path = path;
|
|
9
|
+
this.name = "IntelexiaApiError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const DEFAULT_API_URL = "https://api.innovarticles.intelexia.com.br";
|
|
13
|
+
/**
|
|
14
|
+
* Cria uma instância do cliente. O retorno tem os métodos `getArticles` e
|
|
15
|
+
* `getArticleBySlug`. Idempotente — pode ser instanciado uma vez por process
|
|
16
|
+
* (Node/Edge) e reusado.
|
|
17
|
+
*/
|
|
18
|
+
export function createClient(config) {
|
|
19
|
+
if (!config.token || !config.token.startsWith("itx_")) {
|
|
20
|
+
throw new Error("[@intelex-ia/sdk] token inválido — esperado um token `itx_…` gerado no painel.");
|
|
21
|
+
}
|
|
22
|
+
const fetchFn = config.fetch ?? globalThis.fetch;
|
|
23
|
+
if (typeof fetchFn !== "function") {
|
|
24
|
+
throw new Error("[@intelex-ia/sdk] fetch não encontrado — passe `config.fetch` ou rode em ambiente com fetch global (Node 18+, Edge, browser).");
|
|
25
|
+
}
|
|
26
|
+
const apiUrl = (config.apiUrl ?? DEFAULT_API_URL).replace(/\/+$/, "");
|
|
27
|
+
async function request(path, init) {
|
|
28
|
+
const url = `${apiUrl}${path}`;
|
|
29
|
+
const res = await fetchFn(url, {
|
|
30
|
+
...config.init,
|
|
31
|
+
...init,
|
|
32
|
+
headers: {
|
|
33
|
+
Authorization: `Bearer ${config.token}`,
|
|
34
|
+
Accept: "application/json",
|
|
35
|
+
...config.init?.headers,
|
|
36
|
+
...init?.headers,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
let msg = res.statusText || `HTTP ${res.status}`;
|
|
41
|
+
try {
|
|
42
|
+
const body = (await res.json());
|
|
43
|
+
if (body?.error)
|
|
44
|
+
msg = body.error;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// ignore parse errors — usa msg padrão
|
|
48
|
+
}
|
|
49
|
+
throw new IntelexiaApiError(res.status, msg, path);
|
|
50
|
+
}
|
|
51
|
+
return (await res.json());
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
/**
|
|
55
|
+
* Lista os artigos publicados do site (mais recentes primeiro).
|
|
56
|
+
* Em sites cancelados, retorna a versão "plain" (sem metaTitle/Description).
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* const { items } = await client.getArticles({ limit: 10 });
|
|
60
|
+
*/
|
|
61
|
+
async getArticles(opts) {
|
|
62
|
+
const params = new URLSearchParams();
|
|
63
|
+
if (opts?.limit != null)
|
|
64
|
+
params.set("limit", String(opts.limit));
|
|
65
|
+
if (opts?.offset != null)
|
|
66
|
+
params.set("offset", String(opts.offset));
|
|
67
|
+
const qs = params.toString();
|
|
68
|
+
return request(`/v1/articles${qs ? `?${qs}` : ""}`, opts?.init);
|
|
69
|
+
},
|
|
70
|
+
/**
|
|
71
|
+
* Busca um artigo publicado pelo slug. 404 vira `IntelexiaApiError`.
|
|
72
|
+
* Em sites cancelados, retorna a versão "plain" (sem schema/meta/keywords).
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* try {
|
|
76
|
+
* const { article, mode } = await client.getArticleBySlug("meu-post");
|
|
77
|
+
* } catch (err) {
|
|
78
|
+
* if (err instanceof IntelexiaApiError && err.status === 404) notFound();
|
|
79
|
+
* }
|
|
80
|
+
*/
|
|
81
|
+
async getArticleBySlug(slug, opts) {
|
|
82
|
+
const safeSlug = encodeURIComponent(slug);
|
|
83
|
+
return request(`/v1/articles/${safeSlug}`, opts?.init);
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry pública do `@intelex-ia/sdk` — core (sem React).
|
|
3
|
+
*
|
|
4
|
+
* Pra os helpers React (ArticleJsonLd, articleToMetadata), importe de
|
|
5
|
+
* `@intelex-ia/sdk/react`.
|
|
6
|
+
*/
|
|
7
|
+
export { createClient, IntelexiaApiError, type ClientConfig, type ArticlesListResponse, type ArticleResponse, type IntelexiaClient, } from "./client.js";
|
|
8
|
+
export type { Lifecycle, Mode, Article, ArticleListItem, CustomMetaTag, ErrorResponse, } from "./types.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,SAAS,EACT,IAAI,EACJ,OAAO,EACP,eAAe,EACf,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry pública do `@intelex-ia/sdk` — core (sem React).
|
|
3
|
+
*
|
|
4
|
+
* Pra os helpers React (ArticleJsonLd, articleToMetadata), importe de
|
|
5
|
+
* `@intelex-ia/sdk/react`.
|
|
6
|
+
*/
|
|
7
|
+
export { createClient, IntelexiaApiError, } from "./client.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,YAAY,EACZ,iBAAiB,GAKlB,MAAM,aAAa,CAAC"}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers React do `@intelex-ia/sdk`. Import:
|
|
3
|
+
*
|
|
4
|
+
* import { ArticleJsonLd, articleToMetadata } from "@intelex-ia/sdk/react";
|
|
5
|
+
*
|
|
6
|
+
* Compatível com Next.js App Router (Server Components) e qualquer
|
|
7
|
+
* framework React 18+.
|
|
8
|
+
*/
|
|
9
|
+
import type { ReactElement } from "react";
|
|
10
|
+
import type { CustomMetaTag } from "./types.js";
|
|
11
|
+
/** Subset mínimo de Article necessário pro `<ArticleJsonLd>`. */
|
|
12
|
+
interface ArticleSchemaInput {
|
|
13
|
+
schemaJson?: unknown | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Renderiza um `<script type="application/ld+json">` com o schema JSON-LD do
|
|
17
|
+
* artigo. Pode ser colocado em qualquer lugar do `<body>` — o Google lê tanto
|
|
18
|
+
* no `<head>` quanto no body, mas no body é mais compatível com o React do
|
|
19
|
+
* Next.js App Router (que prefere a Metadata API pro `<head>`).
|
|
20
|
+
*
|
|
21
|
+
* No-op (retorna null) quando `article.schemaJson` é null/undefined — útil pra
|
|
22
|
+
* sites cancelados (modo "plain"), que não recebem schema.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // app/blog/[slug]/page.tsx
|
|
26
|
+
* import { ArticleJsonLd } from "@intelex-ia/sdk/react";
|
|
27
|
+
* export default async function Page({ params }) {
|
|
28
|
+
* const { article } = await client.getArticleBySlug(params.slug);
|
|
29
|
+
* return (
|
|
30
|
+
* <>
|
|
31
|
+
* <ArticleJsonLd article={article} />
|
|
32
|
+
* <article dangerouslySetInnerHTML={{ __html: article.contentHtml ?? "" }} />
|
|
33
|
+
* </>
|
|
34
|
+
* );
|
|
35
|
+
* }
|
|
36
|
+
*/
|
|
37
|
+
export declare function ArticleJsonLd({ article, }: {
|
|
38
|
+
article: ArticleSchemaInput;
|
|
39
|
+
}): ReactElement | null;
|
|
40
|
+
/** Subset mínimo de Article necessário pro `articleToMetadata`. */
|
|
41
|
+
interface ArticleMetadataInput {
|
|
42
|
+
title?: string | null;
|
|
43
|
+
metaTitle?: string | null;
|
|
44
|
+
metaDescription?: string | null;
|
|
45
|
+
featuredImageUrl?: string | null;
|
|
46
|
+
keyword?: string | null;
|
|
47
|
+
keywordSynonyms?: string[] | null;
|
|
48
|
+
customMetaTags?: CustomMetaTag[] | null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resultado do `articleToMetadata`. Compatível com o tipo `Metadata` do
|
|
52
|
+
* Next.js App Router (mas não importa de "next" — mantém o SDK
|
|
53
|
+
* framework-agnostic). Sites Astro/Remix também podem usar como referência.
|
|
54
|
+
*/
|
|
55
|
+
export interface ArticleMetadata {
|
|
56
|
+
title?: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
keywords?: string[];
|
|
59
|
+
openGraph?: {
|
|
60
|
+
title?: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
images?: {
|
|
63
|
+
url: string;
|
|
64
|
+
}[];
|
|
65
|
+
};
|
|
66
|
+
twitter?: {
|
|
67
|
+
card: "summary_large_image";
|
|
68
|
+
title?: string;
|
|
69
|
+
description?: string;
|
|
70
|
+
images?: string[];
|
|
71
|
+
};
|
|
72
|
+
other?: Record<string, string>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Converte um Article do SDK em um objeto de metadata compatível com o
|
|
76
|
+
* `Metadata` do Next.js App Router. Use em `generateMetadata`:
|
|
77
|
+
*
|
|
78
|
+
* // app/blog/[slug]/page.tsx
|
|
79
|
+
* import { articleToMetadata } from "@intelex-ia/sdk/react";
|
|
80
|
+
* export async function generateMetadata({ params }) {
|
|
81
|
+
* const { article } = await client.getArticleBySlug(params.slug);
|
|
82
|
+
* return articleToMetadata(article);
|
|
83
|
+
* }
|
|
84
|
+
*
|
|
85
|
+
* Cobre title/description, keywords, OG (title/description/image) e Twitter
|
|
86
|
+
* (summary_large_image). `customMetaTags` (OG/Twitter custom configurados no
|
|
87
|
+
* painel) entram em `other` como `name=value` ou `property=value`.
|
|
88
|
+
*/
|
|
89
|
+
export declare function articleToMetadata(article: ArticleMetadataInput): ArticleMetadata;
|
|
90
|
+
export type { Article, CustomMetaTag } from "./types.js";
|
|
91
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,KAAK,EAAW,aAAa,EAAE,MAAM,YAAY,CAAC;AAEzD,iEAAiE;AACjE,UAAU,kBAAkB;IAC1B,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,GACR,EAAE;IACD,OAAO,EAAE,kBAAkB,CAAC;CAC7B,GAAG,YAAY,GAAG,IAAI,CAYtB;AAED,mEAAmE;AACnE,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC,cAAc,CAAC,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;CACzC;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE;QACV,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KAC5B,CAAC;IACF,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,qBAAqB,CAAC;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,oBAAoB,GAC5B,eAAe,CAiCjB;AAGD,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Renderiza um `<script type="application/ld+json">` com o schema JSON-LD do
|
|
4
|
+
* artigo. Pode ser colocado em qualquer lugar do `<body>` — o Google lê tanto
|
|
5
|
+
* no `<head>` quanto no body, mas no body é mais compatível com o React do
|
|
6
|
+
* Next.js App Router (que prefere a Metadata API pro `<head>`).
|
|
7
|
+
*
|
|
8
|
+
* No-op (retorna null) quando `article.schemaJson` é null/undefined — útil pra
|
|
9
|
+
* sites cancelados (modo "plain"), que não recebem schema.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // app/blog/[slug]/page.tsx
|
|
13
|
+
* import { ArticleJsonLd } from "@intelex-ia/sdk/react";
|
|
14
|
+
* export default async function Page({ params }) {
|
|
15
|
+
* const { article } = await client.getArticleBySlug(params.slug);
|
|
16
|
+
* return (
|
|
17
|
+
* <>
|
|
18
|
+
* <ArticleJsonLd article={article} />
|
|
19
|
+
* <article dangerouslySetInnerHTML={{ __html: article.contentHtml ?? "" }} />
|
|
20
|
+
* </>
|
|
21
|
+
* );
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
export function ArticleJsonLd({ article, }) {
|
|
25
|
+
if (!article.schemaJson)
|
|
26
|
+
return null;
|
|
27
|
+
return (_jsx("script", { type: "application/ld+json",
|
|
28
|
+
// JSON.stringify garante escaping de aspas/HTML — não tem XSS aqui
|
|
29
|
+
// (schema vem do nosso banco, controlado).
|
|
30
|
+
dangerouslySetInnerHTML: {
|
|
31
|
+
__html: JSON.stringify(article.schemaJson),
|
|
32
|
+
} }));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Converte um Article do SDK em um objeto de metadata compatível com o
|
|
36
|
+
* `Metadata` do Next.js App Router. Use em `generateMetadata`:
|
|
37
|
+
*
|
|
38
|
+
* // app/blog/[slug]/page.tsx
|
|
39
|
+
* import { articleToMetadata } from "@intelex-ia/sdk/react";
|
|
40
|
+
* export async function generateMetadata({ params }) {
|
|
41
|
+
* const { article } = await client.getArticleBySlug(params.slug);
|
|
42
|
+
* return articleToMetadata(article);
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* Cobre title/description, keywords, OG (title/description/image) e Twitter
|
|
46
|
+
* (summary_large_image). `customMetaTags` (OG/Twitter custom configurados no
|
|
47
|
+
* painel) entram em `other` como `name=value` ou `property=value`.
|
|
48
|
+
*/
|
|
49
|
+
export function articleToMetadata(article) {
|
|
50
|
+
const title = article.metaTitle ?? article.title ?? undefined;
|
|
51
|
+
const description = article.metaDescription ?? undefined;
|
|
52
|
+
const image = article.featuredImageUrl ?? undefined;
|
|
53
|
+
const keywords = [
|
|
54
|
+
...(article.keyword ? [article.keyword] : []),
|
|
55
|
+
...(article.keywordSynonyms ?? []),
|
|
56
|
+
].filter(Boolean);
|
|
57
|
+
const other = {};
|
|
58
|
+
for (const tag of article.customMetaTags ?? []) {
|
|
59
|
+
if (tag?.content == null)
|
|
60
|
+
continue;
|
|
61
|
+
if (tag.property)
|
|
62
|
+
other[tag.property] = tag.content;
|
|
63
|
+
else if (tag.name)
|
|
64
|
+
other[tag.name] = tag.content;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
...(title ? { title } : {}),
|
|
68
|
+
...(description ? { description } : {}),
|
|
69
|
+
...(keywords.length > 0 ? { keywords } : {}),
|
|
70
|
+
openGraph: {
|
|
71
|
+
...(title ? { title } : {}),
|
|
72
|
+
...(description ? { description } : {}),
|
|
73
|
+
...(image ? { images: [{ url: image }] } : {}),
|
|
74
|
+
},
|
|
75
|
+
twitter: {
|
|
76
|
+
card: "summary_large_image",
|
|
77
|
+
...(title ? { title } : {}),
|
|
78
|
+
...(description ? { description } : {}),
|
|
79
|
+
...(image ? { images: [image] } : {}),
|
|
80
|
+
},
|
|
81
|
+
...(Object.keys(other).length > 0 ? { other } : {}),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tipos públicos do `@intelex-ia/sdk`. Espelham o shape REAL da Content API /v1
|
|
3
|
+
* (ver apps/api/src/routes/content-api.ts). Mantém compatibilidade futura:
|
|
4
|
+
* campos opcionais ficam `?:` pra não quebrar quando a API evolui.
|
|
5
|
+
*/
|
|
6
|
+
/** Ciclo de vida comercial do site — define se a inteligência é servida. */
|
|
7
|
+
export type Lifecycle = "active" | "paused" | "cancelled";
|
|
8
|
+
/**
|
|
9
|
+
* Modo da resposta:
|
|
10
|
+
* - "full": site `active`/`paused` → inclui inteligência (schema, meta SEO,
|
|
11
|
+
* keywords, interlinking dentro do contentHtml).
|
|
12
|
+
* - "plain": site `cancelled` → só conteúdo cru (sem schema/meta/keywords;
|
|
13
|
+
* interlinking interno removido do HTML).
|
|
14
|
+
*/
|
|
15
|
+
export type Mode = "full" | "plain";
|
|
16
|
+
/** Custom meta tag (OG/Twitter custom configurado globalmente no painel). */
|
|
17
|
+
export interface CustomMetaTag {
|
|
18
|
+
name?: string | null;
|
|
19
|
+
property?: string | null;
|
|
20
|
+
content: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Item de listagem (GET /v1/articles). Campos comuns. Em modo "full" inclui
|
|
24
|
+
* também `metaTitle`/`metaDescription`; em "plain" eles vêm ausentes.
|
|
25
|
+
*/
|
|
26
|
+
export interface ArticleListItem {
|
|
27
|
+
id: string;
|
|
28
|
+
slug: string | null;
|
|
29
|
+
title: string | null;
|
|
30
|
+
featuredImageUrl: string | null;
|
|
31
|
+
words: number;
|
|
32
|
+
publishedAt: string | null;
|
|
33
|
+
/** Só presente em modo "full". */
|
|
34
|
+
metaTitle?: string | null;
|
|
35
|
+
/** Só presente em modo "full". */
|
|
36
|
+
metaDescription?: string | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Artigo completo (GET /v1/articles/:slug). Tipo unificado — em modo "plain"
|
|
40
|
+
* os campos de inteligência (schemaJson, metaTitle, keyword, etc.) vêm
|
|
41
|
+
* ausentes/null porque o plain-serializer os omite. Use o `mode` da resposta
|
|
42
|
+
* pra saber qual versão você recebeu.
|
|
43
|
+
*/
|
|
44
|
+
export interface Article {
|
|
45
|
+
id: string;
|
|
46
|
+
title: string | null;
|
|
47
|
+
slug: string | null;
|
|
48
|
+
/** Em "full" inclui interlinking; em "plain" o interlinking é removido. */
|
|
49
|
+
contentHtml: string | null;
|
|
50
|
+
featuredImageUrl: string | null;
|
|
51
|
+
ctaImage1Url?: string | null;
|
|
52
|
+
ctaImage1Title?: string | null;
|
|
53
|
+
ctaImage1Subtitle?: string | null;
|
|
54
|
+
ctaImage2Url?: string | null;
|
|
55
|
+
ctaImage2Title?: string | null;
|
|
56
|
+
ctaImage2Subtitle?: string | null;
|
|
57
|
+
ctaImage3Url?: string | null;
|
|
58
|
+
ctaImage3Title?: string | null;
|
|
59
|
+
ctaImage3Subtitle?: string | null;
|
|
60
|
+
categoryIds?: number[] | null;
|
|
61
|
+
primaryCategoryId?: number | null;
|
|
62
|
+
tagNames?: string[] | null;
|
|
63
|
+
words?: number | null;
|
|
64
|
+
metaTitle?: string | null;
|
|
65
|
+
metaDescription?: string | null;
|
|
66
|
+
keyword?: string | null;
|
|
67
|
+
keywordSynonyms?: string[] | null;
|
|
68
|
+
additionalKeywords?: string[] | null;
|
|
69
|
+
/** JSON-LD @graph (Article/WebPage/Breadcrumb/FAQ/HowTo/Org/Person). */
|
|
70
|
+
schemaJson?: unknown | null;
|
|
71
|
+
/** Meta tags custom (OG/Twitter customizados no painel). */
|
|
72
|
+
customMetaTags?: CustomMetaTag[] | null;
|
|
73
|
+
seoScore?: number | null;
|
|
74
|
+
publishedAt?: string | null;
|
|
75
|
+
}
|
|
76
|
+
/** Resposta de erro padrão (HTTP 4xx/5xx). */
|
|
77
|
+
export interface ErrorResponse {
|
|
78
|
+
ok: false;
|
|
79
|
+
error: string;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC;AAEpC,6EAA6E;AAC7E,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,kCAAkC;IAClC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAEhC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACrC,wEAAwE;IACxE,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5B,4DAA4D;IAC5D,cAAc,CAAC,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,8CAA8C;AAC9C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;CACf"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tipos públicos do `@intelex-ia/sdk`. Espelham o shape REAL da Content API /v1
|
|
3
|
+
* (ver apps/api/src/routes/content-api.ts). Mantém compatibilidade futura:
|
|
4
|
+
* campos opcionais ficam `?:` pra não quebrar quando a API evolui.
|
|
5
|
+
*/
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intelex-ia/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "SDK pra consumir a Content API da IntelexIA em sites headless (Next.js, Astro, etc.). Multiplataforma Fase 2b.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "intelex-ia",
|
|
7
|
+
"homepage": "https://github.com/intelex-ia/combo_automatico/tree/main/packages/sdk",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/intelex-ia/combo_automatico.git",
|
|
11
|
+
"directory": "packages/sdk"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/intelex-ia/combo_automatico/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"intelexia",
|
|
18
|
+
"content-api",
|
|
19
|
+
"headless",
|
|
20
|
+
"cms",
|
|
21
|
+
"next",
|
|
22
|
+
"nextjs",
|
|
23
|
+
"react",
|
|
24
|
+
"sdk"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./react": {
|
|
36
|
+
"types": "./dist/react.d.ts",
|
|
37
|
+
"default": "./dist/react.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"README.md"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"react": ">=18"
|
|
50
|
+
},
|
|
51
|
+
"peerDependenciesMeta": {
|
|
52
|
+
"react": {
|
|
53
|
+
"optional": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/react": "^18.3.12",
|
|
58
|
+
"typescript": "^5.6.3"
|
|
59
|
+
},
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public",
|
|
62
|
+
"provenance": true
|
|
63
|
+
}
|
|
64
|
+
}
|