Skip to main content
NetScriptdocs Search docs ⌘K v0.0.9
Browse documentation
View as Markdown

Host workers and streams services

Use the singular @netscript/plugin-workers/service and @netscript/plugin-streams/service entrypoints when your host owns authentication, CORS or listener configuration. Imports are inert; calling a factory validates the required native ServiceAuthPolicy before runtime I/O and returns an ordinary RunningService. Keep the plural ./services entrypoints for the existing CLI flow.

Entrypoint Import and startup behavior
Workers ./service Inert import; startWorkersService(context, options) requires explicit auth.
Streams ./service Inert import; startStreamsService(options) requires explicit auth.
Workers ./services Existing default factory and direct CLI bootstrap; authored public policy.
Streams ./services Existing start-on-import CLI entrypoint; authored public and wildcard CORS policy.

Start workers with the host context

Your bootstrap supplies the existing plugin context and authenticator. Register the host's chosen KV adapter before calling the factory, just as for the legacy runtime. This entrypoint adds listener and policy options without creating another worker runtime or changing job registration.

TypeScript
import type { PluginServiceContext } from '@netscript/plugin/sdk';
import type { AuthenticatorPort } from '@netscript/service/auth';
import { startWorkersService } from '@netscript/plugin-workers/service';

declare const context: PluginServiceContext;
declare const authenticator: AuthenticatorPort;

if (import.meta.main) {
  const running = await startWorkersService(context, {
    auth: { authn: { authenticator } },
    cors: { origin: ['https://app.example'] },
    serve: { hostname: '127.0.0.1', port: 0 },
  });
  console.log(running.addr);
}

Workers keeps its plugin-owned request context and job/task registries. The legacy host context selects the fallback port through context.env.PORT; the runtime still uses the host-registered global KV adapter. It does not resolve the opaque host DB on startup or replace the native principal. Stopping a service drains its listener and leaves host-owned KV and stream producers available.

Guard the streams raw routes

Native auth defaults protect /api, while streams serves raw /v1/stream/... routes. Explicitly select protect: ['/'], or the intended stream prefix, when configuring a guarded streams host. The factory forwards your native policy unchanged. An authenticator alone keeps native /api scope.

Keep the health probes your launcher needs anonymous. These exact entries allow GET and HEAD on the three health paths; a custom nonempty list replaces the default /health prefix. Native immediate service-info remains public. CORS handles OPTIONS before authentication.

TypeScript
import type { AnonymousRequestMatch, AuthenticatorPort } from '@netscript/service/auth';
import { startStreamsService } from '@netscript/plugin-streams/service';

declare const authenticator: AuthenticatorPort;
const anonymousHealth = [
  { method: 'GET', path: '/health' },
  { method: 'HEAD', path: '/health' },
  { method: 'GET', path: '/health/live' },
  { method: 'HEAD', path: '/health/live' },
  { method: 'GET', path: '/health/ready' },
  { method: 'HEAD', path: '/health/ready' },
] satisfies readonly AnonymousRequestMatch[];

if (import.meta.main) {
  const running = await startStreamsService({
    auth: { authn: { authenticator, protect: ['/'], allowAnonymous: anonymousHealth } },
    cors: { origin: ['https://app.example'] },
    serve: { hostname: '127.0.0.1', port: 0 },
  });
  console.log(running.addr);
}

Missing, ambiguous and blank-reason policies fail before factory I/O. A deliberate public service uses auth: { public: true, reason: 'The existing ingress authenticates this service' }. A guarded service returns 401 for missing/wrong credentials and 503 when its verifier is unavailable. Keep operation authorization in the native authorizer or your existing application policy.

Origins, listener precedence and lifecycle

cors is the native CorsOptions. Omitted origins consume NETSCRIPT_CORS_ORIGINS; an explicit origin or origin array takes precedence, including an empty array. Exact allowed origins receive ACAO, while unrelated, lookalike, opaque null and malformed origins receive none. This controls browser response access; it does not prevent a request from executing or authenticate the caller.

Streams supplies its protocol methods and allowed/exposed headers when those arrays are omitted. An origin-only override keeps those defaults, including stream/producer sequence and retention headers. Explicit protocol arrays replace their respective defaults. The existing proxy still repairs response headers and missing-stream long polls; storage and upstream health are unchanged.

Option Source precedence
Workers port serve.port, including zero, then context.env.PORT, then process PORT.
Streams port serve.port, including zero, then PORT, then STREAMS_PORT.
Hostname Explicit serve.hostname; omission retains the native all-interface default.
TLS Native serve.tls, then the existing native certificate/key file environment pair.

The returned running.addr is the observed listener address. Pass native signal, drainTimeoutMs, handleSignals and TLS options through serve. running.stop() drains the listener; streams also stops its factory-owned upstream. Startup failure attempts upstream cleanup and preserves the primary error. Streams memory storage is ephemeral; the existing STREAMS_DATA_DIR contract remains an explicit, probed opt-in.

Add an internal caller explicitly

For an installation service identity, compose createInternalCredentialAuthenticator into the host policy with service: 'workers' and the provisioned installation-secret handle. Preserve an existing session/credential authenticator through createCompositeAuthenticator when needed. The host policy selects this adoption; the factory never installs an SDK credential contribution automatically.

Another backend uses the normal workers service reference and the existing SDK contribution:

TypeScript
import { workersContract } from '@netscript/plugin-workers/contracts';
import {
  createInternalCredentialSdkClientContribution,
  createServiceClient,
} from '@netscript/sdk/client';

const workers = createServiceClient({
  contract: workersContract,
  serviceName: 'workers',
  contributions: [createInternalCredentialSdkClientContribution({ service: 'workers' })] as const,
});
const description = await workers.describe({});
console.log(description.pluginName);

Match the service name on both sides and deliver discovery plus NETSCRIPT_INSTALLATION_SECRET_FILE through the existing backend configuration. Only the file reference belongs in generated topology; secret bytes and derived credentials stay out of browser configuration, logs and contract payloads. See Call internal procedures for provisioning and policy composition. If a client already owns authorization, retain that contribution and select its matching server policy; composing two owners is rejected rather than overwriting either.

Protected raw stream readers use their own explicit reader headers; the SDK procedure contribution does not configure their credentials or browser bootstrap.

Adoption boundary

The factories are additive. Existing plural entrypoints retain their authored public behavior, workers bootstrap and streams wildcard policy. For the deliberate health/CORS middleware migration, see native service ordering.

Sagas keeps its current context-taking entrypoint and KV/DB projection selection. Triggers keeps its current bootstrap and separate HMAC webhook ingress. These caller options currently apply to workers and streams; they do not migrate process supervision or introduce parameterized raw-route contract authorization. Continue to use the existing native ports and application authority for those tasks.

Search all documentation

Type a term to search the documentation.