@8ux-co/eelzap 0.0.0-stage → 0.10.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,207 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.10.1] - Unreleased
9
+
10
+ ### Added
11
+
12
+ - The site client's on-page read returns the viewer's own `email` and an `editorUrl` for the record the page resolves to («Abrir en Zap»), plus `records` naming the other records the page shows.
13
+ - **`webhookChanges` covers SEO, collection, schema and site events**, so a
14
+ site that revalidates on webhooks also refreshes when they change:
15
+ - `zap.seo.updated` gives the same `item` or `document` change an edit
16
+ does (action `updated`), one per entry or document;
17
+ - `zap.collection.created`, `updated` and `deleted` give a `collection`
18
+ change carrying `collectionKey`;
19
+ - `zap.schema.field_changed` (action `field_changed`) gives one
20
+ `collection` change per collection whose fields changed, with
21
+ `resourceKey` and `collectionKey` set to the collection's key, and one
22
+ `document` change per document whose fields changed, named by the
23
+ document's key. Zap now sends `collection_key` and `document_key` on
24
+ every schema change. An older payload without them names a collection
25
+ by its id (no `collectionKey`) and widens a document's fields to one
26
+ `site` change;
27
+ - `zap.site.updated` gives a `site` change.
28
+ - `WebhookEventType` adds `'collection'` and `'site'`, and `WebhookAction`
29
+ adds `'field_changed'`. The item, document and media changes keep their
30
+ shape.
31
+ - Typed `data` for these events: `WebhookSeoEventData`,
32
+ `WebhookCollectionEventData`, `WebhookSchemaEventData` (with optional
33
+ `collection_key` and `document_key`) and `WebhookSiteEventData`.
34
+
35
+ ### Changed
36
+
37
+ - **`canonicalUrl` takes a path or a full URL** (`SeoInput`, docs only; the
38
+ type is still `string | null`). A path such as `/blog/original-post` is
39
+ stored as sent and resolved against the site URL on delivery, so it
40
+ follows a change of address; a full https URL (http only on localhost) is
41
+ kept as sent, for content first published on another domain. Leave it
42
+ unset and delivery uses the record's own URL. Zap refuses `//host`,
43
+ `javascript:` and other schemes, whitespace and credentials with a 400
44
+ whose `details[].message` says why.
45
+ - `Seo.canonicalUrl` on delivery is always an absolute URL or null, as
46
+ before; a stored path arrives resolved. `VersionSeo.canonicalUrl` and the
47
+ SEO routes return the value as stored.
48
+ - The canonical is an SEO field only: it no longer changes the page Zap's
49
+ preview opens. Where a record lives is its preview path.
50
+ - **A document without a preview path is site-wide** (a header and footer
51
+ document, say): `Seo.canonicalUrl` and `ogUrl` are null for it unless an
52
+ editor set a canonical, instead of `/{documentKey}`. A document that is a
53
+ page keeps its preview path's URL.
54
+ - **Zap keeps every version.** The per-site version limit is gone, so
55
+ `WebhookSiteEventData.changed` on `zap.site.updated` never lists
56
+ `maxVersionsPerEntry`, and `itemVersions.list()` and `documentVersions.list()`
57
+ return the whole history. No SDK type carried the setting, so no code changes.
58
+
59
+ ### Fixed
60
+
61
+ - `webhookChanges` returns an empty list for `zap.item.draft_updated` and
62
+ `zap.document.draft_updated`: saving a draft changes nothing the live site
63
+ serves.
64
+ - **The preview client pauses instead of running away.** When the tagged
65
+ count passes 5,000, or grows on three passes in a row that nothing on the
66
+ page explains, the client stops observing the page and writing values,
67
+ logs one warning and tells Zap's editor (`zap:paused`), which offers a
68
+ reload. Values carrying stega markers no longer add markers on each pass.
69
+
70
+ ## [0.10.0] - 2026-10-06
71
+
72
+ The first release as **`@8ux-co/eelzap`**, which replaces
73
+ `@8ux-co/eelzap-api-sdk-ts` (its last release, 0.9.1, points here). One
74
+ package for the delivery client and the preview client, with subpaths. The
75
+ version continues the old line.
76
+
77
+ ### Added
78
+
79
+ - `EelZapError.details`: a validation refusal from the API lists each problem as `{ path, message, code }` (`ApiErrorDetail`); empty for other errors.
80
+ - **Retries of `429`, and of `503` with `Retry-After`.** On by default: the
81
+ client honours `Retry-After` (seconds or an HTTP date, plus jitter), backs
82
+ off exponentially without it, and gives up after `retries` (default 3) or
83
+ when `Retry-After` exceeds `maxDelayMs` (default 60 s). Only reads and writes
84
+ that carry an `Idempotency-Key` are retried; no other write is ever
85
+ repeated. `createClient({ retry: false | { retries, maxDelayMs, baseDelayMs,
86
+ onRetry } })`; `RetryOptions` and `RetryEvent` are exported. `timeout` is per
87
+ attempt.
88
+ - **Subpaths.** `.` (the client), `./fields`, `./next`, `./react` and
89
+ `./preview`; `./analytics` is reserved. Zero runtime dependencies, React and
90
+ Next optional peers, ES2020, `sideEffects: false`, ESM and CJS for `.` and
91
+ `./fields`, ESM for the browser subpaths, with a gzip budget per subpath
92
+ checked in CI (`.` under 6 KB for a delivery-only import, `./fields` 1 KB,
93
+ `./next` 2 KB, `./react` about 2.2 KB, the boot about 1.2 KB, `./preview`
94
+ about 13.25 KB).
95
+ - **The preview boot.** `<ZapPreview />` (`./next`, `./react`) and a script
96
+ tag: under 1 KB, no request outside a preview session (framed by Zap,
97
+ `?zap`, the suggestion shortcut, a draft-mode session); in one, it loads the
98
+ overlay with an SRI hash compiled into the package, from the Zap that framed
99
+ the page, else `zapOrigin`, else `https://zap.eel.software`. A local Zap
100
+ counts only from a local page: `localhost`, `127.0.0.1`, `[::1]` or
101
+ `*.localhost`, over http or https, so local preview needs no shim. One
102
+ script and one overlay per page, under React StrictMode and remounts too.
103
+ - **The overlay** (`./preview`), formerly the unpublished
104
+ `@8ux-co/eelzap-preview`: the editor bridge, tag index, outlines, value
105
+ substitution, select mode and the suggestion chunks. `zap:ready` announces
106
+ the site's draft-mode route as a path; `zap:tags` says whether each field was
107
+ found by a tag or by stega. A URL or EMAIL value (`{ url }`, `{ email }`,
108
+ for a client advertising `links`) updates a tagged link's `href`
109
+ (`mailto:` for an email) and never its label. «Editar o comentar» sits at
110
+ the bottom centre, clear of a site's own corner buttons. Zap's editor frames the site by its real URL:
111
+ its side of the bridge accepts messages only from the site's own preview
112
+ origins and posts only to the exact origin that said `zap:ready`, never to
113
+ `'*'`.
114
+ - **Stega.** Preview reads carry invisible markers on TEXT, LONG_TEXT and
115
+ RICH_TEXT values, and the overlay finds the elements that render them with
116
+ no tag. `cleanStega(value)` and `hasStega(value)` in `.`; a `stega: false`
117
+ read option sends `stega=0`.
118
+ - **`fields(record)`** (`./fields`): typed pick helpers (`text`, `value`,
119
+ `attrs`, `image`, `list`) whose keys come from generated types; plain values
120
+ outside preview, `data-zap` attributes in preview. `list(prefix, n)` returns
121
+ `FieldSlot`s with the same helpers scoped to each slot, for `prefix_{i}`
122
+ (`s.text()`) and for slots of several fields `prefix_{i}_{suffix}`
123
+ (`nav.text('texto')`, `nav.value('url')`), suffixes typed; each has `key`,
124
+ `index` and `empty`.
125
+ - **`./next`:** `isZapPreview(request)`, `<ZapPreview />` announcing
126
+ `/api/zap-preview` by default, beside `createDraftModeRoute`,
127
+ `createDraftModeExitRoute`, `getPreviewToken` and `getValidPreviewToken`.
128
+ - **`./react`:** `onValues(entry, handler)` and `useZapLiveUpdates(entry)`
129
+ without the overlay in your bundle (they listen to the overlay's
130
+ `eelzap:values` event).
131
+ - **The public routes the client did not reach:** `sites.list`,
132
+ `previewTokens.validate`, `media.fromUrl`, and `listDeleted` and `restore`
133
+ on collection and document fields. `media.fromUrl` sends an
134
+ `Idempotency-Key`.
135
+ - **`comments`** («Comentarios»): `list`, `get`, `create`, `update`, `reply`,
136
+ `apply`, `saveToDraft` and `onPage` over the public `/comments` routes,
137
+ typed from the routes' schemas (`CommentThread`, `ThreadComment`,
138
+ `CreateCommentInput`, …). A thread is a plain comment or, with
139
+ `isChangeRequest`, a change request with an assignee, proposed values and a
140
+ resolution. `create`, `reply` and `saveToDraft` send an `Idempotency-Key`.
141
+ - From the 0.8.0 to 0.9.0 line, now in this package: `cachedFetch` with
142
+ `network-first` and `cache-first`, `itemVersions` and `documentVersions`,
143
+ `verifyWebhookSignature` (WebCrypto, so edge runtimes and workers too) and
144
+ `webhookChanges`, `getMediaUrl`, and the `preview` read option with `zpt_`
145
+ preview tokens as the API key.
146
+ - **Webhook test vectors** in the repository: a fixed secret, timestamp, body
147
+ and signature from Zap's signer, with tests of `verifyWebhookSignature` over
148
+ them in Node and in an edge-like runtime.
149
+
150
+ ### Changed
151
+
152
+ - **The CLI and codegen moved to `@8ux-co/eelzap-cli`** (bin `eelzap`,
153
+ `eelzap codegen`; `@8ux-co/eelzap-cli/codegen` for the programmatic API).
154
+ Generated code imports its types from `@8ux-co/eelzap`. This package no
155
+ longer depends on `@inquirer/prompts` or `dotenv`.
156
+ - `verifyWebhookSignature(payload, headers, secret, options?)` takes the
157
+ request headers and checks the signed timestamp; `WebhookPayload` is the
158
+ suite event envelope.
159
+ - The cache strategies never store a preview response.
160
+ - **`FieldType` is the API's**: `TEXT`, not `SHORT_TEXT`, which the field
161
+ routes refuse with a 400. Field creates, the field routes' answers and the
162
+ delivery schema reads (`collections.list`, `collections.get`,
163
+ `documents.list`) all use it: the delivery API publishes a text field as
164
+ `TEXT` too, no longer `SHORT_TEXT`.
165
+ - **Every create sends an `Idempotency-Key`**, which suite bearers must send:
166
+ `collections.create`, `collections.fields.create`,
167
+ `collections.sections.create`, `items.create`, `documents.create`,
168
+ `documents.fields.create` and `documents.sections.create` now do, as
169
+ `media.fromUrl` and the comment writes already did. A fresh key per call;
170
+ each takes a last `{ idempotencyKey }` argument to reuse a key on your own
171
+ retry. Make these writes from server code (the API's CORS does not allow the
172
+ header from a browser).
173
+ - **Comment webhook events.** The `zap.change_request.*` events are now
174
+ `zap.comment.created`, `zap.comment.replied`, `zap.comment.resolved`,
175
+ `zap.comment.reopened` and `zap.comment.updated`, with typed `data`
176
+ (`WebhookCommentCreatedData`, …), for plain comments and change requests
177
+ alike.
178
+ - **The live-site suggestion client calls `/comments`** instead of
179
+ `/change-requests`: it sends `isChangeRequest` (true when there is a
180
+ proposed value) and one top-level `pageUrl` in place of a per-anchor one, and
181
+ reads `liveEditing` and `comments` from `on-page`. New CDN release
182
+ (`boot.v1.a86632b937c1e248.js`).
183
+ - **`CurrencyValue` is `{ amountMinor, currency }`**, the name a write takes:
184
+ the delivery API answered `amount` while every write took `amountMinor`,
185
+ both in minor units. A currency value read can be written back unchanged.
186
+ - **`site.update({ url, previewOrigins })`** (`PATCH /site`) sets the site's
187
+ address and the extra origins drafts may be shown on, under the settings
188
+ page's rules, and `site.get()` reads both. `collections.update()` and
189
+ `documents.update()` take `previewPath`. Server code, with a `secret_` key
190
+ or an ADMIN suite credential.
191
+ - **A refused body says what was wrong.** The `400` message names each problem
192
+ (`Invalid input: key: …; type: …`) instead of a bare `Invalid input`, and the
193
+ body lists them in `error.details` (`path`, `message`, `code`).
194
+
195
+ ## [0.2.0] - 2026-03-14
196
+
197
+ ### Added
198
+
199
+ - Write operations for collections, items, documents, media, and site introspection.
200
+ - Nested resource clients for fields, sections, document values, and SEO.
201
+ - Configurable `pathPrefix` support for production rewrites and local `next-app` development.
202
+
203
+ ## [0.1.0] - 2026-03-11
204
+
205
+ ### Added
206
+
207
+ - Initial standalone SDK implementation for the EelZap Content Delivery API.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 EelZap
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.