@digital-gravy/etch-public-api 0.6.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 +87 -57
- package/dist/index.cjs +4 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -60
- package/dist/index.d.ts +77 -60
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +58 -44
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
|
|
29
|
+
import { getEtch, isEtchAvailable } from '@digital-gravy/etch-public-api';
|
|
30
30
|
|
|
31
31
|
function run() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
44
|
+
import { getEtch, isEtchAvailable } from '@digital-gravy/etch-public-api';
|
|
45
45
|
|
|
46
46
|
async function whenEtchReady(timeoutMs = 10_000) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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:
|
|
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],
|
|
67
|
-
etch.blocks.addClass(textIds[0],
|
|
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(
|
|
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:
|
|
81
|
-
const myStyle = etch.styles.list().find((s) => s.selector ===
|
|
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(
|
|
86
|
-
etch.styles.getVariable(
|
|
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(
|
|
90
|
-
etch.styles.getVariable(
|
|
91
|
-
etch.styles.listVariables(
|
|
92
|
-
etch.styles.removeVariable(
|
|
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:
|
|
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);
|
|
@@ -128,20 +129,47 @@ To discard in-memory changes and restore the original block:
|
|
|
128
129
|
etch.blocks.exitComponentEditMode({ revert: true });
|
|
129
130
|
```
|
|
130
131
|
|
|
132
|
+
### Component props
|
|
133
|
+
|
|
134
|
+
A component **instance** exposes its bound props as block attributes — set them
|
|
135
|
+
with `setAttribute` / `update`, read them with `getAttribute`. Unlike an HTML
|
|
136
|
+
block's free-form attributes, a component's props are a **closed schema**: the
|
|
137
|
+
key must be a property declared by the component definition, or the call throws
|
|
138
|
+
`INVALID_ARGUMENT`.
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
const [cardId] = etch.blocks.find({ type: 'etch/component' });
|
|
142
|
+
|
|
143
|
+
// Set a prop the component declares
|
|
144
|
+
etch.blocks.setAttribute(cardId, 'title', 'Hello world');
|
|
145
|
+
|
|
146
|
+
// Read it back
|
|
147
|
+
etch.blocks.getAttribute(cardId, 'title'); // "Hello world"
|
|
148
|
+
|
|
149
|
+
// Or patch several props at once
|
|
150
|
+
etch.blocks.update(cardId, { attributes: { title: 'Hi', variant: 'primary' } });
|
|
151
|
+
|
|
152
|
+
// An undeclared key is rejected
|
|
153
|
+
etch.blocks.setAttribute(cardId, 'notAProp', 'x'); // ✗ throws INVALID_ARGUMENT
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
> Values are stored as-is. For typed props such as classes or repeater/group
|
|
157
|
+
> data, pass the value in the component's internal format.
|
|
158
|
+
|
|
131
159
|
### Error handling
|
|
132
160
|
|
|
133
161
|
Methods throw a typed `EtchApiError` with a `code`, rather than returning
|
|
134
162
|
sentinels:
|
|
135
163
|
|
|
136
164
|
```ts
|
|
137
|
-
import { isEtchApiError } from
|
|
165
|
+
import { isEtchApiError } from '@digital-gravy/etch-public-api';
|
|
138
166
|
|
|
139
167
|
try {
|
|
140
|
-
|
|
168
|
+
etch.blocks.getJson('does-not-exist');
|
|
141
169
|
} catch (err) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
170
|
+
if (isEtchApiError(err)) {
|
|
171
|
+
console.warn(err.code, err.message); // e.g. "BLOCK_NOT_FOUND"
|
|
172
|
+
}
|
|
145
173
|
}
|
|
146
174
|
```
|
|
147
175
|
|
|
@@ -155,8 +183,8 @@ experimental, **prefer feature detection** over version comparison:
|
|
|
155
183
|
|
|
156
184
|
```ts
|
|
157
185
|
const etch = getEtch();
|
|
158
|
-
if (typeof etch.blocks.someNewMethod ===
|
|
159
|
-
|
|
186
|
+
if (typeof etch.blocks.someNewMethod === 'function') {
|
|
187
|
+
// safe to use
|
|
160
188
|
}
|
|
161
189
|
```
|
|
162
190
|
|
|
@@ -167,7 +195,7 @@ targets, and failing fast when the runtime can't satisfy it:
|
|
|
167
195
|
|
|
168
196
|
```ts
|
|
169
197
|
// Reserved API — shape of versioned access once the contract is stable:
|
|
170
|
-
const etch = getEtch({ apiVersion:
|
|
198
|
+
const etch = getEtch({ apiVersion: '^1.0', id: 'my-plugin' });
|
|
171
199
|
// └─ delegates to window.etch.connect({ apiVersion: "^1.0", id }) when present,
|
|
172
200
|
// yielding a version-pinned instance (throws on an incompatible runtime).
|
|
173
201
|
```
|
|
@@ -185,19 +213,19 @@ results narrow by `type`:
|
|
|
185
213
|
```ts
|
|
186
214
|
const block = etch.blocks.getJson(id);
|
|
187
215
|
|
|
188
|
-
if (block.type ===
|
|
189
|
-
|
|
190
|
-
} else if (block.type ===
|
|
191
|
-
|
|
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);
|
|
192
220
|
}
|
|
193
221
|
|
|
194
222
|
// Authoring is checked too — this is a type error (an `etch/text` has no `tag`):
|
|
195
223
|
etch.blocks.create({
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
224
|
+
type: 'etch/text',
|
|
225
|
+
version: 1,
|
|
226
|
+
context: {},
|
|
227
|
+
children: [],
|
|
228
|
+
tag: 'div' // ✗ type error
|
|
201
229
|
});
|
|
202
230
|
```
|
|
203
231
|
|
|
@@ -206,22 +234,24 @@ etch.blocks.create({
|
|
|
206
234
|
Some block types recognise **special attributes** in addition to standard HTML:
|
|
207
235
|
|
|
208
236
|
**`etch/dynamic-image`** — rendered as `<img>`:
|
|
237
|
+
|
|
209
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}`).
|
|
210
239
|
- `useSrcSet` — `"true"` to generate a responsive `srcset` from the media (requires `mediaId`).
|
|
211
240
|
- `maximumSize` — WordPress image size slug (e.g. `"large"`, `"full"`) used when resolving the image. Defaults to `"full"`.
|
|
212
241
|
|
|
213
242
|
```ts
|
|
214
|
-
etch.blocks.setAttribute(imgBlockId,
|
|
215
|
-
etch.blocks.setAttribute(imgBlockId,
|
|
243
|
+
etch.blocks.setAttribute(imgBlockId, 'mediaId', '{post.featured_image_id}');
|
|
244
|
+
etch.blocks.setAttribute(imgBlockId, 'useSrcSet', 'true');
|
|
216
245
|
```
|
|
217
246
|
|
|
218
247
|
**`etch/svg`** — inline SVG:
|
|
248
|
+
|
|
219
249
|
- `src` — URL of an external `.svg` file. Etch fetches and inlines the SVG at render time. Supports dynamic expressions.
|
|
220
250
|
- `stripColors` — `"true"` to strip `fill` and `stroke` colour declarations from the fetched SVG, so CSS can drive its colours instead.
|
|
221
251
|
|
|
222
252
|
```ts
|
|
223
|
-
etch.blocks.setAttribute(svgBlockId,
|
|
224
|
-
etch.blocks.setAttribute(svgBlockId,
|
|
253
|
+
etch.blocks.setAttribute(svgBlockId, 'src', '/icons/logo.svg');
|
|
254
|
+
etch.blocks.setAttribute(svgBlockId, 'stripColors', 'true');
|
|
225
255
|
```
|
|
226
256
|
|
|
227
257
|
### Types only
|
|
@@ -231,9 +261,9 @@ directly:
|
|
|
231
261
|
|
|
232
262
|
```ts
|
|
233
263
|
import type {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
} from
|
|
264
|
+
PublicBlockJson,
|
|
265
|
+
EtchBlocksApi
|
|
266
|
+
} from '@digital-gravy/etch-public-api';
|
|
237
267
|
```
|
|
238
268
|
|
|
239
269
|
You can also work against the global directly — the package augments
|
|
@@ -246,14 +276,14 @@ is imported.
|
|
|
246
276
|
- `EtchApiError` / `isEtchApiError()` / `EtchApiErrorCode` — typed errors.
|
|
247
277
|
- `ETCH_API_VERSION` — the contract version this package targets (`0.x`).
|
|
248
278
|
- The full contract as exported types:
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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`
|
|
257
287
|
|
|
258
288
|
## Versioning
|
|
259
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(
|
|
50
|
+
warnIfIncompatible(
|
|
51
|
+
options.apiVersion,
|
|
52
|
+
etch.apiVersion ?? ETCH_API_VERSION
|
|
53
|
+
);
|
|
51
54
|
}
|
|
52
55
|
return etch;
|
|
53
56
|
}
|
package/dist/index.cjs.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,
|
|
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"]}
|