@digital-gravy/etch-public-api 0.7.0 → 0.7.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/README.md CHANGED
@@ -26,13 +26,13 @@ Acquire it with `getEtch()`, guarded by `isEtchAvailable()` for code that might
26
26
  run outside the builder:
27
27
 
28
28
  ```ts
29
- import { getEtch, isEtchAvailable } from "@digital-gravy/etch-public-api";
29
+ import { getEtch, isEtchAvailable } from '@digital-gravy/etch-public-api';
30
30
 
31
31
  function run() {
32
- if (!isEtchAvailable()) return; // not running inside the Etch builder
33
- const etch = getEtch();
34
- const textIds = etch.blocks.find({ type: "text" });
35
- etch.blocks.setText(textIds[0], "Hello world");
32
+ if (!isEtchAvailable()) return; // not running inside the Etch builder
33
+ const etch = getEtch();
34
+ const textIds = etch.blocks.find({ type: 'text' });
35
+ etch.blocks.setText(textIds[0], 'Hello world');
36
36
  }
37
37
  ```
38
38
 
@@ -41,15 +41,16 @@ isn't on the page, so you can also `try`/`catch` it. If your script may run
41
41
  before the builder has finished loading, wait until it appears:
42
42
 
43
43
  ```ts
44
- import { getEtch, isEtchAvailable } from "@digital-gravy/etch-public-api";
44
+ import { getEtch, isEtchAvailable } from '@digital-gravy/etch-public-api';
45
45
 
46
46
  async function whenEtchReady(timeoutMs = 10_000) {
47
- const start = Date.now();
48
- while (!isEtchAvailable()) {
49
- if (Date.now() - start > timeoutMs) throw new Error("Etch did not load");
50
- await new Promise((resolve) => setTimeout(resolve, 100));
51
- }
52
- return getEtch();
47
+ const start = Date.now();
48
+ while (!isEtchAvailable()) {
49
+ if (Date.now() - start > timeoutMs)
50
+ throw new Error('Etch did not load');
51
+ await new Promise((resolve) => setTimeout(resolve, 100));
52
+ }
53
+ return getEtch();
53
54
  }
54
55
 
55
56
  const etch = await whenEtchReady();
@@ -59,12 +60,12 @@ const etch = await whenEtchReady();
59
60
 
60
61
  ```ts
61
62
  // Read
62
- const textIds = etch.blocks.find({ type: "etch/text" });
63
+ const textIds = etch.blocks.find({ type: 'etch/text' });
63
64
  const json = etch.blocks.getJson(textIds[0]);
64
65
 
65
66
  // Mutate (routes through the same guarded paths as the UI; undo/redo works)
66
- etch.blocks.setText(textIds[0], "Hello world");
67
- etch.blocks.addClass(textIds[0], "lead");
67
+ etch.blocks.setText(textIds[0], 'Hello world');
68
+ etch.blocks.addClass(textIds[0], 'lead');
68
69
 
69
70
  // Persist (blocks/styles wait for save; stylesheets/components/fields persist immediately)
70
71
  await etch.saveAsync();
@@ -74,22 +75,22 @@ await etch.saveAsync();
74
75
 
75
76
  ```ts
76
77
  // Create a class or id rule
77
- const styleId = etch.styles.create(".lead", "font-size: 1.25rem;");
78
+ const styleId = etch.styles.create('.lead', 'font-size: 1.25rem;');
78
79
 
79
80
  // Find existing styles by selector type
80
- const classStyles = etch.styles.list({ type: "class" });
81
- const myStyle = etch.styles.list().find((s) => s.selector === ".lead");
81
+ const classStyles = etch.styles.list({ type: 'class' });
82
+ const myStyle = etch.styles.list().find((s) => s.selector === '.lead');
82
83
  console.log(myStyle?.id); // the id you pass to blocks.addClass etc.
83
84
 
84
85
  // Global CSS custom properties (default collection)
85
- etch.styles.setVariable("--brand", "#0af");
86
- etch.styles.getVariable("--brand"); // "#0af"
86
+ etch.styles.setVariable('--brand', '#0af');
87
+ etch.styles.getVariable('--brand'); // "#0af"
87
88
 
88
89
  // Variable methods accept an optional collection for multi-collection :root setups
89
- etch.styles.setVariable("--brand", "#0af", "theme-a");
90
- etch.styles.getVariable("--brand", "theme-a"); // "#0af"
91
- etch.styles.listVariables("theme-a");
92
- etch.styles.removeVariable("--brand", "theme-a");
90
+ etch.styles.setVariable('--brand', '#0af', 'theme-a');
91
+ etch.styles.getVariable('--brand', 'theme-a'); // "#0af"
92
+ etch.styles.listVariables('theme-a');
93
+ etch.styles.removeVariable('--brand', 'theme-a');
93
94
  ```
94
95
 
95
96
  > **Note:** The `collection` field on style **objects** (`StyleSummary`) and the
@@ -106,7 +107,7 @@ for direct inspection or mutation, then save and exit when done:
106
107
 
107
108
  ```ts
108
109
  // Find a component block
109
- const [compId] = etch.blocks.find({ type: "etch/component" });
110
+ const [compId] = etch.blocks.find({ type: 'etch/component' });
110
111
 
111
112
  // Enter edit mode — the component's block tree becomes accessible
112
113
  etch.blocks.enterComponentEditMode(compId);
@@ -137,19 +138,19 @@ key must be a property declared by the component definition, or the call throws
137
138
  `INVALID_ARGUMENT`.
138
139
 
139
140
  ```ts
140
- const [cardId] = etch.blocks.find({ type: "etch/component" });
141
+ const [cardId] = etch.blocks.find({ type: 'etch/component' });
141
142
 
142
143
  // Set a prop the component declares
143
- etch.blocks.setAttribute(cardId, "title", "Hello world");
144
+ etch.blocks.setAttribute(cardId, 'title', 'Hello world');
144
145
 
145
146
  // Read it back
146
- etch.blocks.getAttribute(cardId, "title"); // "Hello world"
147
+ etch.blocks.getAttribute(cardId, 'title'); // "Hello world"
147
148
 
148
149
  // Or patch several props at once
149
- etch.blocks.update(cardId, { attributes: { title: "Hi", variant: "primary" } });
150
+ etch.blocks.update(cardId, { attributes: { title: 'Hi', variant: 'primary' } });
150
151
 
151
152
  // An undeclared key is rejected
152
- etch.blocks.setAttribute(cardId, "notAProp", "x"); // ✗ throws INVALID_ARGUMENT
153
+ etch.blocks.setAttribute(cardId, 'notAProp', 'x'); // ✗ throws INVALID_ARGUMENT
153
154
  ```
154
155
 
155
156
  > Values are stored as-is. For typed props such as classes or repeater/group
@@ -161,14 +162,14 @@ Methods throw a typed `EtchApiError` with a `code`, rather than returning
161
162
  sentinels:
162
163
 
163
164
  ```ts
164
- import { isEtchApiError } from "@digital-gravy/etch-public-api";
165
+ import { isEtchApiError } from '@digital-gravy/etch-public-api';
165
166
 
166
167
  try {
167
- etch.blocks.getJson("does-not-exist");
168
+ etch.blocks.getJson('does-not-exist');
168
169
  } catch (err) {
169
- if (isEtchApiError(err)) {
170
- console.warn(err.code, err.message); // e.g. "BLOCK_NOT_FOUND"
171
- }
170
+ if (isEtchApiError(err)) {
171
+ console.warn(err.code, err.message); // e.g. "BLOCK_NOT_FOUND"
172
+ }
172
173
  }
173
174
  ```
174
175
 
@@ -182,8 +183,8 @@ experimental, **prefer feature detection** over version comparison:
182
183
 
183
184
  ```ts
184
185
  const etch = getEtch();
