@lofcz/embedpdf-plugin-commands 2.15.0 → 3.0.0-next.7

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/dist/index.js CHANGED
@@ -1,381 +1,191 @@
1
- import { BasePlugin, createEmitter, createBehaviorEmitter, arePropsEqual } from "@embedpdf/core";
2
- const COMMANDS_PLUGIN_ID = "commands";
3
- const manifest = {
4
- id: COMMANDS_PLUGIN_ID,
5
- name: "Commands Plugin",
6
- version: "1.0.0",
7
- provides: ["commands"],
8
- requires: [],
9
- optional: ["i18n", "ui"],
10
- defaultConfig: {
11
- commands: {}
12
- }
1
+ import { createCapabilityToken, definePlugin } from "@embedpdf/core";
2
+ import { I18nToken } from "@embedpdf/plugin-i18n";
3
+ import { ShellToken } from "@embedpdf/plugin-shell";
4
+ import { matchShortcut, parseShortcut } from "@embedpdf/core-ui";
5
+ //#region src/capability.ts
6
+ function registerCommand(registry, def) {
7
+ if (registry.has(def.id)) throw new Error(`[commands] duplicate command: ${def.id}`);
8
+ const shortcuts = def.shortcut === void 0 ? [] : [].concat(def.shortcut);
9
+ registry.set(def.id, {
10
+ def,
11
+ shortcuts,
12
+ parsed: shortcuts.map(parseShortcut)
13
+ });
14
+ }
15
+ const panelTarget = (def) => def.panel === void 0 ? null : typeof def.panel === "string" ? { id: def.panel } : def.panel;
16
+ function createCommandsCapability(ctx, registry) {
17
+ /** Bind capability resolution to the command's target document. The kernel
18
+ * resolves workspace tokens regardless of the document argument, so one
19
+ * code path serves both scopes. */
20
+ const commandCtx = (documentId) => {
21
+ const target = documentId ?? ctx.core().activeId;
22
+ const get = (token) => target ? ctx.forDocument(token, target) : ctx.get(token);
23
+ return {
24
+ documentId: target,
25
+ core: ctx.core,
26
+ get,
27
+ tryGet: (token) => {
28
+ try {
29
+ return get(token);
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+ };
35
+ };
36
+ /** Derivations run against live state; a derivation that throws (e.g. it
37
+ * needs a document and none is open) falls back to the safe default —
38
+ * the button renders, disabled, exactly like v2's empty state. */
39
+ const derive = (fn, c, fallback) => {
40
+ if (!fn) return fallback;
41
+ try {
42
+ return fn(c);
43
+ } catch {
44
+ return fallback;
45
+ }
46
+ };
47
+ /** Same guard as `derive`, for the icon-accent derivation: a throw (no
48
+ * document, provider missing) means "no accent" — the icon renders plain. */
49
+ const deriveAccent = (fn, c) => {
50
+ if (!fn) return void 0;
51
+ try {
52
+ return fn(c) ?? void 0;
53
+ } catch {
54
+ return;
55
+ }
56
+ };
57
+ const resolve = (id, documentId) => {
58
+ const entry = registry.get(id);
59
+ if (!entry) return null;
60
+ const { def } = entry;
61
+ const c = commandCtx(documentId);
62
+ const disabled = ctx.getState().disabledCategories;
63
+ const categoryHidden = (def.categories ?? []).some((cat) => disabled.includes(cat));
64
+ const i18n = c.tryGet(I18nToken);
65
+ const label = i18n ? i18n.t(def.labelKey) : def.labelKey;
66
+ let active;
67
+ if (def.active) active = derive(def.active, c, false);
68
+ else {
69
+ const shell = c.tryGet(ShellToken);
70
+ const panel = panelTarget(def);
71
+ active = shell ? def.menu ? shell.isMenuOpen(def.menu) : panel ? shell.isOpen(panel.id) : def.modal ? shell.isOpen(def.modal) : false : false;
72
+ }
73
+ return {
74
+ id: def.id,
75
+ label,
76
+ icon: def.icon,
77
+ iconAccent: deriveAccent(def.iconAccent, c),
78
+ shortcuts: entry.shortcuts,
79
+ menu: def.menu,
80
+ enabled: derive(def.enabled, c, true) && !categoryHidden,
81
+ active,
82
+ visible: derive(def.visible, c, true) && !categoryHidden,
83
+ categories: def.categories ?? []
84
+ };
85
+ };
86
+ const execute = (id, documentId) => {
87
+ const entry = registry.get(id);
88
+ if (!entry) return;
89
+ const resolved = resolve(id, documentId);
90
+ if (!resolved || !resolved.enabled || !resolved.visible) return;
91
+ const c = commandCtx(documentId);
92
+ if (entry.def.run) {
93
+ entry.def.run(c);
94
+ return;
95
+ }
96
+ const shell = c.tryGet(ShellToken);
97
+ if (!shell) return;
98
+ const panel = panelTarget(entry.def);
99
+ if (entry.def.menu) shell.toggleMenu(entry.def.menu);
100
+ else if (panel) shell.toggle(panel.id, { exclusive: panel.exclusive });
101
+ else if (entry.def.modal) shell.toggle(entry.def.modal, { exclusive: "modal" });
102
+ };
103
+ return {
104
+ register: (def) => registerCommand(registry, def),
105
+ unregister: (id) => void registry.delete(id),
106
+ has: (id) => registry.has(id),
107
+ ids: () => [...registry.keys()],
108
+ resolve,
109
+ search: (query, documentId) => {
110
+ const q = query.trim().toLowerCase();
111
+ const hits = [];
112
+ for (const id of registry.keys()) {
113
+ const r = resolve(id, documentId);
114
+ if (!r || !r.visible) continue;
115
+ if (q === "" || r.label.toLowerCase().includes(q) || r.id.includes(q)) hits.push(r);
116
+ }
117
+ return hits;
118
+ },
119
+ menuTarget: (id) => {
120
+ const entry = registry.get(id);
121
+ return entry ? { menu: entry.def.menu } : null;
122
+ },
123
+ execute,
124
+ matchStroke: (stroke, opts) => {
125
+ for (const [id, entry] of registry) if (entry.parsed.some((p) => matchShortcut(p, stroke, opts))) return id;
126
+ return null;
127
+ },
128
+ disabledCategories: () => ctx.getState().disabledCategories,
129
+ isCategoryDisabled: (category) => ctx.getState().disabledCategories.includes(category),
130
+ disableCategory: (category) => ctx.dispatch({
131
+ type: "COMMANDS/DISABLE_CATEGORY",
132
+ category
133
+ }),
134
+ enableCategory: (category) => ctx.dispatch({
135
+ type: "COMMANDS/ENABLE_CATEGORY",
136
+ category
137
+ }),
138
+ setDisabledCategories: (categories) => ctx.dispatch({
139
+ type: "COMMANDS/SET_DISABLED_CATEGORIES",
140
+ categories
141
+ })
142
+ };
143
+ }
144
+ //#endregion
145
+ //#region src/reducer.ts
146
+ const initialCommandsState = { disabledCategories: [] };
147
+ function commandsReducer(state, action) {
148
+ switch (action.type) {
149
+ case "COMMANDS/DISABLE_CATEGORY": return state.disabledCategories.includes(action.category) ? state : { disabledCategories: [...state.disabledCategories, action.category] };
150
+ case "COMMANDS/ENABLE_CATEGORY": return state.disabledCategories.includes(action.category) ? { disabledCategories: state.disabledCategories.filter((c) => c !== action.category) } : state;
151
+ case "COMMANDS/SET_DISABLED_CATEGORIES": return { disabledCategories: [...action.categories] };
152
+ default: return state;
153
+ }
154
+ }
155
+ //#endregion
156
+ //#region src/types.ts
157
+ /** Value equality over resolved commands — `resolve()` mints a fresh object
158
+ * per read, so reactive bindings memo by value to re-render on real change. */
159
+ const resolvedCommandsEqual = (a, b) => {
160
+ if (a === b) return true;
161
+ if (!a || !b) return false;
162
+ return a.id === b.id && a.label === b.label && a.icon === b.icon && a.iconAccent?.primary === b.iconAccent?.primary && a.iconAccent?.secondary === b.iconAccent?.secondary && a.menu === b.menu && a.enabled === b.enabled && a.active === b.active && a.visible === b.visible && a.shortcuts.length === b.shortcuts.length && a.shortcuts.every((s, i) => s === b.shortcuts[i]);
13
163
  };
14
- const SET_DISABLED_CATEGORIES = "COMMANDS/SET_DISABLED_CATEGORIES";
15
- const setDisabledCategories = (categories) => ({
16
- type: SET_DISABLED_CATEGORIES,
17
- payload: categories
18
- });
19
- const _CommandsPlugin = class _CommandsPlugin extends BasePlugin {
20
- constructor(id, registry, config) {
21
- var _a;
22
- super(id, registry);
23
- this.commands = /* @__PURE__ */ new Map();
24
- this.i18n = null;
25
- this.shortcutMap = /* @__PURE__ */ new Map();
26
- this.commandExecuted$ = createEmitter();
27
- this.commandStateChanged$ = createEmitter();
28
- this.shortcutExecuted$ = createEmitter();
29
- this.categoryChanged$ = createBehaviorEmitter();
30
- this.previousStates = /* @__PURE__ */ new Map();
31
- const i18nPlugin = registry.getPlugin("i18n");
32
- this.i18n = (i18nPlugin == null ? void 0 : i18nPlugin.provides()) ?? null;
33
- if ((_a = config.disabledCategories) == null ? void 0 : _a.length) {
34
- this.dispatch(setDisabledCategories(config.disabledCategories));
35
- }
36
- Object.values(config.commands).forEach((command) => {
37
- this.registerCommand(command);
38
- });
39
- this.registry.getStore().subscribe((_action, newState) => {
40
- this.onGlobalStoreChange(newState);
41
- });
42
- }
43
- onDocumentClosed(documentId) {
44
- this.previousStates.delete(documentId);
45
- this.logger.debug(
46
- "CommandsPlugin",
47
- "DocumentClosed",
48
- `Cleaned up command state cache for document: ${documentId}`
49
- );
50
- }
51
- async initialize() {
52
- this.logger.info("CommandsPlugin", "Initialize", "Commands plugin initialized");
53
- }
54
- async destroy() {
55
- this.commandExecuted$.clear();
56
- this.commandStateChanged$.clear();
57
- this.shortcutExecuted$.clear();
58
- this.categoryChanged$.clear();
59
- this.commands.clear();
60
- this.shortcutMap.clear();
61
- this.previousStates.clear();
62
- super.destroy();
63
- }
64
- // ─────────────────────────────────────────────────────────
65
- // Category Management
66
- // ─────────────────────────────────────────────────────────
67
- disableCategoryImpl(category) {
68
- const current = new Set(this.state.disabledCategories);
69
- if (!current.has(category)) {
70
- current.add(category);
71
- this.dispatch(setDisabledCategories(Array.from(current)));
72
- this.categoryChanged$.emit({ disabledCategories: Array.from(current) });
73
- }
74
- }
75
- enableCategoryImpl(category) {
76
- const current = new Set(this.state.disabledCategories);
77
- if (current.has(category)) {
78
- current.delete(category);
79
- this.dispatch(setDisabledCategories(Array.from(current)));
80
- this.categoryChanged$.emit({ disabledCategories: Array.from(current) });
81
- }
82
- }
83
- toggleCategoryImpl(category) {
84
- if (this.state.disabledCategories.includes(category)) {
85
- this.enableCategoryImpl(category);
86
- } else {
87
- this.disableCategoryImpl(category);
88
- }
89
- }
90
- setDisabledCategoriesImpl(categories) {
91
- this.dispatch(setDisabledCategories(categories));
92
- this.categoryChanged$.emit({ disabledCategories: categories });
93
- }
94
- /**
95
- * Check if command has any disabled category
96
- */
97
- isCommandCategoryDisabled(command) {
98
- var _a;
99
- if (!((_a = command.categories) == null ? void 0 : _a.length)) return false;
100
- return command.categories.some((cat) => this.state.disabledCategories.includes(cat));
101
- }
102
- // ─────────────────────────────────────────────────────────
103
- // Capability
104
- // ─────────────────────────────────────────────────────────
105
- buildCapability() {
106
- return {
107
- resolve: (commandId, documentId) => this.resolve(commandId, documentId),
108
- execute: (commandId, documentId, source = "ui") => this.execute(commandId, documentId, source),
109
- getAllCommands: (documentId) => this.getAllCommands(documentId),
110
- getCommandsByCategory: (category, documentId) => this.getCommandsByCategory(category, documentId),
111
- getCommandByShortcut: (shortcut) => this.getCommandByShortcut(shortcut),
112
- getAllShortcuts: () => new Map(this.shortcutMap),
113
- forDocument: (documentId) => this.createCommandScope(documentId),
114
- registerCommand: (command) => this.registerCommand(command),
115
- unregisterCommand: (commandId) => this.unregisterCommand(commandId),
116
- // Category management
117
- disableCategory: (category) => this.disableCategoryImpl(category),
118
- enableCategory: (category) => this.enableCategoryImpl(category),
119
- toggleCategory: (category) => this.toggleCategoryImpl(category),
120
- setDisabledCategories: (categories) => this.setDisabledCategoriesImpl(categories),
121
- getDisabledCategories: () => this.state.disabledCategories,
122
- isCategoryDisabled: (category) => this.state.disabledCategories.includes(category),
123
- // Events
124
- onCommandExecuted: this.commandExecuted$.on,
125
- onCommandStateChanged: this.commandStateChanged$.on,
126
- onShortcutExecuted: this.shortcutExecuted$.on,
127
- onCategoryChanged: this.categoryChanged$.on
128
- };
129
- }
130
- // ─────────────────────────────────────────────────────────
131
- // Document Scoping
132
- // ─────────────────────────────────────────────────────────
133
- createCommandScope(documentId) {
134
- return {
135
- resolve: (commandId) => this.resolve(commandId, documentId),
136
- execute: (commandId, source = "ui") => this.execute(commandId, documentId, source),
137
- getAllCommands: () => this.getAllCommands(documentId),
138
- getCommandsByCategory: (category) => this.getCommandsByCategory(category, documentId),
139
- onCommandStateChanged: (listener) => this.commandStateChanged$.on((event) => {
140
- if (event.documentId === documentId) {
141
- const { documentId: _, ...rest } = event;
142
- listener(rest);
143
- }
144
- })
145
- };
146
- }
147
- // ─────────────────────────────────────────────────────────
148
- // Command Resolution
149
- // ─────────────────────────────────────────────────────────
150
- resolve(commandId, documentId) {
151
- const resolvedDocId = documentId ?? this.getActiveDocumentId();
152
- const command = this.commands.get(commandId);
153
- if (!command) {
154
- throw new Error(`Command not found: ${commandId}`);
155
- }
156
- const state = this.registry.getStore().getState();
157
- const label = this.resolveLabel(command, state, resolvedDocId);
158
- const shortcuts = command.shortcuts ? Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts] : void 0;
159
- const explicitDisabled = this.resolveDynamic(command.disabled, state, resolvedDocId) ?? false;
160
- const categoryDisabled = this.isCommandCategoryDisabled(command);
161
- const isDisabled = explicitDisabled || categoryDisabled;
162
- return {
163
- id: command.id,
164
- label,
165
- icon: this.resolveDynamic(command.icon, state, resolvedDocId),
166
- iconProps: this.resolveDynamic(command.iconProps, state, resolvedDocId),
167
- active: this.resolveDynamic(command.active, state, resolvedDocId) ?? false,
168
- disabled: isDisabled,
169
- visible: this.resolveDynamic(command.visible, state, resolvedDocId) ?? true,
170
- shortcuts,
171
- shortcutLabel: command.shortcutLabel,
172
- categories: command.categories,
173
- description: command.description,
174
- execute: () => command.action({
175
- registry: this.registry,
176
- state,
177
- documentId: resolvedDocId,
178
- logger: this.logger
179
- })
180
- };
181
- }
182
- resolveLabel(command, state, documentId) {
183
- const labelKey = this.resolveDynamic(command.labelKey, state, documentId);
184
- if (labelKey && this.i18n) {
185
- const params = this.resolveDynamic(command.labelParams, state, documentId);
186
- return this.i18n.t(labelKey, { params, documentId });
187
- }
188
- if (command.label) {
189
- return command.label;
190
- }
191
- return command.id;
192
- }
193
- resolveDynamic(value, state, documentId) {
194
- if (value === void 0) return void 0;
195
- if (typeof value === "function") {
196
- return value({
197
- registry: this.registry,
198
- state,
199
- documentId,
200
- logger: this.logger
201
- });
202
- }
203
- return value;
204
- }
205
- // ─────────────────────────────────────────────────────────
206
- // Command Execution
207
- // ─────────────────────────────────────────────────────────
208
- execute(commandId, documentId, source = "ui") {
209
- const resolvedDocId = documentId ?? this.getActiveDocumentId();
210
- const resolved = this.resolve(commandId, resolvedDocId);
211
- if (resolved.disabled) {
212
- this.logger.warn(
213
- "CommandsPlugin",
214
- "ExecutionBlocked",
215
- `Command '${commandId}' is disabled for document '${resolvedDocId}'`
216
- );
217
- return;
218
- }
219
- if (!resolved.visible) {
220
- this.logger.warn(
221
- "CommandsPlugin",
222
- "ExecutionBlocked",
223
- `Command '${commandId}' is not visible for document '${resolvedDocId}'`
224
- );
225
- return;
226
- }
227
- resolved.execute();
228
- this.commandExecuted$.emit({
229
- commandId,
230
- documentId: resolvedDocId,
231
- source
232
- });
233
- this.logger.debug(
234
- "CommandsPlugin",
235
- "CommandExecuted",
236
- `Command '${commandId}' executed for document '${resolvedDocId}' (source: ${source})`
237
- );
238
- }
239
- // ─────────────────────────────────────────────────────────
240
- // Command Registration
241
- // ─────────────────────────────────────────────────────────
242
- registerCommand(command) {
243
- if (this.commands.has(command.id)) {
244
- this.logger.warn(
245
- "CommandsPlugin",
246
- "CommandOverwrite",
247
- `Command '${command.id}' already exists and will be overwritten`
248
- );
249
- }
250
- this.commands.set(command.id, command);
251
- if (command.shortcuts) {
252
- const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];
253
- shortcuts.forEach((shortcut) => {
254
- const normalized = this.normalizeShortcut(shortcut);
255
- this.shortcutMap.set(normalized, command.id);
256
- });
257
- }
258
- this.logger.debug("CommandsPlugin", "CommandRegistered", `Command '${command.id}' registered`);
259
- }
260
- unregisterCommand(commandId) {
261
- const command = this.commands.get(commandId);
262
- if (!command) return;
263
- if (command.shortcuts) {
264
- const shortcuts = Array.isArray(command.shortcuts) ? command.shortcuts : [command.shortcuts];
265
- shortcuts.forEach((shortcut) => {
266
- const normalized = this.normalizeShortcut(shortcut);
267
- this.shortcutMap.delete(normalized);
268
- });
269
- }
270
- this.commands.delete(commandId);
271
- this.logger.debug(
272
- "CommandsPlugin",
273
- "CommandUnregistered",
274
- `Command '${commandId}' unregistered`
275
- );
276
- }
277
- // ─────────────────────────────────────────────────────────
278
- // Shortcuts
279
- // ─────────────────────────────────────────────────────────
280
- getCommandByShortcut(shortcut) {
281
- const normalized = this.normalizeShortcut(shortcut);
282
- const commandId = this.shortcutMap.get(normalized);
283
- return commandId ? this.commands.get(commandId) ?? null : null;
284
- }
285
- normalizeShortcut(shortcut) {
286
- return shortcut.toLowerCase().split("+").sort().join("+");
287
- }
288
- // ─────────────────────────────────────────────────────────
289
- // Query Methods
290
- // ─────────────────────────────────────────────────────────
291
- getAllCommands(documentId) {
292
- const resolvedDocId = documentId ?? this.getActiveDocumentId();
293
- return Array.from(this.commands.keys()).map((id) => this.resolve(id, resolvedDocId));
294
- }
295
- getCommandsByCategory(category, documentId) {
296
- const resolvedDocId = documentId ?? this.getActiveDocumentId();
297
- return Array.from(this.commands.values()).filter((cmd) => {
298
- var _a;
299
- return (_a = cmd.categories) == null ? void 0 : _a.includes(category);
300
- }).map((cmd) => this.resolve(cmd.id, resolvedDocId));
301
- }
302
- // ─────────────────────────────────────────────────────────
303
- // State Change Detection
304
- // ─────────────────────────────────────────────────────────
305
- onGlobalStoreChange(newState) {
306
- const documentIds = Object.keys(newState.core.documents);
307
- documentIds.forEach((documentId) => {
308
- this.detectCommandChanges(documentId, newState);
309
- });
310
- }
311
- detectCommandChanges(documentId, newState) {
312
- const coreDoc = newState.core.documents[documentId];
313
- if (!coreDoc || coreDoc.status !== "loaded") return;
314
- const previousCache = this.previousStates.get(documentId) ?? /* @__PURE__ */ new Map();
315
- this.commands.forEach((command, commandId) => {
316
- const newResolved = this.resolve(commandId, documentId);
317
- const prevResolved = previousCache.get(commandId);
318
- if (!prevResolved) {
319
- previousCache.set(commandId, newResolved);
320
- return;
321
- }
322
- const changes = {};
323
- if (prevResolved.active !== newResolved.active) {
324
- changes.active = newResolved.active;
325
- }
326
- if (prevResolved.disabled !== newResolved.disabled) {
327
- changes.disabled = newResolved.disabled;
328
- }
329
- if (prevResolved.visible !== newResolved.visible) {
330
- changes.visible = newResolved.visible;
331
- }
332
- if (prevResolved.label !== newResolved.label) {
333
- changes.label = newResolved.label;
334
- }
335
- if (prevResolved.icon !== newResolved.icon) {
336
- changes.icon = newResolved.icon;
337
- }
338
- if (!arePropsEqual(prevResolved.iconProps, newResolved.iconProps)) {
339
- changes.iconProps = newResolved.iconProps;
340
- }
341
- if (Object.keys(changes).length > 0) {
342
- previousCache.set(commandId, newResolved);
343
- this.commandStateChanged$.emit({
344
- commandId,
345
- documentId,
346
- changes
347
- });
348
- }
349
- });
350
- this.previousStates.set(documentId, previousCache);
351
- }
164
+ const CommandsToken = createCapabilityToken("commands");
165
+ //#endregion
166
+ //#region src/commands.plugin.ts
167
+ /**
168
+ * The commands plugin: workspace-scoped (one vocabulary for the whole
169
+ * workspace; resolution/execution bind to a target document per call).
170
+ * Definitions live in this closure — never in the store (they hold
171
+ * functions); the store slice holds only `disabledCategories`.
172
+ */
173
+ const commandsPlugin = (config) => {
174
+ const registry = /* @__PURE__ */ new Map();
175
+ for (const def of config?.commands ?? []) registerCommand(registry, def);
176
+ return definePlugin({
177
+ id: "commands",
178
+ scope: "workspace",
179
+ token: CommandsToken,
180
+ initialState: {
181
+ ...initialCommandsState,
182
+ disabledCategories: [...config?.disabledCategories ?? []]
183
+ },
184
+ reduce: commandsReducer,
185
+ capability: (ctx) => createCommandsCapability(ctx, registry)
186
+ });
352
187
  };
353
- _CommandsPlugin.id = "commands";
354
- let CommandsPlugin = _CommandsPlugin;
355
- const initialState = {
356
- disabledCategories: []
357
- };
358
- const commandsReducer = (state = initialState, action) => {
359
- switch (action.type) {
360
- case SET_DISABLED_CATEGORIES:
361
- return {
362
- ...state,
363
- disabledCategories: action.payload
364
- };
365
- default:
366
- return state;
367
- }
368
- };
369
- const CommandsPluginPackage = {
370
- manifest,
371
- create: (registry, config) => new CommandsPlugin(COMMANDS_PLUGIN_ID, registry, config),
372
- reducer: commandsReducer,
373
- initialState
374
- };
375
- export {
376
- COMMANDS_PLUGIN_ID,
377
- CommandsPlugin,
378
- CommandsPluginPackage,
379
- manifest
380
- };
381
- //# sourceMappingURL=index.js.map
188
+ //#endregion
189
+ export { CommandsToken, commandsPlugin, commandsReducer, initialCommandsState, resolvedCommandsEqual };
190
+
191
+ //# sourceMappingURL=index.js.map