@holdyapp/sdk 1.6.0 → 1.9.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 +8 -1
- package/dist/changes.d.ts +16 -2
- package/dist/changes.d.ts.map +1 -1
- package/dist/core.d.ts +1 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/friction.d.ts +2 -1
- package/dist/friction.d.ts.map +1 -1
- package/dist/holdy.js +25 -4
- package/dist/holdy.js.map +4 -4
- package/dist/index.cjs +420 -36
- package/dist/index.cjs.map +4 -4
- package/dist/index.mjs +420 -36
- package/dist/index.mjs.map +4 -4
- package/dist/server.cjs +3 -0
- package/dist/server.cjs.map +2 -2
- package/dist/server.mjs +3 -0
- package/dist/server.mjs.map +2 -2
- package/dist/skeleton.d.ts +3 -1
- package/dist/skeleton.d.ts.map +1 -1
- package/dist/theme.d.ts +43 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/tip-css.d.ts +9 -0
- package/dist/tip-css.d.ts.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/web-context.d.ts +1 -0
- package/dist/web-context.d.ts.map +1 -1
- package/dist/web.d.ts +2 -1
- package/dist/web.d.ts.map +1 -1
- package/dist/web.mjs +420 -36
- package/dist/web.mjs.map +4 -4
- package/package.json +1 -1
- package/src/changes.dom.test.ts +221 -0
- package/src/changes.test.ts +38 -0
- package/src/changes.ts +299 -26
- package/src/core.test.ts +15 -0
- package/src/core.ts +3 -0
- package/src/friction.dom.test.ts +54 -0
- package/src/friction.test.ts +43 -0
- package/src/friction.ts +44 -7
- package/src/skeleton.ts +12 -3
- package/src/theme.test.ts +118 -0
- package/src/theme.ts +120 -0
- package/src/tip-css.ts +32 -0
- package/src/types.ts +6 -0
- package/src/web-context.test.ts +18 -0
- package/src/web-context.ts +8 -0
- package/src/web.ts +8 -2
package/dist/server.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/server.ts", "../src/core.ts", "../src/run.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @holdyapp/sdk (server) \u00B7 Node/Edge (source: sdk_server).\n *\n * Stateless por default: user_id/accountKey v\u00E3o por chamada em overrides.\n * identify()/group() de sess\u00E3o existem mas em server multi-tenant prefira\n * overrides \u2014 estado compartilhado entre requests vaza identidade.\n */\n\nimport { HoldyCore } from './core'\nimport { withRun, type RunHandle, type RunOptions } from './run'\nimport type { HoldyOptions } from './types'\n\nexport class Holdy extends HoldyCore {\n constructor(opts: HoldyOptions) {\n super('sdk_server', opts)\n }\n\n /**\n * Executa `fn` como UMA execu\u00E7\u00E3o de agente: todo evento l\u00E1 dentro carrega a\n * mesma `ai_run_id`, e `<name>.started` / `.completed` / `.failed` saem\n * sozinhos.\n *\n * await holdy.run({ name: 'support_agent', accountKey: 'acme' }, async (run) => {\n * run.track('ticket_drafted', { ai_tokens: 1200, ai_cost_usd: 0.02 })\n * return resolveTicket(ticket)\n * })\n */\n run<T>(opts: RunOptions, fn: (run: RunHandle) => Promise<T> | T): Promise<T> {\n return withRun((name, properties, overrides) => this.track(name, properties, overrides), opts, fn)\n }\n}\n\nexport { HoldyCore, DEFAULT_BASE_URL } from './core'\nexport type { HoldyOptions, Properties, TrackOverrides, CanonicalEvent } from './types'\nexport { newRunId, runEventName } from './run'\nexport type { RunHandle, RunOptions } from './run'\n", "/**\n * Core do @holdyapp/sdk \u00B7 fila + flush pra POST /api/v1/events/bulk.\n *\n * Todo evento sai com `external_id` pr\u00F3prio, ent\u00E3o reenviar um lote nunca\n * duplica (dedupe server-side por source + external_id + occurred_at).\n * 429 respeita Retry-After; 5xx e rede esperam com backoff exponencial; o lote\n * volta pra frente da fila em vez de sumir. Chave inv\u00E1lida ou origem recusada\n * avisam uma vez no console, mesmo sem debug. Fila \u00E9 bounded: acima de\n * MAX_QUEUE dropa os mais antigos (telemetria nunca derruba o app do cliente \u2014\n * nenhum m\u00E9todo p\u00FAblico lan\u00E7a).\n */\n\nimport type { CanonicalEvent, HoldyOptions, Properties, TrackOverrides } from './types'\n\nexport const DEFAULT_BASE_URL = 'https://holdy.chat/api/v1'\nconst DEFAULT_FLUSH_AT = 20\nconst DEFAULT_FLUSH_INTERVAL_MS = 5000\nconst MAX_QUEUE = 1000\nconst BULK_LIMIT = 500\nconst MAX_BACKOFF_MS = 60_000\n\ntype SendOutcome = { kind: 'sent' } | { kind: 'dropped' } | { kind: 'retry'; afterMs: number | null }\n\nexport class HoldyCore {\n protected readonly apiKey: string\n protected readonly baseUrl: string\n private readonly flushAt: number\n private readonly debug: boolean\n private readonly source: 'sdk_web' | 'sdk_server'\n\n private queue: CanonicalEvent[] = []\n private timer: ReturnType<typeof setInterval> | null = null\n private flushing: Promise<void> | null = null\n private retryAt = 0\n private failures = 0\n private readonly warned = new Set<string>()\n\n protected userId: string | null = null\n protected anonymousId: string | null = null\n protected accountKey: string | null = null\n\n constructor(source: 'sdk_web' | 'sdk_server', opts: HoldyOptions) {\n this.source = source\n this.apiKey = opts.apiKey\n this.accountKey = opts.accountKey ?? null\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.flushAt = Math.max(1, opts.flushAt ?? DEFAULT_FLUSH_AT)\n this.debug = opts.debug ?? false\n\n const intervalMs = opts.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS\n if (intervalMs > 0) {\n this.timer = setInterval(() => void this.flush(), intervalMs)\n // Node: n\u00E3o segura o processo vivo s\u00F3 pelo timer do SDK.\n if (typeof (this.timer as { unref?: () => void }).unref === 'function') {\n ;(this.timer as unknown as { unref: () => void }).unref()\n }\n }\n }\n\n track(name: string, properties?: Properties, overrides?: TrackOverrides): void {\n if (!name || typeof name !== 'string') return\n\n const userId = overrides?.userId ?? this.userId ?? undefined\n const accountKey = overrides?.accountKey ?? this.accountKey ?? undefined\n const occurredAt = overrides?.occurredAt\n ? new Date(overrides.occurredAt).toISOString()\n : new Date().toISOString()\n\n // Ordem: ambiente observado pelo SDK \u2192 context da chamada \u2192 carrier de\n // account. O que o caller passou vence o inferido; o carrier vence tudo,\n // porque \u00E9 o que a Data layer usa pra resolver a conta.\n const context: Properties = {\n ...this.environmentContext(),\n ...(overrides?.context ?? {}),\n }\n if (accountKey) context.account_external_id = accountKey\n\n const event: CanonicalEvent = {\n event: name,\n occurred_at: occurredAt,\n source: this.source,\n external_id: newEventId(),\n ...(userId ? { user_id: userId } : {}),\n ...(this.anonymousId ? { anonymous_id: this.anonymousId } : {}),\n properties: properties ?? {},\n ...(Object.keys(context).length > 0 ? { context } : {}),\n }\n\n this.queue.push(event)\n this.trimQueue()\n if (this.queue.length >= this.flushAt) void this.flush()\n }\n\n identify(userId: string, traits?: Properties): void {\n if (!userId || typeof userId !== 'string') return\n this.userId = userId\n this.track('$identify', traits ?? {})\n }\n\n group(accountKey: string, traits?: Properties): void {\n if (!accountKey || typeof accountKey !== 'string') return\n this.accountKey = accountKey\n this.track('$group', traits ?? {})\n }\n\n /** Drena a fila. Nunca lan\u00E7a \u2014 falha re-enfileira e espera antes de tentar de novo. */\n async flush(): Promise<void> {\n return this.startFlush(false)\n }\n\n /** Flush final + para o timer. Chamar em shutdown do server / unload do web. */\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = null\n }\n await this.startFlush(true)\n }\n\n private startFlush(force: boolean): Promise<void> {\n // Serializa flushes concorrentes (timer + flushAt + manual).\n if (this.flushing) return this.flushing\n if (this.queue.length === 0) return Promise.resolve()\n if (!force && Date.now() < this.retryAt) return Promise.resolve()\n\n this.flushing = this.drain().finally(() => {\n this.flushing = null\n })\n return this.flushing\n }\n\n private async drain(): Promise<void> {\n while (this.queue.length > 0) {\n const batch = this.queue.splice(0, BULK_LIMIT)\n const outcome = await this.send(batch)\n if (outcome.kind === 'retry') {\n this.queue.unshift(...batch)\n this.trimQueue()\n this.scheduleRetry(outcome.afterMs)\n return\n }\n this.failures = 0\n this.retryAt = 0\n }\n }\n\n private scheduleRetry(afterMs: number | null): void {\n this.failures += 1\n if (afterMs !== null) {\n this.retryAt = Date.now() + afterMs\n return\n }\n const backoff = Math.min(MAX_BACKOFF_MS, 1000 * 2 ** (this.failures - 1))\n this.retryAt = Date.now() + backoff + Math.floor(Math.random() * backoff * 0.2)\n }\n\n private trimQueue(): void {\n if (this.queue.length > MAX_QUEUE) this.queue.splice(0, this.queue.length - MAX_QUEUE)\n }\n\n private async send(events: CanonicalEvent[]): Promise<SendOutcome> {\n try {\n const res = await fetch(`${this.baseUrl}/events/bulk`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ events }),\n ...(this.source === 'sdk_web' ? { keepalive: true } : {}),\n })\n if (res.ok) return { kind: 'sent' }\n\n if (res.status === 429) {\n this.log('rate limited \u00B7 will retry after Retry-After')\n return { kind: 'retry', afterMs: retryAfterMs(res) }\n }\n if (res.status >= 500) {\n this.log(`bulk failed ${res.status} \u00B7 will retry with backoff`)\n return { kind: 'retry', afterMs: null }\n }\n if (res.status === 401) {\n this.warnOnce('401', 'API key inv\u00E1lida ou revogada \u00B7 eventos descartados. Confira a chave em Configura\u00E7\u00F5es \u203A SDK.')\n return { kind: 'dropped' }\n }\n if (res.status === 403) {\n this.warnOnce('403', 'Origem n\u00E3o permitida ou chave sem escopo events:write \u00B7 eventos descartados.')\n return { kind: 'dropped' }\n }\n this.log(`bulk rejected ${res.status} \u00B7 batch dropped`)\n return { kind: 'dropped' }\n } catch (err) {\n this.log(`bulk network error: ${(err as Error).message} \u00B7 will retry with backoff`)\n return { kind: 'retry', afterMs: null }\n }\n }\n\n private log(msg: string): void {\n if (this.debug) console.warn(`[holdy] ${msg}`)\n }\n\n private warnOnce(key: string, msg: string): void {\n if (this.warned.has(key)) return\n this.warned.add(key)\n console.warn(`[holdy] ${msg}`)\n }\n\n /**\n * Ambiente que o SDK observa sozinho (url, referrer, browser, utm\u2026).\n * Vazio no core; `HoldyWeb` preenche. O server n\u00E3o infere ambiente \u2014 n\u00E3o\n * existe \"p\u00E1gina atual\" num worker.\n */\n protected environmentContext(): Properties {\n return {}\n }\n\n /** Interno \u00B7 exposto pra testes. */\n get pending(): number {\n return this.queue.length\n }\n}\n\nfunction retryAfterMs(res: Response): number | null {\n const raw = typeof res.headers?.get === 'function' ? res.headers.get('Retry-After') : null\n if (!raw) return null\n const seconds = Number(raw)\n if (!Number.isFinite(seconds) || seconds < 0) return null\n return Math.min(MAX_BACKOFF_MS, seconds * 1000)\n}\n\nfunction newEventId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (typeof c?.randomUUID === 'function') return c.randomUUID()\n const rand = () => Math.random().toString(36).slice(2, 12)\n return `${Date.now().toString(36)}-${rand()}-${rand()}`\n}\n", "/**\n * Execu\u00E7\u00E3o como unidade de trabalho (source: sdk_server).\n *\n * Produto de agente n\u00E3o tem sess\u00E3o de browser: o trabalho roda no servidor,\n * por API, em background. Pra Holdy dizer \"come\u00E7ou e concluiu na mesma\n * execu\u00E7\u00E3o\" e dividir recurso por resultado entregue, todos os eventos de uma\n * tarefa carregam a mesma `ai_run_id` \u2014 a chave que o composer usa por padr\u00E3o\n * no gr\u00E3o de execu\u00E7\u00E3o (lib/knowledge/compose-definition.ts).\n *\n * N\u00E3o inventa vocabul\u00E1rio: in\u00EDcio e fim saem com o nome que o cliente deu \u00E0\n * execu\u00E7\u00E3o (`support_agent.started`), e todo passo no meio \u00E9 nome dele. O\n * retorno passa direto e o erro propaga; s\u00F3 o NOME do erro vira propriedade,\n * porque a mensagem carrega dado do cliente com frequ\u00EAncia demais.\n */\n\nimport type { Properties, TrackOverrides } from './types'\n\nexport interface RunOptions {\n /** Nome da execu\u00E7\u00E3o no vocabul\u00E1rio do produto, ex.: 'support_agent'. */\n name: string\n /** Conta (id externo) dona da execu\u00E7\u00E3o. */\n accountKey?: string\n userId?: string\n /** Chave pr\u00F3pria (trace id do agente); ausente = gerada aqui. */\n runId?: string\n /** Propriedades repetidas em todos os eventos da execu\u00E7\u00E3o. */\n properties?: Properties\n}\n\nexport interface RunHandle {\n /** A chave que agrupa tudo desta execu\u00E7\u00E3o. */\n id: string\n /** Um passo dentro da execu\u00E7\u00E3o, j\u00E1 carimbado com ai_run_id. */\n track(event: string, properties?: Properties): void\n}\n\nexport type TrackFn = (name: string, properties?: Properties, overrides?: TrackOverrides) => void\n\nexport function newRunId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (typeof c?.randomUUID === 'function') return c.randomUUID()\n return `run_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`\n}\n\nexport function runEventName(name: string, suffix: 'started' | 'completed' | 'failed'): string {\n const base = name.trim().replace(/\\.$/, '')\n return `${base || 'run'}.${suffix}`\n}\n\nexport async function withRun<T>(\n track: TrackFn,\n opts: RunOptions,\n fn: (run: RunHandle) => Promise<T> | T,\n): Promise<T> {\n if (!opts || !opts.name) throw new Error('[holdy] run: name is required')\n\n const id = opts.runId && opts.runId.length > 0 ? opts.runId : newRunId()\n const base: Properties = { ...(opts.properties ?? {}), ai_run_id: id }\n const overrides: TrackOverrides = {\n ...(opts.accountKey ? { accountKey: opts.accountKey } : {}),\n ...(opts.userId ? { userId: opts.userId } : {}),\n }\n const emit = (event: string, properties?: Properties) =>\n track(event, { ...base, ...(properties ?? {}), ai_run_id: id }, overrides)\n\n const startedAt = Date.now()\n emit(runEventName(opts.name, 'started'))\n\n try {\n const result = await fn({ id, track: emit })\n emit(runEventName(opts.name, 'completed'), { duration_ms: Date.now() - startedAt })\n return result\n } catch (err) {\n emit(runEventName(opts.name, 'failed'), {\n duration_ms: Date.now() - startedAt,\n error: err instanceof Error ? err.name : 'Error',\n })\n throw err\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACcO,IAAM,mBAAmB;AAChC,IAAM,mBAAmB;AACzB,IAAM,4BAA4B;AAClC,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,iBAAiB;AAIhB,IAAM,YAAN,MAAgB;AAAA,EACF;AAAA,EACA;AAAA,EACF;AAAA,EACA;AAAA,EACA;AAAA,EAET,QAA0B,CAAC;AAAA,EAC3B,QAA+C;AAAA,EAC/C,WAAiC;AAAA,EACjC,UAAU;AAAA,EACV,WAAW;AAAA,EACF,SAAS,oBAAI,IAAY;AAAA,EAEhC,SAAwB;AAAA,EACxB,cAA6B;AAAA,EAC7B,aAA4B;AAAA,EAEtC,YAAY,QAAkC,MAAoB;AAChE,SAAK,SAAS;AACd,SAAK,SAAS,KAAK;AACnB,SAAK,aAAa,KAAK,cAAc;AACrC,SAAK,WAAW,KAAK,WAAW,kBAAkB,QAAQ,OAAO,EAAE;AACnE,SAAK,UAAU,KAAK,IAAI,GAAG,KAAK,WAAW,gBAAgB;AAC3D,SAAK,QAAQ,KAAK,SAAS;
|
|
4
|
+
"sourcesContent": ["/**\n * @holdyapp/sdk (server) \u00B7 Node/Edge (source: sdk_server).\n *\n * Stateless por default: user_id/accountKey v\u00E3o por chamada em overrides.\n * identify()/group() de sess\u00E3o existem mas em server multi-tenant prefira\n * overrides \u2014 estado compartilhado entre requests vaza identidade.\n */\n\nimport { HoldyCore } from './core'\nimport { withRun, type RunHandle, type RunOptions } from './run'\nimport type { HoldyOptions } from './types'\n\nexport class Holdy extends HoldyCore {\n constructor(opts: HoldyOptions) {\n super('sdk_server', opts)\n }\n\n /**\n * Executa `fn` como UMA execu\u00E7\u00E3o de agente: todo evento l\u00E1 dentro carrega a\n * mesma `ai_run_id`, e `<name>.started` / `.completed` / `.failed` saem\n * sozinhos.\n *\n * await holdy.run({ name: 'support_agent', accountKey: 'acme' }, async (run) => {\n * run.track('ticket_drafted', { ai_tokens: 1200, ai_cost_usd: 0.02 })\n * return resolveTicket(ticket)\n * })\n */\n run<T>(opts: RunOptions, fn: (run: RunHandle) => Promise<T> | T): Promise<T> {\n return withRun((name, properties, overrides) => this.track(name, properties, overrides), opts, fn)\n }\n}\n\nexport { HoldyCore, DEFAULT_BASE_URL } from './core'\nexport type { HoldyOptions, Properties, TrackOverrides, CanonicalEvent } from './types'\nexport { newRunId, runEventName } from './run'\nexport type { RunHandle, RunOptions } from './run'\n", "/**\n * Core do @holdyapp/sdk \u00B7 fila + flush pra POST /api/v1/events/bulk.\n *\n * Todo evento sai com `external_id` pr\u00F3prio, ent\u00E3o reenviar um lote nunca\n * duplica (dedupe server-side por source + external_id + occurred_at).\n * 429 respeita Retry-After; 5xx e rede esperam com backoff exponencial; o lote\n * volta pra frente da fila em vez de sumir. Chave inv\u00E1lida ou origem recusada\n * avisam uma vez no console, mesmo sem debug. Fila \u00E9 bounded: acima de\n * MAX_QUEUE dropa os mais antigos (telemetria nunca derruba o app do cliente \u2014\n * nenhum m\u00E9todo p\u00FAblico lan\u00E7a).\n */\n\nimport type { CanonicalEvent, HoldyOptions, Properties, TrackOverrides } from './types'\n\nexport const DEFAULT_BASE_URL = 'https://holdy.chat/api/v1'\nconst DEFAULT_FLUSH_AT = 20\nconst DEFAULT_FLUSH_INTERVAL_MS = 5000\nconst MAX_QUEUE = 1000\nconst BULK_LIMIT = 500\nconst MAX_BACKOFF_MS = 60_000\n\ntype SendOutcome = { kind: 'sent' } | { kind: 'dropped' } | { kind: 'retry'; afterMs: number | null }\n\nexport class HoldyCore {\n protected readonly apiKey: string\n protected readonly baseUrl: string\n private readonly flushAt: number\n private readonly debug: boolean\n private readonly source: 'sdk_web' | 'sdk_server'\n private readonly release: string | null\n\n private queue: CanonicalEvent[] = []\n private timer: ReturnType<typeof setInterval> | null = null\n private flushing: Promise<void> | null = null\n private retryAt = 0\n private failures = 0\n private readonly warned = new Set<string>()\n\n protected userId: string | null = null\n protected anonymousId: string | null = null\n protected accountKey: string | null = null\n\n constructor(source: 'sdk_web' | 'sdk_server', opts: HoldyOptions) {\n this.source = source\n this.apiKey = opts.apiKey\n this.accountKey = opts.accountKey ?? null\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.flushAt = Math.max(1, opts.flushAt ?? DEFAULT_FLUSH_AT)\n this.debug = opts.debug ?? false\n this.release = typeof opts.release === 'string' && opts.release.trim() ? opts.release.trim().slice(0, 64) : null\n\n const intervalMs = opts.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS\n if (intervalMs > 0) {\n this.timer = setInterval(() => void this.flush(), intervalMs)\n // Node: n\u00E3o segura o processo vivo s\u00F3 pelo timer do SDK.\n if (typeof (this.timer as { unref?: () => void }).unref === 'function') {\n ;(this.timer as unknown as { unref: () => void }).unref()\n }\n }\n }\n\n track(name: string, properties?: Properties, overrides?: TrackOverrides): void {\n if (!name || typeof name !== 'string') return\n\n const userId = overrides?.userId ?? this.userId ?? undefined\n const accountKey = overrides?.accountKey ?? this.accountKey ?? undefined\n const occurredAt = overrides?.occurredAt\n ? new Date(overrides.occurredAt).toISOString()\n : new Date().toISOString()\n\n // Ordem: ambiente observado pelo SDK \u2192 context da chamada \u2192 carrier de\n // account. O que o caller passou vence o inferido; o carrier vence tudo,\n // porque \u00E9 o que a Data layer usa pra resolver a conta.\n const context: Properties = {\n ...this.environmentContext(),\n ...(this.release ? { release: this.release } : {}),\n ...(overrides?.context ?? {}),\n }\n if (accountKey) context.account_external_id = accountKey\n\n const event: CanonicalEvent = {\n event: name,\n occurred_at: occurredAt,\n source: this.source,\n external_id: newEventId(),\n ...(userId ? { user_id: userId } : {}),\n ...(this.anonymousId ? { anonymous_id: this.anonymousId } : {}),\n properties: properties ?? {},\n ...(Object.keys(context).length > 0 ? { context } : {}),\n }\n\n this.queue.push(event)\n this.trimQueue()\n if (this.queue.length >= this.flushAt) void this.flush()\n }\n\n identify(userId: string, traits?: Properties): void {\n if (!userId || typeof userId !== 'string') return\n this.userId = userId\n this.track('$identify', traits ?? {})\n }\n\n group(accountKey: string, traits?: Properties): void {\n if (!accountKey || typeof accountKey !== 'string') return\n this.accountKey = accountKey\n this.track('$group', traits ?? {})\n }\n\n /** Drena a fila. Nunca lan\u00E7a \u2014 falha re-enfileira e espera antes de tentar de novo. */\n async flush(): Promise<void> {\n return this.startFlush(false)\n }\n\n /** Flush final + para o timer. Chamar em shutdown do server / unload do web. */\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = null\n }\n await this.startFlush(true)\n }\n\n private startFlush(force: boolean): Promise<void> {\n // Serializa flushes concorrentes (timer + flushAt + manual).\n if (this.flushing) return this.flushing\n if (this.queue.length === 0) return Promise.resolve()\n if (!force && Date.now() < this.retryAt) return Promise.resolve()\n\n this.flushing = this.drain().finally(() => {\n this.flushing = null\n })\n return this.flushing\n }\n\n private async drain(): Promise<void> {\n while (this.queue.length > 0) {\n const batch = this.queue.splice(0, BULK_LIMIT)\n const outcome = await this.send(batch)\n if (outcome.kind === 'retry') {\n this.queue.unshift(...batch)\n this.trimQueue()\n this.scheduleRetry(outcome.afterMs)\n return\n }\n this.failures = 0\n this.retryAt = 0\n }\n }\n\n private scheduleRetry(afterMs: number | null): void {\n this.failures += 1\n if (afterMs !== null) {\n this.retryAt = Date.now() + afterMs\n return\n }\n const backoff = Math.min(MAX_BACKOFF_MS, 1000 * 2 ** (this.failures - 1))\n this.retryAt = Date.now() + backoff + Math.floor(Math.random() * backoff * 0.2)\n }\n\n private trimQueue(): void {\n if (this.queue.length > MAX_QUEUE) this.queue.splice(0, this.queue.length - MAX_QUEUE)\n }\n\n private async send(events: CanonicalEvent[]): Promise<SendOutcome> {\n try {\n const res = await fetch(`${this.baseUrl}/events/bulk`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ events }),\n ...(this.source === 'sdk_web' ? { keepalive: true } : {}),\n })\n if (res.ok) return { kind: 'sent' }\n\n if (res.status === 429) {\n this.log('rate limited \u00B7 will retry after Retry-After')\n return { kind: 'retry', afterMs: retryAfterMs(res) }\n }\n if (res.status >= 500) {\n this.log(`bulk failed ${res.status} \u00B7 will retry with backoff`)\n return { kind: 'retry', afterMs: null }\n }\n if (res.status === 401) {\n this.warnOnce('401', 'API key inv\u00E1lida ou revogada \u00B7 eventos descartados. Confira a chave em Configura\u00E7\u00F5es \u203A SDK.')\n return { kind: 'dropped' }\n }\n if (res.status === 403) {\n this.warnOnce('403', 'Origem n\u00E3o permitida ou chave sem escopo events:write \u00B7 eventos descartados.')\n return { kind: 'dropped' }\n }\n this.log(`bulk rejected ${res.status} \u00B7 batch dropped`)\n return { kind: 'dropped' }\n } catch (err) {\n this.log(`bulk network error: ${(err as Error).message} \u00B7 will retry with backoff`)\n return { kind: 'retry', afterMs: null }\n }\n }\n\n private log(msg: string): void {\n if (this.debug) console.warn(`[holdy] ${msg}`)\n }\n\n private warnOnce(key: string, msg: string): void {\n if (this.warned.has(key)) return\n this.warned.add(key)\n console.warn(`[holdy] ${msg}`)\n }\n\n /**\n * Ambiente que o SDK observa sozinho (url, referrer, browser, utm\u2026).\n * Vazio no core; `HoldyWeb` preenche. O server n\u00E3o infere ambiente \u2014 n\u00E3o\n * existe \"p\u00E1gina atual\" num worker.\n */\n protected environmentContext(): Properties {\n return {}\n }\n\n /** Interno \u00B7 exposto pra testes. */\n get pending(): number {\n return this.queue.length\n }\n}\n\nfunction retryAfterMs(res: Response): number | null {\n const raw = typeof res.headers?.get === 'function' ? res.headers.get('Retry-After') : null\n if (!raw) return null\n const seconds = Number(raw)\n if (!Number.isFinite(seconds) || seconds < 0) return null\n return Math.min(MAX_BACKOFF_MS, seconds * 1000)\n}\n\nfunction newEventId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (typeof c?.randomUUID === 'function') return c.randomUUID()\n const rand = () => Math.random().toString(36).slice(2, 12)\n return `${Date.now().toString(36)}-${rand()}-${rand()}`\n}\n", "/**\n * Execu\u00E7\u00E3o como unidade de trabalho (source: sdk_server).\n *\n * Produto de agente n\u00E3o tem sess\u00E3o de browser: o trabalho roda no servidor,\n * por API, em background. Pra Holdy dizer \"come\u00E7ou e concluiu na mesma\n * execu\u00E7\u00E3o\" e dividir recurso por resultado entregue, todos os eventos de uma\n * tarefa carregam a mesma `ai_run_id` \u2014 a chave que o composer usa por padr\u00E3o\n * no gr\u00E3o de execu\u00E7\u00E3o (lib/knowledge/compose-definition.ts).\n *\n * N\u00E3o inventa vocabul\u00E1rio: in\u00EDcio e fim saem com o nome que o cliente deu \u00E0\n * execu\u00E7\u00E3o (`support_agent.started`), e todo passo no meio \u00E9 nome dele. O\n * retorno passa direto e o erro propaga; s\u00F3 o NOME do erro vira propriedade,\n * porque a mensagem carrega dado do cliente com frequ\u00EAncia demais.\n */\n\nimport type { Properties, TrackOverrides } from './types'\n\nexport interface RunOptions {\n /** Nome da execu\u00E7\u00E3o no vocabul\u00E1rio do produto, ex.: 'support_agent'. */\n name: string\n /** Conta (id externo) dona da execu\u00E7\u00E3o. */\n accountKey?: string\n userId?: string\n /** Chave pr\u00F3pria (trace id do agente); ausente = gerada aqui. */\n runId?: string\n /** Propriedades repetidas em todos os eventos da execu\u00E7\u00E3o. */\n properties?: Properties\n}\n\nexport interface RunHandle {\n /** A chave que agrupa tudo desta execu\u00E7\u00E3o. */\n id: string\n /** Um passo dentro da execu\u00E7\u00E3o, j\u00E1 carimbado com ai_run_id. */\n track(event: string, properties?: Properties): void\n}\n\nexport type TrackFn = (name: string, properties?: Properties, overrides?: TrackOverrides) => void\n\nexport function newRunId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (typeof c?.randomUUID === 'function') return c.randomUUID()\n return `run_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`\n}\n\nexport function runEventName(name: string, suffix: 'started' | 'completed' | 'failed'): string {\n const base = name.trim().replace(/\\.$/, '')\n return `${base || 'run'}.${suffix}`\n}\n\nexport async function withRun<T>(\n track: TrackFn,\n opts: RunOptions,\n fn: (run: RunHandle) => Promise<T> | T,\n): Promise<T> {\n if (!opts || !opts.name) throw new Error('[holdy] run: name is required')\n\n const id = opts.runId && opts.runId.length > 0 ? opts.runId : newRunId()\n const base: Properties = { ...(opts.properties ?? {}), ai_run_id: id }\n const overrides: TrackOverrides = {\n ...(opts.accountKey ? { accountKey: opts.accountKey } : {}),\n ...(opts.userId ? { userId: opts.userId } : {}),\n }\n const emit = (event: string, properties?: Properties) =>\n track(event, { ...base, ...(properties ?? {}), ai_run_id: id }, overrides)\n\n const startedAt = Date.now()\n emit(runEventName(opts.name, 'started'))\n\n try {\n const result = await fn({ id, track: emit })\n emit(runEventName(opts.name, 'completed'), { duration_ms: Date.now() - startedAt })\n return result\n } catch (err) {\n emit(runEventName(opts.name, 'failed'), {\n duration_ms: Date.now() - startedAt,\n error: err instanceof Error ? err.name : 'Error',\n })\n throw err\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/server.mjs
CHANGED
|
@@ -11,6 +11,7 @@ var HoldyCore = class {
|
|
|
11
11
|
flushAt;
|
|
12
12
|
debug;
|
|
13
13
|
source;
|
|
14
|
+
release;
|
|
14
15
|
queue = [];
|
|
15
16
|
timer = null;
|
|
16
17
|
flushing = null;
|
|
@@ -27,6 +28,7 @@ var HoldyCore = class {
|
|
|
27
28
|
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
28
29
|
this.flushAt = Math.max(1, opts.flushAt ?? DEFAULT_FLUSH_AT);
|
|
29
30
|
this.debug = opts.debug ?? false;
|
|
31
|
+
this.release = typeof opts.release === "string" && opts.release.trim() ? opts.release.trim().slice(0, 64) : null;
|
|
30
32
|
const intervalMs = opts.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
|
|
31
33
|
if (intervalMs > 0) {
|
|
32
34
|
this.timer = setInterval(() => void this.flush(), intervalMs);
|
|
@@ -43,6 +45,7 @@ var HoldyCore = class {
|
|
|
43
45
|
const occurredAt = overrides?.occurredAt ? new Date(overrides.occurredAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
44
46
|
const context = {
|
|
45
47
|
...this.environmentContext(),
|
|
48
|
+
...this.release ? { release: this.release } : {},
|
|
46
49
|
...overrides?.context ?? {}
|
|
47
50
|
};
|
|
48
51
|
if (accountKey) context.account_external_id = accountKey;
|
package/dist/server.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/core.ts", "../src/run.ts", "../src/server.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Core do @holdyapp/sdk \u00B7 fila + flush pra POST /api/v1/events/bulk.\n *\n * Todo evento sai com `external_id` pr\u00F3prio, ent\u00E3o reenviar um lote nunca\n * duplica (dedupe server-side por source + external_id + occurred_at).\n * 429 respeita Retry-After; 5xx e rede esperam com backoff exponencial; o lote\n * volta pra frente da fila em vez de sumir. Chave inv\u00E1lida ou origem recusada\n * avisam uma vez no console, mesmo sem debug. Fila \u00E9 bounded: acima de\n * MAX_QUEUE dropa os mais antigos (telemetria nunca derruba o app do cliente \u2014\n * nenhum m\u00E9todo p\u00FAblico lan\u00E7a).\n */\n\nimport type { CanonicalEvent, HoldyOptions, Properties, TrackOverrides } from './types'\n\nexport const DEFAULT_BASE_URL = 'https://holdy.chat/api/v1'\nconst DEFAULT_FLUSH_AT = 20\nconst DEFAULT_FLUSH_INTERVAL_MS = 5000\nconst MAX_QUEUE = 1000\nconst BULK_LIMIT = 500\nconst MAX_BACKOFF_MS = 60_000\n\ntype SendOutcome = { kind: 'sent' } | { kind: 'dropped' } | { kind: 'retry'; afterMs: number | null }\n\nexport class HoldyCore {\n protected readonly apiKey: string\n protected readonly baseUrl: string\n private readonly flushAt: number\n private readonly debug: boolean\n private readonly source: 'sdk_web' | 'sdk_server'\n\n private queue: CanonicalEvent[] = []\n private timer: ReturnType<typeof setInterval> | null = null\n private flushing: Promise<void> | null = null\n private retryAt = 0\n private failures = 0\n private readonly warned = new Set<string>()\n\n protected userId: string | null = null\n protected anonymousId: string | null = null\n protected accountKey: string | null = null\n\n constructor(source: 'sdk_web' | 'sdk_server', opts: HoldyOptions) {\n this.source = source\n this.apiKey = opts.apiKey\n this.accountKey = opts.accountKey ?? null\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.flushAt = Math.max(1, opts.flushAt ?? DEFAULT_FLUSH_AT)\n this.debug = opts.debug ?? false\n\n const intervalMs = opts.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS\n if (intervalMs > 0) {\n this.timer = setInterval(() => void this.flush(), intervalMs)\n // Node: n\u00E3o segura o processo vivo s\u00F3 pelo timer do SDK.\n if (typeof (this.timer as { unref?: () => void }).unref === 'function') {\n ;(this.timer as unknown as { unref: () => void }).unref()\n }\n }\n }\n\n track(name: string, properties?: Properties, overrides?: TrackOverrides): void {\n if (!name || typeof name !== 'string') return\n\n const userId = overrides?.userId ?? this.userId ?? undefined\n const accountKey = overrides?.accountKey ?? this.accountKey ?? undefined\n const occurredAt = overrides?.occurredAt\n ? new Date(overrides.occurredAt).toISOString()\n : new Date().toISOString()\n\n // Ordem: ambiente observado pelo SDK \u2192 context da chamada \u2192 carrier de\n // account. O que o caller passou vence o inferido; o carrier vence tudo,\n // porque \u00E9 o que a Data layer usa pra resolver a conta.\n const context: Properties = {\n ...this.environmentContext(),\n ...(overrides?.context ?? {}),\n }\n if (accountKey) context.account_external_id = accountKey\n\n const event: CanonicalEvent = {\n event: name,\n occurred_at: occurredAt,\n source: this.source,\n external_id: newEventId(),\n ...(userId ? { user_id: userId } : {}),\n ...(this.anonymousId ? { anonymous_id: this.anonymousId } : {}),\n properties: properties ?? {},\n ...(Object.keys(context).length > 0 ? { context } : {}),\n }\n\n this.queue.push(event)\n this.trimQueue()\n if (this.queue.length >= this.flushAt) void this.flush()\n }\n\n identify(userId: string, traits?: Properties): void {\n if (!userId || typeof userId !== 'string') return\n this.userId = userId\n this.track('$identify', traits ?? {})\n }\n\n group(accountKey: string, traits?: Properties): void {\n if (!accountKey || typeof accountKey !== 'string') return\n this.accountKey = accountKey\n this.track('$group', traits ?? {})\n }\n\n /** Drena a fila. Nunca lan\u00E7a \u2014 falha re-enfileira e espera antes de tentar de novo. */\n async flush(): Promise<void> {\n return this.startFlush(false)\n }\n\n /** Flush final + para o timer. Chamar em shutdown do server / unload do web. */\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = null\n }\n await this.startFlush(true)\n }\n\n private startFlush(force: boolean): Promise<void> {\n // Serializa flushes concorrentes (timer + flushAt + manual).\n if (this.flushing) return this.flushing\n if (this.queue.length === 0) return Promise.resolve()\n if (!force && Date.now() < this.retryAt) return Promise.resolve()\n\n this.flushing = this.drain().finally(() => {\n this.flushing = null\n })\n return this.flushing\n }\n\n private async drain(): Promise<void> {\n while (this.queue.length > 0) {\n const batch = this.queue.splice(0, BULK_LIMIT)\n const outcome = await this.send(batch)\n if (outcome.kind === 'retry') {\n this.queue.unshift(...batch)\n this.trimQueue()\n this.scheduleRetry(outcome.afterMs)\n return\n }\n this.failures = 0\n this.retryAt = 0\n }\n }\n\n private scheduleRetry(afterMs: number | null): void {\n this.failures += 1\n if (afterMs !== null) {\n this.retryAt = Date.now() + afterMs\n return\n }\n const backoff = Math.min(MAX_BACKOFF_MS, 1000 * 2 ** (this.failures - 1))\n this.retryAt = Date.now() + backoff + Math.floor(Math.random() * backoff * 0.2)\n }\n\n private trimQueue(): void {\n if (this.queue.length > MAX_QUEUE) this.queue.splice(0, this.queue.length - MAX_QUEUE)\n }\n\n private async send(events: CanonicalEvent[]): Promise<SendOutcome> {\n try {\n const res = await fetch(`${this.baseUrl}/events/bulk`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ events }),\n ...(this.source === 'sdk_web' ? { keepalive: true } : {}),\n })\n if (res.ok) return { kind: 'sent' }\n\n if (res.status === 429) {\n this.log('rate limited \u00B7 will retry after Retry-After')\n return { kind: 'retry', afterMs: retryAfterMs(res) }\n }\n if (res.status >= 500) {\n this.log(`bulk failed ${res.status} \u00B7 will retry with backoff`)\n return { kind: 'retry', afterMs: null }\n }\n if (res.status === 401) {\n this.warnOnce('401', 'API key inv\u00E1lida ou revogada \u00B7 eventos descartados. Confira a chave em Configura\u00E7\u00F5es \u203A SDK.')\n return { kind: 'dropped' }\n }\n if (res.status === 403) {\n this.warnOnce('403', 'Origem n\u00E3o permitida ou chave sem escopo events:write \u00B7 eventos descartados.')\n return { kind: 'dropped' }\n }\n this.log(`bulk rejected ${res.status} \u00B7 batch dropped`)\n return { kind: 'dropped' }\n } catch (err) {\n this.log(`bulk network error: ${(err as Error).message} \u00B7 will retry with backoff`)\n return { kind: 'retry', afterMs: null }\n }\n }\n\n private log(msg: string): void {\n if (this.debug) console.warn(`[holdy] ${msg}`)\n }\n\n private warnOnce(key: string, msg: string): void {\n if (this.warned.has(key)) return\n this.warned.add(key)\n console.warn(`[holdy] ${msg}`)\n }\n\n /**\n * Ambiente que o SDK observa sozinho (url, referrer, browser, utm\u2026).\n * Vazio no core; `HoldyWeb` preenche. O server n\u00E3o infere ambiente \u2014 n\u00E3o\n * existe \"p\u00E1gina atual\" num worker.\n */\n protected environmentContext(): Properties {\n return {}\n }\n\n /** Interno \u00B7 exposto pra testes. */\n get pending(): number {\n return this.queue.length\n }\n}\n\nfunction retryAfterMs(res: Response): number | null {\n const raw = typeof res.headers?.get === 'function' ? res.headers.get('Retry-After') : null\n if (!raw) return null\n const seconds = Number(raw)\n if (!Number.isFinite(seconds) || seconds < 0) return null\n return Math.min(MAX_BACKOFF_MS, seconds * 1000)\n}\n\nfunction newEventId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (typeof c?.randomUUID === 'function') return c.randomUUID()\n const rand = () => Math.random().toString(36).slice(2, 12)\n return `${Date.now().toString(36)}-${rand()}-${rand()}`\n}\n", "/**\n * Execu\u00E7\u00E3o como unidade de trabalho (source: sdk_server).\n *\n * Produto de agente n\u00E3o tem sess\u00E3o de browser: o trabalho roda no servidor,\n * por API, em background. Pra Holdy dizer \"come\u00E7ou e concluiu na mesma\n * execu\u00E7\u00E3o\" e dividir recurso por resultado entregue, todos os eventos de uma\n * tarefa carregam a mesma `ai_run_id` \u2014 a chave que o composer usa por padr\u00E3o\n * no gr\u00E3o de execu\u00E7\u00E3o (lib/knowledge/compose-definition.ts).\n *\n * N\u00E3o inventa vocabul\u00E1rio: in\u00EDcio e fim saem com o nome que o cliente deu \u00E0\n * execu\u00E7\u00E3o (`support_agent.started`), e todo passo no meio \u00E9 nome dele. O\n * retorno passa direto e o erro propaga; s\u00F3 o NOME do erro vira propriedade,\n * porque a mensagem carrega dado do cliente com frequ\u00EAncia demais.\n */\n\nimport type { Properties, TrackOverrides } from './types'\n\nexport interface RunOptions {\n /** Nome da execu\u00E7\u00E3o no vocabul\u00E1rio do produto, ex.: 'support_agent'. */\n name: string\n /** Conta (id externo) dona da execu\u00E7\u00E3o. */\n accountKey?: string\n userId?: string\n /** Chave pr\u00F3pria (trace id do agente); ausente = gerada aqui. */\n runId?: string\n /** Propriedades repetidas em todos os eventos da execu\u00E7\u00E3o. */\n properties?: Properties\n}\n\nexport interface RunHandle {\n /** A chave que agrupa tudo desta execu\u00E7\u00E3o. */\n id: string\n /** Um passo dentro da execu\u00E7\u00E3o, j\u00E1 carimbado com ai_run_id. */\n track(event: string, properties?: Properties): void\n}\n\nexport type TrackFn = (name: string, properties?: Properties, overrides?: TrackOverrides) => void\n\nexport function newRunId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (typeof c?.randomUUID === 'function') return c.randomUUID()\n return `run_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`\n}\n\nexport function runEventName(name: string, suffix: 'started' | 'completed' | 'failed'): string {\n const base = name.trim().replace(/\\.$/, '')\n return `${base || 'run'}.${suffix}`\n}\n\nexport async function withRun<T>(\n track: TrackFn,\n opts: RunOptions,\n fn: (run: RunHandle) => Promise<T> | T,\n): Promise<T> {\n if (!opts || !opts.name) throw new Error('[holdy] run: name is required')\n\n const id = opts.runId && opts.runId.length > 0 ? opts.runId : newRunId()\n const base: Properties = { ...(opts.properties ?? {}), ai_run_id: id }\n const overrides: TrackOverrides = {\n ...(opts.accountKey ? { accountKey: opts.accountKey } : {}),\n ...(opts.userId ? { userId: opts.userId } : {}),\n }\n const emit = (event: string, properties?: Properties) =>\n track(event, { ...base, ...(properties ?? {}), ai_run_id: id }, overrides)\n\n const startedAt = Date.now()\n emit(runEventName(opts.name, 'started'))\n\n try {\n const result = await fn({ id, track: emit })\n emit(runEventName(opts.name, 'completed'), { duration_ms: Date.now() - startedAt })\n return result\n } catch (err) {\n emit(runEventName(opts.name, 'failed'), {\n duration_ms: Date.now() - startedAt,\n error: err instanceof Error ? err.name : 'Error',\n })\n throw err\n }\n}\n", "/**\n * @holdyapp/sdk (server) \u00B7 Node/Edge (source: sdk_server).\n *\n * Stateless por default: user_id/accountKey v\u00E3o por chamada em overrides.\n * identify()/group() de sess\u00E3o existem mas em server multi-tenant prefira\n * overrides \u2014 estado compartilhado entre requests vaza identidade.\n */\n\nimport { HoldyCore } from './core'\nimport { withRun, type RunHandle, type RunOptions } from './run'\nimport type { HoldyOptions } from './types'\n\nexport class Holdy extends HoldyCore {\n constructor(opts: HoldyOptions) {\n super('sdk_server', opts)\n }\n\n /**\n * Executa `fn` como UMA execu\u00E7\u00E3o de agente: todo evento l\u00E1 dentro carrega a\n * mesma `ai_run_id`, e `<name>.started` / `.completed` / `.failed` saem\n * sozinhos.\n *\n * await holdy.run({ name: 'support_agent', accountKey: 'acme' }, async (run) => {\n * run.track('ticket_drafted', { ai_tokens: 1200, ai_cost_usd: 0.02 })\n * return resolveTicket(ticket)\n * })\n */\n run<T>(opts: RunOptions, fn: (run: RunHandle) => Promise<T> | T): Promise<T> {\n return withRun((name, properties, overrides) => this.track(name, properties, overrides), opts, fn)\n }\n}\n\nexport { HoldyCore, DEFAULT_BASE_URL } from './core'\nexport type { HoldyOptions, Properties, TrackOverrides, CanonicalEvent } from './types'\nexport { newRunId, runEventName } from './run'\nexport type { RunHandle, RunOptions } from './run'\n"],
|
|
5
|
-
"mappings": ";AAcO,IAAM,mBAAmB;AAChC,IAAM,mBAAmB;AACzB,IAAM,4BAA4B;AAClC,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,iBAAiB;AAIhB,IAAM,YAAN,MAAgB;AAAA,EACF;AAAA,EACA;AAAA,EACF;AAAA,EACA;AAAA,EACA;AAAA,EAET,QAA0B,CAAC;AAAA,EAC3B,QAA+C;AAAA,EAC/C,WAAiC;AAAA,EACjC,UAAU;AAAA,EACV,WAAW;AAAA,EACF,SAAS,oBAAI,IAAY;AAAA,EAEhC,SAAwB;AAAA,EACxB,cAA6B;AAAA,EAC7B,aAA4B;AAAA,EAEtC,YAAY,QAAkC,MAAoB;AAChE,SAAK,SAAS;AACd,SAAK,SAAS,KAAK;AACnB,SAAK,aAAa,KAAK,cAAc;AACrC,SAAK,WAAW,KAAK,WAAW,kBAAkB,QAAQ,OAAO,EAAE;AACnE,SAAK,UAAU,KAAK,IAAI,GAAG,KAAK,WAAW,gBAAgB;AAC3D,SAAK,QAAQ,KAAK,SAAS;
|
|
4
|
+
"sourcesContent": ["/**\n * Core do @holdyapp/sdk \u00B7 fila + flush pra POST /api/v1/events/bulk.\n *\n * Todo evento sai com `external_id` pr\u00F3prio, ent\u00E3o reenviar um lote nunca\n * duplica (dedupe server-side por source + external_id + occurred_at).\n * 429 respeita Retry-After; 5xx e rede esperam com backoff exponencial; o lote\n * volta pra frente da fila em vez de sumir. Chave inv\u00E1lida ou origem recusada\n * avisam uma vez no console, mesmo sem debug. Fila \u00E9 bounded: acima de\n * MAX_QUEUE dropa os mais antigos (telemetria nunca derruba o app do cliente \u2014\n * nenhum m\u00E9todo p\u00FAblico lan\u00E7a).\n */\n\nimport type { CanonicalEvent, HoldyOptions, Properties, TrackOverrides } from './types'\n\nexport const DEFAULT_BASE_URL = 'https://holdy.chat/api/v1'\nconst DEFAULT_FLUSH_AT = 20\nconst DEFAULT_FLUSH_INTERVAL_MS = 5000\nconst MAX_QUEUE = 1000\nconst BULK_LIMIT = 500\nconst MAX_BACKOFF_MS = 60_000\n\ntype SendOutcome = { kind: 'sent' } | { kind: 'dropped' } | { kind: 'retry'; afterMs: number | null }\n\nexport class HoldyCore {\n protected readonly apiKey: string\n protected readonly baseUrl: string\n private readonly flushAt: number\n private readonly debug: boolean\n private readonly source: 'sdk_web' | 'sdk_server'\n private readonly release: string | null\n\n private queue: CanonicalEvent[] = []\n private timer: ReturnType<typeof setInterval> | null = null\n private flushing: Promise<void> | null = null\n private retryAt = 0\n private failures = 0\n private readonly warned = new Set<string>()\n\n protected userId: string | null = null\n protected anonymousId: string | null = null\n protected accountKey: string | null = null\n\n constructor(source: 'sdk_web' | 'sdk_server', opts: HoldyOptions) {\n this.source = source\n this.apiKey = opts.apiKey\n this.accountKey = opts.accountKey ?? null\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '')\n this.flushAt = Math.max(1, opts.flushAt ?? DEFAULT_FLUSH_AT)\n this.debug = opts.debug ?? false\n this.release = typeof opts.release === 'string' && opts.release.trim() ? opts.release.trim().slice(0, 64) : null\n\n const intervalMs = opts.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS\n if (intervalMs > 0) {\n this.timer = setInterval(() => void this.flush(), intervalMs)\n // Node: n\u00E3o segura o processo vivo s\u00F3 pelo timer do SDK.\n if (typeof (this.timer as { unref?: () => void }).unref === 'function') {\n ;(this.timer as unknown as { unref: () => void }).unref()\n }\n }\n }\n\n track(name: string, properties?: Properties, overrides?: TrackOverrides): void {\n if (!name || typeof name !== 'string') return\n\n const userId = overrides?.userId ?? this.userId ?? undefined\n const accountKey = overrides?.accountKey ?? this.accountKey ?? undefined\n const occurredAt = overrides?.occurredAt\n ? new Date(overrides.occurredAt).toISOString()\n : new Date().toISOString()\n\n // Ordem: ambiente observado pelo SDK \u2192 context da chamada \u2192 carrier de\n // account. O que o caller passou vence o inferido; o carrier vence tudo,\n // porque \u00E9 o que a Data layer usa pra resolver a conta.\n const context: Properties = {\n ...this.environmentContext(),\n ...(this.release ? { release: this.release } : {}),\n ...(overrides?.context ?? {}),\n }\n if (accountKey) context.account_external_id = accountKey\n\n const event: CanonicalEvent = {\n event: name,\n occurred_at: occurredAt,\n source: this.source,\n external_id: newEventId(),\n ...(userId ? { user_id: userId } : {}),\n ...(this.anonymousId ? { anonymous_id: this.anonymousId } : {}),\n properties: properties ?? {},\n ...(Object.keys(context).length > 0 ? { context } : {}),\n }\n\n this.queue.push(event)\n this.trimQueue()\n if (this.queue.length >= this.flushAt) void this.flush()\n }\n\n identify(userId: string, traits?: Properties): void {\n if (!userId || typeof userId !== 'string') return\n this.userId = userId\n this.track('$identify', traits ?? {})\n }\n\n group(accountKey: string, traits?: Properties): void {\n if (!accountKey || typeof accountKey !== 'string') return\n this.accountKey = accountKey\n this.track('$group', traits ?? {})\n }\n\n /** Drena a fila. Nunca lan\u00E7a \u2014 falha re-enfileira e espera antes de tentar de novo. */\n async flush(): Promise<void> {\n return this.startFlush(false)\n }\n\n /** Flush final + para o timer. Chamar em shutdown do server / unload do web. */\n async shutdown(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer = null\n }\n await this.startFlush(true)\n }\n\n private startFlush(force: boolean): Promise<void> {\n // Serializa flushes concorrentes (timer + flushAt + manual).\n if (this.flushing) return this.flushing\n if (this.queue.length === 0) return Promise.resolve()\n if (!force && Date.now() < this.retryAt) return Promise.resolve()\n\n this.flushing = this.drain().finally(() => {\n this.flushing = null\n })\n return this.flushing\n }\n\n private async drain(): Promise<void> {\n while (this.queue.length > 0) {\n const batch = this.queue.splice(0, BULK_LIMIT)\n const outcome = await this.send(batch)\n if (outcome.kind === 'retry') {\n this.queue.unshift(...batch)\n this.trimQueue()\n this.scheduleRetry(outcome.afterMs)\n return\n }\n this.failures = 0\n this.retryAt = 0\n }\n }\n\n private scheduleRetry(afterMs: number | null): void {\n this.failures += 1\n if (afterMs !== null) {\n this.retryAt = Date.now() + afterMs\n return\n }\n const backoff = Math.min(MAX_BACKOFF_MS, 1000 * 2 ** (this.failures - 1))\n this.retryAt = Date.now() + backoff + Math.floor(Math.random() * backoff * 0.2)\n }\n\n private trimQueue(): void {\n if (this.queue.length > MAX_QUEUE) this.queue.splice(0, this.queue.length - MAX_QUEUE)\n }\n\n private async send(events: CanonicalEvent[]): Promise<SendOutcome> {\n try {\n const res = await fetch(`${this.baseUrl}/events/bulk`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ events }),\n ...(this.source === 'sdk_web' ? { keepalive: true } : {}),\n })\n if (res.ok) return { kind: 'sent' }\n\n if (res.status === 429) {\n this.log('rate limited \u00B7 will retry after Retry-After')\n return { kind: 'retry', afterMs: retryAfterMs(res) }\n }\n if (res.status >= 500) {\n this.log(`bulk failed ${res.status} \u00B7 will retry with backoff`)\n return { kind: 'retry', afterMs: null }\n }\n if (res.status === 401) {\n this.warnOnce('401', 'API key inv\u00E1lida ou revogada \u00B7 eventos descartados. Confira a chave em Configura\u00E7\u00F5es \u203A SDK.')\n return { kind: 'dropped' }\n }\n if (res.status === 403) {\n this.warnOnce('403', 'Origem n\u00E3o permitida ou chave sem escopo events:write \u00B7 eventos descartados.')\n return { kind: 'dropped' }\n }\n this.log(`bulk rejected ${res.status} \u00B7 batch dropped`)\n return { kind: 'dropped' }\n } catch (err) {\n this.log(`bulk network error: ${(err as Error).message} \u00B7 will retry with backoff`)\n return { kind: 'retry', afterMs: null }\n }\n }\n\n private log(msg: string): void {\n if (this.debug) console.warn(`[holdy] ${msg}`)\n }\n\n private warnOnce(key: string, msg: string): void {\n if (this.warned.has(key)) return\n this.warned.add(key)\n console.warn(`[holdy] ${msg}`)\n }\n\n /**\n * Ambiente que o SDK observa sozinho (url, referrer, browser, utm\u2026).\n * Vazio no core; `HoldyWeb` preenche. O server n\u00E3o infere ambiente \u2014 n\u00E3o\n * existe \"p\u00E1gina atual\" num worker.\n */\n protected environmentContext(): Properties {\n return {}\n }\n\n /** Interno \u00B7 exposto pra testes. */\n get pending(): number {\n return this.queue.length\n }\n}\n\nfunction retryAfterMs(res: Response): number | null {\n const raw = typeof res.headers?.get === 'function' ? res.headers.get('Retry-After') : null\n if (!raw) return null\n const seconds = Number(raw)\n if (!Number.isFinite(seconds) || seconds < 0) return null\n return Math.min(MAX_BACKOFF_MS, seconds * 1000)\n}\n\nfunction newEventId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (typeof c?.randomUUID === 'function') return c.randomUUID()\n const rand = () => Math.random().toString(36).slice(2, 12)\n return `${Date.now().toString(36)}-${rand()}-${rand()}`\n}\n", "/**\n * Execu\u00E7\u00E3o como unidade de trabalho (source: sdk_server).\n *\n * Produto de agente n\u00E3o tem sess\u00E3o de browser: o trabalho roda no servidor,\n * por API, em background. Pra Holdy dizer \"come\u00E7ou e concluiu na mesma\n * execu\u00E7\u00E3o\" e dividir recurso por resultado entregue, todos os eventos de uma\n * tarefa carregam a mesma `ai_run_id` \u2014 a chave que o composer usa por padr\u00E3o\n * no gr\u00E3o de execu\u00E7\u00E3o (lib/knowledge/compose-definition.ts).\n *\n * N\u00E3o inventa vocabul\u00E1rio: in\u00EDcio e fim saem com o nome que o cliente deu \u00E0\n * execu\u00E7\u00E3o (`support_agent.started`), e todo passo no meio \u00E9 nome dele. O\n * retorno passa direto e o erro propaga; s\u00F3 o NOME do erro vira propriedade,\n * porque a mensagem carrega dado do cliente com frequ\u00EAncia demais.\n */\n\nimport type { Properties, TrackOverrides } from './types'\n\nexport interface RunOptions {\n /** Nome da execu\u00E7\u00E3o no vocabul\u00E1rio do produto, ex.: 'support_agent'. */\n name: string\n /** Conta (id externo) dona da execu\u00E7\u00E3o. */\n accountKey?: string\n userId?: string\n /** Chave pr\u00F3pria (trace id do agente); ausente = gerada aqui. */\n runId?: string\n /** Propriedades repetidas em todos os eventos da execu\u00E7\u00E3o. */\n properties?: Properties\n}\n\nexport interface RunHandle {\n /** A chave que agrupa tudo desta execu\u00E7\u00E3o. */\n id: string\n /** Um passo dentro da execu\u00E7\u00E3o, j\u00E1 carimbado com ai_run_id. */\n track(event: string, properties?: Properties): void\n}\n\nexport type TrackFn = (name: string, properties?: Properties, overrides?: TrackOverrides) => void\n\nexport function newRunId(): string {\n const c = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto\n if (typeof c?.randomUUID === 'function') return c.randomUUID()\n return `run_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`\n}\n\nexport function runEventName(name: string, suffix: 'started' | 'completed' | 'failed'): string {\n const base = name.trim().replace(/\\.$/, '')\n return `${base || 'run'}.${suffix}`\n}\n\nexport async function withRun<T>(\n track: TrackFn,\n opts: RunOptions,\n fn: (run: RunHandle) => Promise<T> | T,\n): Promise<T> {\n if (!opts || !opts.name) throw new Error('[holdy] run: name is required')\n\n const id = opts.runId && opts.runId.length > 0 ? opts.runId : newRunId()\n const base: Properties = { ...(opts.properties ?? {}), ai_run_id: id }\n const overrides: TrackOverrides = {\n ...(opts.accountKey ? { accountKey: opts.accountKey } : {}),\n ...(opts.userId ? { userId: opts.userId } : {}),\n }\n const emit = (event: string, properties?: Properties) =>\n track(event, { ...base, ...(properties ?? {}), ai_run_id: id }, overrides)\n\n const startedAt = Date.now()\n emit(runEventName(opts.name, 'started'))\n\n try {\n const result = await fn({ id, track: emit })\n emit(runEventName(opts.name, 'completed'), { duration_ms: Date.now() - startedAt })\n return result\n } catch (err) {\n emit(runEventName(opts.name, 'failed'), {\n duration_ms: Date.now() - startedAt,\n error: err instanceof Error ? err.name : 'Error',\n })\n throw err\n }\n}\n", "/**\n * @holdyapp/sdk (server) \u00B7 Node/Edge (source: sdk_server).\n *\n * Stateless por default: user_id/accountKey v\u00E3o por chamada em overrides.\n * identify()/group() de sess\u00E3o existem mas em server multi-tenant prefira\n * overrides \u2014 estado compartilhado entre requests vaza identidade.\n */\n\nimport { HoldyCore } from './core'\nimport { withRun, type RunHandle, type RunOptions } from './run'\nimport type { HoldyOptions } from './types'\n\nexport class Holdy extends HoldyCore {\n constructor(opts: HoldyOptions) {\n super('sdk_server', opts)\n }\n\n /**\n * Executa `fn` como UMA execu\u00E7\u00E3o de agente: todo evento l\u00E1 dentro carrega a\n * mesma `ai_run_id`, e `<name>.started` / `.completed` / `.failed` saem\n * sozinhos.\n *\n * await holdy.run({ name: 'support_agent', accountKey: 'acme' }, async (run) => {\n * run.track('ticket_drafted', { ai_tokens: 1200, ai_cost_usd: 0.02 })\n * return resolveTicket(ticket)\n * })\n */\n run<T>(opts: RunOptions, fn: (run: RunHandle) => Promise<T> | T): Promise<T> {\n return withRun((name, properties, overrides) => this.track(name, properties, overrides), opts, fn)\n }\n}\n\nexport { HoldyCore, DEFAULT_BASE_URL } from './core'\nexport type { HoldyOptions, Properties, TrackOverrides, CanonicalEvent } from './types'\nexport { newRunId, runEventName } from './run'\nexport type { RunHandle, RunOptions } from './run'\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/skeleton.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PageTheme } from './theme';
|
|
1
2
|
export declare const SKELETON_SELECTOR = "a[href], button, input, select, textarea, [role=\"button\"], [role=\"link\"], [role=\"tab\"], [role=\"menuitem\"], [role=\"checkbox\"], [role=\"radio\"], [role=\"switch\"], [data-testid]";
|
|
2
3
|
export declare const SKELETON_MAX_ELEMENTS = 80;
|
|
3
4
|
export declare const SKELETON_DELAY_MS = 1500;
|
|
@@ -34,10 +35,11 @@ export interface PageSkeleton {
|
|
|
34
35
|
hash: string;
|
|
35
36
|
count: number;
|
|
36
37
|
elements: SkeletonElement[];
|
|
38
|
+
theme?: PageTheme;
|
|
37
39
|
}
|
|
38
40
|
export declare function fnv1a(input: string): string;
|
|
39
41
|
export declare function describeSkeletonElement(el: SkeletonElementLike, viewport: SkeletonViewport | null): SkeletonElement;
|
|
40
|
-
export declare function collectSkeleton(root: SkeletonRootLike, path: string, viewport: SkeletonViewport | null): PageSkeleton;
|
|
42
|
+
export declare function collectSkeleton(root: SkeletonRootLike, path: string, viewport: SkeletonViewport | null, theme?: PageTheme | null): PageSkeleton;
|
|
41
43
|
export interface SkeletonCaptureOptions {
|
|
42
44
|
onSkeleton: (skeleton: PageSkeleton) => void;
|
|
43
45
|
delayMs?: number;
|
package/dist/skeleton.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../src/skeleton.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,+LACkJ,CAAA;AAChL,eAAO,MAAM,qBAAqB,KAAK,CAAA;AACvC,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAIrC,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACzC,qBAAqB,CAAC,IAAI,YAAY,CAAA;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC,mBAAmB,CAAC,CAAA;CACnE;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,eAAe,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../src/skeleton.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,SAAS,CAAA;AAEnD,eAAO,MAAM,iBAAiB,+LACkJ,CAAA;AAChL,eAAO,MAAM,qBAAqB,KAAK,CAAA;AACvC,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAIrC,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACzC,qBAAqB,CAAC,IAAI,YAAY,CAAA;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC,mBAAmB,CAAC,CAAA;CACnE;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,eAAe,EAAE,CAAA;IAC3B,KAAK,CAAC,EAAE,SAAS,CAAA;CAClB;AAED,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAO3C;AAoBD,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,mBAAmB,EAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAAG,eAAe,CAgBnH;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,gBAAgB,EACtB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,gBAAgB,GAAG,IAAI,EACjC,KAAK,GAAE,SAAS,GAAG,IAAW,GAC7B,YAAY,CAYd;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAA;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,QAAQ,EAAE,MAAM,IAAI,CAAA;CACrB;AAoBD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,sBAAsB,GAAG,eAAe,CAuCpF"}
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface PageTheme {
|
|
2
|
+
font?: string;
|
|
3
|
+
size?: string;
|
|
4
|
+
fg?: string;
|
|
5
|
+
bg?: string;
|
|
6
|
+
accent?: string;
|
|
7
|
+
accentFg?: string;
|
|
8
|
+
radius?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ThemeStyleLike {
|
|
11
|
+
getPropertyValue(name: string): string;
|
|
12
|
+
}
|
|
13
|
+
export interface ThemeElementLike {
|
|
14
|
+
tagName: string;
|
|
15
|
+
getBoundingClientRect?(): {
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export interface ThemeDocLike {
|
|
21
|
+
body: ThemeElementLike | null;
|
|
22
|
+
documentElement: ThemeElementLike;
|
|
23
|
+
querySelectorAll(selector: string): ArrayLike<ThemeElementLike>;
|
|
24
|
+
}
|
|
25
|
+
export declare const THEME_BUTTON_SELECTOR = "button[type=\"submit\"],[data-testid*=\"primary\"],.btn-primary,button,[role=\"button\"],a.button";
|
|
26
|
+
export declare const THEME_MAX_BUTTONS = 40;
|
|
27
|
+
export declare const THEME_KEYS: readonly (keyof PageTheme)[];
|
|
28
|
+
/** Distância mínima entre o botão e o fundo pra valer como cor primária: um botão branco em fundo claro não é acento. */
|
|
29
|
+
export declare const MIN_ACCENT_CONTRAST = 60;
|
|
30
|
+
export declare function colorDistance(a: string, b: string | undefined): number;
|
|
31
|
+
export declare function themeVarName(key: keyof PageTheme): string;
|
|
32
|
+
export declare function cleanColor(value: string | null | undefined): string | undefined;
|
|
33
|
+
export declare function cleanFont(value: string | null | undefined): string | undefined;
|
|
34
|
+
export declare function cleanPx(value: string | null | undefined, min: number, max: number): string | undefined;
|
|
35
|
+
export declare function readTheme(doc: ThemeDocLike, getStyle: (el: ThemeElementLike) => ThemeStyleLike, anchor?: ThemeElementLike | null): PageTheme | null;
|
|
36
|
+
export declare function themeVars(theme: PageTheme | null | undefined): Array<[string, string]>;
|
|
37
|
+
export declare function applyThemeVars(el: {
|
|
38
|
+
style: {
|
|
39
|
+
setProperty(name: string, value: string): void;
|
|
40
|
+
removeProperty(name: string): void;
|
|
41
|
+
};
|
|
42
|
+
}, theme: PageTheme | null | undefined): void;
|
|
43
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,qBAAqB,CAAC,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAC5D;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC7B,eAAe,EAAE,gBAAgB,CAAA;IACjC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAA;CAChE;AAED,eAAO,MAAM,qBAAqB,sGAAgG,CAAA;AAClI,eAAO,MAAM,iBAAiB,KAAK,CAAA;AACnC,eAAO,MAAM,UAAU,EAAE,SAAS,CAAC,MAAM,SAAS,CAAC,EAAiE,CAAA;AAGpH,yHAAyH;AACzH,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAGrC,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAMtE;AAID,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,SAAS,GAAG,MAAM,CAEzD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG/E;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG9E;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAItG;AAOD,wBAAgB,SAAS,CACvB,GAAG,EAAE,YAAY,EACjB,QAAQ,EAAE,CAAC,EAAE,EAAE,gBAAgB,KAAK,cAAc,EAClD,MAAM,GAAE,gBAAgB,GAAG,IAAW,GACrC,SAAS,GAAG,IAAI,CAgClB;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAOtF;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE;IAAE,KAAK,EAAE;QAAE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CAAE,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAG/K"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O card da dica e da pergunta, como o SDK desenha no produto do cliente.
|
|
3
|
+
* O painel da Holdy importa daqui pra prévia: a mesma folha, nunca uma cópia.
|
|
4
|
+
* As variáveis --holdy-* chegam do tema lido na página (theme.ts): fonte,
|
|
5
|
+
* cores, raio e cor do botão primário do produto do cliente. Sem tema, o
|
|
6
|
+
* card cai no visual próprio (escuro no claro, claro no escuro).
|
|
7
|
+
*/
|
|
8
|
+
export declare const TIP_CSS = ":host{all:initial;--h-bg:#111;--h-fg:#fff;--h-accent:#fff;--h-accent-fg:#111;--h-border:transparent}\n@media (prefers-color-scheme:dark){:host{--h-bg:#fff;--h-fg:#111;--h-accent:#111;--h-accent-fg:#fff}}\n.tip{position:fixed;box-sizing:border-box;max-width:280px;padding:10px 12px;border-radius:var(--holdy-radius,8px);background:var(--holdy-bg,var(--h-bg));color:var(--holdy-fg,var(--h-fg));border:1px solid color-mix(in srgb,var(--holdy-fg,var(--h-fg)) 14%,transparent);font:var(--holdy-size,13px)/1.45 var(--holdy-font,system-ui),system-ui,-apple-system,sans-serif;box-shadow:0 8px 24px rgba(0,0,0,.18);pointer-events:auto;display:flex;gap:10px;align-items:flex-start}\n.tip p{margin:0;flex:1}\n.tip button{all:unset;cursor:pointer;opacity:.7;font-size:15px;line-height:1;color:inherit}\n.tip button:hover,.tip button:focus-visible{opacity:1}\n.ask{flex-direction:column;width:300px;max-width:calc(100vw - 16px);gap:8px}\n.ask .head{display:flex;gap:10px;align-items:flex-start;width:100%}\n.ask textarea{all:unset;box-sizing:border-box;width:100%;min-height:56px;padding:8px;border-radius:calc(var(--holdy-radius,8px) * .75);background:color-mix(in srgb,var(--holdy-fg,var(--h-fg)) 8%,transparent);color:inherit;font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;cursor:text}\n.ask textarea:focus-visible{outline:2px solid color-mix(in srgb,var(--holdy-fg,var(--h-fg)) 45%,transparent)}\n.ask .send{align-self:flex-end;padding:5px 12px;border-radius:calc(var(--holdy-radius,8px) * .75);background:var(--holdy-accent,var(--h-accent));color:var(--holdy-accent-fg,var(--h-accent-fg));font-size:12.5px;font-weight:500;opacity:1}\n.ask .send[disabled]{opacity:.4;cursor:default}\n.list{flex-direction:column;width:300px;max-width:calc(100vw - 16px);gap:8px}\n.list .head{display:flex;gap:10px;align-items:flex-start;width:100%}\n.list .head p{display:flex;justify-content:space-between;gap:10px;align-items:baseline}\n.list .count{opacity:.7;font-size:12px;white-space:nowrap}\n.list ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px;width:100%}\n.list li{display:flex;gap:8px;align-items:flex-start}\n.list li.done{opacity:.55;text-decoration:line-through}\n.list .mark{flex:none;width:16px;height:16px;border-radius:4px;border:1px solid color-mix(in srgb,var(--holdy-fg,var(--h-fg)) 45%,transparent);font-size:11px;line-height:16px;text-align:center}\n.list li.done .mark{background:var(--holdy-accent,var(--h-accent));color:var(--holdy-accent-fg,var(--h-accent-fg));border-color:var(--holdy-accent,var(--h-accent))}\n.list.folded ul{display:none}\n.list.folded{width:auto}\n.preview{flex:none;order:-1;width:100%;font-size:11px;opacity:.7}\n.tip:has(.preview){flex-wrap:wrap;row-gap:4px}";
|
|
9
|
+
//# sourceMappingURL=tip-css.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tip-css.d.ts","sourceRoot":"","sources":["../src/tip-css.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,2qFAwB2B,CAAA"}
|
package/dist/types.d.ts
CHANGED
|
@@ -32,6 +32,12 @@ export interface HoldyOptions {
|
|
|
32
32
|
* declarar a account COM traits.
|
|
33
33
|
*/
|
|
34
34
|
accountKey?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Versão do produto no ar (sha do commit, tag ou número do build). Vai em
|
|
37
|
+
* `context.release` de todo evento, pra Holdy dizer em que versão um erro
|
|
38
|
+
* apareceu.
|
|
39
|
+
*/
|
|
40
|
+
release?: string;
|
|
35
41
|
/** Logs de debug no console. */
|
|
36
42
|
debug?: boolean;
|
|
37
43
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEhD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,SAAS,GAAG,YAAY,CAAA;IAChC,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,CAAC,EAAE,UAAU,CAAA;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAA;IACd,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gCAAgC;IAChC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;IAC1B,sCAAsC;IACtC,OAAO,CAAC,EAAE,UAAU,CAAA;CACrB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEhD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,SAAS,GAAG,YAAY,CAAA;IAChC,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,UAAU,CAAA;IACtB,OAAO,CAAC,EAAE,UAAU,CAAA;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAA;IACd,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gCAAgC;IAChC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;IAC1B,sCAAsC;IACtC,OAAO,CAAC,EAAE,UAAU,CAAA;CACrB"}
|
package/dist/web-context.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ interface UaParts {
|
|
|
35
35
|
* separar mobile de desktop e Safari de Chrome, não em cravar a versão.
|
|
36
36
|
*/
|
|
37
37
|
export declare function parseUserAgent(ua: string): UaParts;
|
|
38
|
+
export declare function clearSessionId(): void;
|
|
38
39
|
/** ID da sessão de browser · vive enquanto a aba viver. */
|
|
39
40
|
export declare function resolveSessionId(): string;
|
|
40
41
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-context.d.ts","sourceRoot":"","sources":["../src/web-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAe/C,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOpD;AAED,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAYjD;AAID,UAAU,OAAO;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CA6ClD;AA8BD,2DAA2D;AAC3D,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CAsBlG;AAYD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAyB5C"}
|
|
1
|
+
{"version":3,"file":"web-context.d.ts","sourceRoot":"","sources":["../src/web-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAe/C,+DAA+D;AAC/D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOpD;AAED,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAYjD;AAID,UAAU,OAAO;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CA6ClD;AA8BD,wBAAgB,cAAc,IAAI,IAAI,CAMrC;AAED,2DAA2D;AAC3D,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CAsBlG;AAYD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAyB5C"}
|
package/dist/web.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { HoldyCore } from './core';
|
|
14
14
|
import { type FrictionCaptureOptions } from './friction';
|
|
15
|
-
import type { HoldyOptions, Properties } from './types';
|
|
15
|
+
import type { HoldyOptions, Properties, TrackOverrides } from './types';
|
|
16
16
|
export interface HoldyWebOptions extends HoldyOptions {
|
|
17
17
|
/**
|
|
18
18
|
* Emitir `$pageview` sozinho no load e a cada mudança de rota · default true.
|
|
@@ -56,6 +56,7 @@ export declare class HoldyWeb extends HoldyCore {
|
|
|
56
56
|
*/
|
|
57
57
|
page(name?: string, properties?: Properties): void;
|
|
58
58
|
group(accountKey: string, traits?: Properties): void;
|
|
59
|
+
track(name: string, properties?: Properties, overrides?: TrackOverrides): void;
|
|
59
60
|
reset(): void;
|
|
60
61
|
/** Flush final + desinstala o auto-capture (devolve `history` ao original). */
|
|
61
62
|
shutdown(): Promise<void>;
|
package/dist/web.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElC,OAAO,EAAgD,KAAK,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAItG,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElC,OAAO,EAAgD,KAAK,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAItG,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAIvE,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,sBAAsB,EAAE,YAAY,CAAC,CAAA;IAC/D;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,qBAAa,QAAS,SAAQ,SAAS;IACrC,OAAO,CAAC,mBAAmB,CAA4B;IACvD,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,QAAQ,CAA+B;gBAEnC,IAAI,EAAE,eAAe;IAiDjC;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI;IAQzC,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,IAAI;IAKpD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,cAAc,GAAG,IAAI;IAKvF,KAAK,IAAI,IAAI;IAab,+EAA+E;IAChE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;cAYrB,kBAAkB,IAAI,UAAU;CAGpD;AAgBD,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,IAAI,EAAE,eAAe,GAAG,QAAQ,CAYzD;AAED,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,CAAA"}
|