185
- if (typeof etch.blocks.someNewMethod === "function") {
186
- // safe to use
186
+ if (typeof etch.blocks.someNewMethod === 'function') {
187
+ // safe to use
187
188
  }
188
189
  ```
189
190
 
@@ -194,7 +195,7 @@ targets, and failing fast when the runtime can't satisfy it:
194
195
 
195
196
  ```ts
196
197
  // Reserved API — shape of versioned access once the contract is stable:
197
- const etch = getEtch({ apiVersion: "^1.0", id: "my-plugin" });
198
+ const etch = getEtch({ apiVersion: '^1.0', id: 'my-plugin' });
198
199
  // └─ delegates to window.etch.connect({ apiVersion: "^1.0", id }) when present,
199
200
  // yielding a version-pinned instance (throws on an incompatible runtime).
200
201
  ```
@@ -212,19 +213,19 @@ results narrow by `type`:
212
213
  ```ts
213
214
  const block = etch.blocks.getJson(id);
214
215
 
215
- if (block.type === "etch/text") {
216
- console.log(block.text); // narrowed to the text-block shape
217
- } else if (block.type === "etch/element") {
218
- console.log(block.tag, block.attributes);
216
+ if (block.type === 'etch/text') {
217
+ console.log(block.text); // narrowed to the text-block shape
218
+ } else if (block.type === 'etch/element') {
219
+ console.log(block.tag, block.attributes);
219
220
  }
220
221
 
221
222
  // Authoring is checked too — this is a type error (an `etch/text` has no `tag`):
222
223
  etch.blocks.create({
223
- type: "etch/text",
224
- version: 1,
225
- context: {},
226
- children: [],
227
- tag: "div", // ✗ type error
224
+ type: 'etch/text',
225
+ version: 1,
226
+ context: {},
227
+ children: [],
228
+ tag: 'div' // ✗ type error
228
229
  });
229
230
  ```
230
231
 
@@ -233,22 +234,24 @@ etch.blocks.create({
233
234
  Some block types recognise **special attributes** in addition to standard HTML:
234
235
 
235
236
  **`etch/dynamic-image`** — rendered as `<img>`:
237
+
236
238
  - `mediaId` — WordPress attachment ID. Etch fetches the media object and uses its URL as `src`, overriding any explicit `src`. Supports dynamic expressions (e.g. `{post.featured_image_id}`).
237
239
  - `useSrcSet` — `"true"` to generate a responsive `srcset` from the media (requires `mediaId`).
238
240
  - `maximumSize` — WordPress image size slug (e.g. `"large"`, `"full"`) used when resolving the image. Defaults to `"full"`.
239
241
 
240
242
  ```ts
241
- etch.blocks.setAttribute(imgBlockId, "mediaId", "{post.featured_image_id}");
242
- etch.blocks.setAttribute(imgBlockId, "useSrcSet", "true");
243
+ etch.blocks.setAttribute(imgBlockId, 'mediaId', '{post.featured_image_id}');
244
+ etch.blocks.setAttribute(imgBlockId, 'useSrcSet', 'true');
243
245
  ```
244
246
 
245
247
  **`etch/svg`** — inline SVG:
248
+
246
249
  - `src` — URL of an external `.svg` file. Etch fetches and inlines the SVG at render time. Supports dynamic expressions.
247
250
  - `stripColors` — `"true"` to strip `fill` and `stroke` colour declarations from the fetched SVG, so CSS can drive its colours instead.
248
251
 
249
252
  ```ts
250
- etch.blocks.setAttribute(svgBlockId, "src", "/icons/logo.svg");
251
- etch.blocks.setAttribute(svgBlockId, "stripColors", "true");
253
+ etch.blocks.setAttribute(svgBlockId, 'src', '/icons/logo.svg');
254
+ etch.blocks.setAttribute(svgBlockId, 'stripColors', 'true');
252
255
  ```
253
256
 
254
257
  ### Types only
@@ -258,9 +261,9 @@ directly:
258
261
 
259
262
  ```ts
260
263
  import type {
261
- PublicBlockJson,
262
- EtchBlocksApi,
263
- } from "@digital-gravy/etch-public-api";
264
+ PublicBlockJson,
265
+ EtchBlocksApi
266
+ } from '@digital-gravy/etch-public-api';
264
267
  ```
265
268
 
266
269
  You can also work against the global directly — the package augments
@@ -273,14 +276,14 @@ is imported.
273
276
  - `EtchApiError` / `isEtchApiError()` / `EtchApiErrorCode` — typed errors.
274
277
  - `ETCH_API_VERSION` — the contract version this package targets (`0.x`).
275
278
  - The full contract as exported types:
276
- - **Blocks** — `Etch`, `EtchBlocksApi`, `EtchBlockJson`, `PublicBlockJson`, `FindBlocksPredicate`, `BlockPatch`, …
277
- - **Styles** — `EtchStylesApi`, `StyleSummary`, `StyleListFilter`, `StyleSelectorType`, `StylePatch`
278
- - **Stylesheets** — `EtchStylesheetsApi`, `StylesheetSummary`, `StylesheetInput`, `StylesheetPatch`
279
- - **Components** — `EtchComponentsApi`, `PublicComponentSummary`, `PublicComponentJson`, `ComponentPatch`, `ComponentProperty`, …
280
- - **Loops** — `EtchLoopsApi`, `EtchLoop`, `EtchLoopConfig`, `BlockLoopBinding`, …
281
- - **Navigation** — `EtchNavigationApi`, `NavigationPlace`, `PostSummary`, `TemplateSummary`
282
- - **Fields** — `EtchFieldsApi`, `CustomField`, `CustomFieldGroup`, …
283
- - **UI / History** — `EtchUiApi`, `EtchHistoryApi`, `ColorScheme`
279
+ - **Blocks** — `Etch`, `EtchBlocksApi`, `EtchBlockJson`, `PublicBlockJson`, `FindBlocksPredicate`, `BlockPatch`, …
280
+ - **Styles** — `EtchStylesApi`, `StyleSummary`, `StyleListFilter`, `StyleSelectorType`, `StylePatch`
281
+ - **Stylesheets** — `EtchStylesheetsApi`, `StylesheetSummary`, `StylesheetInput`, `StylesheetPatch`
282
+ - **Components** — `EtchComponentsApi`, `PublicComponentSummary`, `PublicComponentJson`, `ComponentPatch`, `ComponentProperty`, …
283
+ - **Loops** — `EtchLoopsApi`, `EtchLoop`, `EtchLoopConfig`, `BlockLoopBinding`, …
284
+ - **Navigation** — `EtchNavigationApi`, `NavigationPlace`, `PostSummary`, `TemplateSummary`
285
+ - **Fields** — `EtchFieldsApi`, `CustomField`, `CustomFieldGroup`, …
286
+ - **UI / History** — `EtchUiApi`, `EtchHistoryApi`, `ColorScheme`
284
287
 
285
288
  ## Versioning
286
289
 
package/dist/index.cjs CHANGED
@@ -47,7 +47,10 @@ function getEtch(options = {}) {
47
47
  return etch.connect(options);
48
48
  }
49
49
  if (options.apiVersion) {
50
- warnIfIncompatible(options.apiVersion, etch.apiVersion ?? ETCH_API_VERSION);
50
+ warnIfIncompatible(
51
+ options.apiVersion,
52
+ etch.apiVersion ?? ETCH_API_VERSION
53
+ );
51
54
  }
52
55
  return etch;
53
56
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/client.ts"],"names":[],"mappings":";;;AAyBO,IAAM,YAAA,GAAN,cAA2B,KAAA,CAAM;AAAA,EAGvC,WAAA,CAAY,MAAwB,OAAA,EAAiB;AACpD,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,cAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACb;AACD;AAGO,SAAS,eAAe,KAAA,EAAuC;AACrE,EAAA,OAAO,KAAA,YAAiB,YAAA,IAAiB,KAAA,EAAiB,IAAA,KAAS,cAAA;AACpE;;;AC9BO,IAAM,gBAAA,GAAmB;;;ACIhC,SAAS,QAAA,GAA6B;AACrC,EAAA,MAAM,KAAA,GAAQ,UAAA;AACd,EAAA,OAAO,KAAA,CAAM,IAAA;AACd;AAMO,SAAS,eAAA,GAA2B;AAC1C,EAAA,OAAO,UAAS,KAAM,MAAA;AACvB;AAGA,SAAS,QAAQ,OAAA,EAAgC;AAChD,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA;AACtC,EAAA,OAAO,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA,GAAI,IAAA;AACnC;AAOA,SAAS,kBAAA,CAAmB,WAAmB,OAAA,EAAuB;AACrE,EAAA,MAAM,IAAA,GAAO,QAAQ,SAAS,CAAA;AAC9B,EAAA,MAAM,IAAA,GAAO,QAAQ,OAAO,CAAA;AAC5B,EAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,IAAA,IAAQ,SAAS,IAAA,EAAM;AAErD,EAAA,OAAA,CAAQ,IAAA;AAAA,IACP,CAAA,qDAAA,EAAwD,SAAS,CAAA,wBAAA,EAC9C,OAAO,CAAA,sBAAA;AAAA,GAC3B;AACD;AAsBO,SAAS,OAAA,CAAQ,OAAA,GAA0B,EAAC,EAAS;AAC3D,EAAA,MAAM,OAAO,QAAA,EAAS;AACtB,EAAA,IAAI,CAAC,IAAA,EAAM;AACV,IAAA,MAAM,IAAI,YAAA;AAAA,MACT,eAAA;AAAA,MACA;AAAA,KAED;AAAA,EACD;AAEA,EAAA,IAAI,OAAO,IAAA,CAAK,OAAA,KAAY,UAAA,EAAY;AACvC,IAAA,OAAO,IAAA,CAAK,QAAQ,OAAO,CAAA;AAAA,EAC5B;AAEA,EAAA,IAAI,QAAQ,UAAA,EAAY;AACvB,IAAA,kBAAA,CAAmB,OAAA,CAAQ,UAAA,EAAY,IAAA,CAAK,UAAA,IAAc,gBAAgB,CAAA;AAAA,EAC3E;AACA,EAAA,OAAO,IAAA;AACR","file":"index.cjs","sourcesContent":["/**\n * Error codes thrown by the public `window.etch` API.\n *\n * The API throws typed errors (rather than returning sentinels) so that AI\n * assistants and plugin authors can `try`/`catch` and react to a precise cause.\n *\n * The union ends with `(string & {})` so that codes added by newer Etch\n * runtimes still type-check as `EtchApiErrorCode` while keeping autocomplete for\n * the known values.\n */\nexport type EtchApiErrorCode =\n\t| 'BLOCK_NOT_FOUND'\n\t| 'WRONG_BLOCK_TYPE'\n\t| 'READONLY'\n\t| 'INVALID_ARGUMENT'\n\t| 'LOOP_NOT_FOUND'\n\t| 'STYLE_NOT_FOUND'\n\t| 'STYLESHEET_NOT_FOUND'\n\t| 'COMPONENT_NOT_FOUND'\n\t| 'POST_NOT_FOUND'\n\t| 'OPERATION_FAILED'\n\t| 'NOT_AVAILABLE'\n\t| (string & {});\n\n/** Error thrown by the public Etch API (and by this client). */\nexport class EtchApiError extends Error {\n\treadonly code: EtchApiErrorCode;\n\n\tconstructor(code: EtchApiErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'EtchApiError';\n\t\tthis.code = code;\n\t}\n}\n\n/** Narrow an unknown caught value to an {@link EtchApiError}. */\nexport function isEtchApiError(value: unknown): value is EtchApiError {\n\treturn value instanceof EtchApiError || (value as Error)?.name === 'EtchApiError';\n}\n","/**\n * Version of the Etch scripting **contract** this package targets, independent\n * of the Etch product version and of this package's own npm version.\n *\n * `0.x` signals the surface is **experimental** and may change without a major\n * bump until it stabilizes. It matches the value returned by the runtime's\n * {@link Etch.apiVersion} getter on `window.etch`.\n */\nexport const ETCH_API_VERSION = '0.x';\n","import type { ConnectOptions, Etch } from './contract';\nimport { EtchApiError } from './errors';\nimport { ETCH_API_VERSION } from './version';\n\ndeclare global {\n\tinterface Window {\n\t\t/** The Etch scripting API, present once the builder has loaded. */\n\t\tetch?: Etch;\n\t}\n}\n\n/** Read `window.etch` from whatever global object exists, or `undefined`. */\nfunction readEtch(): Etch | undefined {\n\tconst scope = globalThis as { etch?: Etch };\n\treturn scope.etch;\n}\n\n/**\n * Whether the Etch scripting API is present on the page. Use this to guard code\n * that should no-op when not running inside the builder.\n */\nexport function isEtchAvailable(): boolean {\n\treturn readEtch() !== undefined;\n}\n\n/** The major version number of a semver-ish string, or `null` if unparseable. */\nfunction majorOf(version: string): number | null {\n\tconst match = /^\\D*(\\d+)/.exec(version);\n\treturn match ? Number(match[1]) : null;\n}\n\n/**\n * Best-effort compatibility check for `0.x` runtimes that have no native\n * `connect()`. Warns (does not throw) when the requested major differs from the\n * runtime's, so experimental consumers aren't hard-blocked.\n */\nfunction warnIfIncompatible(requested: string, runtime: string): void {\n\tconst want = majorOf(requested);\n\tconst have = majorOf(runtime);\n\tif (want === null || have === null || want === have) return;\n\t// eslint-disable-next-line no-console\n\tconsole.warn(\n\t\t`[@digital-gravy/etch-public-api] Requested Etch API v${requested} but the ` +\n\t\t\t`page provides v${runtime}. Behavior may differ.`\n\t);\n}\n\n/**\n * Acquire the Etch scripting API from the page.\n *\n * The runtime lives on `window.etch` (injected by the builder); this returns it\n * typed. When the page exposes a future stable runtime with a native\n * `connect()`, version negotiation is delegated to it. On today's `0.x`\n * runtime, the global is returned directly after a best-effort version check.\n *\n * @throws {EtchApiError} `NOT_AVAILABLE` when the builder is not present.\n *\n * @example\n * ```ts\n * import { getEtch } from '@etchwp/public-api';\n *\n * const etch = getEtch();\n * const ids = etch.blocks.find({ type: 'text' });\n * etch.blocks.setText(ids[0], 'Hello');\n * await etch.saveAsync();\n * ```\n */\nexport function getEtch(options: ConnectOptions = {}): Etch {\n\tconst etch = readEtch();\n\tif (!etch) {\n\t\tthrow new EtchApiError(\n\t\t\t'NOT_AVAILABLE',\n\t\t\t'window.etch is not available. The Etch builder is not loaded on this page, ' +\n\t\t\t\t'or getEtch() ran before it finished initializing.'\n\t\t);\n\t}\n\n\tif (typeof etch.connect === 'function') {\n\t\treturn etch.connect(options);\n\t}\n\n\tif (options.apiVersion) {\n\t\twarnIfIncompatible(options.apiVersion, etch.apiVersion ?? ETCH_API_VERSION);\n\t}\n\treturn etch;\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/client.ts"],"names":[],"mappings":";;;AAyBO,IAAM,YAAA,GAAN,cAA2B,KAAA,CAAM;AAAA,EAGvC,WAAA,CAAY,MAAwB,OAAA,EAAiB;AACpD,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,cAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACb;AACD;AAGO,SAAS,eAAe,KAAA,EAAuC;AACrE,EAAA,OACC,KAAA,YAAiB,YAAA,IAChB,KAAA,EAAiB,IAAA,KAAS,cAAA;AAE7B;;;ACjCO,IAAM,gBAAA,GAAmB;;;ACIhC,SAAS,QAAA,GAA6B;AACrC,EAAA,MAAM,KAAA,GAAQ,UAAA;AACd,EAAA,OAAO,KAAA,CAAM,IAAA;AACd;AAMO,SAAS,eAAA,GAA2B;AAC1C,EAAA,OAAO,UAAS,KAAM,MAAA;AACvB;AAGA,SAAS,QAAQ,OAAA,EAAgC;AAChD,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA;AACtC,EAAA,OAAO,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA,GAAI,IAAA;AACnC;AAOA,SAAS,kBAAA,CAAmB,WAAmB,OAAA,EAAuB;AACrE,EAAA,MAAM,IAAA,GAAO,QAAQ,SAAS,CAAA;AAC9B,EAAA,MAAM,IAAA,GAAO,QAAQ,OAAO,CAAA;AAC5B,EAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,IAAA,IAAQ,SAAS,IAAA,EAAM;AACrD,EAAA,OAAA,CAAQ,IAAA;AAAA,IACP,CAAA,qDAAA,EAAwD,SAAS,CAAA,wBAAA,EAC9C,OAAO,CAAA,sBAAA;AAAA,GAC3B;AACD;AAsBO,SAAS,OAAA,CAAQ,OAAA,GAA0B,EAAC,EAAS;AAC3D,EAAA,MAAM,OAAO,QAAA,EAAS;AACtB,EAAA,IAAI,CAAC,IAAA,EAAM;AACV,IAAA,MAAM,IAAI,YAAA;AAAA,MACT,eAAA;AAAA,MACA;AAAA,KAED;AAAA,EACD;AAEA,EAAA,IAAI,OAAO,IAAA,CAAK,OAAA,KAAY,UAAA,EAAY;AACvC,IAAA,OAAO,IAAA,CAAK,QAAQ,OAAO,CAAA;AAAA,EAC5B;AAEA,EAAA,IAAI,QAAQ,UAAA,EAAY;AACvB,IAAA,kBAAA;AAAA,MACC,OAAA,CAAQ,UAAA;AAAA,MACR,KAAK,UAAA,IAAc;AAAA,KACpB;AAAA,EACD;AACA,EAAA,OAAO,IAAA;AACR","file":"index.cjs","sourcesContent":["/**\n * Error codes thrown by the public `window.etch` API.\n *\n * The API throws typed errors (rather than returning sentinels) so that AI\n * assistants and plugin authors can `try`/`catch` and react to a precise cause.\n *\n * The union ends with `(string & {})` so that codes added by newer Etch\n * runtimes still type-check as `EtchApiErrorCode` while keeping autocomplete for\n * the known values.\n */\nexport type EtchApiErrorCode =\n\t| 'BLOCK_NOT_FOUND'\n\t| 'WRONG_BLOCK_TYPE'\n\t| 'READONLY'\n\t| 'INVALID_ARGUMENT'\n\t| 'LOOP_NOT_FOUND'\n\t| 'STYLE_NOT_FOUND'\n\t| 'STYLESHEET_NOT_FOUND'\n\t| 'COMPONENT_NOT_FOUND'\n\t| 'POST_NOT_FOUND'\n\t| 'OPERATION_FAILED'\n\t| 'NOT_AVAILABLE'\n\t| (string & {});\n\n/** Error thrown by the public Etch API (and by this client). */\nexport class EtchApiError extends Error {\n\treadonly code: EtchApiErrorCode;\n\n\tconstructor(code: EtchApiErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'EtchApiError';\n\t\tthis.code = code;\n\t}\n}\n\n/** Narrow an unknown caught value to an {@link EtchApiError}. */\nexport function isEtchApiError(value: unknown): value is EtchApiError {\n\treturn (\n\t\tvalue instanceof EtchApiError ||\n\t\t(value as Error)?.name === 'EtchApiError'\n\t);\n}\n","/**\n * Version of the Etch scripting **contract** this package targets, independent\n * of the Etch product version and of this package's own npm version.\n *\n * `0.x` signals the surface is **experimental** and may change without a major\n * bump until it stabilizes. It matches the value returned by the runtime's\n * {@link Etch.apiVersion} getter on `window.etch`.\n */\nexport const ETCH_API_VERSION = '0.x';\n","import type { ConnectOptions, Etch } from './contract';\nimport { EtchApiError } from './errors';\nimport { ETCH_API_VERSION } from './version';\n\ndeclare global {\n\tinterface Window {\n\t\t/** The Etch scripting API, present once the builder has loaded. */\n\t\tetch?: Etch;\n\t}\n}\n\n/** Read `window.etch` from whatever global object exists, or `undefined`. */\nfunction readEtch(): Etch | undefined {\n\tconst scope = globalThis as { etch?: Etch };\n\treturn scope.etch;\n}\n\n/**\n * Whether the Etch scripting API is present on the page. Use this to guard code\n * that should no-op when not running inside the builder.\n */\nexport function isEtchAvailable(): boolean {\n\treturn readEtch() !== undefined;\n}\n\n/** The major version number of a semver-ish string, or `null` if unparseable. */\nfunction majorOf(version: string): number | null {\n\tconst match = /^\\D*(\\d+)/.exec(version);\n\treturn match ? Number(match[1]) : null;\n}\n\n/**\n * Best-effort compatibility check for `0.x` runtimes that have no native\n * `connect()`. Warns (does not throw) when the requested major differs from the\n * runtime's, so experimental consumers aren't hard-blocked.\n */\nfunction warnIfIncompatible(requested: string, runtime: string): void {\n\tconst want = majorOf(requested);\n\tconst have = majorOf(runtime);\n\tif (want === null || have === null || want === have) return;\n\tconsole.warn(\n\t\t`[@digital-gravy/etch-public-api] Requested Etch API v${requested} but the ` +\n\t\t\t`page provides v${runtime}. Behavior may differ.`\n\t);\n}\n\n/**\n * Acquire the Etch scripting API from the page.\n *\n * The runtime lives on `window.etch` (injected by the builder); this returns it\n * typed. When the page exposes a future stable runtime with a native\n * `connect()`, version negotiation is delegated to it. On today's `0.x`\n * runtime, the global is returned directly after a best-effort version check.\n *\n * @throws {EtchApiError} `NOT_AVAILABLE` when the builder is not present.\n *\n * @example\n * ```ts\n * import { getEtch } from '@etchwp/public-api';\n *\n * const etch = getEtch();\n * const ids = etch.blocks.find({ type: 'text' });\n * etch.blocks.setText(ids[0], 'Hello');\n * await etch.saveAsync();\n * ```\n */\nexport function getEtch(options: ConnectOptions = {}): Etch {\n\tconst etch = readEtch();\n\tif (!etch) {\n\t\tthrow new EtchApiError(\n\t\t\t'NOT_AVAILABLE',\n\t\t\t'window.etch is not available. The Etch builder is not loaded on this page, ' +\n\t\t\t\t'or getEtch() ran before it finished initializing.'\n\t\t);\n\t}\n\n\tif (typeof etch.connect === 'function') {\n\t\treturn etch.connect(options);\n\t}\n\n\tif (options.apiVersion) {\n\t\twarnIfIncompatible(\n\t\t\toptions.apiVersion,\n\t\t\tetch.apiVersion ?? ETCH_API_VERSION\n\t\t);\n\t}\n\treturn etch;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -12,7 +12,7 @@ interface EtchBlockContext {
12
12
  * panel. This is editor UI state, not document data — most scripts can
13
13
  * ignore it.
14
14
  */
15
- structureState?: "open" | "closed";
15
+ structureState?: 'open' | 'closed';
16
16
  /** Whether the block is hidden (not rendered) on the canvas. */
17
17
  hidden?: boolean;
18
18
  }
@@ -64,7 +64,7 @@ interface EtchBlockCommon {
64
64
  }
65
65
  /** A text block (`etch/text`). */
66
66
  interface EtchTextBlockJson extends EtchBlockCommon {
67
- type: "etch/text";
67
+ type: 'etch/text';
68
68
  /** The block's text content. */
69
69
  text: string;
70
70
  }
@@ -76,7 +76,7 @@ interface EtchTextBlockJson extends EtchBlockCommon {
76
76
  * `blocks.create()` / `blocks.replace()` ignore them.
77
77
  */
78
78
  interface EtchElementBlockJson extends EtchBlockCommon {
79
- type: "etch/element";
79
+ type: 'etch/element';
80
80
  /** The HTML tag name, e.g. `div`, `p`, `h1`. */
81
81
  tag: string;
82
82
  /** HTML attributes. */
@@ -90,7 +90,7 @@ interface EtchElementBlockJson extends EtchBlockCommon {
90
90
  * {@link EtchElementBlockJson}).
91
91
  */
92
92
  interface EtchDynamicElementBlockJson extends EtchBlockCommon {
93
- type: "etch/dynamic-element";
93
+ type: 'etch/dynamic-element';
94
94
  /** HTML attributes (the rendered tag is read from `attributes.tag`). */
95
95
  attributes: EtchHtmlAttributes;
96
96
  }
@@ -111,7 +111,7 @@ interface EtchDynamicElementBlockJson extends EtchBlockCommon {
111
111
  * to `"full"` when omitted.
112
112
  */
113
113
  interface EtchDynamicImageBlockJson extends EtchBlockCommon {
114
- type: "etch/dynamic-image";
114
+ type: 'etch/dynamic-image';
115
115
  /** HTML attributes (e.g. `src`, `alt`). */
116
116
  attributes: EtchHtmlAttributes;
117
117
  }
@@ -129,13 +129,13 @@ interface EtchDynamicImageBlockJson extends EtchBlockCommon {
129
129
  * when `src` is set.
130
130
  */
131
131
  interface EtchSvgBlockJson extends EtchBlockCommon {
132
- type: "etch/svg";
132
+ type: 'etch/svg';
133
133
  /** HTML/SVG attributes. */
134
134
  attributes: EtchHtmlAttributes;
135
135
  }
136
136
  /** A loop block (`etch/loop`) that repeats its children over a data source. */
137
137
  interface EtchLoopBlockJson extends EtchBlockCommon {
138
- type: "etch/loop";
138
+ type: 'etch/loop';
139
139
  /** Variable name bound to the current item (e.g. `item`). */
140
140
  itemId: string;
141
141
  /** What the block iterates over (a dynamic path); omitted when bound via `loopId`. */
@@ -149,13 +149,13 @@ interface EtchLoopBlockJson extends EtchBlockCommon {
149
149
  }
150
150
  /** A conditional block (`etch/condition`); renders its children when the expression holds. */
151
151
  interface EtchConditionBlockJson extends EtchBlockCommon {
152
- type: "etch/condition";
152
+ type: 'etch/condition';
153
153
  /** The condition expression. */
154
154
  conditionString: string;
155
155
  }
156
156
  /** An instance of a reusable component (`etch/component`). */
157
157
  interface EtchComponentBlockJson extends EtchBlockCommon {
158
- type: "etch/component";
158
+ type: 'etch/component';
159
159
  /** Id of the component being instantiated. */
160
160
  componentId: number;
161
161
  /** Values bound to the component's properties. */
@@ -163,23 +163,23 @@ interface EtchComponentBlockJson extends EtchBlockCommon {
163
163
  }
164
164
  /** Content projected into a component slot (`etch/slot-content`). */
165
165
  interface EtchSlotContentBlockJson extends EtchBlockCommon {
166
- type: "etch/slot-content";
166
+ type: 'etch/slot-content';
167
167
  /** Name of the slot this content targets. */
168
168
  slotName: string;
169
169
  }
170
170
  /** A slot placeholder inside a component definition (`etch/slot-placeholder`). */
171
171
  interface EtchSlotPlaceholderBlockJson extends EtchBlockCommon {
172
- type: "etch/slot-placeholder";
172
+ type: 'etch/slot-placeholder';
173
173
  /** Name of the slot. */
174
174
  slotName: string;
175
175
  }
176
176
  /** The post-content insertion point (`etch/post-content`). No extra fields. */
177
177
  interface EtchPostContentBlockJson extends EtchBlockCommon {
178
- type: "etch/post-content";
178
+ type: 'etch/post-content';
179
179
  }
180
180
  /** A raw-HTML block (`etch/raw-html`). */
181
181
  interface EtchRawHtmlBlockJson extends EtchBlockCommon {
182
- type: "etch/raw-html";
182
+ type: 'etch/raw-html';
183
183
  /** Sanitized HTML content. */
184
184
  content: string;
185
185
  /** The original, unsanitized HTML as authored. */
@@ -187,7 +187,7 @@ interface EtchRawHtmlBlockJson extends EtchBlockCommon {
187
187
  }
188
188
  /** A pass-through wrapper around a native Gutenberg block (`etch/passthrough`). */
189
189
  interface EtchPassthroughBlockJson extends EtchBlockCommon {
190
- type: "etch/passthrough";
190
+ type: 'etch/passthrough';
191
191
  /** The wrapped Gutenberg block. */
192
192
  gutenbergBlock: GutenbergBlock;
193
193
  }
@@ -201,7 +201,7 @@ interface EtchPassthroughBlockJson extends EtchBlockCommon {
201
201
  */
202
202
  type EtchBlockJson = EtchTextBlockJson | EtchElementBlockJson | EtchDynamicElementBlockJson | EtchDynamicImageBlockJson | EtchSvgBlockJson | EtchLoopBlockJson | EtchConditionBlockJson | EtchComponentBlockJson | EtchSlotContentBlockJson | EtchSlotPlaceholderBlockJson | EtchPostContentBlockJson | EtchRawHtmlBlockJson | EtchPassthroughBlockJson;
203
203
  /** Every known block `type` string (the discriminants of {@link EtchBlockJson}). */
204
- type EtchBlockTypeName = EtchBlockJson["type"];
204
+ type EtchBlockTypeName = EtchBlockJson['type'];
205
205
  /** Read-only identity attached to every serialized (read) block. */
206
206
  interface BlockIdentity {
207
207
  /** Stable id of this block. */
@@ -217,7 +217,7 @@ interface BlockIdentity {
217
217
  * writable {@link EtchBlockJson}, so they cannot be set via
218
218
  * `blocks.create()` / `blocks.replace()`.
219
219
  */
220
- type StyledBlockType = "etch/element" | "etch/dynamic-element" | "etch/dynamic-image" | "etch/svg";
220
+ type StyledBlockType = 'etch/element' | 'etch/dynamic-element' | 'etch/dynamic-image' | 'etch/svg';
221
221
  /** The read-only `styles` exposed on a {@link StyledBlockType} when reading. */
222
222
  interface ReadOnlyBlockStyles {
223
223
  /** Ids of the global styles applied to this block (read-only). */
@@ -227,7 +227,7 @@ interface ReadOnlyBlockStyles {
227
227
  * Attach read-only identity (`id`/`parentId`) to a block, recursively, plus the
228
228
  * read-only `styles` array for the {@link StyledBlockType}s that carry one.
229
229
  */
230
- type WithIdentity<B> = B extends EtchBlockCommon ? Omit<B, "children"> & BlockIdentity & (B extends {
230
+ type WithIdentity<B> = B extends EtchBlockCommon ? Omit<B, 'children'> & BlockIdentity & (B extends {
231
231
  type: StyledBlockType;
232
232
  } ? ReadOnlyBlockStyles : unknown) : never;
233
233
  /**
@@ -390,9 +390,9 @@ interface MetaQueryItem {
390
390
  /** The value(s) to compare against. */
391
391
  value: string | number | Array<string | number>;
392
392
  /** Comparison operator (defaults to `=`). */
393
- compare?: "=" | "!=" | ">" | ">=" | "<" | "<=" | "LIKE" | "NOT LIKE" | "IN" | "NOT IN" | "BETWEEN" | "NOT BETWEEN" | "EXISTS" | "NOT EXISTS";
393
+ compare?: '=' | '!=' | '>' | '>=' | '<' | '<=' | 'LIKE' | 'NOT LIKE' | 'IN' | 'NOT IN' | 'BETWEEN' | 'NOT BETWEEN' | 'EXISTS' | 'NOT EXISTS';
394
394
  /** SQL type the value is cast to before comparison. */
395
- type?: "NUMERIC" | "BINARY" | "CHAR" | "DATE" | "DATETIME" | "DECIMAL" | "SIGNED" | "TIME" | "UNSIGNED";
395
+ type?: 'NUMERIC' | 'BINARY' | 'CHAR' | 'DATE' | 'DATETIME' | 'DECIMAL' | 'SIGNED' | 'TIME' | 'UNSIGNED';
396
396
  [key: string]: unknown;
397
397
  }
398
398
  /**
@@ -403,11 +403,11 @@ interface TaxQueryItem {
403
403
  /** The taxonomy to query (e.g. `category`, `post_tag`). */
404
404
  taxonomy: string;
405
405
  /** Which term field `terms` refers to. */
406
- field: "term_id" | "slug" | "name";
406
+ field: 'term_id' | 'slug' | 'name';
407
407
  /** The term(s) to match. */
408
408
  terms: string | number | Array<string | number>;
409
409
  /** How to match the terms (defaults to `IN`). */
410
- operator?: "IN" | "NOT IN" | "AND";
410
+ operator?: 'IN' | 'NOT IN' | 'AND';
411
411
  /** Whether to include child terms of a hierarchical taxonomy. */
412
412
  include_children?: boolean;
413
413
  [key: string]: unknown;
@@ -429,11 +429,11 @@ interface WpQueryArgs {
429
429
  /** Alias of `paged` used in some contexts. */
430
430
  page?: NumericParam;
431
431
  /** Field to order results by. */
432
- orderby?: "date" | "title" | "menu_order" | "rand" | "ID" | "author" | "name" | "modified" | "parent" | "comment_count" | (string & {});
432
+ orderby?: 'date' | 'title' | 'menu_order' | 'rand' | 'ID' | 'author' | 'name' | 'modified' | 'parent' | 'comment_count' | (string & {});
433
433
  /** Sort direction. */
434
- order?: "ASC" | "DESC" | (string & {});
434
+ order?: 'ASC' | 'DESC' | (string & {});
435
435
  /** Post status to include. */
436
- post_status?: "publish" | "pending" | "draft" | "auto-draft" | "future" | "private" | "inherit" | "trash" | (string & {});
436
+ post_status?: 'publish' | 'pending' | 'draft' | 'auto-draft' | 'future' | 'private' | 'inherit' | 'trash' | (string & {});
437
437
  /** Whether to ignore sticky posts. */
438
438
  ignore_sticky_posts?: BooleanParam;
439
439
  /** Author id (number) or username (string). */
@@ -459,9 +459,9 @@ interface WpTermsArgs {
459
459
  /** Taxonomy to fetch terms from. */
460
460
  taxonomy?: string;
461
461
  /** Field to order terms by. */
462
- orderby?: "name" | "slug" | "term_group" | "term_id" | "description" | "count" | (string & {});
462
+ orderby?: 'name' | 'slug' | 'term_group' | 'term_id' | 'description' | 'count' | (string & {});
463
463
  /** Sort direction. */
464
- order?: "ASC" | "DESC" | (string & {});
464
+ order?: 'ASC' | 'DESC' | (string & {});
465
465
  [key: string]: unknown;
466
466
  }
467
467
  /** WordPress user query arguments (extensible). */
@@ -477,9 +477,9 @@ interface WpUsersArgs {
477
477
  /** Columns the `search` keyword is matched against. */
478
478
  search_columns?: string[] | string;
479
479
  /** Field to order users by. */
480
- orderby?: "ID" | "display_name" | "name" | "user_login" | "user_email" | "user_registered" | "post_count" | "meta_value" | "meta_value_num" | (string & {});
480
+ orderby?: 'ID' | 'display_name' | 'name' | 'user_login' | 'user_email' | 'user_registered' | 'post_count' | 'meta_value' | 'meta_value_num' | (string & {});
481
481
  /** Sort direction. */
482
- order?: "ASC" | "DESC" | (string & {});
482
+ order?: 'ASC' | 'DESC' | (string & {});
483
483
  /** Number of users to return. */
484
484
  number?: NumericParam;
485
485
  /** Number of users to skip. */
@@ -490,19 +490,19 @@ interface WpUsersArgs {
490
490
  }
491
491
  /** Type-specific configuration of an {@link EtchLoop}, discriminated by `type`. */
492
492
  type EtchLoopConfig = {
493
- type: "wp-query";
493
+ type: 'wp-query';
494
494
  args: WpQueryArgs;
495
495
  } | {
496
- type: "wp-terms";
496
+ type: 'wp-terms';
497
497
  args: WpTermsArgs;
498
498
  } | {
499
- type: "wp-users";
499
+ type: 'wp-users';
500
500
  args: WpUsersArgs;
501
501
  } | {
502
- type: "main-query";
502
+ type: 'main-query';
503
503
  args: WpQueryArgs;
504
504
  } | {
505
- type: "json";
505
+ type: 'json';
506
506
  data: unknown[];
507
507
  };
508
508
  /** A loop definition (extensible). */
@@ -566,7 +566,7 @@ interface EtchLoopsApi {
566
566
  * - `attribute` — `[data-foo]`, `[type="submit"]`, etc.
567
567
  * - `custom` — anything else (pseudo-classes, combinators, etc.)
568
568
  */
569
- type StyleSelectorType = "class" | "id" | "tag" | "element" | "attribute" | "custom";
569
+ type StyleSelectorType = 'class' | 'id' | 'tag' | 'element' | 'attribute' | 'custom';
570
570
  /** A style entry as returned by `styles.list()`. */
571
571
  interface StyleSummary {
572
572
  /** Stable id of the style rule. */
@@ -653,7 +653,7 @@ interface EtchStylesApi {
653
653
  * Global stylesheet shapes and the `etch.stylesheets` API surface.
654
654
  */
655
655
  /** Type of a global stylesheet. */
656
- type StylesheetType = "default" | "@custom-media";
656
+ type StylesheetType = 'default' | '@custom-media';
657
657
  /** A global stylesheet entry. */
658
658
  interface StylesheetSummary {
659
659
  /** Stable id of the stylesheet. */
@@ -754,8 +754,8 @@ type SelectOptionsString = string;
754
754
  */
755
755
  interface StringComponentProperty {
756
756
  type: {
757
- primitive: "string";
758
- specialized?: "color" | "url" | "image" | "select" | "array" | "wpMediaId";
757
+ primitive: 'string';
758
+ specialized?: 'color' | 'url' | 'image' | 'select' | 'array' | 'wpMediaId';
759
759
  };
760
760
  /** Default value. */
761
761
  default?: string;
@@ -777,7 +777,7 @@ interface StringComponentProperty {
777
777
  */
778
778
  interface NumberComponentProperty {
779
779
  type: {
780
- primitive: "number";
780
+ primitive: 'number';
781
781
  };
782
782
  /** Default value. */
783
783
  default?: number;
@@ -787,7 +787,7 @@ interface NumberComponentProperty {
787
787
  /** A boolean property. */
788
788
  interface BooleanComponentProperty {
789
789
  type: {
790
- primitive: "boolean";
790
+ primitive: 'boolean';
791
791
  };
792
792
  /** Default value (a string is allowed for expression-driven defaults). */
793
793
  default?: boolean | string;
@@ -801,7 +801,7 @@ interface BooleanComponentProperty {
801
801
  */
802
802
  interface ObjectComponentProperty {
803
803
  type: {
804
- primitive: "object";
804
+ primitive: 'object';
805
805
  specialized?: string;
806
806
  };
807
807
  /** Default value. */
@@ -816,7 +816,7 @@ interface ObjectComponentProperty {
816
816
  */
817
817
  interface ArrayComponentProperty {
818
818
  type: {
819
- primitive: "array";
819
+ primitive: 'array';
820
820
  specialized?: string;
821
821
  };
822
822
  /** Default value. */
@@ -825,8 +825,8 @@ interface ArrayComponentProperty {
825
825
  /** A list of CSS class names — an `array` specialized as `'class'`. */
826
826
  interface ClassComponentProperty {
827
827
  type: {
828
- primitive: "array";
829
- specialized: "class";
828
+ primitive: 'array';
829
+ specialized: 'class';
830
830
  };
831
831
  /** Default value. */
832
832
  default?: string[];
@@ -834,8 +834,8 @@ interface ClassComponentProperty {
834
834
  /** A group of nested properties — an `object` specialized as `'group'` (no default). */
835
835
  interface GroupComponentProperty {
836
836
  type: {
837
- primitive: "object";
838
- specialized: "group";
837
+ primitive: 'object';
838
+ specialized: 'group';
839
839
  };
840
840
  /** The nested properties in this group. */
841
841
  properties: ComponentProperty[];
@@ -843,8 +843,8 @@ interface GroupComponentProperty {
843
843
  /** A repeatable group — an `array` specialized as `'repeater'` (no default). */
844
844
  interface RepeaterComponentProperty {
845
845
  type: {
846
- primitive: "array";
847
- specialized: "repeater";
846
+ primitive: 'array';
847
+ specialized: 'repeater';
848
848
  };
849
849
  /** The nested properties repeated per row. */
850
850
  properties: ComponentProperty[];
@@ -852,8 +852,8 @@ interface RepeaterComponentProperty {
852
852
  /** A conditional group gated by an expression — a `string` specialized as `'condition'`. */
853
853
  interface ConditionComponentProperty {
854
854
  type: {
855
- primitive: "string";
856
- specialized: "condition";
855
+ primitive: 'string';
856
+ specialized: 'condition';
857
857
  };
858
858
  /** The nested properties shown when the condition holds. */
859
859
  properties: ComponentProperty[];
@@ -959,7 +959,7 @@ interface EtchComponentsApi {
959
959
  * - `style-manager` — the global style manager
960
960
  * - `loop-manager` — the loop manager
961
961
  */
962
- type NavigationPlace = "builder" | "templates" | "style-manager" | "content-hub" | "loop-manager";
962
+ type NavigationPlace = 'builder' | 'templates' | 'style-manager' | 'content-hub' | 'loop-manager';
963
963
  /** Lightweight post entry returned by `navigation.listPostsAsync()`. */
964
964
  interface PostSummary {
965
965
  /** Post id. */
@@ -1008,7 +1008,7 @@ interface EtchNavigationApi {
1008
1008
  * Custom field group/value shapes and the `etch.fields` API surface.
1009
1009
  */
1010
1010
  /** Custom field type. Open-ended for future field types. */
1011
- type CustomFieldType = "text" | "textarea" | "number" | "boolean" | (string & {});
1011
+ type CustomFieldType = 'text' | 'textarea' | 'number' | 'boolean' | (string & {});
1012
1012
  /** A custom field definition (extensible). */
1013
1013
  interface CustomField {
1014
1014
  /** Display label. */
@@ -1026,13 +1026,13 @@ interface CustomField {
1026
1026
  /** Where a custom field group is assigned. */
1027
1027
  type CustomFieldAssignment = {
1028
1028
  post_types: string[];
1029
- op: "isIn" | "isNotIn";
1029
+ op: 'isIn' | 'isNotIn';
1030
1030
  } | {
1031
1031
  post_ids: number[];
1032
- op: "isIn" | "isNotIn";
1032
+ op: 'isIn' | 'isNotIn';
1033
1033
  } | {
1034
1034
  taxonomies: string[];
1035
- op: "isIn" | "isNotIn";
1035
+ op: 'isIn' | 'isNotIn';
1036
1036
  };
1037
1037
  /** A custom field group definition (extensible). */
1038
1038
  interface CustomFieldGroup {
@@ -1128,7 +1128,7 @@ interface EtchFieldsApi {
1128
1128
  * Builder chrome controls (`etch.ui`) and undo/redo (`etch.history`).
1129
1129
  */
1130
1130
  /** Canvas color scheme. */
1131
- type ColorScheme = "light" | "dark";
1131
+ type ColorScheme = 'light' | 'dark';
1132
1132
  /** Builder app/chrome controls: color scheme, interface visibility, exit. */
1133
1133
  interface EtchUiApi {
1134
1134
  /** The current canvas color scheme. */
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ interface EtchBlockContext {
12
12
  * panel. This is editor UI state, not document data — most scripts can
13
13
  * ignore it.
14
14
  */
15
- structureState?: "open" | "closed";
15
+ structureState?: 'open' | 'closed';
16
16
  /** Whether the block is hidden (not rendered) on the canvas. */
17
17
  hidden?: boolean;
18
18
  }
@@ -64,7 +64,7 @@ interface EtchBlockCommon {
64
64
  }
65
65
  /** A text block (`etch/text`). */
66
66
  interface EtchTextBlockJson extends EtchBlockCommon {
67
- type: "etch/text";
67
+ type: 'etch/text';
68
68
  /** The block's text content. */
69
69
  text: string;
70
70
  }
@@ -76,7 +76,7 @@ interface EtchTextBlockJson extends EtchBlockCommon {
76
76
  * `blocks.create()` / `blocks.replace()` ignore them.
77
77
  */
78
78
  interface EtchElementBlockJson extends EtchBlockCommon {
79
- type: "etch/element";
79
+ type: 'etch/element';
80
80
  /** The HTML tag name, e.g. `div`, `p`, `h1`. */
81
81
  tag: string;
82
82
  /** HTML attributes. */
@@ -90,7 +90,7 @@ interface EtchElementBlockJson extends EtchBlockCommon {
90
90
  * {@link EtchElementBlockJson}).
91
91
  */
92
92
  interface EtchDynamicElementBlockJson extends EtchBlockCommon {
93
- type: "etch/dynamic-element";
93
+ type: 'etch/dynamic-element';
94
94
  /** HTML attributes (the rendered tag is read from `attributes.tag`). */
95
95
  attributes: EtchHtmlAttributes;
96
96
  }
@@ -111,7 +111,7 @@ interface EtchDynamicElementBlockJson extends EtchBlockCommon {
111
111
  * to `"full"` when omitted.
112
112
  */
113
113
  interface EtchDynamicImageBlockJson extends EtchBlockCommon {
114
- type: "etch/dynamic-image";
114
+ type: 'etch/dynamic-image';
115
115
  /** HTML attributes (e.g. `src`, `alt`). */
116
116
  attributes: EtchHtmlAttributes;
117
117
  }
@@ -129,13 +129,13 @@ interface EtchDynamicImageBlockJson extends EtchBlockCommon {
129
129
  * when `src` is set.
130
130
  */
131
131
  interface EtchSvgBlockJson extends EtchBlockCommon {
132
- type: "etch/svg";
132
+ type: 'etch/svg';
133
133
  /** HTML/SVG attributes. */
134
134
  attributes: EtchHtmlAttributes;
135
135
  }
136
136
  /** A loop block (`etch/loop`) that repeats its children over a data source. */
137
137
  interface EtchLoopBlockJson extends EtchBlockCommon {
138
- type: "etch/loop";
138
+ type: 'etch/loop';
139
139
  /** Variable name bound to the current item (e.g. `item`). */
140
140
  itemId: string;
141
141
  /** What the block iterates over (a dynamic path); omitted when bound via `loopId`. */
@@ -149,13 +149,13 @@ interface EtchLoopBlockJson extends EtchBlockCommon {
149
149
  }
150
150
  /** A conditional block (`etch/condition`); renders its children when the expression holds. */
151
151
  interface EtchConditionBlockJson extends EtchBlockCommon {
152
- type: "etch/condition";
152
+ type: 'etch/condition';
153
153
  /** The condition expression. */
154
154
  conditionString: string;
155
155
  }
156
156
  /** An instance of a reusable component (`etch/component`). */
157
157
  interface EtchComponentBlockJson extends EtchBlockCommon {
158
- type: "etch/component";
158
+ type: 'etch/component';
159
159
  /** Id of the component being instantiated. */
160
160
  componentId: number;
161
161
  /** Values bound to the component's properties. */
@@ -163,23 +163,23 @@ interface EtchComponentBlockJson extends EtchBlockCommon {
163
163
  }
164
164
  /** Content projected into a component slot (`etch/slot-content`). */
165
165
  interface EtchSlotContentBlockJson extends EtchBlockCommon {
166
- type: "etch/slot-content";
166
+ type: 'etch/slot-content';
167
167
  /** Name of the slot this content targets. */
168
168
  slotName: string;
169
169
  }
170
170
  /** A slot placeholder inside a component definition (`etch/slot-placeholder`). */
171
171
  interface EtchSlotPlaceholderBlockJson extends EtchBlockCommon {
172
- type: "etch/slot-placeholder";
172
+ type: 'etch/slot-placeholder';
173
173
  /** Name of the slot. */
174
174
  slotName: string;
175
175
  }
176
176
  /** The post-content insertion point (`etch/post-content`). No extra fields. */
177
177
  interface EtchPostContentBlockJson extends EtchBlockCommon {
178
- type: "etch/post-content";
178
+ type: 'etch/post-content';
179
179
  }
180
180
  /** A raw-HTML block (`etch/raw-html`). */
181
181
  interface EtchRawHtmlBlockJson extends EtchBlockCommon {
182
- type: "etch/raw-html";
182
+ type: 'etch/raw-html';
183
183
  /** Sanitized HTML content. */
184
184
  content: string;
185
185
  /** The original, unsanitized HTML as authored. */
@@ -187,7 +187,7 @@ interface EtchRawHtmlBlockJson extends EtchBlockCommon {
187
187
  }
188
188
  /** A pass-through wrapper around a native Gutenberg block (`etch/passthrough`). */
189
189
  interface EtchPassthroughBlockJson extends EtchBlockCommon {
190
- type: "etch/passthrough";
190
+ type: 'etch/passthrough';
191
191
  /** The wrapped Gutenberg block. */
192
192
  gutenbergBlock: GutenbergBlock;
193
193
  }
@@ -201,7 +201,7 @@ interface EtchPassthroughBlockJson extends EtchBlockCommon {
201
201
  */
202
202
  type EtchBlockJson = EtchTextBlockJson | EtchElementBlockJson | EtchDynamicElementBlockJson | EtchDynamicImageBlockJson | EtchSvgBlockJson | EtchLoopBlockJson | EtchConditionBlockJson | EtchComponentBlockJson | EtchSlotContentBlockJson | EtchSlotPlaceholderBlockJson | EtchPostContentBlockJson | EtchRawHtmlBlockJson | EtchPassthroughBlockJson;
203
203
  /** Every known block `type` string (the discriminants of {@link EtchBlockJson}). */
204
- type EtchBlockTypeName = EtchBlockJson["type"];
204
+ type EtchBlockTypeName = EtchBlockJson['type'];
205
205
  /** Read-only identity attached to every serialized (read) block. */
206
206
  interface BlockIdentity {
207
207
  /** Stable id of this block. */
@@ -217,7 +217,7 @@ interface BlockIdentity {
217
217
  * writable {@link EtchBlockJson}, so they cannot be set via
218
218
  * `blocks.create()` / `blocks.replace()`.
219
219
  */
220
- type StyledBlockType = "etch/element" | "etch/dynamic-element" | "etch/dynamic-image" | "etch/svg";
220
+ type StyledBlockType = 'etch/element' | 'etch/dynamic-element' | 'etch/dynamic-image' | 'etch/svg';
221
221
  /** The read-only `styles` exposed on a {@link StyledBlockType} when reading. */
222
222
  interface ReadOnlyBlockStyles {
223
223
  /** Ids of the global styles applied to this block (read-only). */
@@ -227,7 +227,7 @@ interface ReadOnlyBlockStyles {
227
227
  * Attach read-only identity (`id`/`parentId`) to a block, recursively, plus the
228
228
  * read-only `styles` array for the {@link StyledBlockType}s that carry one.
229
229
  */
230
- type WithIdentity<B> = B extends EtchBlockCommon ? Omit<B, "children"> & BlockIdentity & (B extends {
230
+ type WithIdentity<B> = B extends EtchBlockCommon ? Omit<B, 'children'> & BlockIdentity & (B extends {
231
231
  type: StyledBlockType;
232
232
  } ? ReadOnlyBlockStyles : unknown) : never;
233
233
  /**
@@ -390,9 +390,9 @@ interface MetaQueryItem {
390
390
  /** The value(s) to compare against. */
391
391
  value: string | number | Array<string | number>;
392
392
  /** Comparison operator (defaults to `=`). */
393
- compare?: "=" | "!=" | ">" | ">=" | "<" | "<=" | "LIKE" | "NOT LIKE" | "IN" | "NOT IN" | "BETWEEN" | "NOT BETWEEN" | "EXISTS" | "NOT EXISTS";
393
+ compare?: '=' | '!=' | '>' | '>=' | '<' | '<=' | 'LIKE' | 'NOT LIKE' | 'IN' | 'NOT IN' | 'BETWEEN' | 'NOT BETWEEN' | 'EXISTS' | 'NOT EXISTS';
394
394
  /** SQL type the value is cast to before comparison. */
395
- type?: "NUMERIC" | "BINARY" | "CHAR" | "DATE" | "DATETIME" | "DECIMAL" | "SIGNED" | "TIME" | "UNSIGNED";
395
+ type?: 'NUMERIC' | 'BINARY' | 'CHAR' | 'DATE' | 'DATETIME' | 'DECIMAL' | 'SIGNED' | 'TIME' | 'UNSIGNED';
396
396
  [key: string]: unknown;
397
397
  }
398
398
  /**
@@ -403,11 +403,11 @@ interface TaxQueryItem {
403
403
  /** The taxonomy to query (e.g. `category`, `post_tag`). */
404
404
  taxonomy: string;
405
405
  /** Which term field `terms` refers to. */
406
- field: "term_id" | "slug" | "name";
406
+ field: 'term_id' | 'slug' | 'name';
407
407
  /** The term(s) to match. */
408
408
  terms: string | number | Array<string | number>;
409
409
  /** How to match the terms (defaults to `IN`). */
410
- operator?: "IN" | "NOT IN" | "AND";
410
+ operator?: 'IN' | 'NOT IN' | 'AND';
411
411
  /** Whether to include child terms of a hierarchical taxonomy. */
412
412
  include_children?: boolean;
413
413
  [key: string]: unknown;
@@ -429,11 +429,11 @@ interface WpQueryArgs {
429
429
  /** Alias of `paged` used in some contexts. */
430
430
  page?: NumericParam;
431
431
  /** Field to order results by. */
432
- orderby?: "date" | "title" | "menu_order" | "rand" | "ID" | "author" | "name" | "modified" | "parent" | "comment_count" | (string & {});
432
+ orderby?: 'date' | 'title' | 'menu_order' | 'rand' | 'ID' | 'author' | 'name' | 'modified' | 'parent' | 'comment_count' | (string & {});
433
433
  /** Sort direction. */
434
- order?: "ASC" | "DESC" | (string & {});
434
+ order?: 'ASC' | 'DESC' | (string & {});
435
435
  /** Post status to include. */
436
- post_status?: "publish" | "pending" | "draft" | "auto-draft" | "future" | "private" | "inherit" | "trash" | (string & {});
436
+ post_status?: 'publish' | 'pending' | 'draft' | 'auto-draft' | 'future' | 'private' | 'inherit' | 'trash' | (string & {});
437
437
  /** Whether to ignore sticky posts. */
438
438
  ignore_sticky_posts?: BooleanParam;
439
439
  /** Author id (number) or username (string). */
@@ -459,9 +459,9 @@ interface WpTermsArgs {
459
459
  /** Taxonomy to fetch terms from. */
460
460
  taxonomy?: string;
461
461
  /** Field to order terms by. */
462
- orderby?: "name" | "slug" | "term_group" | "term_id" | "description" | "count" | (string & {});
462
+ orderby?: 'name' | 'slug' | 'term_group' | 'term_id' | 'description' | 'count' | (string & {});
463
463
  /** Sort direction. */
464
- order?: "ASC" | "DESC" | (string & {});
464
+ order?: 'ASC' | 'DESC' | (string & {});
465
465
  [key: string]: unknown;
466
466
  }
467
467
  /** WordPress user query arguments (extensible). */
@@ -477,9 +477,9 @@ interface WpUsersArgs {
477
477
  /** Columns the `search` keyword is matched against. */
478
478
  search_columns?: string[] | string;
479
479
  /** Field to order users by. */
480
- orderby?: "ID" | "display_name" | "name" | "user_login" | "user_email" | "user_registered" | "post_count" | "meta_value" | "meta_value_num" | (string & {});
480
+ orderby?: 'ID' | 'display_name' | 'name' | 'user_login' | 'user_email' | 'user_registered' | 'post_count' | 'meta_value' | 'meta_value_num' | (string & {});
481
481
  /** Sort direction. */
482
- order?: "ASC" | "DESC" | (string & {});
482
+ order?: 'ASC' | 'DESC' | (string & {});
483
483
  /** Number of users to return. */
484
484
  number?: NumericParam;
485
485
  /** Number of users to skip. */
@@ -490,19 +490,19 @@ interface WpUsersArgs {
490
490
  }
491
491
  /** Type-specific configuration of an {@link EtchLoop}, discriminated by `type`. */
492
492
  type EtchLoopConfig = {
493
- type: "wp-query";
493
+ type: 'wp-query';
494
494
  args: WpQueryArgs;
495
495
  } | {
496
- type: "wp-terms";
496
+ type: 'wp-terms';
497
497
  args: WpTermsArgs;
498
498
  } | {
499
- type: "wp-users";
499
+ type: 'wp-users';
500
500
  args: WpUsersArgs;
501
501
  } | {
502
- type: "main-query";
502
+ type: 'main-query';
503
503
  args: WpQueryArgs;
504
504
  } | {
505
- type: "json";
505
+ type: 'json';
506
506
  data: unknown[];
507
507
  };
508
508
  /** A loop definition (extensible). */
@@ -566,7 +566,7 @@ interface EtchLoopsApi {
566
566
  * - `attribute` — `[data-foo]`, `[type="submit"]`, etc.
567
567
  * - `custom` — anything else (pseudo-classes, combinators, etc.)
568
568
  */
569
- type StyleSelectorType = "class" | "id" | "tag" | "element" | "attribute" | "custom";
569
+ type StyleSelectorType = 'class' | 'id' | 'tag' | 'element' | 'attribute' | 'custom';
570
570
  /** A style entry as returned by `styles.list()`. */
571
571
  interface StyleSummary {
572
572
  /** Stable id of the style rule. */
@@ -653,7 +653,7 @@ interface EtchStylesApi {
653
653
  * Global stylesheet shapes and the `etch.stylesheets` API surface.
654
654
  */
655
655
  /** Type of a global stylesheet. */
656
- type StylesheetType = "default" | "@custom-media";
656
+ type StylesheetType = 'default' | '@custom-media';
657
657
  /** A global stylesheet entry. */
658
658
  interface StylesheetSummary {
659
659
  /** Stable id of the stylesheet. */
@@ -754,8 +754,8 @@ type SelectOptionsString = string;
754
754
  */
755
755
  interface StringComponentProperty {
756
756
  type: {
757
- primitive: "string";
758
- specialized?: "color" | "url" | "image" | "select" | "array" | "wpMediaId";
757
+ primitive: 'string';
758
+ specialized?: 'color' | 'url' | 'image' | 'select' | 'array' | 'wpMediaId';
759
759
  };
760
760
  /** Default value. */
761
761
  default?: string;
@@ -777,7 +777,7 @@ interface StringComponentProperty {
777
777
  */
778
778
  interface NumberComponentProperty {
779
779
  type: {
780
- primitive: "number";
780
+ primitive: 'number';
781
781
  };
782
782
  /** Default value. */
783
783
  default?: number;
@@ -787,7 +787,7 @@ interface NumberComponentProperty {
787
787
  /** A boolean property. */
788
788
  interface BooleanComponentProperty {
789
789
  type: {
790
- primitive: "boolean";
790
+ primitive: 'boolean';
791
791
  };
792
792
  /** Default value (a string is allowed for expression-driven defaults). */
793
793
  default?: boolean | string;
@@ -801,7 +801,7 @@ interface BooleanComponentProperty {
801
801
  */
802
802
  interface ObjectComponentProperty {
803
803
  type: {
804
- primitive: "object";
804
+ primitive: 'object';
805
805
  specialized?: string;
806
806
  };
807
807
  /** Default value. */
@@ -816,7 +816,7 @@ interface ObjectComponentProperty {
816
816
  */
817
817
  interface ArrayComponentProperty {
818
818
  type: {
819
- primitive: "array";
819
+ primitive: 'array';
820
820
  specialized?: string;
821
821
  };
822
822
  /** Default value. */
@@ -825,8 +825,8 @@ interface ArrayComponentProperty {
825
825
  /** A list of CSS class names — an `array` specialized as `'class'`. */
826
826
  interface ClassComponentProperty {
827
827
  type: {
828
- primitive: "array";
829
- specialized: "class";
828
+ primitive: 'array';
829
+ specialized: 'class';
830
830
  };
831
831
  /** Default value. */
832
832
  default?: string[];
@@ -834,8 +834,8 @@ interface ClassComponentProperty {
834
834
  /** A group of nested properties — an `object` specialized as `'group'` (no default). */
835
835
  interface GroupComponentProperty {
836
836
  type: {
837
- primitive: "object";
838
- specialized: "group";
837
+ primitive: 'object';
838
+ specialized: 'group';
839
839
  };
840
840
  /** The nested properties in this group. */
841
841
  properties: ComponentProperty[];
@@ -843,8 +843,8 @@ interface GroupComponentProperty {
843
843
  /** A repeatable group — an `array` specialized as `'repeater'` (no default). */
844
844
  interface RepeaterComponentProperty {
845
845
  type: {
846
- primitive: "array";
847
- specialized: "repeater";
846
+ primitive: 'array';
847
+ specialized: 'repeater';
848
848
  };
849
849
  /** The nested properties repeated per row. */
850
850
  properties: ComponentProperty[];
@@ -852,8 +852,8 @@ interface RepeaterComponentProperty {
852
852
  /** A conditional group gated by an expression — a `string` specialized as `'condition'`. */
853
853
  interface ConditionComponentProperty {
854
854
  type: {
855
- primitive: "string";
856
- specialized: "condition";
855
+ primitive: 'string';
856
+ specialized: 'condition';
857
857
  };
858
858
  /** The nested properties shown when the condition holds. */
859
859
  properties: ComponentProperty[];
@@ -959,7 +959,7 @@ interface EtchComponentsApi {
959
959
  * - `style-manager` — the global style manager
960
960
  * - `loop-manager` — the loop manager
961
961
  */
962
- type NavigationPlace = "builder" | "templates" | "style-manager" | "content-hub" | "loop-manager";
962
+ type NavigationPlace = 'builder' | 'templates' | 'style-manager' | 'content-hub' | 'loop-manager';
963
963
  /** Lightweight post entry returned by `navigation.listPostsAsync()`. */
964
964
  interface PostSummary {
965
965
  /** Post id. */
@@ -1008,7 +1008,7 @@ interface EtchNavigationApi {
1008
1008
  * Custom field group/value shapes and the `etch.fields` API surface.
1009
1009
  */
1010
1010
  /** Custom field type. Open-ended for future field types. */
1011
- type CustomFieldType = "text" | "textarea" | "number" | "boolean" | (string & {});
1011
+ type CustomFieldType = 'text' | 'textarea' | 'number' | 'boolean' | (string & {});
1012
1012
  /** A custom field definition (extensible). */
1013
1013
  interface CustomField {
1014
1014
  /** Display label. */
@@ -1026,13 +1026,13 @@ interface CustomField {
1026
1026
  /** Where a custom field group is assigned. */
1027
1027
  type CustomFieldAssignment = {
1028
1028
  post_types: string[];
1029
- op: "isIn" | "isNotIn";
1029
+ op: 'isIn' | 'isNotIn';
1030
1030
  } | {
1031
1031
  post_ids: number[];
1032
- op: "isIn" | "isNotIn";
1032
+ op: 'isIn' | 'isNotIn';
1033
1033
  } | {
1034
1034
  taxonomies: string[];
1035
- op: "isIn" | "isNotIn";
1035
+ op: 'isIn' | 'isNotIn';
1036
1036
  };
1037
1037
  /** A custom field group definition (extensible). */
1038
1038
  interface CustomFieldGroup {
@@ -1128,7 +1128,7 @@ interface EtchFieldsApi {
1128
1128
  * Builder chrome controls (`etch.ui`) and undo/redo (`etch.history`).
1129
1129
  */
1130
1130
  /** Canvas color scheme. */
1131
- type ColorScheme = "light" | "dark";
1131
+ type ColorScheme = 'light' | 'dark';
1132
1132
  /** Builder app/chrome controls: color scheme, interface visibility, exit. */
1133
1133
  interface EtchUiApi {
1134
1134
  /** The current canvas color scheme. */
package/dist/index.js CHANGED
@@ -45,7 +45,10 @@ function getEtch(options = {}) {
45
45
  return etch.connect(options);
46
46
  }
47
47
  if (options.apiVersion) {
48
- warnIfIncompatible(options.apiVersion, etch.apiVersion ?? ETCH_API_VERSION);
48
+ warnIfIncompatible(
49
+ options.apiVersion,
50
+ etch.apiVersion ?? ETCH_API_VERSION
51
+ );
49
52
  }
50
53
  return etch;
51
54
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/client.ts"],"names":[],"mappings":";AAyBO,IAAM,YAAA,GAAN,cAA2B,KAAA,CAAM;AAAA,EAGvC,WAAA,CAAY,MAAwB,OAAA,EAAiB;AACpD,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,cAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACb;AACD;AAGO,SAAS,eAAe,KAAA,EAAuC;AACrE,EAAA,OAAO,KAAA,YAAiB,YAAA,IAAiB,KAAA,EAAiB,IAAA,KAAS,cAAA;AACpE;;;AC9BO,IAAM,gBAAA,GAAmB;;;ACIhC,SAAS,QAAA,GAA6B;AACrC,EAAA,MAAM,KAAA,GAAQ,UAAA;AACd,EAAA,OAAO,KAAA,CAAM,IAAA;AACd;AAMO,SAAS,eAAA,GAA2B;AAC1C,EAAA,OAAO,UAAS,KAAM,MAAA;AACvB;AAGA,SAAS,QAAQ,OAAA,EAAgC;AAChD,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA;AACtC,EAAA,OAAO,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA,GAAI,IAAA;AACnC;AAOA,SAAS,kBAAA,CAAmB,WAAmB,OAAA,EAAuB;AACrE,EAAA,MAAM,IAAA,GAAO,QAAQ,SAAS,CAAA;AAC9B,EAAA,MAAM,IAAA,GAAO,QAAQ,OAAO,CAAA;AAC5B,EAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,IAAA,IAAQ,SAAS,IAAA,EAAM;AAErD,EAAA,OAAA,CAAQ,IAAA;AAAA,IACP,CAAA,qDAAA,EAAwD,SAAS,CAAA,wBAAA,EAC9C,OAAO,CAAA,sBAAA;AAAA,GAC3B;AACD;AAsBO,SAAS,OAAA,CAAQ,OAAA,GAA0B,EAAC,EAAS;AAC3D,EAAA,MAAM,OAAO,QAAA,EAAS;AACtB,EAAA,IAAI,CAAC,IAAA,EAAM;AACV,IAAA,MAAM,IAAI,YAAA;AAAA,MACT,eAAA;AAAA,MACA;AAAA,KAED;AAAA,EACD;AAEA,EAAA,IAAI,OAAO,IAAA,CAAK,OAAA,KAAY,UAAA,EAAY;AACvC,IAAA,OAAO,IAAA,CAAK,QAAQ,OAAO,CAAA;AAAA,EAC5B;AAEA,EAAA,IAAI,QAAQ,UAAA,EAAY;AACvB,IAAA,kBAAA,CAAmB,OAAA,CAAQ,UAAA,EAAY,IAAA,CAAK,UAAA,IAAc,gBAAgB,CAAA;AAAA,EAC3E;AACA,EAAA,OAAO,IAAA;AACR","file":"index.js","sourcesContent":["/**\n * Error codes thrown by the public `window.etch` API.\n *\n * The API throws typed errors (rather than returning sentinels) so that AI\n * assistants and plugin authors can `try`/`catch` and react to a precise cause.\n *\n * The union ends with `(string & {})` so that codes added by newer Etch\n * runtimes still type-check as `EtchApiErrorCode` while keeping autocomplete for\n * the known values.\n */\nexport type EtchApiErrorCode =\n\t| 'BLOCK_NOT_FOUND'\n\t| 'WRONG_BLOCK_TYPE'\n\t| 'READONLY'\n\t| 'INVALID_ARGUMENT'\n\t| 'LOOP_NOT_FOUND'\n\t| 'STYLE_NOT_FOUND'\n\t| 'STYLESHEET_NOT_FOUND'\n\t| 'COMPONENT_NOT_FOUND'\n\t| 'POST_NOT_FOUND'\n\t| 'OPERATION_FAILED'\n\t| 'NOT_AVAILABLE'\n\t| (string & {});\n\n/** Error thrown by the public Etch API (and by this client). */\nexport class EtchApiError extends Error {\n\treadonly code: EtchApiErrorCode;\n\n\tconstructor(code: EtchApiErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'EtchApiError';\n\t\tthis.code = code;\n\t}\n}\n\n/** Narrow an unknown caught value to an {@link EtchApiError}. */\nexport function isEtchApiError(value: unknown): value is EtchApiError {\n\treturn value instanceof EtchApiError || (value as Error)?.name === 'EtchApiError';\n}\n","/**\n * Version of the Etch scripting **contract** this package targets, independent\n * of the Etch product version and of this package's own npm version.\n *\n * `0.x` signals the surface is **experimental** and may change without a major\n * bump until it stabilizes. It matches the value returned by the runtime's\n * {@link Etch.apiVersion} getter on `window.etch`.\n */\nexport const ETCH_API_VERSION = '0.x';\n","import type { ConnectOptions, Etch } from './contract';\nimport { EtchApiError } from './errors';\nimport { ETCH_API_VERSION } from './version';\n\ndeclare global {\n\tinterface Window {\n\t\t/** The Etch scripting API, present once the builder has loaded. */\n\t\tetch?: Etch;\n\t}\n}\n\n/** Read `window.etch` from whatever global object exists, or `undefined`. */\nfunction readEtch(): Etch | undefined {\n\tconst scope = globalThis as { etch?: Etch };\n\treturn scope.etch;\n}\n\n/**\n * Whether the Etch scripting API is present on the page. Use this to guard code\n * that should no-op when not running inside the builder.\n */\nexport function isEtchAvailable(): boolean {\n\treturn readEtch() !== undefined;\n}\n\n/** The major version number of a semver-ish string, or `null` if unparseable. */\nfunction majorOf(version: string): number | null {\n\tconst match = /^\\D*(\\d+)/.exec(version);\n\treturn match ? Number(match[1]) : null;\n}\n\n/**\n * Best-effort compatibility check for `0.x` runtimes that have no native\n * `connect()`. Warns (does not throw) when the requested major differs from the\n * runtime's, so experimental consumers aren't hard-blocked.\n */\nfunction warnIfIncompatible(requested: string, runtime: string): void {\n\tconst want = majorOf(requested);\n\tconst have = majorOf(runtime);\n\tif (want === null || have === null || want === have) return;\n\t// eslint-disable-next-line no-console\n\tconsole.warn(\n\t\t`[@digital-gravy/etch-public-api] Requested Etch API v${requested} but the ` +\n\t\t\t`page provides v${runtime}. Behavior may differ.`\n\t);\n}\n\n/**\n * Acquire the Etch scripting API from the page.\n *\n * The runtime lives on `window.etch` (injected by the builder); this returns it\n * typed. When the page exposes a future stable runtime with a native\n * `connect()`, version negotiation is delegated to it. On today's `0.x`\n * runtime, the global is returned directly after a best-effort version check.\n *\n * @throws {EtchApiError} `NOT_AVAILABLE` when the builder is not present.\n *\n * @example\n * ```ts\n * import { getEtch } from '@etchwp/public-api';\n *\n * const etch = getEtch();\n * const ids = etch.blocks.find({ type: 'text' });\n * etch.blocks.setText(ids[0], 'Hello');\n * await etch.saveAsync();\n * ```\n */\nexport function getEtch(options: ConnectOptions = {}): Etch {\n\tconst etch = readEtch();\n\tif (!etch) {\n\t\tthrow new EtchApiError(\n\t\t\t'NOT_AVAILABLE',\n\t\t\t'window.etch is not available. The Etch builder is not loaded on this page, ' +\n\t\t\t\t'or getEtch() ran before it finished initializing.'\n\t\t);\n\t}\n\n\tif (typeof etch.connect === 'function') {\n\t\treturn etch.connect(options);\n\t}\n\n\tif (options.apiVersion) {\n\t\twarnIfIncompatible(options.apiVersion, etch.apiVersion ?? ETCH_API_VERSION);\n\t}\n\treturn etch;\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/client.ts"],"names":[],"mappings":";AAyBO,IAAM,YAAA,GAAN,cAA2B,KAAA,CAAM;AAAA,EAGvC,WAAA,CAAY,MAAwB,OAAA,EAAiB;AACpD,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,cAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACb;AACD;AAGO,SAAS,eAAe,KAAA,EAAuC;AACrE,EAAA,OACC,KAAA,YAAiB,YAAA,IAChB,KAAA,EAAiB,IAAA,KAAS,cAAA;AAE7B;;;ACjCO,IAAM,gBAAA,GAAmB;;;ACIhC,SAAS,QAAA,GAA6B;AACrC,EAAA,MAAM,KAAA,GAAQ,UAAA;AACd,EAAA,OAAO,KAAA,CAAM,IAAA;AACd;AAMO,SAAS,eAAA,GAA2B;AAC1C,EAAA,OAAO,UAAS,KAAM,MAAA;AACvB;AAGA,SAAS,QAAQ,OAAA,EAAgC;AAChD,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,IAAA,CAAK,OAAO,CAAA;AACtC,EAAA,OAAO,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA,GAAI,IAAA;AACnC;AAOA,SAAS,kBAAA,CAAmB,WAAmB,OAAA,EAAuB;AACrE,EAAA,MAAM,IAAA,GAAO,QAAQ,SAAS,CAAA;AAC9B,EAAA,MAAM,IAAA,GAAO,QAAQ,OAAO,CAAA;AAC5B,EAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,IAAA,IAAQ,SAAS,IAAA,EAAM;AACrD,EAAA,OAAA,CAAQ,IAAA;AAAA,IACP,CAAA,qDAAA,EAAwD,SAAS,CAAA,wBAAA,EAC9C,OAAO,CAAA,sBAAA;AAAA,GAC3B;AACD;AAsBO,SAAS,OAAA,CAAQ,OAAA,GAA0B,EAAC,EAAS;AAC3D,EAAA,MAAM,OAAO,QAAA,EAAS;AACtB,EAAA,IAAI,CAAC,IAAA,EAAM;AACV,IAAA,MAAM,IAAI,YAAA;AAAA,MACT,eAAA;AAAA,MACA;AAAA,KAED;AAAA,EACD;AAEA,EAAA,IAAI,OAAO,IAAA,CAAK,OAAA,KAAY,UAAA,EAAY;AACvC,IAAA,OAAO,IAAA,CAAK,QAAQ,OAAO,CAAA;AAAA,EAC5B;AAEA,EAAA,IAAI,QAAQ,UAAA,EAAY;AACvB,IAAA,kBAAA;AAAA,MACC,OAAA,CAAQ,UAAA;AAAA,MACR,KAAK,UAAA,IAAc;AAAA,KACpB;AAAA,EACD;AACA,EAAA,OAAO,IAAA;AACR","file":"index.js","sourcesContent":["/**\n * Error codes thrown by the public `window.etch` API.\n *\n * The API throws typed errors (rather than returning sentinels) so that AI\n * assistants and plugin authors can `try`/`catch` and react to a precise cause.\n *\n * The union ends with `(string & {})` so that codes added by newer Etch\n * runtimes still type-check as `EtchApiErrorCode` while keeping autocomplete for\n * the known values.\n */\nexport type EtchApiErrorCode =\n\t| 'BLOCK_NOT_FOUND'\n\t| 'WRONG_BLOCK_TYPE'\n\t| 'READONLY'\n\t| 'INVALID_ARGUMENT'\n\t| 'LOOP_NOT_FOUND'\n\t| 'STYLE_NOT_FOUND'\n\t| 'STYLESHEET_NOT_FOUND'\n\t| 'COMPONENT_NOT_FOUND'\n\t| 'POST_NOT_FOUND'\n\t| 'OPERATION_FAILED'\n\t| 'NOT_AVAILABLE'\n\t| (string & {});\n\n/** Error thrown by the public Etch API (and by this client). */\nexport class EtchApiError extends Error {\n\treadonly code: EtchApiErrorCode;\n\n\tconstructor(code: EtchApiErrorCode, message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'EtchApiError';\n\t\tthis.code = code;\n\t}\n}\n\n/** Narrow an unknown caught value to an {@link EtchApiError}. */\nexport function isEtchApiError(value: unknown): value is EtchApiError {\n\treturn (\n\t\tvalue instanceof EtchApiError ||\n\t\t(value as Error)?.name === 'EtchApiError'\n\t);\n}\n","/**\n * Version of the Etch scripting **contract** this package targets, independent\n * of the Etch product version and of this package's own npm version.\n *\n * `0.x` signals the surface is **experimental** and may change without a major\n * bump until it stabilizes. It matches the value returned by the runtime's\n * {@link Etch.apiVersion} getter on `window.etch`.\n */\nexport const ETCH_API_VERSION = '0.x';\n","import type { ConnectOptions, Etch } from './contract';\nimport { EtchApiError } from './errors';\nimport { ETCH_API_VERSION } from './version';\n\ndeclare global {\n\tinterface Window {\n\t\t/** The Etch scripting API, present once the builder has loaded. */\n\t\tetch?: Etch;\n\t}\n}\n\n/** Read `window.etch` from whatever global object exists, or `undefined`. */\nfunction readEtch(): Etch | undefined {\n\tconst scope = globalThis as { etch?: Etch };\n\treturn scope.etch;\n}\n\n/**\n * Whether the Etch scripting API is present on the page. Use this to guard code\n * that should no-op when not running inside the builder.\n */\nexport function isEtchAvailable(): boolean {\n\treturn readEtch() !== undefined;\n}\n\n/** The major version number of a semver-ish string, or `null` if unparseable. */\nfunction majorOf(version: string): number | null {\n\tconst match = /^\\D*(\\d+)/.exec(version);\n\treturn match ? Number(match[1]) : null;\n}\n\n/**\n * Best-effort compatibility check for `0.x` runtimes that have no native\n * `connect()`. Warns (does not throw) when the requested major differs from the\n * runtime's, so experimental consumers aren't hard-blocked.\n */\nfunction warnIfIncompatible(requested: string, runtime: string): void {\n\tconst want = majorOf(requested);\n\tconst have = majorOf(runtime);\n\tif (want === null || have === null || want === have) return;\n\tconsole.warn(\n\t\t`[@digital-gravy/etch-public-api] Requested Etch API v${requested} but the ` +\n\t\t\t`page provides v${runtime}. Behavior may differ.`\n\t);\n}\n\n/**\n * Acquire the Etch scripting API from the page.\n *\n * The runtime lives on `window.etch` (injected by the builder); this returns it\n * typed. When the page exposes a future stable runtime with a native\n * `connect()`, version negotiation is delegated to it. On today's `0.x`\n * runtime, the global is returned directly after a best-effort version check.\n *\n * @throws {EtchApiError} `NOT_AVAILABLE` when the builder is not present.\n *\n * @example\n * ```ts\n * import { getEtch } from '@etchwp/public-api';\n *\n * const etch = getEtch();\n * const ids = etch.blocks.find({ type: 'text' });\n * etch.blocks.setText(ids[0], 'Hello');\n * await etch.saveAsync();\n * ```\n */\nexport function getEtch(options: ConnectOptions = {}): Etch {\n\tconst etch = readEtch();\n\tif (!etch) {\n\t\tthrow new EtchApiError(\n\t\t\t'NOT_AVAILABLE',\n\t\t\t'window.etch is not available. The Etch builder is not loaded on this page, ' +\n\t\t\t\t'or getEtch() ran before it finished initializing.'\n\t\t);\n\t}\n\n\tif (typeof etch.connect === 'function') {\n\t\treturn etch.connect(options);\n\t}\n\n\tif (options.apiVersion) {\n\t\twarnIfIncompatible(\n\t\t\toptions.apiVersion,\n\t\t\tetch.apiVersion ?? ETCH_API_VERSION\n\t\t);\n\t}\n\treturn etch;\n}\n"]}
package/package.json CHANGED
@@ -1,46 +1,60 @@
1
1
  {
2
- "name": "@digital-gravy/etch-public-api",
3
- "version": "0.7.0",
4
- "description": "MIT-licensed typed client and contract for the Etch builder scripting API (window.etch). Etch itself is a separate proprietary product governed by its own commercial terms.",
5
- "license": "MIT",
6
- "type": "module",
7
- "main": "./dist/index.cjs",
8
- "module": "./dist/index.js",
9
- "types": "./dist/index.d.ts",
10
- "exports": {
11
- ".": {
12
- "types": "./dist/index.d.ts",
13
- "import": "./dist/index.js",
14
- "require": "./dist/index.cjs"
15
- }
16
- },
17
- "files": [
18
- "dist",
19
- "README.md"
20
- ],
21
- "sideEffects": false,
22
- "scripts": {
23
- "build": "tsup",
24
- "dev": "tsup --watch",
25
- "test": "vitest run",
26
- "test:watch": "vitest",
27
- "typecheck": "tsc --noEmit",
28
- "prepublishOnly": "bun run build"
29
- },
30
- "keywords": [
31
- "etch",
32
- "etchwp",
33
- "wordpress",
34
- "builder",
35
- "scripting",
36
- "api"
37
- ],
38
- "publishConfig": {
39
- "access": "public"
40
- },
41
- "devDependencies": {
42
- "tsup": "^8.3.5",
43
- "typescript": "^5.7.2",
44
- "vitest": "^3.0.5"
45
- }
2
+ "name": "@digital-gravy/etch-public-api",
3
+ "version": "0.7.1",
4
+ "description": "MIT-licensed typed client and contract for the Etch builder scripting API (window.etch). Etch itself is a separate proprietary product governed by its own commercial terms.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Digital-Gravy/etch-public-api.git"
9
+ },
10
+ "type": "module",
11
+ "main": "./dist/index.cjs",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js",
18
+ "require": "./dist/index.cjs"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "sideEffects": false,
26
+ "scripts": {
27
+ "build": "tsup",
28
+ "dev": "tsup --watch",
29
+ "test": "vitest run",
30
+ "test:watch": "vitest",
31
+ "typecheck": "tsc --noEmit",
32
+ "lint": "bun run eslint && bun run format:check",
33
+ "eslint": "eslint .",
34
+ "format": "prettier --write .",
35
+ "format:check": "prettier --check .",
36
+ "prepublishOnly": "bun run build"
37
+ },
38
+ "keywords": [
39
+ "etch",
40
+ "etchwp",
41
+ "wordpress",
42
+ "builder",
43
+ "scripting",
44
+ "api"
45
+ ],
46
+ "publishConfig": {
47
+ "access": "public"
48
+ },
49
+ "devDependencies": {
50
+ "@eslint/js": "^9.39.2",
51
+ "eslint": "^9.39.2",
52
+ "eslint-config-prettier": "^10.1.8",
53
+ "globals": "^17.1.0",
54
+ "prettier": "^3.8.1",
55
+ "tsup": "^8.3.5",
56
+ "typescript": "^5.7.2",
57
+ "typescript-eslint": "^8.53.1",
58
+ "vitest": "^3.0.5"
59
+ }
46
60
  }