@cloudscaile-eng/platform-ext-utils
v0.1.0
Published
Utilities for CloudScaile extensions: env validation, logging, Kafka, and platform HTTP client
Maintainers
Keywords
Readme
@cloudscaile-eng/platform-ext-utils
Utilities for CloudScaile extensions: environment validation, structured logging, Kafka messaging, and platform HTTP client helpers.
Install
npm install @cloudscaile-eng/platform-ext-utilsQuick start
ESM
import { initExtUtils, logger } from "@cloudscaile-eng/platform-ext-utils";
const utils = await initExtUtils();
logger.info("Extension started");
await utils.produceMessage({ action: "sync" }, "topic");
process.on("SIGINT", async () => {
await utils.shutdown();
process.exit(0);
});CommonJS
const { initExtUtils } = require("@cloudscaile-eng/platform-ext-utils");
(async () => {
const utils = await initExtUtils();
await utils.produceMessage({ action: "sync" }, "topic");
})();API
| Export | Description |
|--------|-------------|
| initExtUtils(options?) | Validates env, optionally connects Kafka, returns a configured instance |
| validateEnv(overrides?) | Explicit environment validation without full init |
| logger | Standalone JSON console logger (error, warn, info) |
| KafkaService | Low-level Kafka wrapper for advanced use |
| platformAxiosInstance(req, platformUrl) | Creates an Axios client for the platform portal API (/v1/portal) |
| callExtensionAxiosInstance(req, platformUrl) | Creates an Axios client against /v1/extensions/access for calling another extension's module |
| recordAuditEvent(input, options?) | Thin client for POST /internal/v1/audit-events (best-effort) |
| shutdown(instance) | Disconnects Kafka on a given instance |
callExtension/restartExtension reuse PLATFORM_URL, TENANT_NAME, and EXTENSION_NAME, already required above. restartExtension additionally requires EXTENSION_RESTART_TOKEN — a Vault-issued secret minted automatically at extension-creation time, not something an extension author sets.
initExtUtils return value
{
env: ValidatedEnv;
kafka: KafkaService | null;
produceMessage(message, routingKey): Promise<void>;
consumeMessages(callback): Promise<void>;
platformAxiosInstance(req): AxiosInstance;
recordAuditEvent(input, options?): Promise<void>;
callExtension(req, { extensionName, module, path, method?, data? }): Promise<unknown>;
restartExtension(): Promise<{ dispatched: boolean; workflowRunId?: number }>;
shutdown(): Promise<void>;
}Breaking (0.1.0): instance.secrets / buildSecrets / Secrets / PgSecrets were removed. Replace instance.secrets.pgDB.* with utils.env.PG_*.
When PG_DB_REQUIRED=true, read Postgres settings from utils.env (PG_HOST, PG_PORT, PG_DB, PG_USERNAME, PG_PASSWORD).
callExtension proxies a call to another extension's module through the platform (/v1/extensions/access). It is request-scoped only — it requires a real inbound HTTP req carrying the caller's own Authorization header, so it cannot be used from a background job, Kafka consumer, or cron task with no end-user token to forward.
restartExtension dispatches a restart of this extension's own js module via the platform (/v1/extensions/restart). Resolving means the restart was dispatched, not that the pod(s) have actually restarted — there is no confirmation step.
recordAuditEvent
Writes an extension-runtime audit event to the platform internal API. Soft-fails (logs, does not throw). Platform forces module EXTENSION_RUNTIME; any non-empty action string is allowed.
import { recordAuditEvent } from "@cloudscaile-eng/platform-ext-utils";
await recordAuditEvent({
action: "TWILIO_EMAIL_SENT",
result: "SUCCESS", // SUCCESS | FAILURE | DENIED
tenantName: process.env.TENANT_NAME!,
metadata: { extensionName: process.env.EXTENSION_NAME },
});Requires PLATFORM_INTERNAL_URL (cluster/svc base URL, no path suffix), e.g. http://platform:3001. Auth is not sent in V1.
Environment variables
Required (always)
| Variable | Description |
|----------|-------------|
| TENANT_NAME | Tenant name for the application |
| EXTENSION_NAME | Name of the extension |
| MODULE_NAME | Name of the module |
| PLATFORM_URL | Base URL for the platform portal API |
Optional
| Variable | Default | Description |
|----------|---------|-------------|
| PORT | 8000 | Application port |
| PG_DB_REQUIRED | false | Enable PostgreSQL config validation |
| KAFKA_REQUIRED | false | Enable Kafka integration |
| PLATFORM_INTERNAL_URL | "" | Internal platform svc URL for /internal/v1 (required to use recordAuditEvent) |
| EXTENSION_RESTART_TOKEN | "" | Vault-issued secret for restartExtension() (minted at extension creation) |
When PG_DB_REQUIRED=true
| Variable | Description |
|----------|-------------|
| PG_HOST | PostgreSQL host |
| PG_PORT | PostgreSQL port |
| PG_DB | Database name |
| PG_USERNAME | Database username |
| PG_PASSWORD | Database password |
When KAFKA_REQUIRED=true
| Variable | Default | Description |
|----------|---------|-------------|
| KAFKA_BROKERS | — | Comma-separated broker list |
| KAFKA_CLIENT_ID | — | Kafka client ID |
| KAFKA_GROUP_ID | cs-platform-group-ext | Consumer group ID |
| KAFKA_PRODUCER_TOPIC | cs-platform-producer-topic | Physical Kafka topic for outbound messages |
| KAFKA_CONSUMER_TOPIC | cs-platform-consumer-topic | Topic to consume from |
| KAFKA_SASL | false | Enable SASL SCRAM-SHA-512 auth |
| KAFKA_SASL_USERNAME | — | SASL username (when KAFKA_SASL=true) |
| KAFKA_SASL_PASSWORD | — | SASL password (when KAFKA_SASL=true) |
Kafka message format
Messages are published to the fixed KAFKA_PRODUCER_TOPIC. The second argument to produceMessage is a routing key, not the Kafka topic:
{
"topic": "topic",
"message": { "action": "sync" }
}Consumers should parse the envelope and route on topic.
License
Copyright 2026 CloudScaile
Licensed under the Apache License, Version 2.0 — see LICENSE.
