Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
173fd3e
Update Node.js version in publish workflow
alexcos20 Jul 6, 2026
268f373
Merge branch 'main' into next-release-v9
alexcos20 Jul 9, 2026
7aa1aae
Feature/services (#2101)
alexcos20 Jul 9, 2026
3009f70
Feature/new bundle for escrow (#2109)
alexcos20 Jul 9, 2026
54afe0d
Update ci.yml
alexcos20 Jul 9, 2026
181beff
sign issuer peer id (#2111)
giurgiur99 Jul 9, 2026
7ff612b
Update NODE_VERSION from pr-1404 to pr-1408
alexcos20 Jul 9, 2026
687ec49
Release 9.0.0-next.1
alexcos20 Jul 9, 2026
8a9cf6f
add service streamable logs (#2113)
andreip136 Jul 9, 2026
a64f21d
Release 9.0.0-next.2
alexcos20 Jul 9, 2026
de8dcba
add dockerCmd/dockerEntrypoint params on service restart (#2114)
andreip136 Jul 10, 2026
e14d380
Release 9.0.0-next.3
alexcos20 Jul 10, 2026
188ac1f
add service list (#2115)
alexcos20 Jul 17, 2026
90ff9e7
Release 9.0.0-next.4
alexcos20 Jul 17, 2026
972ae4f
Feature/162 inference services es (#2118)
giurgiur99 Jul 23, 2026
d229d54
Release 9.0.0-next.5
giurgiur99 Jul 23, 2026
306583e
allow dockerspecs on service restart (#2119)
alexcos20 Jul 24, 2026
cedce7b
Release 9.0.0-next.6
alexcos20 Jul 24, 2026
ea4c3f7
Feat/162 service restart notify (#2125)
giurgiur99 Jul 29, 2026
bc87e0e
Release 9.0.0-next.7
giurgiur99 Jul 29, 2026
c3529b9
add missing enum (restarting) (#2126)
alexcos20 Jul 29, 2026
101351b
Release 9.0.0-next.8
alexcos20 Jul 29, 2026
a148671
output bucke & workflows (#2129)
giurgiur99 Aug 5, 2026
ad36739
Release 9.0.0-next.9
giurgiur99 Aug 5, 2026
209c986
Merge branch 'main' into next-release-v9
alexcos20 Aug 14, 2026
144b82c
Merge branch 'main' into next-release-v9
alexcos20 Aug 17, 2026
de8c9b0
add node compute job/service runTimeMetrics (#2132)
alexcos20 Aug 20, 2026
97aebf0
hardcode http paths (#2133)
alexcos20 Aug 20, 2026
14fa5b0
test node 24 (#2135)
alexcos20 Aug 20, 2026
c8684b7
Feature/auth for policy server (#2134)
alexcos20 Aug 20, 2026
7fed9c7
Release 9.0.0-next.10
alexcos20 Aug 20, 2026
5f68414
Update NODE_VERSION in CI workflow to pr-1408
alexcos20 Aug 20, 2026
2dd0ee1
update deps (#2137)
alexcos20 Aug 28, 2026
1b76abe
Update NODE_VERSION in CI workflow to pr-1408
alexcos20 Aug 28, 2026
c0cf526
use proper ci values
alexcos20 Aug 28, 2026
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
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ jobs:
with:
repository: "oceanprotocol/barge"
path: "barge"
ref: "feature/node-v4"

- name: Set Database Environment Variables
run: |
Expand All @@ -61,7 +62,9 @@ jobs:
working-directory: ${{ github.workspace }}/barge
run: |
bash -x start_ocean.sh 2>&1 > start_ocean.log &

env:
NODE_VERSION: "pr-1402"

- name: Install deps & build
run: npm ci && npm run build:metadata
- name: Wait for node to be ready
Expand Down Expand Up @@ -131,6 +134,7 @@ jobs:
with:
repository: "oceanprotocol/barge"
path: "barge"
ref: "feature/node-v4"

- name: Login to Docker Hub
if: ${{ env.DOCKERHUB_PASSWORD && env.DOCKERHUB_USERNAME }}
Expand All @@ -151,6 +155,8 @@ jobs:
working-directory: ${{ github.workspace }}/barge
run: |
bash -x start_ocean.sh 2>&1 > start-node.log &
env:
NODE_VERSION: "pr-1402"

- name: Install deps & build
run: npm ci && npm run build:metadata
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v4
with:
node-version: '20'
node-version: '22'
registry-url: https://registry.npmjs.org/
- run: npm ci

Expand Down
8 changes: 8 additions & 0 deletions src/@types/Compute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,19 @@ export interface ComputeEnvironmentFreeOptions {
maxJobs?: number // maximum number of simultaneous free jobs
resources?: ComputeResource[]
}
// Per-environment capability flags. Both default to true node-side; only an
// explicit false disables a capability. `services` gates Service-on-Demand.
export interface ComputeEnvFeatures {
computeJobs?: boolean // false → COMPUTE_START + FREE_COMPUTE_START rejected
services?: boolean // false → SERVICE_START rejected; env not service-eligible
}

export interface ComputeEnvironment {
id: string
description?: string
consumerAddress: string
access?: ComputeEnvironmentAccessOptions
features?: ComputeEnvFeatures
storageExpiry?: number // amount of seconds for storage
minJobDuration?: number // min billable seconds for a paid job
maxJobDuration?: number // max duration in seconds for a paid job
Expand Down
8 changes: 7 additions & 1 deletion src/@types/Provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,13 @@ export const PROTOCOL_COMMANDS = {
PERSISTENT_STORAGE_LIST_FILES: 'persistentStorageListFiles',
PERSISTENT_STORAGE_UPLOAD_FILE: 'persistentStorageUploadFile',
PERSISTENT_STORAGE_GET_FILE_OBJECT: 'persistentStorageGetFileObject',
PERSISTENT_STORAGE_DELETE_FILE: 'persistentStorageDeleteFile'
PERSISTENT_STORAGE_DELETE_FILE: 'persistentStorageDeleteFile',
SERVICE_GET_TEMPLATES: 'serviceGetTemplates',
SERVICE_START: 'serviceStart',
SERVICE_STOP: 'serviceStop',
SERVICE_RESTART: 'serviceRestart',
SERVICE_GET_STATUS: 'serviceGetStatus',
SERVICE_EXTEND: 'serviceExtend'
}

export interface NodeLogsParams {
Expand Down
139 changes: 139 additions & 0 deletions src/@types/Services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { ComputeResourceRequest } from './Compute.js'

// Service-on-Demand client types. Mirror of ocean-node
// `src/@types/C2D/ServiceOnDemand.ts` (the API surface a client interacts with).

// ── Resource requirements (templates) ─────────────────────────────────

export interface TemplateResourceRequirement {
// Exactly one of `id` or `kind` is set.
id?: string // exact resource id: 'cpu' | 'ram' | 'disk' | named GPU ('gpu-0')
kind?: 'discrete' | 'fungible' // match ANY resource of this kind across the env pool
type?: string // optional: further filter within kind ('gpu', 'fpga', 'tpu')
min: number // MUST have at least this much
recommended?: number // ideal amount; below this the env is a poorer fit
unit?: string // display hint: 'cores' | 'GB' | 'count'
description?: string
}

export interface UserConfigurableEnvVar {
key: string // env var name, supplied via userData
validation?: string // optional regex; validated by the node at SERVICE_START time
sensitive?: boolean // advisory hint for clients/UI (e.g. mask on input)
}

// ── Public / sanitized template ───────────────────────────────────────
// Returned by SERVICE_GET_TEMPLATES. `envVars` values are stripped (keys only).
// Choosing a matching compute environment is the client's responsibility — see
// getComputeEnvironments() and the per-env `features.services` flag.
export interface ServiceTemplatePublic {
id: string // [a-z0-9][a-z0-9_-]{0,63}
name?: string
description?: string
image: string // base image name
tag?: string // mutually exclusive with checksum/dockerfile
checksum?: string // digest: "sha256:<64 hex>"
dockerfile?: string // inline Dockerfile content
additionalDockerFiles?: Record<string, string> // filename → content; only with dockerfile
exposedPorts: number[]
envVarKeys?: string[] // keys of the operator-set env vars only, never values
userConfigurableEnvVars?: UserConfigurableEnvVar[]
command?: string[] // Docker CMD override; ${KEY} expanded from userData
entrypoint?: string[] // Docker ENTRYPOINT override
requiredResources?: TemplateResourceRequirement[]
recommendedResources?: TemplateResourceRequirement[]
}

// ── Runtime service job ────────────────────────────────────────────────

// Port mapping for a running service (named ServiceJobEndpoint to avoid colliding
// with the provider-route `ServiceEndpoint` type used for node endpoint discovery).
export interface ServiceJobEndpoint {
containerPort: number
hostPort: number
url: string // e.g. "http://<nodeHost>:31042"
}

/* eslint-disable no-unused-vars */
export enum ServiceStatusNumber {
Starting = 10, // DB record created by the start handler; awaits background processing
PullImage = 11, // pulling pre-built image from registry
PullImageFailed = 12,
BuildImage = 13, // building from Dockerfile
BuildImageFailed = 14,
VulnerableImage = 15, // image scan found critical vulnerabilities
Locking = 20, // escrow createLock in progress (funds locked, not yet claimed)
Claiming = 30, // payment phase: claimLock on success, or cancelLock if the image step failed
Running = 40,
Stopping = 50,
Stopped = 70,
Expired = 75,
Error = 99
}
/* eslint-enable no-unused-vars */

// Payment record attached to a service job (start payment + each extend).
export interface ServiceJobPayment {
chainId?: number
token?: string
lockTx?: string
claimTx?: string
cost?: string | number
[key: string]: any
}

// As returned by the node (userData is always stripped from responses).
export interface ServiceJob {
serviceId: string // unique id for a running service — distinct from a compute jobId
clusterHash: string
environment: string // envId the service runs on
owner: string // consumerAddress
image: string
tag?: string
checksum?: string
dockerfile?: string
additionalDockerFiles?: Record<string, string>
dockerCmd?: string[]
dockerEntrypoint?: string[]
containerImage: string // resolved final reference used by Docker
containerId: string
networkId: string // per-service Docker network id
status: ServiceStatusNumber
statusText: string
dateCreated: string // ISO timestamp
expiresAt: number // Unix ms timestamp
duration: number // requested seconds
exposedPorts: number[]
endpoints: ServiceJobEndpoint[]
resources: any[] // ComputeResourceRequestWithPrice[] on the node
payment: ServiceJobPayment // initial start payment
extendPayments?: ServiceJobPayment[] // one entry per successful SERVICE_EXTEND
}

// ── Request shapes ─────────────────────────────────────────────────────

export interface ServicePayment {
chainId: number
token: string
}

// A plain key→value map of container env vars. The client always ECIES-encrypts it
// to the node's public key before sending — callers never pass pre-encrypted data,
// so a plaintext secret can never be forwarded unencrypted.
export type ServiceUserData = Record<string, unknown>

export interface ServiceStartParams {
environment: string // required: the envId to run the service on
image: string // base image name (or build label when dockerfile is set)
tag?: string // pull by name:tag
checksum?: string // pull by digest: "sha256:<64 hex>"
dockerfile?: string // build from inline Dockerfile; requires allowImageBuild on the env
additionalDockerFiles?: Record<string, string>
dockerCmd?: string[] // exec-form CMD override (no shell)
dockerEntrypoint?: string[]
exposedPorts?: number[]
resources?: ComputeResourceRequest[]
duration: number // seconds; capped by serviceOnDemand.maxDurationSeconds
userData?: ServiceUserData
payment: ServicePayment
}
1 change: 1 addition & 0 deletions src/@types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './Contracts.js'
export * from './File.js'
export * from './FileInfo.js'
export * from './Compute.js'
export * from './Services.js'
export * from './Datatoken.js'
export * from './Dispenser.js'
export * from './DownloadResponse.js'
Expand Down
86 changes: 86 additions & 0 deletions src/services/providers/BaseProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ import {
PersistentStorageFileEntry,
PersistentStorageObject,
PersistentStorageUpdateBucketResponse,
ServiceJob,
ServiceTemplatePublic,
ServiceStartParams,
ServiceUserData,
ServicePayment,
OceanNode,
NodeP2P,
CompleteSignature,
Expand Down Expand Up @@ -739,6 +744,87 @@ export class BaseProvider {
)
}

// ── Service on Demand ────────────────────────────────────────────────

public async getServiceTemplates(
nodeUri: OceanNode,
chainId?: number,
signal?: AbortSignal
): Promise<ServiceTemplatePublic[]> {
return this.getImpl(nodeUri).getServiceTemplates(nodeUri, chainId, signal)
}

public async serviceStart(
nodeUri: OceanNode,
signerOrAuthToken: SignerOrAuthTokenOrSignature,
params: ServiceStartParams,
signal?: AbortSignal
): Promise<ServiceJob[]> {
return this.getImpl(nodeUri).serviceStart(nodeUri, signerOrAuthToken, params, signal)
}

public async serviceStop(
nodeUri: OceanNode,
signerOrAuthToken: SignerOrAuthTokenOrSignature,
serviceId: string,
signal?: AbortSignal
): Promise<ServiceJob[]> {
return this.getImpl(nodeUri).serviceStop(
nodeUri,
signerOrAuthToken,
serviceId,
signal
)
}

public async serviceExtend(
nodeUri: OceanNode,
signerOrAuthToken: SignerOrAuthTokenOrSignature,
serviceId: string,
additionalDuration: number,
payment: ServicePayment,
signal?: AbortSignal
): Promise<ServiceJob[]> {
return this.getImpl(nodeUri).serviceExtend(
nodeUri,
signerOrAuthToken,
serviceId,
additionalDuration,
payment,
signal
)
}

public async serviceRestart(
nodeUri: OceanNode,
signerOrAuthToken: SignerOrAuthTokenOrSignature,
serviceId: string,
userData?: ServiceUserData,
signal?: AbortSignal
): Promise<ServiceJob[]> {
return this.getImpl(nodeUri).serviceRestart(
nodeUri,
signerOrAuthToken,
serviceId,
userData,
signal
)
}

public async getServiceStatus(
nodeUri: OceanNode,
signerOrAuthToken: SignerOrAuthTokenOrSignature,
serviceId?: string,
signal?: AbortSignal
): Promise<ServiceJob[]> {
return this.getImpl(nodeUri).getServiceStatus(
nodeUri,
signerOrAuthToken,
serviceId,
signal
)
}

public async fetchConfig(
nodeUri: OceanNode,
payload: Record<string, any>
Expand Down
Loading
Loading