@digital-gravy/etch-public-api 0.7.0 → 0.7.2
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 +65 -62
- package/dist/index.cjs +4 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +129 -58
- package/dist/index.d.ts +129 -58
- 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);
|
|
@@ -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:
|
|
141
|
+
const [cardId] = etch.blocks.find({ type: 'etch/component' });
|
|
141
142
|
|
|
142
143
|
// Set a prop the component declares
|
|
143
|
-
etch.blocks.setAttribute(cardId,
|
|
144
|
+
etch.blocks.setAttribute(cardId, 'title', 'Hello world');
|
|
144
145
|
|
|
145
146
|
// Read it back
|
|
146
|
-
etch.blocks.getAttribute(cardId,
|
|
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:
|
|
150
|
+
etch.blocks.update(cardId, { attributes: { title: 'Hi', variant: 'primary' } });
|
|
150
151
|
|
|
151
152
|
// An undeclared key is rejected
|
|
152
|
-
etch.blocks.setAttribute(cardId,
|
|
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
|
|
165
|
+
import { isEtchApiError } from '@digital-gravy/etch-public-api';
|
|
165
166
|
|
|
166
167
|
try {
|
|
167
|
-
|
|
168
|
+
etch.blocks.getJson('does-not-exist');
|
|
168
169
|
} catch (err) {
|
|
169
|
-
|
|
170
|
-
|
|
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 ===
|
|
186
|
-
|
|
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:
|
|
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 ===
|
|
216
|
-
|
|
217
|
-
} else if (block.type ===
|
|
218
|
-
|
|
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
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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,
|
|
242
|
-
etch.blocks.setAttribute(imgBlockId,
|
|
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,
|
|
251
|
-
etch.blocks.setAttribute(svgBlockId,
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
} from
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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(
|
|
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"]}
|