@stringpush/sdk 0.1.0

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.
@@ -0,0 +1,78 @@
1
+ import { RuntimeInitOptions, TranslateValues } from '@stringpush/runtime-core';
2
+ export { Environment, ManifestLocaleEntry, MissingKeyFallback, RetryOptions, TranslateValues, TranslationCatalog, TranslationManifest } from '@stringpush/runtime-core';
3
+
4
+ /**
5
+ * Public SDK types — stable contract for customer apps (M1-SDK-01).
6
+ *
7
+ * Intent: runtime fields from @stringpush/runtime-core; overlay/edit fields stay on @stringpush/sdk.
8
+ */
9
+
10
+ type InitOptions = RuntimeInitOptions & {
11
+ /** Short-lived edit JWT from `POST /v1/auth/edit-session` (overlay + realtime). */
12
+ editToken?: string;
13
+ /** WebSocket gateway URL (defaults from `apiBaseUrl`, e.g. ws://localhost:3001 in local dev). */
14
+ realtimeUrl?: string;
15
+ /**
16
+ * When true (default), `?translation_edit=1` plus a resolvable edit token auto-calls `enableEditMode()`.
17
+ * When only `?translation_edit=1` is present, use {@link EditLauncherOptions} instead (FAB, no auto-enable).
18
+ */
19
+ autoEnableEditFromQuery?: boolean;
20
+ /**
21
+ * Staging overlay launcher: `?translation_edit=1` shows a FAB; sign-in then `enableEditMode()` on click.
22
+ * Intent: avoids accidental overlay and keeps JWT out of the visible URL when using hash/callback auth.
23
+ */
24
+ editLauncher?: EditLauncherOptions;
25
+ };
26
+ /** Configures the staging edit launcher FAB (M2-SDK-05). */
27
+ type EditLauncherOptions = {
28
+ /** When set, require `?translation_edit_key=` to match before showing the launcher. */
29
+ armingKey?: string;
30
+ /** Redirect here to sign in; `returnUrl` is appended. */
31
+ signInUrl?: string;
32
+ /**
33
+ * Mint an edit JWT in-process (local demo only). Ignored when `signInUrl` is set.
34
+ * Intent: never ship admin/dev secrets in production customer bundles.
35
+ */
36
+ requestEditToken?: () => Promise<string>;
37
+ };
38
+ /** Options for {@link enableEditMode}. */
39
+ type EnableEditModeOptions = {
40
+ editToken?: string;
41
+ };
42
+
43
+ /**
44
+ * Maps DOM nodes to translation keys for overlay edit mode (M2-SDK-02).
45
+ *
46
+ * Intent: host `registerResolver` first; `data-i18n-key` on the element or an ancestor is the fallback.
47
+ */
48
+
49
+ declare const I18N_KEY_ATTR = "data-i18n-key";
50
+
51
+ /**
52
+ * @stringpush/sdk — plain JS runtime: load manifest + bundles, expose `t()` (ICU in M1-SDK-03).
53
+ *
54
+ * Intent: customer-facing surface; runtime catalog/manifest delegated to @stringpush/runtime-core.
55
+ */
56
+
57
+ /**
58
+ * Initialize the SDK: fetch manifest and the active locale bundle into an in-memory catalog.
59
+ *
60
+ * Intent: entry point for customer apps; triggers `onTranslationsUpdated` when the first catalog is ready.
61
+ */
62
+ declare function init(options: InitOptions): Promise<void>;
63
+ declare function destroy(): void;
64
+ declare function getLocale(): string;
65
+ /**
66
+ * Switch active locale and reload its bundle from the manifest.
67
+ */
68
+ declare function setLocale(locale: string): Promise<void>;
69
+ /**
70
+ * Translate a key using the loaded catalog and ICU MessageFormat.
71
+ */
72
+ declare function t(key: string, values?: TranslateValues): string;
73
+ declare function loadNamespace(_namespace: string): Promise<void>;
74
+ declare function enableEditMode(options?: EnableEditModeOptions): Promise<void>;
75
+ declare function disableEditMode(): void;
76
+ declare function registerResolver(resolver: (element: Element) => string | null): () => void;
77
+
78
+ export { type EditLauncherOptions, type EnableEditModeOptions, I18N_KEY_ATTR, type InitOptions, destroy, disableEditMode, enableEditMode, getLocale, init, loadNamespace, registerResolver, setLocale, t };
package/dist/index.mjs ADDED
@@ -0,0 +1,260 @@
1
+ import {
2
+ decodeEditTokenClaims,
3
+ isEditLauncherArmed,
4
+ readEditTokenFromHash,
5
+ readEditTokenFromQuery,
6
+ resolveEditToken,
7
+ shouldAutoEnableEditMode,
8
+ stripEditTokenFromUrl
9
+ } from "./chunk-X3WTVBZ6.mjs";
10
+
11
+ // src/resolve-key.ts
12
+ var I18N_KEY_ATTR = "data-i18n-key";
13
+ function resolveKeyForElement(start, resolver) {
14
+ if (resolver) {
15
+ let current2 = start;
16
+ while (current2) {
17
+ const resolved = resolver(current2);
18
+ if (resolved) {
19
+ return resolved;
20
+ }
21
+ current2 = current2.parentElement;
22
+ }
23
+ }
24
+ let current = start;
25
+ while (current) {
26
+ const fromAttr = current.getAttribute(I18N_KEY_ATTR);
27
+ if (fromAttr) {
28
+ return fromAttr;
29
+ }
30
+ current = current.parentElement;
31
+ }
32
+ return null;
33
+ }
34
+
35
+ // src/index.ts
36
+ import {
37
+ changeLocale,
38
+ destroyRuntime,
39
+ getRuntime as getRuntime2,
40
+ getRuntimeLocale,
41
+ initializeRuntime,
42
+ translateKey
43
+ } from "@stringpush/runtime-core";
44
+
45
+ // src/edit-mode.ts
46
+ import {
47
+ patchCatalogEntry,
48
+ resolveApiBaseUrl
49
+ } from "@stringpush/runtime-core";
50
+
51
+ // src/runtime.ts
52
+ import {
53
+ assertInitialized as assertCoreInitialized,
54
+ getRuntime,
55
+ resetRuntime
56
+ } from "@stringpush/runtime-core";
57
+ function assertInitialized() {
58
+ return assertCoreInitialized();
59
+ }
60
+ var keyResolver = null;
61
+ function setKeyResolver(resolver) {
62
+ keyResolver = resolver;
63
+ }
64
+ function getKeyResolver() {
65
+ return keyResolver;
66
+ }
67
+
68
+ // src/urls.ts
69
+ function resolveRealtimeUrl(apiBaseUrl, explicit) {
70
+ if (explicit) {
71
+ return explicit.replace(/\/$/, "");
72
+ }
73
+ const api = new URL(apiBaseUrl);
74
+ if (api.hostname === "localhost" && (api.port === "3000" || api.port === "")) {
75
+ return "ws://localhost:3001";
76
+ }
77
+ const protocol = api.protocol === "https:" ? "wss:" : "ws:";
78
+ return `${protocol}//${api.host}`;
79
+ }
80
+
81
+ // src/edit-mode.ts
82
+ var overlayHandle = null;
83
+ var overlayLoadPromise = null;
84
+ function loadOverlayModule() {
85
+ if (!overlayLoadPromise) {
86
+ overlayLoadPromise = import("./overlay-7KC2RRGB.mjs");
87
+ }
88
+ return overlayLoadPromise;
89
+ }
90
+ function isEditModeActive() {
91
+ return overlayHandle !== null;
92
+ }
93
+ async function enableEditMode(options = {}) {
94
+ if (overlayHandle) {
95
+ return;
96
+ }
97
+ const initOptions = assertInitialized();
98
+ const state = getRuntime();
99
+ const manifest = state.manifest;
100
+ if (!manifest) {
101
+ throw new Error("@stringpush/sdk: manifest is not loaded \u2014 call init() before enableEditMode()");
102
+ }
103
+ const editToken = resolveEditToken(initOptions, options.editToken);
104
+ if (!editToken) {
105
+ throw new Error(
106
+ "@stringpush/sdk: edit token required \u2014 pass editToken, ?edit_token=, or sessionStorage"
107
+ );
108
+ }
109
+ const apiBaseUrl = resolveApiBaseUrl(initOptions.apiBaseUrl);
110
+ const realtimeUrl = resolveRealtimeUrl(apiBaseUrl, initOptions.realtimeUrl);
111
+ const overlay = await loadOverlayModule();
112
+ const editClaims = decodeEditTokenClaims(editToken);
113
+ if (!editClaims) {
114
+ throw new Error("@stringpush/sdk: edit token is malformed");
115
+ }
116
+ if (editClaims.projectId !== manifest.projectId) {
117
+ throw new Error("@stringpush/sdk: edit token project does not match loaded manifest");
118
+ }
119
+ if (editClaims.applicationId !== manifest.applicationId) {
120
+ throw new Error("@stringpush/sdk: edit token application does not match init()");
121
+ }
122
+ if (editClaims.environmentName !== initOptions.environment) {
123
+ throw new Error(
124
+ "@stringpush/sdk: edit token environment does not match init() environment"
125
+ );
126
+ }
127
+ overlayHandle = overlay.mountOverlay({
128
+ projectId: manifest.projectId,
129
+ applicationId: manifest.applicationId,
130
+ environmentId: editClaims.environmentId,
131
+ realtimeUrl,
132
+ editToken,
133
+ apiBaseUrl,
134
+ origin: initOptions.origin,
135
+ activeLocaleCode: state.locale,
136
+ resolveKey: (element) => resolveKeyForElement(element, getKeyResolver()),
137
+ onCatalogPatched: (keyPath, localeCode, value, version) => {
138
+ if (patchCatalogEntry(keyPath, localeCode, value, version)) {
139
+ initOptions.onTranslationsUpdated?.();
140
+ }
141
+ },
142
+ onTranslationsUpdated: () => {
143
+ initOptions.onTranslationsUpdated?.();
144
+ }
145
+ });
146
+ }
147
+ function disableEditMode() {
148
+ overlayHandle?.destroy();
149
+ overlayHandle = null;
150
+ }
151
+ function teardownEditMode() {
152
+ disableEditMode();
153
+ overlayLoadPromise = null;
154
+ }
155
+
156
+ // src/edit-launcher-lifecycle.ts
157
+ var launcherHandle = null;
158
+ var launcherLoadPromise = null;
159
+ function loadLauncherModule() {
160
+ if (!launcherLoadPromise) {
161
+ launcherLoadPromise = import("./edit-launcher-PTZ5BIO2.mjs");
162
+ }
163
+ return launcherLoadPromise;
164
+ }
165
+ function shouldMountEditLauncher(options) {
166
+ if (!options.editLauncher) {
167
+ return false;
168
+ }
169
+ if (options.environment !== "staging") {
170
+ return false;
171
+ }
172
+ if (shouldAutoEnableEditMode(options)) {
173
+ return false;
174
+ }
175
+ return isEditLauncherArmed(options.editLauncher);
176
+ }
177
+ async function mountEditLauncherIfNeeded(options) {
178
+ if (!shouldMountEditLauncher(options)) {
179
+ return;
180
+ }
181
+ const launcherOptions = options.editLauncher;
182
+ const mod = await loadLauncherModule();
183
+ launcherHandle = mod.mountEditLauncher({
184
+ initOptions: options,
185
+ launcherOptions,
186
+ isEditModeActive,
187
+ enableEditMode: () => enableEditMode(),
188
+ disableEditMode
189
+ });
190
+ }
191
+ function teardownEditLauncher() {
192
+ launcherHandle?.destroy();
193
+ launcherHandle = null;
194
+ launcherLoadPromise = null;
195
+ }
196
+
197
+ // src/index.ts
198
+ async function init(options) {
199
+ await initializeRuntime(options);
200
+ const tokenFromUrl = readEditTokenFromQuery() ?? readEditTokenFromHash();
201
+ if (tokenFromUrl || options.editToken) {
202
+ resolveEditToken(options);
203
+ if (tokenFromUrl) {
204
+ stripEditTokenFromUrl();
205
+ }
206
+ }
207
+ if (shouldAutoEnableEditMode(options)) {
208
+ await enableEditMode();
209
+ } else {
210
+ await mountEditLauncherIfNeeded(options);
211
+ }
212
+ }
213
+ function destroy() {
214
+ teardownEditLauncher();
215
+ teardownEditMode();
216
+ setKeyResolver(null);
217
+ destroyRuntime();
218
+ }
219
+ function getLocale() {
220
+ return getRuntimeLocale();
221
+ }
222
+ async function setLocale(locale) {
223
+ await changeLocale(locale);
224
+ }
225
+ function t(key, values) {
226
+ if (!getRuntime2().options) {
227
+ throw new Error("@stringpush/sdk: call init() before using the runtime");
228
+ }
229
+ return translateKey(key, values);
230
+ }
231
+ function loadNamespace(_namespace) {
232
+ return Promise.resolve();
233
+ }
234
+ async function enableEditMode2(options) {
235
+ await enableEditMode(options);
236
+ }
237
+ function disableEditMode2() {
238
+ disableEditMode();
239
+ }
240
+ function registerResolver(resolver) {
241
+ setKeyResolver(resolver);
242
+ return () => {
243
+ if (getKeyResolver() === resolver) {
244
+ setKeyResolver(null);
245
+ }
246
+ };
247
+ }
248
+ export {
249
+ I18N_KEY_ATTR,
250
+ destroy,
251
+ disableEditMode2 as disableEditMode,
252
+ enableEditMode2 as enableEditMode,
253
+ getLocale,
254
+ init,
255
+ loadNamespace,
256
+ registerResolver,
257
+ setLocale,
258
+ t
259
+ };
260
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/resolve-key.ts","../src/index.ts","../src/edit-mode.ts","../src/runtime.ts","../src/urls.ts","../src/edit-launcher-lifecycle.ts"],"sourcesContent":["/**\n * Maps DOM nodes to translation keys for overlay edit mode (M2-SDK-02).\n *\n * Intent: host `registerResolver` first; `data-i18n-key` on the element or an ancestor is the fallback.\n */\nimport type { KeyResolver } from \"./runtime.js\";\n\nexport const I18N_KEY_ATTR = \"data-i18n-key\";\n\n/**\n * Resolves a translation key for a DOM node by walking ancestors.\n */\nexport function resolveKeyForElement(\n start: Element,\n resolver: KeyResolver | null,\n): string | null {\n if (resolver) {\n let current: Element | null = start;\n while (current) {\n const resolved = resolver(current);\n if (resolved) {\n return resolved;\n }\n current = current.parentElement;\n }\n }\n\n let current: Element | null = start;\n while (current) {\n const fromAttr = current.getAttribute(I18N_KEY_ATTR);\n if (fromAttr) {\n return fromAttr;\n }\n current = current.parentElement;\n }\n\n return null;\n}\n","/**\n * @stringpush/sdk — plain JS runtime: load manifest + bundles, expose `t()` (ICU in M1-SDK-03).\n *\n * Intent: customer-facing surface; runtime catalog/manifest delegated to @stringpush/runtime-core.\n */\nexport { I18N_KEY_ATTR } from \"./resolve-key.js\";\n\nexport type {\n EditLauncherOptions,\n EnableEditModeOptions,\n Environment,\n InitOptions,\n ManifestLocaleEntry,\n MissingKeyFallback,\n RetryOptions,\n TranslateValues,\n TranslationCatalog,\n TranslationManifest,\n} from \"./types.js\";\n\nimport type { EnableEditModeOptions, InitOptions, TranslateValues } from \"./types.js\";\nimport {\n changeLocale,\n destroyRuntime,\n getRuntime,\n getRuntimeLocale,\n initializeRuntime,\n translateKey,\n} from \"@stringpush/runtime-core\";\nimport { teardownEditLauncher, mountEditLauncherIfNeeded } from \"./edit-launcher-lifecycle.js\";\nimport {\n readEditTokenFromHash,\n readEditTokenFromQuery,\n resolveEditToken,\n shouldAutoEnableEditMode,\n stripEditTokenFromUrl,\n} from \"./edit-token.js\";\nimport {\n disableEditMode as disableEditModeInternal,\n enableEditMode as enableEditModeInternal,\n teardownEditMode,\n} from \"./edit-mode.js\";\nimport { getKeyResolver, setKeyResolver } from \"./runtime.js\";\n\n/**\n * Initialize the SDK: fetch manifest and the active locale bundle into an in-memory catalog.\n *\n * Intent: entry point for customer apps; triggers `onTranslationsUpdated` when the first catalog is ready.\n */\nexport async function init(options: InitOptions): Promise<void> {\n await initializeRuntime(options);\n\n const tokenFromUrl = readEditTokenFromQuery() ?? readEditTokenFromHash();\n if (tokenFromUrl || options.editToken) {\n resolveEditToken(options);\n if (tokenFromUrl) {\n stripEditTokenFromUrl();\n }\n }\n\n if (shouldAutoEnableEditMode(options)) {\n await enableEditModeInternal();\n } else {\n await mountEditLauncherIfNeeded(options);\n }\n}\n\nexport function destroy(): void {\n teardownEditLauncher();\n teardownEditMode();\n setKeyResolver(null);\n destroyRuntime();\n}\n\nexport function getLocale(): string {\n return getRuntimeLocale();\n}\n\n/**\n * Switch active locale and reload its bundle from the manifest.\n */\nexport async function setLocale(locale: string): Promise<void> {\n await changeLocale(locale);\n}\n\n/**\n * Translate a key using the loaded catalog and ICU MessageFormat.\n */\nexport function t(key: string, values?: TranslateValues): string {\n // Intent: preserve @stringpush/sdk error text for public `t()` callers (runtime-core uses initializeRuntime wording).\n if (!getRuntime().options) {\n throw new Error(\"@stringpush/sdk: call init() before using the runtime\");\n }\n return translateKey(key, values);\n}\n\nexport function loadNamespace(_namespace: string): Promise<void> {\n return Promise.resolve();\n}\n\nexport async function enableEditMode(options?: EnableEditModeOptions): Promise<void> {\n await enableEditModeInternal(options);\n}\n\nexport function disableEditMode(): void {\n disableEditModeInternal();\n}\n\nexport function registerResolver(resolver: (element: Element) => string | null): () => void {\n setKeyResolver(resolver);\n return () => {\n if (getKeyResolver() === resolver) {\n setKeyResolver(null);\n }\n };\n}\n","/**\n * Edit-mode lifecycle: lazy overlay chunk load and teardown (M2-SDK-01).\n */\nimport {\n patchCatalogEntry,\n resolveApiBaseUrl,\n} from \"@stringpush/runtime-core\";\nimport { decodeEditTokenClaims } from \"./edit-token-decode.js\";\nimport { resolveEditToken } from \"./edit-token.js\";\nimport { resolveKeyForElement } from \"./resolve-key.js\";\nimport { assertInitialized, getKeyResolver, getRuntime } from \"./runtime.js\";\nimport type { EnableEditModeOptions } from \"./types.js\";\nimport { resolveRealtimeUrl } from \"./urls.js\";\n\ntype OverlayModule = typeof import(\"./overlay/index.js\");\n\nlet overlayHandle: { destroy: () => void } | null = null;\nlet overlayLoadPromise: Promise<OverlayModule> | null = null;\n\nfunction loadOverlayModule(): Promise<OverlayModule> {\n if (!overlayLoadPromise) {\n // Intent: dynamic import keeps overlay + WS client out of the default SDK bundle.\n overlayLoadPromise = import(\"./overlay/index.js\");\n }\n return overlayLoadPromise;\n}\n\nexport function isEditModeActive(): boolean {\n return overlayHandle !== null;\n}\n\n/**\n * Activates overlay edit mode when a valid edit JWT is available.\n */\nexport async function enableEditMode(options: EnableEditModeOptions = {}): Promise<void> {\n if (overlayHandle) {\n return;\n }\n\n const initOptions = assertInitialized();\n const state = getRuntime();\n const manifest = state.manifest;\n if (!manifest) {\n throw new Error(\"@stringpush/sdk: manifest is not loaded — call init() before enableEditMode()\");\n }\n\n const editToken = resolveEditToken(initOptions, options.editToken);\n if (!editToken) {\n throw new Error(\n \"@stringpush/sdk: edit token required — pass editToken, ?edit_token=, or sessionStorage\",\n );\n }\n\n const apiBaseUrl = resolveApiBaseUrl(initOptions.apiBaseUrl);\n const realtimeUrl = resolveRealtimeUrl(apiBaseUrl, initOptions.realtimeUrl);\n const overlay = await loadOverlayModule();\n const editClaims = decodeEditTokenClaims(editToken);\n if (!editClaims) {\n throw new Error(\"@stringpush/sdk: edit token is malformed\");\n }\n if (editClaims.projectId !== manifest.projectId) {\n throw new Error(\"@stringpush/sdk: edit token project does not match loaded manifest\");\n }\n if (editClaims.applicationId !== manifest.applicationId) {\n throw new Error(\"@stringpush/sdk: edit token application does not match init()\");\n }\n if (editClaims.environmentName !== initOptions.environment) {\n throw new Error(\n \"@stringpush/sdk: edit token environment does not match init() environment\",\n );\n }\n\n overlayHandle = overlay.mountOverlay({\n projectId: manifest.projectId,\n applicationId: manifest.applicationId,\n environmentId: editClaims.environmentId,\n realtimeUrl,\n editToken,\n apiBaseUrl,\n origin: initOptions.origin,\n activeLocaleCode: state.locale,\n resolveKey: (element) => resolveKeyForElement(element, getKeyResolver()),\n onCatalogPatched: (keyPath, localeCode, value, version) => {\n if (patchCatalogEntry(keyPath, localeCode, value, version)) {\n initOptions.onTranslationsUpdated?.();\n }\n },\n onTranslationsUpdated: () => {\n initOptions.onTranslationsUpdated?.();\n },\n });\n}\n\n/**\n * Tears down overlay DOM and closes the realtime WebSocket.\n */\nexport function disableEditMode(): void {\n overlayHandle?.destroy();\n overlayHandle = null;\n}\n\nexport function teardownEditMode(): void {\n disableEditMode();\n overlayLoadPromise = null;\n}\n","/**\n * DOM-specific runtime helpers (key resolver) atop @stringpush/runtime-core state.\n *\n * Intent: overlay `registerResolver` stays in sdk; catalog/manifest live in runtime-core.\n */\nimport {\n assertInitialized as assertCoreInitialized,\n getRuntime,\n resetRuntime,\n type SdkRuntime,\n} from \"@stringpush/runtime-core\";\nimport type { InitOptions } from \"./types.js\";\n\nexport { getRuntime, resetRuntime, type SdkRuntime };\n\n/** SDK init stores overlay fields on the same options object passed to runtime-core. */\nexport function assertInitialized(): InitOptions {\n return assertCoreInitialized() as InitOptions;\n}\n\nexport type KeyResolver = (element: Element) => string | null;\n\nlet keyResolver: KeyResolver | null = null;\n\nexport function setKeyResolver(resolver: KeyResolver | null): void {\n keyResolver = resolver;\n}\n\nexport function getKeyResolver(): KeyResolver | null {\n return keyResolver;\n}\n","/**\n * WebSocket URL helper for overlay realtime (M2-SDK-01).\n *\n * Intent: overlay-specific; runtime-core has no realtime dependency.\n */\nexport function resolveRealtimeUrl(apiBaseUrl: string, explicit?: string): string {\n if (explicit) {\n return explicit.replace(/\\/$/, \"\");\n }\n\n const api = new URL(apiBaseUrl);\n if (api.hostname === \"localhost\" && (api.port === \"3000\" || api.port === \"\")) {\n return \"ws://localhost:3001\";\n }\n\n const protocol = api.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n return `${protocol}//${api.host}`;\n}\n","/**\n * Edit launcher mount/teardown (M2-SDK-05).\n *\n * Intent: dynamic import keeps launcher UI out of the default SDK bundle.\n */\nimport { isEditLauncherArmed, shouldAutoEnableEditMode } from \"./edit-token.js\";\nimport {\n disableEditMode as disableEditModeInternal,\n enableEditMode as enableEditModeInternal,\n isEditModeActive,\n} from \"./edit-mode.js\";\nimport type { InitOptions } from \"./types.js\";\n\ntype EditLauncherModule = typeof import(\"./edit-launcher/index.js\");\n\nlet launcherHandle: { destroy: () => void } | null = null;\nlet launcherLoadPromise: Promise<EditLauncherModule> | null = null;\n\nfunction loadLauncherModule(): Promise<EditLauncherModule> {\n if (!launcherLoadPromise) {\n launcherLoadPromise = import(\"./edit-launcher/index.js\");\n }\n return launcherLoadPromise;\n}\n\nexport function shouldMountEditLauncher(options: InitOptions): boolean {\n if (!options.editLauncher) {\n return false;\n }\n if (options.environment !== \"staging\") {\n return false;\n }\n if (shouldAutoEnableEditMode(options)) {\n return false;\n }\n return isEditLauncherArmed(options.editLauncher);\n}\n\nexport async function mountEditLauncherIfNeeded(options: InitOptions): Promise<void> {\n if (!shouldMountEditLauncher(options)) {\n return;\n }\n\n const launcherOptions = options.editLauncher!;\n const mod = await loadLauncherModule();\n launcherHandle = mod.mountEditLauncher({\n initOptions: options,\n launcherOptions,\n isEditModeActive,\n enableEditMode: () => enableEditModeInternal(),\n disableEditMode: disableEditModeInternal,\n });\n}\n\nexport function teardownEditLauncher(): void {\n launcherHandle?.destroy();\n launcherHandle = null;\n launcherLoadPromise = null;\n}\n"],"mappings":"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","names":["current","getRuntime","getRuntime","enableEditMode","disableEditMode"]}
@@ -0,0 +1,260 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+ var _chunkFROJCNV7umdcjs = require('./chunk-FROJCNV7.umd.cjs');
10
+
11
+ // src/resolve-key.ts
12
+ var I18N_KEY_ATTR = "data-i18n-key";
13
+ function resolveKeyForElement(start, resolver) {
14
+ if (resolver) {
15
+ let current2 = start;
16
+ while (current2) {
17
+ const resolved = resolver(current2);
18
+ if (resolved) {
19
+ return resolved;
20
+ }
21
+ current2 = current2.parentElement;
22
+ }
23
+ }
24
+ let current = start;
25
+ while (current) {
26
+ const fromAttr = current.getAttribute(I18N_KEY_ATTR);
27
+ if (fromAttr) {
28
+ return fromAttr;
29
+ }
30
+ current = current.parentElement;
31
+ }
32
+ return null;
33
+ }
34
+
35
+ // src/index.ts
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+ var _runtimecore = require('@stringpush/runtime-core');
44
+
45
+ // src/edit-mode.ts
46
+
47
+
48
+
49
+
50
+
51
+ // src/runtime.ts
52
+
53
+
54
+
55
+
56
+
57
+ function assertInitialized() {
58
+ return _runtimecore.assertInitialized.call(void 0, );
59
+ }
60
+ var keyResolver = null;
61
+ function setKeyResolver(resolver) {
62
+ keyResolver = resolver;
63
+ }
64
+ function getKeyResolver() {
65
+ return keyResolver;
66
+ }
67
+
68
+ // src/urls.ts
69
+ function resolveRealtimeUrl(apiBaseUrl, explicit) {
70
+ if (explicit) {
71
+ return explicit.replace(/\/$/, "");
72
+ }
73
+ const api = new URL(apiBaseUrl);
74
+ if (api.hostname === "localhost" && (api.port === "3000" || api.port === "")) {
75
+ return "ws://localhost:3001";
76
+ }
77
+ const protocol = api.protocol === "https:" ? "wss:" : "ws:";
78
+ return `${protocol}//${api.host}`;
79
+ }
80
+
81
+ // src/edit-mode.ts
82
+ var overlayHandle = null;
83
+ var overlayLoadPromise = null;
84
+ function loadOverlayModule() {
85
+ if (!overlayLoadPromise) {
86
+ overlayLoadPromise = Promise.resolve().then(() => _interopRequireWildcard(require("./overlay-MLOXYRPA.umd.cjs")));
87
+ }
88
+ return overlayLoadPromise;
89
+ }
90
+ function isEditModeActive() {
91
+ return overlayHandle !== null;
92
+ }
93
+ async function enableEditMode(options = {}) {
94
+ if (overlayHandle) {
95
+ return;
96
+ }
97
+ const initOptions = assertInitialized();
98
+ const state = _runtimecore.getRuntime.call(void 0, );
99
+ const manifest = state.manifest;
100
+ if (!manifest) {
101
+ throw new Error("@stringpush/sdk: manifest is not loaded \u2014 call init() before enableEditMode()");
102
+ }
103
+ const editToken = _chunkFROJCNV7umdcjs.resolveEditToken.call(void 0, initOptions, options.editToken);
104
+ if (!editToken) {
105
+ throw new Error(
106
+ "@stringpush/sdk: edit token required \u2014 pass editToken, ?edit_token=, or sessionStorage"
107
+ );
108
+ }
109
+ const apiBaseUrl = _runtimecore.resolveApiBaseUrl.call(void 0, initOptions.apiBaseUrl);
110
+ const realtimeUrl = resolveRealtimeUrl(apiBaseUrl, initOptions.realtimeUrl);
111
+ const overlay = await loadOverlayModule();
112
+ const editClaims = _chunkFROJCNV7umdcjs.decodeEditTokenClaims.call(void 0, editToken);
113
+ if (!editClaims) {
114
+ throw new Error("@stringpush/sdk: edit token is malformed");
115
+ }
116
+ if (editClaims.projectId !== manifest.projectId) {
117
+ throw new Error("@stringpush/sdk: edit token project does not match loaded manifest");
118
+ }
119
+ if (editClaims.applicationId !== manifest.applicationId) {
120
+ throw new Error("@stringpush/sdk: edit token application does not match init()");
121
+ }
122
+ if (editClaims.environmentName !== initOptions.environment) {
123
+ throw new Error(
124
+ "@stringpush/sdk: edit token environment does not match init() environment"
125
+ );
126
+ }
127
+ overlayHandle = overlay.mountOverlay({
128
+ projectId: manifest.projectId,
129
+ applicationId: manifest.applicationId,
130
+ environmentId: editClaims.environmentId,
131
+ realtimeUrl,
132
+ editToken,
133
+ apiBaseUrl,
134
+ origin: initOptions.origin,
135
+ activeLocaleCode: state.locale,
136
+ resolveKey: (element) => resolveKeyForElement(element, getKeyResolver()),
137
+ onCatalogPatched: (keyPath, localeCode, value, version) => {
138
+ if (_runtimecore.patchCatalogEntry.call(void 0, keyPath, localeCode, value, version)) {
139
+ _optionalChain([initOptions, 'access', _ => _.onTranslationsUpdated, 'optionalCall', _2 => _2()]);
140
+ }
141
+ },
142
+ onTranslationsUpdated: () => {
143
+ _optionalChain([initOptions, 'access', _3 => _3.onTranslationsUpdated, 'optionalCall', _4 => _4()]);
144
+ }
145
+ });
146
+ }
147
+ function disableEditMode() {
148
+ _optionalChain([overlayHandle, 'optionalAccess', _5 => _5.destroy, 'call', _6 => _6()]);
149
+ overlayHandle = null;
150
+ }
151
+ function teardownEditMode() {
152
+ disableEditMode();
153
+ overlayLoadPromise = null;
154
+ }
155
+
156
+ // src/edit-launcher-lifecycle.ts
157
+ var launcherHandle = null;
158
+ var launcherLoadPromise = null;
159
+ function loadLauncherModule() {
160
+ if (!launcherLoadPromise) {
161
+ launcherLoadPromise = Promise.resolve().then(() => _interopRequireWildcard(require("./edit-launcher-DB2DJSQJ.umd.cjs")));
162
+ }
163
+ return launcherLoadPromise;
164
+ }
165
+ function shouldMountEditLauncher(options) {
166
+ if (!options.editLauncher) {
167
+ return false;
168
+ }
169
+ if (options.environment !== "staging") {
170
+ return false;
171
+ }
172
+ if (_chunkFROJCNV7umdcjs.shouldAutoEnableEditMode.call(void 0, options)) {
173
+ return false;
174
+ }
175
+ return _chunkFROJCNV7umdcjs.isEditLauncherArmed.call(void 0, options.editLauncher);
176
+ }
177
+ async function mountEditLauncherIfNeeded(options) {
178
+ if (!shouldMountEditLauncher(options)) {
179
+ return;
180
+ }
181
+ const launcherOptions = options.editLauncher;
182
+ const mod = await loadLauncherModule();
183
+ launcherHandle = mod.mountEditLauncher({
184
+ initOptions: options,
185
+ launcherOptions,
186
+ isEditModeActive,
187
+ enableEditMode: () => enableEditMode(),
188
+ disableEditMode
189
+ });
190
+ }
191
+ function teardownEditLauncher() {
192
+ _optionalChain([launcherHandle, 'optionalAccess', _7 => _7.destroy, 'call', _8 => _8()]);
193
+ launcherHandle = null;
194
+ launcherLoadPromise = null;
195
+ }
196
+
197
+ // src/index.ts
198
+ async function init(options) {
199
+ await _runtimecore.initializeRuntime.call(void 0, options);
200
+ const tokenFromUrl = _nullishCoalesce(_chunkFROJCNV7umdcjs.readEditTokenFromQuery.call(void 0, ), () => ( _chunkFROJCNV7umdcjs.readEditTokenFromHash.call(void 0, )));
201
+ if (tokenFromUrl || options.editToken) {
202
+ _chunkFROJCNV7umdcjs.resolveEditToken.call(void 0, options);
203
+ if (tokenFromUrl) {
204
+ _chunkFROJCNV7umdcjs.stripEditTokenFromUrl.call(void 0, );
205
+ }
206
+ }
207
+ if (_chunkFROJCNV7umdcjs.shouldAutoEnableEditMode.call(void 0, options)) {
208
+ await enableEditMode();
209
+ } else {
210
+ await mountEditLauncherIfNeeded(options);
211
+ }
212
+ }
213
+ function destroy() {
214
+ teardownEditLauncher();
215
+ teardownEditMode();
216
+ setKeyResolver(null);
217
+ _runtimecore.destroyRuntime.call(void 0, );
218
+ }
219
+ function getLocale() {
220
+ return _runtimecore.getRuntimeLocale.call(void 0, );
221
+ }
222
+ async function setLocale(locale) {
223
+ await _runtimecore.changeLocale.call(void 0, locale);
224
+ }
225
+ function t(key, values) {
226
+ if (!_runtimecore.getRuntime.call(void 0, ).options) {
227
+ throw new Error("@stringpush/sdk: call init() before using the runtime");
228
+ }
229
+ return _runtimecore.translateKey.call(void 0, key, values);
230
+ }
231
+ function loadNamespace(_namespace) {
232
+ return Promise.resolve();
233
+ }
234
+ async function enableEditMode2(options) {
235
+ await enableEditMode(options);
236
+ }
237
+ function disableEditMode2() {
238
+ disableEditMode();
239
+ }
240
+ function registerResolver(resolver) {
241
+ setKeyResolver(resolver);
242
+ return () => {
243
+ if (getKeyResolver() === resolver) {
244
+ setKeyResolver(null);
245
+ }
246
+ };
247
+ }
248
+
249
+
250
+
251
+
252
+
253
+
254
+
255
+
256
+
257
+
258
+
259
+ exports.I18N_KEY_ATTR = I18N_KEY_ATTR; exports.destroy = destroy; exports.disableEditMode = disableEditMode2; exports.enableEditMode = enableEditMode2; exports.getLocale = getLocale; exports.init = init; exports.loadNamespace = loadNamespace; exports.registerResolver = registerResolver; exports.setLocale = setLocale; exports.t = t;
260
+ //# sourceMappingURL=index.umd.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/mitopalov/work/translations/packages/sdk/dist/index.umd.cjs","../src/resolve-key.ts","../src/index.ts","../src/edit-mode.ts","../src/runtime.ts","../src/urls.ts","../src/edit-launcher-lifecycle.ts"],"names":["current","getRuntime","disableEditMode"],"mappings":"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","file":"/home/mitopalov/work/translations/packages/sdk/dist/index.umd.cjs","sourcesContent":[null,"/**\n * Maps DOM nodes to translation keys for overlay edit mode (M2-SDK-02).\n *\n * Intent: host `registerResolver` first; `data-i18n-key` on the element or an ancestor is the fallback.\n */\nimport type { KeyResolver } from \"./runtime.js\";\n\nexport const I18N_KEY_ATTR = \"data-i18n-key\";\n\n/**\n * Resolves a translation key for a DOM node by walking ancestors.\n */\nexport function resolveKeyForElement(\n start: Element,\n resolver: KeyResolver | null,\n): string | null {\n if (resolver) {\n let current: Element | null = start;\n while (current) {\n const resolved = resolver(current);\n if (resolved) {\n return resolved;\n }\n current = current.parentElement;\n }\n }\n\n let current: Element | null = start;\n while (current) {\n const fromAttr = current.getAttribute(I18N_KEY_ATTR);\n if (fromAttr) {\n return fromAttr;\n }\n current = current.parentElement;\n }\n\n return null;\n}\n","/**\n * @stringpush/sdk — plain JS runtime: load manifest + bundles, expose `t()` (ICU in M1-SDK-03).\n *\n * Intent: customer-facing surface; runtime catalog/manifest delegated to @stringpush/runtime-core.\n */\nexport { I18N_KEY_ATTR } from \"./resolve-key.js\";\n\nexport type {\n EditLauncherOptions,\n EnableEditModeOptions,\n Environment,\n InitOptions,\n ManifestLocaleEntry,\n MissingKeyFallback,\n RetryOptions,\n TranslateValues,\n TranslationCatalog,\n TranslationManifest,\n} from \"./types.js\";\n\nimport type { EnableEditModeOptions, InitOptions, TranslateValues } from \"./types.js\";\nimport {\n changeLocale,\n destroyRuntime,\n getRuntime,\n getRuntimeLocale,\n initializeRuntime,\n translateKey,\n} from \"@stringpush/runtime-core\";\nimport { teardownEditLauncher, mountEditLauncherIfNeeded } from \"./edit-launcher-lifecycle.js\";\nimport {\n readEditTokenFromHash,\n readEditTokenFromQuery,\n resolveEditToken,\n shouldAutoEnableEditMode,\n stripEditTokenFromUrl,\n} from \"./edit-token.js\";\nimport {\n disableEditMode as disableEditModeInternal,\n enableEditMode as enableEditModeInternal,\n teardownEditMode,\n} from \"./edit-mode.js\";\nimport { getKeyResolver, setKeyResolver } from \"./runtime.js\";\n\n/**\n * Initialize the SDK: fetch manifest and the active locale bundle into an in-memory catalog.\n *\n * Intent: entry point for customer apps; triggers `onTranslationsUpdated` when the first catalog is ready.\n */\nexport async function init(options: InitOptions): Promise<void> {\n await initializeRuntime(options);\n\n const tokenFromUrl = readEditTokenFromQuery() ?? readEditTokenFromHash();\n if (tokenFromUrl || options.editToken) {\n resolveEditToken(options);\n if (tokenFromUrl) {\n stripEditTokenFromUrl();\n }\n }\n\n if (shouldAutoEnableEditMode(options)) {\n await enableEditModeInternal();\n } else {\n await mountEditLauncherIfNeeded(options);\n }\n}\n\nexport function destroy(): void {\n teardownEditLauncher();\n teardownEditMode();\n setKeyResolver(null);\n destroyRuntime();\n}\n\nexport function getLocale(): string {\n return getRuntimeLocale();\n}\n\n/**\n * Switch active locale and reload its bundle from the manifest.\n */\nexport async function setLocale(locale: string): Promise<void> {\n await changeLocale(locale);\n}\n\n/**\n * Translate a key using the loaded catalog and ICU MessageFormat.\n */\nexport function t(key: string, values?: TranslateValues): string {\n // Intent: preserve @stringpush/sdk error text for public `t()` callers (runtime-core uses initializeRuntime wording).\n if (!getRuntime().options) {\n throw new Error(\"@stringpush/sdk: call init() before using the runtime\");\n }\n return translateKey(key, values);\n}\n\nexport function loadNamespace(_namespace: string): Promise<void> {\n return Promise.resolve();\n}\n\nexport async function enableEditMode(options?: EnableEditModeOptions): Promise<void> {\n await enableEditModeInternal(options);\n}\n\nexport function disableEditMode(): void {\n disableEditModeInternal();\n}\n\nexport function registerResolver(resolver: (element: Element) => string | null): () => void {\n setKeyResolver(resolver);\n return () => {\n if (getKeyResolver() === resolver) {\n setKeyResolver(null);\n }\n };\n}\n","/**\n * Edit-mode lifecycle: lazy overlay chunk load and teardown (M2-SDK-01).\n */\nimport {\n patchCatalogEntry,\n resolveApiBaseUrl,\n} from \"@stringpush/runtime-core\";\nimport { decodeEditTokenClaims } from \"./edit-token-decode.js\";\nimport { resolveEditToken } from \"./edit-token.js\";\nimport { resolveKeyForElement } from \"./resolve-key.js\";\nimport { assertInitialized, getKeyResolver, getRuntime } from \"./runtime.js\";\nimport type { EnableEditModeOptions } from \"./types.js\";\nimport { resolveRealtimeUrl } from \"./urls.js\";\n\ntype OverlayModule = typeof import(\"./overlay/index.js\");\n\nlet overlayHandle: { destroy: () => void } | null = null;\nlet overlayLoadPromise: Promise<OverlayModule> | null = null;\n\nfunction loadOverlayModule(): Promise<OverlayModule> {\n if (!overlayLoadPromise) {\n // Intent: dynamic import keeps overlay + WS client out of the default SDK bundle.\n overlayLoadPromise = import(\"./overlay/index.js\");\n }\n return overlayLoadPromise;\n}\n\nexport function isEditModeActive(): boolean {\n return overlayHandle !== null;\n}\n\n/**\n * Activates overlay edit mode when a valid edit JWT is available.\n */\nexport async function enableEditMode(options: EnableEditModeOptions = {}): Promise<void> {\n if (overlayHandle) {\n return;\n }\n\n const initOptions = assertInitialized();\n const state = getRuntime();\n const manifest = state.manifest;\n if (!manifest) {\n throw new Error(\"@stringpush/sdk: manifest is not loaded — call init() before enableEditMode()\");\n }\n\n const editToken = resolveEditToken(initOptions, options.editToken);\n if (!editToken) {\n throw new Error(\n \"@stringpush/sdk: edit token required — pass editToken, ?edit_token=, or sessionStorage\",\n );\n }\n\n const apiBaseUrl = resolveApiBaseUrl(initOptions.apiBaseUrl);\n const realtimeUrl = resolveRealtimeUrl(apiBaseUrl, initOptions.realtimeUrl);\n const overlay = await loadOverlayModule();\n const editClaims = decodeEditTokenClaims(editToken);\n if (!editClaims) {\n throw new Error(\"@stringpush/sdk: edit token is malformed\");\n }\n if (editClaims.projectId !== manifest.projectId) {\n throw new Error(\"@stringpush/sdk: edit token project does not match loaded manifest\");\n }\n if (editClaims.applicationId !== manifest.applicationId) {\n throw new Error(\"@stringpush/sdk: edit token application does not match init()\");\n }\n if (editClaims.environmentName !== initOptions.environment) {\n throw new Error(\n \"@stringpush/sdk: edit token environment does not match init() environment\",\n );\n }\n\n overlayHandle = overlay.mountOverlay({\n projectId: manifest.projectId,\n applicationId: manifest.applicationId,\n environmentId: editClaims.environmentId,\n realtimeUrl,\n editToken,\n apiBaseUrl,\n origin: initOptions.origin,\n activeLocaleCode: state.locale,\n resolveKey: (element) => resolveKeyForElement(element, getKeyResolver()),\n onCatalogPatched: (keyPath, localeCode, value, version) => {\n if (patchCatalogEntry(keyPath, localeCode, value, version)) {\n initOptions.onTranslationsUpdated?.();\n }\n },\n onTranslationsUpdated: () => {\n initOptions.onTranslationsUpdated?.();\n },\n });\n}\n\n/**\n * Tears down overlay DOM and closes the realtime WebSocket.\n */\nexport function disableEditMode(): void {\n overlayHandle?.destroy();\n overlayHandle = null;\n}\n\nexport function teardownEditMode(): void {\n disableEditMode();\n overlayLoadPromise = null;\n}\n","/**\n * DOM-specific runtime helpers (key resolver) atop @stringpush/runtime-core state.\n *\n * Intent: overlay `registerResolver` stays in sdk; catalog/manifest live in runtime-core.\n */\nimport {\n assertInitialized as assertCoreInitialized,\n getRuntime,\n resetRuntime,\n type SdkRuntime,\n} from \"@stringpush/runtime-core\";\nimport type { InitOptions } from \"./types.js\";\n\nexport { getRuntime, resetRuntime, type SdkRuntime };\n\n/** SDK init stores overlay fields on the same options object passed to runtime-core. */\nexport function assertInitialized(): InitOptions {\n return assertCoreInitialized() as InitOptions;\n}\n\nexport type KeyResolver = (element: Element) => string | null;\n\nlet keyResolver: KeyResolver | null = null;\n\nexport function setKeyResolver(resolver: KeyResolver | null): void {\n keyResolver = resolver;\n}\n\nexport function getKeyResolver(): KeyResolver | null {\n return keyResolver;\n}\n","/**\n * WebSocket URL helper for overlay realtime (M2-SDK-01).\n *\n * Intent: overlay-specific; runtime-core has no realtime dependency.\n */\nexport function resolveRealtimeUrl(apiBaseUrl: string, explicit?: string): string {\n if (explicit) {\n return explicit.replace(/\\/$/, \"\");\n }\n\n const api = new URL(apiBaseUrl);\n if (api.hostname === \"localhost\" && (api.port === \"3000\" || api.port === \"\")) {\n return \"ws://localhost:3001\";\n }\n\n const protocol = api.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n return `${protocol}//${api.host}`;\n}\n","/**\n * Edit launcher mount/teardown (M2-SDK-05).\n *\n * Intent: dynamic import keeps launcher UI out of the default SDK bundle.\n */\nimport { isEditLauncherArmed, shouldAutoEnableEditMode } from \"./edit-token.js\";\nimport {\n disableEditMode as disableEditModeInternal,\n enableEditMode as enableEditModeInternal,\n isEditModeActive,\n} from \"./edit-mode.js\";\nimport type { InitOptions } from \"./types.js\";\n\ntype EditLauncherModule = typeof import(\"./edit-launcher/index.js\");\n\nlet launcherHandle: { destroy: () => void } | null = null;\nlet launcherLoadPromise: Promise<EditLauncherModule> | null = null;\n\nfunction loadLauncherModule(): Promise<EditLauncherModule> {\n if (!launcherLoadPromise) {\n launcherLoadPromise = import(\"./edit-launcher/index.js\");\n }\n return launcherLoadPromise;\n}\n\nexport function shouldMountEditLauncher(options: InitOptions): boolean {\n if (!options.editLauncher) {\n return false;\n }\n if (options.environment !== \"staging\") {\n return false;\n }\n if (shouldAutoEnableEditMode(options)) {\n return false;\n }\n return isEditLauncherArmed(options.editLauncher);\n}\n\nexport async function mountEditLauncherIfNeeded(options: InitOptions): Promise<void> {\n if (!shouldMountEditLauncher(options)) {\n return;\n }\n\n const launcherOptions = options.editLauncher!;\n const mod = await loadLauncherModule();\n launcherHandle = mod.mountEditLauncher({\n initOptions: options,\n launcherOptions,\n isEditModeActive,\n enableEditMode: () => enableEditModeInternal(),\n disableEditMode: disableEditModeInternal,\n });\n}\n\nexport function teardownEditLauncher(): void {\n launcherHandle?.destroy();\n launcherHandle = null;\n launcherLoadPromise = null;\n}\n"]}