Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"@objectstack/service-cache",
"@objectstack/service-cluster",
"@objectstack/service-cluster-redis",
"@objectstack/service-external-datasource",
"@objectstack/service-datasource",
"@objectstack/service-feed",
"@objectstack/service-i18n",
"@objectstack/service-job",
Expand Down
3 changes: 1 addition & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@
"@objectstack/service-analytics": "workspace:*",
"@objectstack/service-automation": "workspace:*",
"@objectstack/service-cache": "workspace:*",
"@objectstack/service-datasource-admin": "workspace:*",
"@objectstack/service-external-datasource": "workspace:*",
"@objectstack/service-datasource": "workspace:*",
"@objectstack/service-feed": "workspace:*",
"@objectstack/service-job": "workspace:*",
"@objectstack/service-messaging": "workspace:*",
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/commands/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1611,7 +1611,7 @@ export default class Serve extends Command {
// Federation (introspect / draft / import / validate of external
// tables) ships in the open framework.
try {
const dsMod: any = await import('@objectstack/service-external-datasource');
const dsMod: any = await import('@objectstack/service-datasource');
const { ExternalDatasourceServicePlugin } = dsMod;

if (
Expand Down Expand Up @@ -1644,7 +1644,7 @@ export default class Serve extends Command {
// ── Runtime Datasource Admin (ADR-0015 Addendum) ──────────────
// The "Add Datasource" wizard backend: list / test / create / update /
// remove datasources defined in the UI at runtime. This is open-source
// *mechanism* (`@objectstack/service-datasource-admin`); the tier line
// *mechanism* (`@objectstack/service-datasource`); the tier line
// falls on which ICryptoProvider / driver factory a host injects, not on
// whether the UI can manage datasources. Mounted by default so a
// self-host runtime is a complete low-code platform out of the box.
Expand All @@ -1655,7 +1655,7 @@ export default class Serve extends Command {
// key. Wired BEFORE runtime.start() so the plugin's kernel:ready boot
// rehydration (which decrypts persisted creds) has its binder ready.
try {
const adminMod: any = await import('@objectstack/service-datasource-admin');
const adminMod: any = await import('@objectstack/service-datasource');
const {
DatasourceAdminServicePlugin,
createDefaultDatasourceDriverFactory,
Expand Down
85 changes: 0 additions & 85 deletions packages/services/service-datasource-admin/README.md

This file was deleted.

58 changes: 0 additions & 58 deletions packages/services/service-datasource-admin/src/index.ts

This file was deleted.

11 changes: 0 additions & 11 deletions packages/services/service-datasource-admin/src/logger.ts

This file was deleted.

10 changes: 0 additions & 10 deletions packages/services/service-datasource-admin/tsconfig.json

This file was deleted.

50 changes: 50 additions & 0 deletions packages/services/service-datasource/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# @objectstack/service-datasource

The datasource service (ADR-0015). One package, two cohesive halves of the same
capability:

| Half | ADR-0015 | What it does | Plugin |
|------|----------|--------------|--------|
| **Federation** | main body | introspect / draft / import / validate external tables | `ExternalDatasourceServicePlugin` |
| **Runtime admin** | Addendum | the "Add Datasource" wizard backend — list / test / create / update / remove datasources defined in the UI at runtime, + REST routes under `/api/v1/datasources` | `DatasourceAdminServicePlugin` |

(Previously shipped as the separate `@objectstack/service-external-datasource`
and `@objectstack/service-datasource-admin` packages. The split existed only
because the runtime admin was once private; now that both are open-source, they
are one package. The two plugins still mount independently — merging the package
did not couple them.)

## Open-source mechanism, injectable tier line

This package is mechanism only. Credential storage is delegated to a
host-provided `SecretBinder` over any `ICryptoProvider` (framework default:
`InMemoryCryptoProvider`), and drivers to a swappable factory. The tier line
falls on *which crypto provider / driver factory a host injects* — a neutral,
technical seam — so a managed credential vault + multi-tenant overlay can be
layered on by a private host **without forking**.

## Two axes of "datasource"

| Axis | `origin: 'code'` | `origin: 'runtime'` |
|------|------------------|---------------------|
| Defined by | `*.datasource.ts` (GitOps) | the UI wizard, at runtime |
| Mutable at runtime | no (read-only) | yes |
| Stored in | code / artefacts | `sys_metadata` + secret in `sys_secret` |

The runtime admin owns only the `origin: 'runtime'` lifecycle.

## Exports

- Federation: `ExternalDatasourceService`, `ExternalDatasourceServicePlugin`.
- Runtime admin: `DatasourceAdminService`, `DatasourceAdminServicePlugin`,
`createDefaultDatasourceDriverFactory`, `createDatasourceSecretBinder`,
`registerDatasourceAdminRoutes`.
- `@objectstack/service-datasource/contracts` — `IDatasourceAdminService`,
`IDatasourceDriverFactory` + DTOs.

`os serve` wires both by default. For manual host wiring of the admin half
(secret binder over a crypto provider, driver factory, REST routes), see the
serve composition root in `@objectstack/cli`.

`@objectstack/core` and `@objectstack/spec` are required deps; the driver
packages are optional peers (imported lazily only for the drivers you use).
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "@objectstack/service-datasource-admin",
"name": "@objectstack/service-datasource",
"version": "7.5.0",
"license": "Apache-2.0",
"description": "Runtime UI-created datasource lifecycle (ADR-0015 Addendum) — list/test/create/update/remove datasources defined in the UI. Mechanism only: credential storage is delegated to a host-provided SecretBinder (CryptoProvider) and drivers to a swappable factory, so a managed credential vault / multi-tenant overlay can be layered on without forking.",
"description": "The datasource service (ADR-0015): external-table federation (introspect/draft/import/validate) + runtime UI datasource lifecycle (list/test/create/update/remove + REST routes). Open-source mechanism; the tier line falls on which ICryptoProvider / driver factory a host injects.",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -51,13 +51,20 @@
"keywords": [
"objectstack",
"datasource",
"federation",
"introspection",
"datasource-admin",
"runtime-datasource"
],
"author": "ObjectStack",
"repository": {
"type": "git",
"url": "https://github.com/objectstack-ai/framework.git",
"directory": "packages/services/service-datasource-admin"
"directory": "packages/services/service-datasource"
},
"homepage": "https://objectstack.ai/docs",
"bugs": "https://github.com/objectstack-ai/framework/issues",
"publishConfig": {
"access": "public"
}
}
73 changes: 73 additions & 0 deletions packages/services/service-datasource/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

/**
* @objectstack/service-datasource — the datasource service (ADR-0015).
*
* Two cohesive halves of one capability:
* - **Federation** (ADR-0015 main body): introspect / draft / import /
* validate external tables — {@link ExternalDatasourceServicePlugin}.
* - **Runtime admin** (ADR-0015 Addendum): the "Add Datasource" wizard
* backend — list / test / create / update / remove datasources defined in
* the UI at runtime, plus its REST routes — {@link DatasourceAdminServicePlugin}.
*
* Open-source mechanism throughout. The tier line falls on which
* `ICryptoProvider` / driver factory a host injects into the admin plugin, not
* on whether the UI can manage datasources.
*/

// ── Federation (ADR-0015 main body) ───────────────────────────────────
export { ExternalDatasourceService } from './external-datasource-service.js';
export type {
ExternalDatasourceServiceConfig,
DatasourceLike,
ObjectLike,
// Canonical minimal logger surface for the whole package.
Logger,
} from './external-datasource-service.js';
export { ExternalDatasourceServicePlugin } from './plugin.js';
export type { ExternalDatasourceServicePluginOptions } from './plugin.js';

// ── Runtime admin (ADR-0015 Addendum) ─────────────────────────────────
// Contracts (the canonical datasource-admin DTOs).
export type {
DatasourceOrigin,
SecretInput,
DatasourceDraft,
TestConnectionResult,
DatasourceSummary,
IDatasourceAdminService,
DatasourceConnectionSpec,
DatasourceDriverHandle,
IDatasourceDriverFactory,
} from './contracts/index.js';

// Decoupled lifecycle service + injected-config shape.
export { DatasourceAdminService } from './datasource-admin-service.js';
export type {
DatasourceAdminServiceConfig,
StoredDatasource,
ProbeInput,
} from './datasource-admin-service.js';

// Kernel plugin (registers the `'datasource-admin'` service).
export { DatasourceAdminServicePlugin } from './datasource-admin-plugin.js';
export type {
DatasourceAdminServicePluginOptions,
SecretBinder,
} from './datasource-admin-plugin.js';

// Host glue: dev driver factory + fail-closed secret binder.
export { createDefaultDatasourceDriverFactory } from './default-datasource-driver-factory.js';
export {
createDatasourceSecretBinder,
toCredentialsRef,
parseCredentialsRef,
} from './datasource-secret-binder.js';
export type {
DatasourceSecretBinder,
DatasourceSecretBinderDeps,
SecretStoreEngineLike,
} from './datasource-secret-binder.js';

// REST routes.
export { registerDatasourceAdminRoutes } from './admin-routes.js';
11 changes: 11 additions & 0 deletions packages/services/service-datasource/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

/**
* Minimal logger surface used by the runtime-admin half of this package.
* (Structurally identical to the federation service's own `Logger`; kept
* separate so the admin modules carry no internal import coupling.)
*/
export interface Logger {
warn: (message: string, meta?: unknown) => void;
info?: (message: string, meta?: unknown) => void;
}
Loading