@happyvertical/smrt-template-sveltekit 0.53.3 → 0.53.4

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.
Files changed (47) hide show
  1. package/AGENTS.md +53 -26
  2. package/README.md +23 -16
  3. package/mcp-apps-template/package.dependencies.json +2 -2
  4. package/mcp-apps-template/src/routes/.well-known/oauth-protected-resource/api/mcp/+server.ts +14 -6
  5. package/mcp-apps-template/src/routes/api/mcp/+server.ts +69 -12
  6. package/package.json +17 -15
  7. package/template/AGENTS.md +16 -5
  8. package/template/Dockerfile +0 -1
  9. package/template/INSTALL_PROMPT.md +2 -2
  10. package/template/README.md +52 -27
  11. package/template/compose.yaml +2 -2
  12. package/template/package.json +28 -27
  13. package/template/smrt.config.ts +17 -4
  14. package/template/src/app.d.ts +4 -11
  15. package/template/src/hooks.server.ts +10 -51
  16. package/template/src/lib/server/smrt.ts +70 -62
  17. package/template/src/routes/+layout.server.ts +4 -12
  18. package/template/src/routes/+layout.svelte +27 -99
  19. package/template/src/routes/api/_runtime/diagnostics/+server.ts +17 -3
  20. package/template/src/routes/api/_runtime/health/+server.ts +4 -28
  21. package/template/src/routes/settings/+page.svelte +3 -34
  22. package/template/src/routes/setup/+page.server.ts +15 -88
  23. package/template/src/routes/setup/+page.svelte +3 -23
  24. package/template/vite.config.ts +5 -43
  25. package/template.config.js +11 -11
  26. package/mcp-apps-template/src/lib/McpAppsBridge.svelte +0 -37
  27. package/mcp-apps-template/src/lib/server/mcp-hosted.ts +0 -28
  28. package/mcp-apps-template/src/lib/server/mcp.ts +0 -85
  29. package/template/scripts/smrt-app.mjs +0 -885
  30. package/template/scripts/smrt-mcp-apps.mjs +0 -18
  31. package/template/scripts/smrt-operation-lock.mjs +0 -102
  32. package/template/scripts/smrt-portability-assets.mjs +0 -707
  33. package/template/scripts/smrt-portability.mjs +0 -470
  34. package/template/scripts/smrt-prepare-migration.mjs +0 -93
  35. package/template/scripts/smrt-process.mjs +0 -82
  36. package/template/scripts/smrt-provider-readiness.mjs +0 -33
  37. package/template/scripts/smrt-runtime-identity.mjs +0 -245
  38. package/template/scripts/smrt-vite.mjs +0 -45
  39. package/template/scripts/smrt-web.mjs +0 -10
  40. package/template/scripts/smrt-worker.mjs +0 -100
  41. package/template/scripts/smrt-writer-lease.mjs +0 -199
  42. package/template/src/lib/RuntimeDiagnosticsWebMcp.svelte +0 -11
  43. package/template/src/lib/runtime-diagnostics-webmcp.ts +0 -108
  44. package/template/src/lib/server/application-runtime.ts +0 -262
  45. package/template/src/lib/server/runtime-diagnostics.ts +0 -114
  46. package/template/src/lib/server/tenancy.ts +0 -114
  47. package/template/src/smrt-webmcp.d.ts +0 -6
