@synapseone/sdk 0.7.1-dev.57 → 0.7.1-dev.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@ import { InferenceService } from './inference';
10
10
  import { AiService } from './ai';
11
11
  import { HealthService } from './health';
12
12
  import { StorageService } from './storage';
13
+ import { OcsService } from './ocs';
13
14
  import { NotificationsService } from './notifications';
14
15
  export * from './_http';
15
16
  export * from './iam';
@@ -23,6 +24,7 @@ export * from './stream';
23
24
  export * from './inference';
24
25
  export * from './health';
25
26
  export * from './storage';
27
+ export * from './ocs';
26
28
  export * from './notifications';
27
29
  /** Legacy flat LDS signatures (the namespaced service drops the `lds` prefix). */
28
30
  export interface LdsLegacyMethods {
@@ -56,6 +58,8 @@ export declare class SynapseOneClient {
56
58
  readonly stream: StreamService;
57
59
  readonly inference: InferenceService;
58
60
  readonly storage: StorageService;
61
+ /** SynapseOCS bucket/object API; `storage` remains the default-bucket alias. */
62
+ readonly ocs: OcsService;
59
63
  readonly notifications: NotificationsService;
60
64
  readonly health: HealthService;
61
65
  readonly readiness: HealthService;
package/dist/index.js CHANGED
@@ -50,6 +50,7 @@ const inference_1 = require("./inference");
50
50
  const ai_1 = require("./ai");
51
51
  const health_1 = require("./health");
52
52
  const storage_1 = require("./storage");
53
+ const ocs_1 = require("./ocs");
53
54
  const notifications_1 = require("./notifications");
54
55
  __exportStar(require("./_http"), exports);
55
56
  __exportStar(require("./iam"), exports);
@@ -63,6 +64,7 @@ __exportStar(require("./stream"), exports);
63
64
  __exportStar(require("./inference"), exports);
64
65
  __exportStar(require("./health"), exports);
65
66
  __exportStar(require("./storage"), exports);
67
+ __exportStar(require("./ocs"), exports);
66
68
  __exportStar(require("./notifications"), exports);
67
69
  class SynapseOneClient {
68
70
  http;
@@ -76,6 +78,8 @@ class SynapseOneClient {
76
78
  stream;
77
79
  inference;
78
80
  storage;
81
+ /** SynapseOCS bucket/object API; `storage` remains the default-bucket alias. */
82
+ ocs;
79
83
  notifications;
80
84
  health;
81
85
  readiness;
@@ -91,6 +95,7 @@ class SynapseOneClient {
91
95
  this.stream = new stream_1.StreamService(this.http);
92
96
  this.inference = new inference_1.InferenceService(this.http);
93
97
  this.storage = new storage_1.StorageService(this.http);
98
+ this.ocs = new ocs_1.OcsService(this.http);
94
99
  this.notifications = new notifications_1.NotificationsService(this.http);
95
100
  this.health = new health_1.HealthService(this.http);
96
101
  // Alias: `client.readiness.ready()` reads naturally; same instance.
package/dist/ocs.d.ts ADDED
@@ -0,0 +1,119 @@
1
+ import { HttpClient, RequestOptions } from './_http';
2
+ export interface OcsBucket {
3
+ name: string;
4
+ createdAt: string;
5
+ updatedAt?: string;
6
+ owner?: string;
7
+ quotaBytes?: number;
8
+ objects?: number;
9
+ bytes?: number;
10
+ }
11
+ export interface OcsObject {
12
+ key: string;
13
+ bucket: string;
14
+ size: number;
15
+ contentType: string;
16
+ etag: string;
17
+ checksumSha256?: string;
18
+ createdAt: string;
19
+ updatedAt: string;
20
+ }
21
+ export interface OcsList {
22
+ bucket: string;
23
+ prefix: string;
24
+ delimiter?: string;
25
+ objects: OcsObject[];
26
+ commonPrefixes: string[];
27
+ nextCursor: string | null;
28
+ }
29
+ export interface PutOcsOptions extends RequestOptions {
30
+ contentType?: string;
31
+ checksumSha256?: string;
32
+ }
33
+ export interface GetOcsOptions extends RequestOptions {
34
+ range?: string;
35
+ ifNoneMatch?: string;
36
+ ifMatch?: string;
37
+ }
38
+ export declare class OcsService {
39
+ private readonly http;
40
+ constructor(http: HttpClient);
41
+ createBucket(name: string, opts?: {
42
+ quotaBytes?: number;
43
+ }): Promise<{
44
+ bucket: OcsBucket;
45
+ }>;
46
+ listBuckets(opts?: {
47
+ withStats?: boolean;
48
+ }): Promise<{
49
+ buckets: OcsBucket[];
50
+ total: number;
51
+ }>;
52
+ getBucket(name: string): Promise<{
53
+ bucket: OcsBucket;
54
+ }>;
55
+ headBucket(name: string, opts?: RequestOptions): Promise<Record<string, string> | null>;
56
+ bucketStats(name: string): Promise<{
57
+ bucket: string;
58
+ objects: number;
59
+ bytes: number;
60
+ quotaBytes: number;
61
+ }>;
62
+ deleteBucket(name: string, opts?: {
63
+ force?: boolean;
64
+ }): Promise<{
65
+ ok: boolean;
66
+ bucket: string;
67
+ deletedObjects: number;
68
+ }>;
69
+ putObject(bucket: string, key: string, body: Uint8Array | ArrayBuffer | string, opts?: PutOcsOptions): Promise<OcsObject>;
70
+ getObject(bucket: string, key: string, opts?: GetOcsOptions): Promise<Uint8Array>;
71
+ headObject(bucket: string, key: string, opts?: RequestOptions): Promise<OcsObject | null>;
72
+ deleteObject(bucket: string, key: string): Promise<{
73
+ ok: boolean;
74
+ bucket: string;
75
+ key: string;
76
+ }>;
77
+ listObjects(bucket: string, opts?: {
78
+ prefix?: string;
79
+ delimiter?: string;
80
+ limit?: number;
81
+ cursor?: string;
82
+ }): Promise<OcsList>;
83
+ copyObject(bucket: string, input: {
84
+ sourceKey: string;
85
+ destinationKey: string;
86
+ sourceBucket?: string;
87
+ contentType?: string;
88
+ }): Promise<{
89
+ object: OcsObject;
90
+ }>;
91
+ presign(bucket: string, key: string, opts?: {
92
+ method?: 'GET' | 'PUT' | 'DELETE' | 'HEAD';
93
+ expiresIn?: number;
94
+ }): Promise<{
95
+ url: string;
96
+ bucket: string;
97
+ key: string;
98
+ method: string;
99
+ expiresIn: number;
100
+ }>;
101
+ createMultipart(bucket: string, key: string, contentType?: string): Promise<{
102
+ uploadId: string;
103
+ bucket: string;
104
+ key: string;
105
+ contentType: string;
106
+ }>;
107
+ uploadPart(bucket: string, uploadId: string, key: string, partNumber: number, body: Uint8Array | string): Promise<{
108
+ partNumber: number;
109
+ etag: string;
110
+ size: number;
111
+ }>;
112
+ completeMultipart(bucket: string, uploadId: string, key: string, parts: Array<{
113
+ partNumber: number;
114
+ etag: string;
115
+ }>): Promise<{
116
+ object: OcsObject;
117
+ }>;
118
+ abortMultipart(bucket: string, uploadId: string, key: string): Promise<unknown>;
119
+ }
package/dist/ocs.js ADDED
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2026 VKU.VIC
4
+ /*
5
+ * Copyright 2026 SynapseOne Contributors
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * SynapseOCS client: buckets, objects, copy, range/conditional reads,
8
+ * delimited listing, presigned URLs and multipart uploads.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.OcsService = void 0;
12
+ const P = '/v1/ocs';
13
+ class OcsService {
14
+ http;
15
+ constructor(http) {
16
+ this.http = http;
17
+ }
18
+ createBucket(name, opts = {}) {
19
+ return this.http.req(`${P}/buckets`, {
20
+ method: 'POST',
21
+ body: JSON.stringify({ name, ...(opts.quotaBytes ? { quotaBytes: opts.quotaBytes } : {}) }),
22
+ });
23
+ }
24
+ listBuckets(opts = {}) {
25
+ return this.http.req(`${P}/buckets${opts.withStats ? '?withStats=1' : ''}`);
26
+ }
27
+ getBucket(name) {
28
+ return this.http.req(`${P}/buckets/${encodeURIComponent(name)}`);
29
+ }
30
+ async headBucket(name, opts = {}) {
31
+ try {
32
+ return await this.http.head(`${P}/buckets/${encodeURIComponent(name)}`, opts);
33
+ }
34
+ catch (error) {
35
+ if (error?.status === 404)
36
+ return null;
37
+ throw error;
38
+ }
39
+ }
40
+ bucketStats(name) {
41
+ return this.http.req(`${P}/buckets/${encodeURIComponent(name)}/stats`);
42
+ }
43
+ deleteBucket(name, opts = {}) {
44
+ return this.http.req(`${P}/buckets/${encodeURIComponent(name)}${opts.force ? '?force=true' : ''}`, { method: 'DELETE' });
45
+ }
46
+ async putObject(bucket, key, body, opts = {}) {
47
+ const bytes = typeof body === 'string' ? new TextEncoder().encode(body) : body instanceof Uint8Array ? body : new Uint8Array(body);
48
+ const result = await this.http.upload(`${P}/buckets/${encodeURIComponent(bucket)}/objects/${encodeKey(key)}`, bytes, {
49
+ ...opts,
50
+ contentType: opts.contentType || 'application/octet-stream',
51
+ headers: { ...(opts.checksumSha256 ? { 'x-object-checksum-sha256': opts.checksumSha256 } : {}), ...(opts.headers || {}) },
52
+ });
53
+ return result.object;
54
+ }
55
+ getObject(bucket, key, opts = {}) {
56
+ const headers = { ...(opts.headers || {}) };
57
+ if (opts.range)
58
+ headers.Range = opts.range;
59
+ if (opts.ifNoneMatch)
60
+ headers['If-None-Match'] = opts.ifNoneMatch;
61
+ if (opts.ifMatch)
62
+ headers['If-Match'] = opts.ifMatch;
63
+ return this.http.reqBinary(`${P}/buckets/${encodeURIComponent(bucket)}/objects/${encodeKey(key)}`, undefined, { ...opts, headers });
64
+ }
65
+ async headObject(bucket, key, opts = {}) {
66
+ try {
67
+ const headers = await this.http.head(`${P}/buckets/${encodeURIComponent(bucket)}/objects/${encodeKey(key)}`, opts);
68
+ return {
69
+ key: headers['x-object-key'] || key,
70
+ bucket: headers['x-ocs-bucket'] || bucket,
71
+ size: Number(headers['content-length'] || 0),
72
+ contentType: headers['content-type'] || 'application/octet-stream',
73
+ etag: (headers.etag || '').replace(/"/g, ''),
74
+ checksumSha256: headers['x-object-checksum-sha256'],
75
+ createdAt: headers['x-object-created-at'] || '',
76
+ updatedAt: headers['x-object-updated-at'] || '',
77
+ };
78
+ }
79
+ catch (error) {
80
+ if (error?.status === 404)
81
+ return null;
82
+ throw error;
83
+ }
84
+ }
85
+ deleteObject(bucket, key) {
86
+ return this.http.req(`${P}/buckets/${encodeURIComponent(bucket)}/objects/${encodeKey(key)}`, { method: 'DELETE' });
87
+ }
88
+ listObjects(bucket, opts = {}) {
89
+ const query = new URLSearchParams();
90
+ if (opts.prefix)
91
+ query.set('prefix', opts.prefix);
92
+ if (opts.delimiter)
93
+ query.set('delimiter', opts.delimiter);
94
+ if (opts.limit)
95
+ query.set('limit', String(opts.limit));
96
+ if (opts.cursor)
97
+ query.set('cursor', opts.cursor);
98
+ const suffix = query.toString();
99
+ return this.http.req(`${P}/buckets/${encodeURIComponent(bucket)}/objects${suffix ? `?${suffix}` : ''}`);
100
+ }
101
+ copyObject(bucket, input) {
102
+ return this.http.req(`${P}/buckets/${encodeURIComponent(bucket)}/objects/copy`, {
103
+ method: 'POST',
104
+ body: JSON.stringify(input),
105
+ });
106
+ }
107
+ presign(bucket, key, opts = {}) {
108
+ return this.http.req(`${P}/buckets/${encodeURIComponent(bucket)}/presign`, { method: 'POST', body: JSON.stringify({ key, method: opts.method || 'GET', expiresIn: opts.expiresIn ?? 900 }) });
109
+ }
110
+ createMultipart(bucket, key, contentType = 'application/octet-stream') {
111
+ return this.http.req(`${P}/buckets/${encodeURIComponent(bucket)}/uploads`, { method: 'POST', body: JSON.stringify({ key, contentType }) });
112
+ }
113
+ uploadPart(bucket, uploadId, key, partNumber, body) {
114
+ const bytes = typeof body === 'string' ? new TextEncoder().encode(body) : body;
115
+ return this.http.upload(`${P}/buckets/${encodeURIComponent(bucket)}/uploads/${encodeURIComponent(uploadId)}/parts/${partNumber}?key=${encodeURIComponent(key)}`, bytes, { method: 'PUT', contentType: 'application/octet-stream' });
116
+ }
117
+ completeMultipart(bucket, uploadId, key, parts) {
118
+ return this.http.req(`${P}/buckets/${encodeURIComponent(bucket)}/uploads/${encodeURIComponent(uploadId)}/complete`, { method: 'POST', body: JSON.stringify({ key, parts }) });
119
+ }
120
+ abortMultipart(bucket, uploadId, key) {
121
+ return this.http.req(`${P}/buckets/${encodeURIComponent(bucket)}/uploads/${encodeURIComponent(uploadId)}?key=${encodeURIComponent(key)}`, { method: 'DELETE' });
122
+ }
123
+ }
124
+ exports.OcsService = OcsService;
125
+ function encodeKey(key) {
126
+ return String(key || '')
127
+ .split('/')
128
+ .map((segment) => encodeURIComponent(segment))
129
+ .join('/');
130
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // SPDX-License-Identifier: Apache-2.0
7
+ // SPDX-FileCopyrightText: 2026 VKU.VIC
8
+ /* SynapseOCS JS SDK contract tests: buckets, objects, copy, list, multipart. */
9
+ const node_test_1 = require("node:test");
10
+ const strict_1 = __importDefault(require("node:assert/strict"));
11
+ const node_http_1 = __importDefault(require("node:http"));
12
+ const index_1 = require("./index");
13
+ let server;
14
+ let base = '';
15
+ const calls = [];
16
+ (0, node_test_1.before)(() => new Promise((resolve) => {
17
+ server = node_http_1.default.createServer((req, res) => {
18
+ const url = new URL(req.url || '/', 'http://x');
19
+ const chunks = [];
20
+ req.on('data', (chunk) => chunks.push(chunk));
21
+ req.on('end', () => {
22
+ const body = Buffer.concat(chunks).toString('utf8');
23
+ calls.push({ method: req.method || 'GET', path: url.pathname + url.search, body });
24
+ res.setHeader('content-type', 'application/json');
25
+ if (url.pathname === '/v1/ocs/buckets' && req.method === 'GET') {
26
+ res.end(JSON.stringify({ buckets: [{ name: 'media', createdAt: 't' }], total: 1 }));
27
+ return;
28
+ }
29
+ if (url.pathname === '/v1/ocs/buckets' && req.method === 'POST') {
30
+ res.statusCode = 201;
31
+ res.end(JSON.stringify({ bucket: { name: 'media', createdAt: 't' } }));
32
+ return;
33
+ }
34
+ if (url.pathname.endsWith('/stats')) {
35
+ res.end(JSON.stringify({ bucket: 'media', objects: 1, bytes: 5, quotaBytes: 100 }));
36
+ return;
37
+ }
38
+ if (url.pathname.endsWith('/objects') && req.method === 'GET') {
39
+ res.end(JSON.stringify({ bucket: 'media', prefix: '', objects: [{ key: 'a.txt', bucket: 'media', size: 5, contentType: 'text/plain', etag: 'e', createdAt: 't', updatedAt: 't' }], commonPrefixes: [], nextCursor: null }));
40
+ return;
41
+ }
42
+ if (url.pathname.endsWith('/copy')) {
43
+ res.statusCode = 201;
44
+ res.end(JSON.stringify({ object: { key: 'b.txt', bucket: 'media', size: 5, contentType: 'text/plain', etag: 'e', createdAt: 't', updatedAt: 't' } }));
45
+ return;
46
+ }
47
+ if (url.pathname.endsWith('/presign')) {
48
+ res.end(JSON.stringify({ url: 'https://ocs.example/x', bucket: 'media', key: 'a.txt', method: 'GET', expiresIn: 60 }));
49
+ return;
50
+ }
51
+ if (url.pathname.endsWith('/uploads')) {
52
+ res.statusCode = 201;
53
+ res.end(JSON.stringify({ uploadId: 'u1', bucket: 'media', key: 'a.txt', contentType: 'text/plain' }));
54
+ return;
55
+ }
56
+ if (url.pathname.includes('/parts/')) {
57
+ res.end(JSON.stringify({ partNumber: 1, etag: 'p1', size: 3 }));
58
+ return;
59
+ }
60
+ if (url.pathname.endsWith('/complete')) {
61
+ res.statusCode = 201;
62
+ res.end(JSON.stringify({ object: { key: 'a.txt', bucket: 'media', size: 3, contentType: 'text/plain', etag: 'e', createdAt: 't', updatedAt: 't' } }));
63
+ return;
64
+ }
65
+ if (req.method === 'PUT') {
66
+ res.statusCode = 201;
67
+ res.end(JSON.stringify({ object: { key: 'a.txt', bucket: 'media', size: 5, contentType: 'text/plain', etag: 'e', createdAt: 't', updatedAt: 't' } }));
68
+ return;
69
+ }
70
+ if (req.method === 'HEAD') {
71
+ res.setHeader('content-length', '5');
72
+ res.setHeader('content-type', 'text/plain');
73
+ res.setHeader('etag', '"e"');
74
+ res.setHeader('x-object-key', 'a.txt');
75
+ res.setHeader('x-ocs-bucket', 'media');
76
+ res.end();
77
+ return;
78
+ }
79
+ if (req.method === 'DELETE') {
80
+ res.end(JSON.stringify({ ok: true, bucket: 'media', key: 'a.txt' }));
81
+ return;
82
+ }
83
+ if (req.method === 'GET') {
84
+ res.setHeader('content-type', 'text/plain');
85
+ res.end('hello');
86
+ return;
87
+ }
88
+ res.statusCode = 404;
89
+ res.end('{}');
90
+ });
91
+ }).listen(0, '127.0.0.1', () => {
92
+ const address = server.address();
93
+ base = `http://127.0.0.1:${typeof address === 'object' && address ? address.port : 0}`;
94
+ resolve();
95
+ });
96
+ }));
97
+ (0, node_test_1.after)(() => new Promise((resolve) => server.close(() => resolve())));
98
+ (0, node_test_1.describe)('SynapseOCS SDK', () => {
99
+ (0, node_test_1.it)('manages buckets and stats', async () => {
100
+ const client = new index_1.SynapseOneClient({ baseUrl: base });
101
+ const created = await client.ocs.createBucket('media', { quotaBytes: 100 });
102
+ strict_1.default.equal(created.bucket.name, 'media');
103
+ const list = await client.ocs.listBuckets({ withStats: true });
104
+ strict_1.default.equal(list.total, 1);
105
+ const stats = await client.ocs.bucketStats('media');
106
+ strict_1.default.equal(stats.objects, 1);
107
+ const head = await client.ocs.headBucket('media');
108
+ strict_1.default.equal(head?.['x-ocs-bucket'], 'media');
109
+ await client.ocs.deleteBucket('media', { force: true });
110
+ strict_1.default.ok(calls.some((call) => call.path.includes('force=true')));
111
+ });
112
+ (0, node_test_1.it)('puts, gets, heads, lists, copies and deletes objects', async () => {
113
+ const client = new index_1.SynapseOneClient({ baseUrl: base });
114
+ const object = await client.ocs.putObject('media', 'a.txt', 'hello', { contentType: 'text/plain' });
115
+ strict_1.default.equal(object.key, 'a.txt');
116
+ const body = await client.ocs.getObject('media', 'a.txt', { range: 'bytes=0-1' });
117
+ strict_1.default.equal(Buffer.from(body).toString(), 'hello');
118
+ const head = await client.ocs.headObject('media', 'a.txt');
119
+ strict_1.default.equal(head?.etag, 'e');
120
+ const list = await client.ocs.listObjects('media', { prefix: 'a' });
121
+ strict_1.default.equal(list.objects[0].key, 'a.txt');
122
+ const copy = await client.ocs.copyObject('media', { sourceKey: 'a.txt', destinationKey: 'b.txt' });
123
+ strict_1.default.equal(copy.object.key, 'b.txt');
124
+ await client.ocs.deleteObject('media', 'a.txt');
125
+ });
126
+ (0, node_test_1.it)('presigns and runs multipart uploads', async () => {
127
+ const client = new index_1.SynapseOneClient({ baseUrl: base });
128
+ const presigned = await client.ocs.presign('media', 'a.txt', { expiresIn: 60 });
129
+ strict_1.default.equal(presigned.method, 'GET');
130
+ const upload = await client.ocs.createMultipart('media', 'a.txt', 'text/plain');
131
+ strict_1.default.equal(upload.uploadId, 'u1');
132
+ const part = await client.ocs.uploadPart('media', 'u1', 'a.txt', 1, new Uint8Array([1, 2, 3]));
133
+ strict_1.default.equal(part.etag, 'p1');
134
+ const done = await client.ocs.completeMultipart('media', 'u1', 'a.txt', [{ partNumber: 1, etag: 'p1' }]);
135
+ strict_1.default.equal(done.object.size, 3);
136
+ });
137
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapseone/sdk",
3
- "version": "0.7.1-dev.57",
3
+ "version": "0.7.1-dev.59",
4
4
  "license": "Apache-2.0",
5
5
  "description": "synapseone SDK for JavaScript/TypeScript",
6
6
  "homepage": "https://synapseone.space",