@kmlckj/licos-platform-sdk
v0.10.0
Published
LICOS platform SDK package shell for browser and Node runtimes
Readme
@kmlckj/licos-platform-sdk
LICOS platform SDK for server-side project runtime code.
Runtime Configuration
Server-side helpers call platform Studio runtime APIs. Project code does not pass API base URLs, project IDs, tokens, or environment scopes. The SDK loads identity from runtime environment variables injected by LICOS. Authentication is resolved automatically by the runtime:
LICOS_PLATFORM_API_BASE_URLLICOS_PROJECT_IDorAGENT_PROJECT_IDLICOS_WORKSPACE_IDorAGENT_WORKSPACE_IDLICOS_USER_IDorAGENT_USER_IDLICOS_PROJECT_ENV, mapped internally todevorprod
Database
Database CRUD helpers call the runtime database data plane only. Tooling helpers can fetch platform schema metadata for ORM export. The SDK does not expose service deletion APIs.
database.table(name) is a query builder. Use it for select queries only.
import { database } from '@kmlckj/licos-platform-sdk';
const rows = await database
.table('todos')
.select('id', 'title')
.eq('done', false)
.order('created_at', { desc: true })
.limit(10)
.execute();Use top-level helpers for mutations:
import { database } from '@kmlckj/licos-platform-sdk';
const inserted = await database.insert('todos', {
row: { title: 'Call customer', done: false },
returning: true,
});
await database.updateRows('todos', {
filters: [{ field: 'id', op: 'eq', value: inserted.data?.[0]?.id }],
values: { done: true },
});
await database.deleteRows('todos', {
filters: [{ field: 'done', op: 'eq', value: true }],
});Do not call .table('todos').insert(...), .table('todos').updateRows(...),
or .table('todos').deleteRows(...); those methods do not exist on the query
builder.
ORM export is a tooling helper. It fetches platform schema metadata and returns source text; it does not use direct database credentials.
import { database } from '@kmlckj/licos-platform-sdk';
const source = await database.exportOrm({ language: 'typescript', orm: 'drizzle' });Studio project database management is exposed through studioDatabase for
server-side tooling flows. Use it for tables, rows, controlled SQL, migrations,
sync, and backup. Do not import it into browser/client bundles. Do not put
schema creation or migration logic in normal project runtime request handlers;
run those operations from LICOS agent/tooling flows before the app starts.
import { studioDatabase } from '@kmlckj/licos-platform-sdk';
await studioDatabase.createTable('users', {
columns: [{ name: 'email', type: 'text', nullable: false }],
});
const schema = await studioDatabase.getSchema({ environment: 'dev' });Object Storage
import { storage } from '@kmlckj/licos-platform-sdk';
await storage.createFolder('reports');
const file = await storage.uploadFile('/tmp/report.pdf');
const link = await storage.shareUrl(file.id);uploadFile limits each file to 100 MiB. Payloads larger than 8 MiB automatically use the platform chunk-upload protocol.
The browser entry does not export object storage helpers because runtime tokens must not be bundled into public frontend code.
Knowledge
Knowledge helpers import project documents and run semantic retrieval through the LICOS Knowledge API. Search without dataset filters retrieves from all accessible datasets. Use dataset IDs or names only when the user explicitly targets a specific knowledge base.
import { knowledge } from '@kmlckj/licos-platform-sdk';
await knowledge.addText('FAQ content', {
datasetName: 'project_docs',
name: 'faq.txt',
});
const results = await knowledge.search('How do I reset my password?', {
topK: 5,
});The browser entry does not export knowledge helpers because runtime tokens must not be bundled into public frontend code.
Unified Namespace (UNS)
UNS helpers expose the same Schema, resource discovery, validation, plan, apply, binding, data, point, video, and enterprise path APIs as the Python platform SDK. They are server-only and derive the trusted project scope from the injected runtime identity.
import { uns } from '@kmlckj/licos-platform-sdk';
const schema = await uns.schemaCurrent();
const checked = await uns.validate(document);
const reviewedPlan = await uns.plan(document);
await uns.apply(document, {
expectedDocumentHash: reviewedPlan.documentHash,
expectedPlanHash: reviewedPlan.planHash,
confirmed: true,
});Use a UNSChangeSet for an isolated structural change. Review the dedicated
plan and pass both hashes back unchanged. Destructive or replacement actions
also require impactConfirmed: true.
const changes = await uns.planChanges(changeSet);
await uns.applyChanges(changeSet, {
expectedDocumentHash: changes.documentHash,
expectedPlanHash: changes.planHash,
confirmed: true,
impactConfirmed: true,
});Use uns.openPath(path) when business code targets an existing enterprise UNS
path without creating or changing UNS.json:
const temperature = uns.openPath('project:/production-line/temperature');
const current = await temperature.pointCurrent();Realtime point consumers expose only an application-local WebSocket path. The SDK resolves the DataFactory endpoint, registers each UNS node, handles heartbeat/reconnect, and does not expose upstream addresses or runtime tokens to application code or browsers:
const detachRealtime = uns.attachPointRealtimeRelay({
server,
path: '/ws/uns/points',
codes: ['TEMP_01'],
});Resource apply, data writes, point writes, and video controls require explicit confirmation. Data deletion accepts the exact rows returned by a prior query and also requires explicit confirmation. Point writes require a reason and ticket. The browser entry does not export UNS helpers.
Direct Industrial Integration
The server-only industrial facade manages collection and video resources
without creating DataFactory UNS nodes. Use it only when the user explicitly
selects direct collector integration; UNS failures must not trigger this mode.
import { industrial } from '@kmlckj/licos-platform-sdk';
const points = await industrial.searchResources('collectionPoint', {
scope: 'project',
keyword: 'temperature',
});
const current = await industrial.pointCurrent(points.items[0].id);
const detachRealtime = industrial.attachRealtimeRelay({
server: httpServer,
path: '/ws/industrial/realtime',
pointIds: [points.items[0].id],
transport: 'websocket',
});Realtime subscription defaults to upstream WebSocket and supports explicitly
selected MQTT. Point control defaults to HTTP and supports explicitly selected
MQTT. Neither direction silently falls back. Resource writes use a reviewed
IndustrialChangeSet; point and video writes require independent confirmation.
attachRealtimeRelay exchanges and refreshes the platform user token inside the
SDK, authenticates the upstream WebSocket, sends the subscription, and relays
messages on the exact local path. Application code must not read runtime identity
variables or construct an Authorization header. The browser entry does not
export industrial helpers or external credentials.
OAuth2 Application Management
OAuth2 management is available only from trusted Node runtime code. It uses the current project owner's platform identity and is not exported by the browser entry.
import { oauth } from '@kmlckj/licos-platform-sdk';
const apps = await oauth.listApps();
const app = await oauth.ensureProjectApp({
appId: apps.list?.[0]?.id,
name: 'Project login',
loginAudience: 'ALL',
redirectUriConfigs: [
{ environment: 'prod', redirectUri: 'https://app.example/auth/callback' },
],
});ensureProjectApp requires an explicit login audience and at least one
callback. Store only public PKCE settings in project configuration; never put
the returned client secret or a platform user token in browser code.
OAuth2 Project Runtime
Project server routes use oauthRuntime for Authorization Code + PKCE. The
runtime module reads config/licos-oauth.json; it is intentionally absent from
the browser entry.
import { oauthRuntime } from '@kmlckj/licos-platform-sdk';
const config = await oauthRuntime.loadConfig();
const attempt = oauthRuntime.createAuthorizationRequest(config, {
redirectUri: 'https://app.example/api/auth/licos/callback',
});
// Persist a hash of attempt.state plus codeVerifier, redirectUri and expiresAt
// in a one-time server-side record before redirecting the browser.
const completed = await oauthRuntime.completeAuthorization(config, {
code,
redirectUri: stored.redirectUri,
codeVerifier: stored.codeVerifier,
});completeAuthorization returns platform tokens and userinfo to trusted server
code. Map completed.user.sub to the project's account, create the project's
own session, then revoke tokens unless the application explicitly needs
delegated platform API access. Never return these tokens to the browser.