@@ -1,245 +0,0 @@
1
- import {
2
- closeSync,
3
- constants,
4
- existsSync,
5
- lstatSync,
6
- mkdirSync,
7
- openSync,
8
- readFileSync,
9
- realpathSync,
10
- } from 'node:fs';
11
- import { basename, dirname, join, parse, resolve } from 'node:path';
12
- import { homedir, platform } from 'node:os';
13
- import {
14
- encodeApplicationId,
15
- resolveLocalRuntimePaths,
16
- validateApplicationId,
17
- } from '@happyvertical/smrt-app-runtime';
18
-
19
- /**
20
- * Resolve one stable identity for CLI, development, and app operations.
21
- * @param {{sourceRoot?: string, packageName?: string, explicitId?: string}} [options]
22
- */
23
- export function resolveApplicationId(options = {}) {
24
- const sourceRoot = options.sourceRoot || process.cwd();
25
- let packageName = options.packageName;
26
- if (!packageName) {
27
- packageName = JSON.parse(
28
- readFileSync(join(sourceRoot, 'package.json'), 'utf8'),
29
- ).name;
30
- }
31
- if (typeof packageName !== 'string' || packageName.trim() === '') {
32
- throw new Error('package.json must declare a non-empty package name.');
33
- }
34
- return options.explicitId
35
- ? validateApplicationId(options.explicitId)
36
- : encodeApplicationId(packageName);
37
- }
38
-
39
- /**
40
- * State is derived from the canonical application/data identity. It is not an
41
- * independent override because every process and operator command must share
42
- * one lock domain for a given database root.
43
- * @param {{appId: string, dataDirectory?: string, sourceRoot?: string, platformName?: string, homeDirectory?: string, environment?: Record<string, string | undefined>}} options
44
- */
45
- export function resolveApplicationStateRoot(options) {
46
- const paths = resolveLocalRuntimePaths({
47
- appId: options.appId,
48
- dataDirectory: options.dataDirectory,
49
- sourceRoot: options.sourceRoot,
50
- });
51
- const platformName = options.platformName || platform();
52
- const homeDirectory = options.homeDirectory || homedir();
53
- const environment = options.environment || process.env;
54
- const stateBase =
55
- platformName === 'darwin'
56
- ? join(homeDirectory, 'Library', 'Application Support')
57
- : platformName === 'win32'
58
- ? environment.LOCALAPPDATA || homeDirectory
59
- : environment.XDG_STATE_HOME || join(homeDirectory, '.local', 'state');
60
- const dataIdentity = createHash('sha256')
61
- .update(resolve(paths.root))
62
- .digest('hex')
63
- .slice(0, 12);
64
- return resolve(stateBase, `.${options.appId}-${dataIdentity}-state`);
65
- }
66
-
67
- /** @param {string | undefined} value */
68
- function databaseTargetIdentity(value) {
69
- if (!value) return null;
70
- try {
71
- const target = new URL(value);
72
- const sslMode = target.searchParams.get('sslmode');
73
- target.username = '';
74
- target.password = '';
75
- target.search = '';
76
- target.hash = '';
77
- if (sslMode) target.searchParams.set('sslmode', sslMode);
78
- return target.toString();
79
- } catch {
80
- return resolve(value);
81
- }
82
- }
83
-
84
- /**
85
- * Secret-safe identity used to reject stale managed processes after profile,
86
- * provider, database-target, or listener configuration changes.
87
- * @param {{profile: string, providers: object}} runtime
88
- * @param {Record<string, string | undefined>} [environment]
89
- */
90
- export function runtimeConfigurationFingerprint(
91
- runtime,
92
- environment = process.env,
93
- ) {
94
- return createHash('sha256')
95
- .update(
96
- JSON.stringify({
97
- profile: runtime.profile,
98
- providers: runtime.providers,
99
- databaseTarget: databaseTargetIdentity(environment.DATABASE_URL),
100
- host: environment.HOST || null,
101
- port: environment.PORT || null,
102
- origin: environment.ORIGIN || null,
103
- backgroundJobs: environment.SMRT_BACKGROUND_JOBS === 'true',
104
- readinessModules: {
105
- authentication: environment.SMRT_AUTH_READINESS_MODULE || null,
106
- assets: environment.SMRT_ASSETS_READINESS_MODULE || null,
107
- secrets: environment.SMRT_SECRETS_READINESS_MODULE || null,
108
- },
109
- mcpAuthorization: {
110
- resource: environment.SMRT_MCP_RESOURCE || null,
111
- issuer: environment.SMRT_MCP_ISSUER || null,
112
- jwksUri: environment.SMRT_MCP_JWKS_URI || null,
113
- scopes: environment.SMRT_MCP_SCOPES || null,
114
- },
115
- }),
116
- )
117
- .digest('hex');
118
- }
119
-
120
- /** @param {string} parent @param {string} child */
121
- function isInside(parent, child) {
122
- const relative = child.slice(parent.length);
123
- return (
124
- child === parent ||
125
- (child.startsWith(parent) && (relative.startsWith('/') || relative.startsWith('\\')))
126
- );
127
- }
128
-
129
- /**
130
- * Resolve an operator-selected artifact through its nearest existing ancestor
131
- * and reject paths that could place application data in or over the checkout.
132
- * @param {{sourceRoot: string, path: string, label?: string}} options
133
- */
134
- export function assertExternalArtifactPath(options) {
135
- const canonicalSource = realpathSync(resolve(options.sourceRoot));
136
- const missingSegments = [];
137
- let existingAncestor = resolve(options.path);
138
- while (!existsSync(existingAncestor)) {
139
- const parent = dirname(existingAncestor);
140
- if (parent === existingAncestor) break;
141
- missingSegments.unshift(basename(existingAncestor));
142
- existingAncestor = parent;
143
- }
144
- const canonicalPath = resolve(
145
- realpathSync(existingAncestor),
146
- ...missingSegments,
147
- );
148
- if (
149
- isInside(canonicalSource, canonicalPath) ||
150
- isInside(canonicalPath, canonicalSource)
151
- ) {
152
- throw new Error(
153
- `${options.label || 'Artifact'} must remain outside the source tree.`,
154
- );
155
- }
156
- return canonicalPath;
157
- }
158
-
159
- /** @param {unknown} error */
160
- function errorCode(error) {
161
- return error && typeof error === 'object' && 'code' in error
162
- ? error.code
163
- : undefined;
164
- }
165
-
166
- /**
167
- * Create or verify the private, app-bound state/lock directory.
168
- * @param {{appId: string, dataDirectory?: string, sourceRoot?: string, platformName?: string, homeDirectory?: string, environment?: Record<string, string | undefined>}} options
169
- */
170
- export function prepareApplicationStateRoot(options) {
171
- const sourceRoot = realpathSync(resolve(options.sourceRoot || process.cwd()));
172
- const stateRoot = resolveApplicationStateRoot(options);
173
- if (isInside(sourceRoot, stateRoot) || isInside(stateRoot, sourceRoot)) {
174
- throw new Error('Application state must remain outside the source tree.');
175
- }
176
- const currentUid = process.getuid?.();
177
- let component = parse(stateRoot).root;
178
- for (const part of stateRoot.slice(component.length).split(/[\\/]+/).filter(Boolean)) {
179
- component = join(component, part);
180
- try {
181
- const details = lstatSync(component);
182
- if (details.isSymbolicLink() || !details.isDirectory()) {
183
- throw new Error(`Application state path component is unsafe: ${component}`);
184
- }
185
- const sharedStickyRoot = details.uid === 0 && (details.mode & 0o1000) !== 0;
186
- if (
187
- currentUid !== undefined &&
188
- ((details.uid !== currentUid && details.uid !== 0) ||
189
- ((details.mode & 0o022) !== 0 && !sharedStickyRoot))
190
- ) {
191
- throw new Error(`Application state path lacks trusted custody: ${component}`);
192
- }
193
- } catch (error) {
194
- if (errorCode(error) !== 'ENOENT') throw error;
195
- try {
196
- mkdirSync(component, { mode: 0o700 });
197
- } catch (mkdirError) {
198
- if (errorCode(mkdirError) !== 'EEXIST') throw mkdirError;
199
- }
200
- const created = lstatSync(component);
201
- if (
202
- created.isSymbolicLink() ||
203
- !created.isDirectory() ||
204
- (currentUid !== undefined && created.uid !== currentUid) ||
205
- (created.mode & 0o777) !== 0o700
206
- ) {
207
- throw new Error(`Application state path component is unsafe: ${component}`);
208
- }
209
- }
210
- }
211
- const rootDetails = lstatSync(stateRoot);
212
- if (
213
- rootDetails.isSymbolicLink() ||
214
- !rootDetails.isDirectory() ||
215
- (currentUid !== undefined && rootDetails.uid !== currentUid) ||
216
- (rootDetails.mode & 0o777) !== 0o700
217
- ) {
218
- throw new Error('Application state root must be current-user-owned mode 0700.');
219
- }
220
- const markerPath = join(stateRoot, `.smrt-state-${validateApplicationId(options.appId)}`);
221
- let descriptor;
222
- try {
223
- descriptor = openSync(
224
- markerPath,
225
- constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL,
226
- 0o600,
227
- );
228
- } catch (error) {
229
- if (errorCode(error) !== 'EEXIST') throw error;
230
- const marker = lstatSync(markerPath);
231
- if (
232
- marker.isSymbolicLink() ||
233
- !marker.isFile() ||
234
- marker.size !== 0 ||
235
- (currentUid !== undefined && marker.uid !== currentUid) ||
236
- (marker.mode & 0o777) !== 0o600
237
- ) {
238
- throw new Error('Application state marker is unsafe.');
239
- }
240
- } finally {
241
- if (descriptor !== undefined) closeSync(descriptor);
242
- }
243
- return stateRoot;
244
- }
245
- import { createHash } from 'node:crypto';
@@ -1,45 +0,0 @@
1
- import { existsSync, readFileSync, writeSync } from 'node:fs';
2
- import { dirname, isAbsolute, relative, resolve } from 'node:path';
3
- import { fileURLToPath, pathToFileURL } from 'node:url';
4
-
5
- function fail(message) {
6
- writeSync(2, `s-m-r-t Vite launcher: ${message}\n`);
7
- process.exit(1);
8
- }
9
-
10
- let packagePath;
11
- try {
12
- packagePath = fileURLToPath(import.meta.resolve('vite/package.json'));
13
- } catch (error) {
14
- const detail = error instanceof Error ? `: ${error.message}` : '';
15
- fail(
16
- `Could not resolve the installed Vite package${detail}. Verify the generated app dependencies and Vite compatibility.`,
17
- );
18
- }
19
- const packageRoot = dirname(packagePath);
20
- let metadata;
21
- try {
22
- metadata = JSON.parse(readFileSync(packagePath, 'utf8'));
23
- } catch {
24
- fail('The installed Vite package metadata is invalid; reinstall dependencies.');
25
- }
26
- const declaredBin =
27
- typeof metadata.bin === 'string' ? metadata.bin : metadata.bin?.vite;
28
- if (typeof declaredBin !== 'string' || declaredBin === '') {
29
- fail('The installed Vite package does not declare its CLI.');
30
- }
31
- const entry = resolve(packageRoot, declaredBin);
32
- const relativeEntry = relative(packageRoot, entry);
33
- if (
34
- relativeEntry === '' ||
35
- relativeEntry.startsWith('..') ||
36
- isAbsolute(relativeEntry)
37
- ) {
38
- fail('The installed Vite package declares an unsafe CLI path.');
39
- }
40
- if (!existsSync(entry)) {
41
- fail('The installed Vite package CLI is missing; reinstall dependencies.');
42
- }
43
-
44
- process.argv = [process.execPath, entry, ...process.argv.slice(2)];
45
- await import(pathToFileURL(entry).href);
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const instance = process.argv
4
- .find((value) => value.startsWith('--smrt-instance='))
5
- ?.slice('--smrt-instance='.length);
6
- if (!instance || !/^[a-f0-9]{32}$/.test(instance)) {
7
- throw new Error('A valid application process identity is required.');
8
- }
9
-
10
- await import('../build/index.js');
@@ -1,100 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { existsSync } from 'node:fs';
4
- import { fileURLToPath } from 'node:url';
5
- import { initializeDeployedApplicationRuntime } from '@happyvertical/smrt-app-runtime';
6
- import {
7
- loadConfig,
8
- resolveConfiguredApplicationRuntime,
9
- } from '@happyvertical/smrt-config';
10
- import { getDatabase } from '@happyvertical/sql';
11
- import { createProviderReadinessProbe } from './smrt-provider-readiness.mjs';
12
-
13
- await loadConfig({ cache: false });
14
- const configured = resolveConfiguredApplicationRuntime();
15
- if (configured.profile === 'local') {
16
- throw new Error('Local jobs run inline or embedded; a separate worker requires self-hosted or cloud.');
17
- }
18
- if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is required.');
19
-
20
- // Register this application's own @smrt() objects (and the consumed packages'
21
- // objects) before any runner resolves a job's objectType. `pnpm build`
22
- // compiles the generated registration into this module; the web server's
23
- // bundle is not importable from a separate Node process.
24
- const registration = new URL('../.smrt/runtime/register.js', import.meta.url);
25
- if (!existsSync(fileURLToPath(registration))) {
26
- throw new Error(
27
- 'Missing .smrt/runtime/register.js: run pnpm build before starting a worker.',
28
- );
29
- }
30
- await import(registration.href);
31
-
32
- const runtime = await initializeDeployedApplicationRuntime({
33
- profile: configured.profile,
34
- providers: {
35
- database: configured.providers.database,
36
- authentication: configured.providers.authentication,
37
- tenancy: configured.providers.tenancy,
38
- assets: configured.providers.assets,
39
- secrets: configured.providers.secrets,
40
- jobs: configured.providers.jobs,
41
- network: configured.providers.network,
42
- },
43
- database: {
44
- engine: 'postgres',
45
- connect: () =>
46
- getDatabase({ type: 'postgres', url: process.env.DATABASE_URL }),
47
- close: async (db) => db.close?.(),
48
- },
49
- authentication: {
50
- provider: configured.providers.authentication.provider,
51
- readiness: createProviderReadinessProbe('authentication', {
52
- profile: configured.profile,
53
- provider: configured.providers.authentication.provider,
54
- }),
55
- },
56
- assets: {
57
- provider: configured.providers.assets.provider,
58
- readiness: createProviderReadinessProbe('assets', {
59
- profile: configured.profile,
60
- provider: configured.providers.assets.provider,
61
- }),
62
- },
63
- secrets: {
64
- provider: configured.providers.secrets.provider,
65
- readiness: createProviderReadinessProbe('secrets', {
66
- profile: configured.profile,
67
- provider: configured.providers.secrets.provider,
68
- }),
69
- },
70
- });
71
-
72
- const kind = process.argv[2] || 'task';
73
- const runner =
74
- kind === 'schedule'
75
- ? await runtime.createScheduleWorker()
76
- : await runtime.createTaskWorker({
77
- concurrency: Number.parseInt(
78
- process.env.SMRT_WORKER_CONCURRENCY || '4',
79
- 10,
80
- ),
81
- });
82
-
83
- await runner.start();
84
- console.log(
85
- JSON.stringify({
86
- schemaVersion: 1,
87
- status: 'ready',
88
- kind,
89
- secretValuesIncluded: false,
90
- }),
91
- );
92
-
93
- let stopping = false;
94
- async function stop() {
95
- if (stopping) return;
96
- stopping = true;
97
- await runtime.close();
98
- }
99
- process.once('SIGINT', () => void stop());
100
- process.once('SIGTERM', () => void stop());
@@ -1,199 +0,0 @@
1
- import { randomBytes } from 'node:crypto';
2
- import {
3
- closeSync,
4
- fstatSync,
5
- lstatSync,
6
- mkdirSync,
7
- openSync,
8
- readFileSync,
9
- rmSync,
10
- writeFileSync,
11
- } from 'node:fs';
12
- import { join } from 'node:path';
13
-
14
- /** @param {number} pid */
15
- function processExists(pid) {
16
- try {
17
- process.kill(pid, 0);
18
- return true;
19
- } catch (error) {
20
- const code =
21
- error && typeof error === 'object' && 'code' in error
22
- ? error.code
23
- : undefined;
24
- return code === 'EPERM' || code === 'EACCES';
25
- }
26
- }
27
-
28
- /** @param {{ schemaVersion: number, pid: number, instance: string }} record */
29
- function validateRecord(record) {
30
- if (
31
- record.schemaVersion !== 1 ||
32
- !Number.isSafeInteger(record.pid) ||
33
- record.pid < 1 ||
34
- typeof record.instance !== 'string' ||
35
- !/^[a-f0-9]{32}$/.test(record.instance)
36
- ) {
37
- throw new Error('The application writer lease is malformed.');
38
- }
39
- return record;
40
- }
41
-
42
- /** @param {string | number} pathOrDescriptor */
43
- function readRecord(pathOrDescriptor) {
44
- return validateRecord(
45
- JSON.parse(readFileSync(pathOrDescriptor, 'utf8')),
46
- );
47
- }
48
-
49
- /** @param {string} stateRoot */
50
- export function readActiveWriterLease(stateRoot) {
51
- const path = join(stateRoot, 'writer.lease');
52
- for (let attempt = 0; attempt < 4; attempt += 1) {
53
- let descriptor;
54
- try {
55
- descriptor = openSync(path, 'r');
56
- const identity = fstatSync(descriptor);
57
- const record = readRecord(descriptor);
58
- closeSync(descriptor);
59
- descriptor = undefined;
60
- if (processExists(record.pid)) return record;
61
- const current = lstatSync(path);
62
- if (current.dev !== identity.dev || current.ino !== identity.ino) {
63
- continue;
64
- }
65
- rmSync(path);
66
- return null;
67
- } catch (error) {
68
- if (descriptor !== undefined) closeSync(descriptor);
69
- if (
70
- error &&
71
- typeof error === 'object' &&
72
- 'code' in error &&
73
- error.code === 'ENOENT'
74
- ) {
75
- return null;
76
- }
77
- throw new Error(
78
- 'The application writer lease cannot be verified; inspect the private state directory.',
79
- );
80
- }
81
- }
82
- throw new Error(
83
- 'The application writer lease changed repeatedly and cannot be verified.',
84
- );
85
- }
86
-
87
- /**
88
- * @param {string} stateRoot
89
- * @param {{ operationInstance?: string }} [options]
90
- */
91
- export function acquireWriterLease(stateRoot, options = {}) {
92
- mkdirSync(stateRoot, { recursive: true, mode: 0o700 });
93
- const path = join(stateRoot, 'writer.lease');
94
- const active = readActiveWriterLease(stateRoot);
95
- if (active?.pid === process.pid) return { release() {} };
96
- if (active) {
97
- throw new Error(
98
- `Another application writer is active (process ${active.pid}).`,
99
- );
100
- }
101
- const instance = randomBytes(16).toString('hex');
102
- let descriptor;
103
- for (let attempt = 0; attempt < 2; attempt += 1) {
104
- try {
105
- descriptor = openSync(path, 'wx', 0o600);
106
- writeFileSync(
107
- descriptor,
108
- `${JSON.stringify({ schemaVersion: 1, pid: process.pid, instance })}\n`,
109
- );
110
- break;
111
- } catch (error) {
112
- if (descriptor !== undefined) {
113
- closeSync(descriptor);
114
- descriptor = undefined;
115
- }
116
- if (
117
- error &&
118
- typeof error === 'object' &&
119
- 'code' in error &&
120
- error.code === 'EEXIST'
121
- ) {
122
- const owner = readActiveWriterLease(stateRoot);
123
- if (!owner && attempt === 0) continue;
124
- throw new Error(
125
- `Another application writer is active${owner ? ` (process ${owner.pid})` : ''}.`,
126
- );
127
- }
128
- rmSync(path, { force: true });
129
- throw error;
130
- }
131
- }
132
- if (descriptor === undefined) {
133
- throw new Error('The application writer lease could not be acquired.');
134
- }
135
- closeSync(descriptor);
136
- let released = false;
137
- const release = () => {
138
- if (released) return;
139
- released = true;
140
- try {
141
- const current = readRecord(path);
142
- if (current.pid === process.pid && current.instance === instance) {
143
- rmSync(path, { force: true });
144
- }
145
- } catch {
146
- // A missing or externally repaired lease is not ours to remove.
147
- }
148
- };
149
- let operationDescriptor;
150
- try {
151
- const operationPath = join(stateRoot, 'operation.lock');
152
- operationDescriptor = openSync(operationPath, 'r');
153
- const operationIdentity = fstatSync(operationDescriptor);
154
- const operation = JSON.parse(readFileSync(operationDescriptor, 'utf8'));
155
- closeSync(operationDescriptor);
156
- operationDescriptor = undefined;
157
- if (
158
- !Number.isSafeInteger(operation.pid) ||
159
- operation.pid < 1 ||
160
- typeof operation.instance !== 'string'
161
- ) {
162
- throw new Error('The application operation lock cannot be verified.');
163
- }
164
- if (!processExists(operation.pid)) {
165
- const currentIdentity = lstatSync(operationPath);
166
- if (
167
- currentIdentity.dev !== operationIdentity.dev ||
168
- currentIdentity.ino !== operationIdentity.ino
169
- ) {
170
- throw new Error('The application operation lock changed unexpectedly.');
171
- }
172
- rmSync(operationPath);
173
- } else if (operation.instance !== options.operationInstance) {
174
- release();
175
- throw new Error(
176
- 'An application operation is active; wait for it to finish before starting a writer.',
177
- );
178
- }
179
- } catch (error) {
180
- if (operationDescriptor !== undefined) closeSync(operationDescriptor);
181
- if (
182
- !(
183
- error &&
184
- typeof error === 'object' &&
185
- 'code' in error &&
186
- error.code === 'ENOENT'
187
- )
188
- ) {
189
- if (error instanceof SyntaxError) {
190
- release();
191
- throw new Error('The application operation lock cannot be verified.');
192
- }
193
- release();
194
- throw error;
195
- }
196
- }
197
- process.once('exit', release);
198
- return { release };
199
- }
@@ -1,11 +0,0 @@
1
- <script lang="ts">
2
- import { registerRuntimeDiagnosticsWebMcp } from './runtime-diagnostics-webmcp.js';
3
-
4
- let { enabled = true }: { enabled?: boolean } = $props();
5
-
6
- $effect(() => {
7
- if (!enabled) return;
8
- const owner = registerRuntimeDiagnosticsWebMcp();
9
- return () => owner?.dispose();
10
- });
11
- </script>