@lvce-editor/api 9.30.0 → 9.32.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.
package/README.md CHANGED
@@ -50,3 +50,20 @@ await storeSecret('access-token', token)
50
50
  const savedToken = await getSecret('access-token')
51
51
  await deleteSecret('access-token')
52
52
  ```
53
+
54
+ ## Workspace ports
55
+
56
+ Declare `"onPorts:codespaces"` in the extension's `activation` array and register a provider after activating the API:
57
+
58
+ ```ts
59
+ import { registerPortProvider } from '@lvce-editor/api'
60
+
61
+ const registration = registerPortProvider({
62
+ scheme: 'codespaces',
63
+ async providePorts(workspaceUri) {
64
+ return [{ port: 3000, forwardedAddress: 'https://my-codespace-3000.app.github.dev/', origin: 'devcontainer.json' }]
65
+ },
66
+ })
67
+ ```
68
+
69
+ Ports queries matching extensions with the current workspace URI. Each extension may register one provider per scheme. Return an empty array when no ports are available, and dispose the registration when deactivating. The provider supplies addresses; the API does not create tunnels or change their visibility. Results from disposed registrations are discarded.
package/dist/index.d.ts CHANGED
@@ -62,3 +62,6 @@ export type { ShowQuickPickOptions } from './parts/ShowQuickPickOptions/ShowQuic
62
62
  export type { StatusBarItem, StatusBarItemProvider, StatusBarItemProviderHandle, StatusBarItemProviderRegistrySnapshot, } from './parts/StatusBar/StatusBar.ts';
63
63
  export { setRemoteDescription, startWebRtcAudioStream, stopWebRtcAudioStream, readMicLevels } from './parts/WebRtc/WebRtc.ts';
64
64
  export type { MicLevelsResult, ReadMicLevelOptions, SetRemoteDescriptionOptions, StartWebRpcAudioStreamOptions, WebRtcAudioConstraints, } from './parts/WebRtc/WebRtc.ts';
65
+ export { registerPortProvider } from './parts/PortProviderRegistry/PortProviderRegistry.ts';
66
+ export type { PortProvider } from './parts/PortProvider/PortProvider.ts';
67
+ export type { ForwardedPort } from './parts/ForwardedPort/ForwardedPort.ts';
package/dist/index.js CHANGED
@@ -33,3 +33,4 @@ export { getStatusBarItemProviderRegistrySnapshot, registerStatusBarItemProvider
33
33
  export { handleExtensionManagementMessagePort } from "./parts/HandleExtensionManagementMessagePort/HandleExtensionManagementMessagePort.js";
34
34
  export { createNodeRpc, createRpc } from "./parts/Rpc/Rpc.js";
35
35
  export { setRemoteDescription, startWebRtcAudioStream, stopWebRtcAudioStream, readMicLevels } from "./parts/WebRtc/WebRtc.js";
36
+ export { registerPortProvider } from "./parts/PortProviderRegistry/PortProviderRegistry.js";
@@ -0,0 +1,7 @@
1
+ export interface ForwardedPort {
2
+ readonly active?: boolean;
3
+ readonly forwardedAddress: string;
4
+ readonly origin?: string;
5
+ readonly port: number;
6
+ readonly runningProcess?: string;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { ForwardedPort } from '../ForwardedPort/ForwardedPort.ts';
2
+ export interface PortProvider {
3
+ readonly providePorts: (workspaceUri: string) => readonly ForwardedPort[] | Promise<readonly ForwardedPort[]>;
4
+ readonly scheme: string;
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { Disposable } from '../Disposable/Disposable.ts';
2
+ import type { ForwardedPort } from '../ForwardedPort/ForwardedPort.ts';
3
+ import type { PortProvider } from '../PortProvider/PortProvider.ts';
4
+ export declare const providePorts: (workspaceUri: string) => Promise<readonly ForwardedPort[]>;
5
+ export declare const registerPortProvider: (provider: PortProvider) => Disposable;
@@ -0,0 +1,37 @@
1
+ import * as ExtensionApiCommandRegistry from "../ExtensionApiCommandRegistry/ExtensionApiCommandRegistry.js";
2
+ import { ExtensionApiError } from "../ExtensionApiError/ExtensionApiError.js";
3
+ const providers = new Map();
4
+ export const providePorts = async (workspaceUri) => {
5
+ const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(workspaceUri)?.[1].toLowerCase();
6
+ const provider = scheme ? providers.get(scheme) : undefined;
7
+ if (!provider) {
8
+ return [];
9
+ }
10
+ const ports = await provider.providePorts(workspaceUri);
11
+ if (!Array.isArray(ports) ||
12
+ ports.some((port) => !port || !Number.isSafeInteger(port.port) || port.port < 1 || port.port > 65_535 || typeof port.forwardedAddress !== 'string')) {
13
+ throw new ExtensionApiError('port provider returned invalid ports');
14
+ }
15
+ return providers.get(scheme) === provider ? ports : [];
16
+ };
17
+ export const registerPortProvider = (provider) => {
18
+ if (!provider ||
19
+ typeof provider.scheme !== 'string' ||
20
+ !/^[a-z][a-z0-9+.-]*$/.test(provider.scheme) ||
21
+ typeof provider.providePorts !== 'function') {
22
+ throw new ExtensionApiError('port provider requires a URI scheme and providePorts function');
23
+ }
24
+ const { scheme } = provider;
25
+ if (providers.has(scheme)) {
26
+ throw new ExtensionApiError(`port provider for ${scheme} is already registered`);
27
+ }
28
+ providers.set(scheme, provider);
29
+ ExtensionApiCommandRegistry.registerCommandMap({ 'ExtensionApi.providePorts': providePorts });
30
+ return {
31
+ dispose() {
32
+ if (providers.get(scheme) === provider) {
33
+ providers.delete(scheme);
34
+ }
35
+ },
36
+ };
37
+ };
@@ -1,5 +1,6 @@
1
1
  import type { ShowQuickInputOptions } from '../ShowQuickInputOptions/ShowQuickInputOptions.ts';
2
2
  import type { ShowQuickPickOptions } from '../ShowQuickPickOptions/ShowQuickPickOptions.ts';
3
3
  export declare const showFileQuickPick: () => Promise<void>;
4
+ /** Shows a freeform text field without a results list. Returns undefined on cancellation. */
4
5
  export declare const showQuickInput: (options?: ShowQuickInputOptions) => Promise<string | undefined>;
5
6
  export declare const showQuickPick: (options: ShowQuickPickOptions) => Promise<unknown>;
@@ -3,6 +3,7 @@ import { executeCommand } from "../ExecuteCommand/ExecuteCommand.js";
3
3
  export const showFileQuickPick = async () => {
4
4
  await executeCommand('QuickPick.showFile');
5
5
  };
6
+ /** Shows a freeform text field without a results list. Returns undefined on cancellation. */
6
7
  export const showQuickInput = async (options = {}) => {
7
8
  return ExtensionManagementWorker.invoke('ExtensionHostQuickPick.showQuickInput', options);
8
9
  };
@@ -3,4 +3,6 @@ export interface ShowQuickPickOptions {
3
3
  readonly acceptInput?: boolean;
4
4
  readonly items: readonly QuickPickItem[];
5
5
  readonly placeholder?: string;
6
+ /** Text accepts freeform input without a results list; select filters items (the default). */
7
+ readonly type?: 'text' | 'select';
6
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/api",
3
- "version": "9.30.0",
3
+ "version": "9.32.0",
4
4
  "description": "Tree-shakeable extension API for Lvce Editor extensions.",
5
5
  "keywords": [
6
6
  "lvce-editor",