@synapseone/sdk 0.7.1 → 0.8.0-dev.73
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/iam.d.ts +7 -0
- package/dist/iam.js +6 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +10 -0
- package/dist/ocs.d.ts +119 -0
- package/dist/ocs.js +130 -0
- package/dist/ocs.test.d.ts +1 -0
- package/dist/ocs.test.js +137 -0
- package/dist/search.d.ts +20 -0
- package/dist/search.js +28 -0
- package/dist/workflow.d.ts +30 -0
- package/dist/workflow.js +57 -0
- package/package.json +1 -1
package/dist/iam.d.ts
CHANGED
|
@@ -112,6 +112,13 @@ export declare class IamService {
|
|
|
112
112
|
createUser(orgId: string, email: string, displayName?: string): Promise<unknown>;
|
|
113
113
|
createAccount(orgId: string, slug: string, displayName: string): Promise<unknown>;
|
|
114
114
|
userPolicies(userId: string): Promise<unknown>;
|
|
115
|
+
createScimToken(input?: {
|
|
116
|
+
description?: string;
|
|
117
|
+
scopes?: string[];
|
|
118
|
+
ttlSeconds?: number;
|
|
119
|
+
}): Promise<unknown>;
|
|
120
|
+
listScimTokens(): Promise<unknown>;
|
|
121
|
+
revokeScimToken(id: string): Promise<unknown>;
|
|
115
122
|
createRole(accountId: string, slug: string, description?: string): Promise<unknown>;
|
|
116
123
|
listRoles(accountId: string): Promise<unknown>;
|
|
117
124
|
deleteRole(roleId: string): Promise<unknown>;
|
package/dist/iam.js
CHANGED
|
@@ -110,6 +110,12 @@ class IamService {
|
|
|
110
110
|
return this.http.req(`/v1/orgs/${encodeURIComponent(orgId)}/accounts`, { method: 'POST', body: JSON.stringify({ slug, displayName }) });
|
|
111
111
|
}
|
|
112
112
|
userPolicies(userId) { return this.http.req(`/v1/users/${encodeURIComponent(userId)}/policies`); }
|
|
113
|
+
// ---- SCIM provisioning (#48) ----
|
|
114
|
+
createScimToken(input = {}) {
|
|
115
|
+
return this.http.req('/v1/scim/tokens', { method: 'POST', body: JSON.stringify(input) });
|
|
116
|
+
}
|
|
117
|
+
listScimTokens() { return this.http.req('/v1/scim/tokens'); }
|
|
118
|
+
revokeScimToken(id) { return this.http.req(`/v1/scim/tokens/${encodeURIComponent(id)}`, { method: 'DELETE' }); }
|
|
113
119
|
// ---- roles / policies ----
|
|
114
120
|
createRole(accountId, slug, description = '') {
|
|
115
121
|
return this.http.req(`/v1/accounts/${encodeURIComponent(accountId)}/roles`, { method: 'POST', body: JSON.stringify({ slug, description }) });
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { InferenceService } from './inference';
|
|
|
10
10
|
import { AiService } from './ai';
|
|
11
11
|
import { HealthService } from './health';
|
|
12
12
|
import { StorageService } from './storage';
|
|
13
|
+
import { SearchService } from './search';
|
|
14
|
+
import { OcsService } from './ocs';
|
|
13
15
|
import { NotificationsService } from './notifications';
|
|
14
16
|
export * from './_http';
|
|
15
17
|
export * from './iam';
|
|
@@ -23,6 +25,8 @@ export * from './stream';
|
|
|
23
25
|
export * from './inference';
|
|
24
26
|
export * from './health';
|
|
25
27
|
export * from './storage';
|
|
28
|
+
export * from './search';
|
|
29
|
+
export * from './ocs';
|
|
26
30
|
export * from './notifications';
|
|
27
31
|
/** Legacy flat LDS signatures (the namespaced service drops the `lds` prefix). */
|
|
28
32
|
export interface LdsLegacyMethods {
|
|
@@ -56,6 +60,10 @@ export declare class SynapseOneClient {
|
|
|
56
60
|
readonly stream: StreamService;
|
|
57
61
|
readonly inference: InferenceService;
|
|
58
62
|
readonly storage: StorageService;
|
|
63
|
+
/** Tenant-scoped search over Base documents (#46). */
|
|
64
|
+
readonly search: SearchService;
|
|
65
|
+
/** SynapseOCS bucket/object API; `storage` remains the default-bucket alias. */
|
|
66
|
+
readonly ocs: OcsService;
|
|
59
67
|
readonly notifications: NotificationsService;
|
|
60
68
|
readonly health: HealthService;
|
|
61
69
|
readonly readiness: HealthService;
|
package/dist/index.js
CHANGED
|
@@ -50,6 +50,8 @@ 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 search_1 = require("./search");
|
|
54
|
+
const ocs_1 = require("./ocs");
|
|
53
55
|
const notifications_1 = require("./notifications");
|
|
54
56
|
__exportStar(require("./_http"), exports);
|
|
55
57
|
__exportStar(require("./iam"), exports);
|
|
@@ -63,6 +65,8 @@ __exportStar(require("./stream"), exports);
|
|
|
63
65
|
__exportStar(require("./inference"), exports);
|
|
64
66
|
__exportStar(require("./health"), exports);
|
|
65
67
|
__exportStar(require("./storage"), exports);
|
|
68
|
+
__exportStar(require("./search"), exports);
|
|
69
|
+
__exportStar(require("./ocs"), exports);
|
|
66
70
|
__exportStar(require("./notifications"), exports);
|
|
67
71
|
class SynapseOneClient {
|
|
68
72
|
http;
|
|
@@ -76,6 +80,10 @@ class SynapseOneClient {
|
|
|
76
80
|
stream;
|
|
77
81
|
inference;
|
|
78
82
|
storage;
|
|
83
|
+
/** Tenant-scoped search over Base documents (#46). */
|
|
84
|
+
search;
|
|
85
|
+
/** SynapseOCS bucket/object API; `storage` remains the default-bucket alias. */
|
|
86
|
+
ocs;
|
|
79
87
|
notifications;
|
|
80
88
|
health;
|
|
81
89
|
readiness;
|
|
@@ -91,6 +99,8 @@ class SynapseOneClient {
|
|
|
91
99
|
this.stream = new stream_1.StreamService(this.http);
|
|
92
100
|
this.inference = new inference_1.InferenceService(this.http);
|
|
93
101
|
this.storage = new storage_1.StorageService(this.http);
|
|
102
|
+
this.search = new search_1.SearchService(this.http);
|
|
103
|
+
this.ocs = new ocs_1.OcsService(this.http);
|
|
94
104
|
this.notifications = new notifications_1.NotificationsService(this.http);
|
|
95
105
|
this.health = new health_1.HealthService(this.http);
|
|
96
106
|
// 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 {};
|
package/dist/ocs.test.js
ADDED
|
@@ -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/dist/search.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { HttpClient } from './_http';
|
|
2
|
+
export interface SearchQuery {
|
|
3
|
+
query: string;
|
|
4
|
+
mode?: 'fulltext' | 'semantic' | 'hybrid';
|
|
5
|
+
collection?: string;
|
|
6
|
+
collections?: string[];
|
|
7
|
+
filters?: Record<string, string>;
|
|
8
|
+
limit?: number;
|
|
9
|
+
cursor?: string | null;
|
|
10
|
+
}
|
|
11
|
+
export declare class SearchService {
|
|
12
|
+
private readonly http;
|
|
13
|
+
constructor(http: HttpClient);
|
|
14
|
+
query(input: SearchQuery): Promise<unknown>;
|
|
15
|
+
fulltext(query: string, opts?: Omit<SearchQuery, 'query' | 'mode'>): Promise<unknown>;
|
|
16
|
+
semantic(query: string, opts?: Omit<SearchQuery, 'query' | 'mode'>): Promise<unknown>;
|
|
17
|
+
hybrid(query: string, opts?: Omit<SearchQuery, 'query' | 'mode'>): Promise<unknown>;
|
|
18
|
+
reindex(collections?: string[]): Promise<unknown>;
|
|
19
|
+
status(): Promise<unknown>;
|
|
20
|
+
}
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SearchService = void 0;
|
|
4
|
+
class SearchService {
|
|
5
|
+
http;
|
|
6
|
+
constructor(http) {
|
|
7
|
+
this.http = http;
|
|
8
|
+
}
|
|
9
|
+
query(input) {
|
|
10
|
+
return this.http.req('/v1/search', { method: 'POST', body: JSON.stringify(input) });
|
|
11
|
+
}
|
|
12
|
+
fulltext(query, opts = {}) {
|
|
13
|
+
return this.query({ query, ...opts, mode: 'fulltext' });
|
|
14
|
+
}
|
|
15
|
+
semantic(query, opts = {}) {
|
|
16
|
+
return this.query({ query, ...opts, mode: 'semantic' });
|
|
17
|
+
}
|
|
18
|
+
hybrid(query, opts = {}) {
|
|
19
|
+
return this.query({ query, ...opts, mode: 'hybrid' });
|
|
20
|
+
}
|
|
21
|
+
reindex(collections) {
|
|
22
|
+
return this.http.req('/v1/search/reindex', {
|
|
23
|
+
method: 'POST', body: JSON.stringify(collections ? { collections } : {}),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
status() { return this.http.req('/v1/search/status'); }
|
|
27
|
+
}
|
|
28
|
+
exports.SearchService = SearchService;
|
package/dist/workflow.d.ts
CHANGED
|
@@ -50,6 +50,36 @@ export declare class WorkflowService {
|
|
|
50
50
|
getCredential(id: string): Promise<CredentialMetadata>;
|
|
51
51
|
rotateCredential(id: string, secret: string): Promise<CredentialMetadata>;
|
|
52
52
|
deleteCredential(id: string): Promise<unknown>;
|
|
53
|
+
/** Create a standalone human task (workflow nodes create theirs on pause). */
|
|
54
|
+
createHumanTask(input: {
|
|
55
|
+
title: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
assignee?: string;
|
|
58
|
+
candidateRoles?: string[];
|
|
59
|
+
deadline?: string;
|
|
60
|
+
decisionSchema?: Record<string, unknown>;
|
|
61
|
+
payload?: Record<string, unknown>;
|
|
62
|
+
workflowId?: string;
|
|
63
|
+
executionId?: string;
|
|
64
|
+
node?: string;
|
|
65
|
+
}): Promise<unknown>;
|
|
66
|
+
listHumanTasks(query?: Record<string, string | number | boolean | undefined>): Promise<unknown>;
|
|
67
|
+
getHumanTask(id: string): Promise<unknown>;
|
|
68
|
+
claimHumanTask(id: string): Promise<unknown>;
|
|
69
|
+
completeHumanTask(id: string, decision?: Record<string, unknown>, note?: string): Promise<unknown>;
|
|
70
|
+
rejectHumanTask(id: string, note: string, decision?: Record<string, unknown>): Promise<unknown>;
|
|
71
|
+
expireHumanTask(id: string, force?: boolean): Promise<unknown>;
|
|
72
|
+
createSecret(name: string, value: string, opts?: {
|
|
73
|
+
description?: string;
|
|
74
|
+
scope?: string;
|
|
75
|
+
accountId?: string;
|
|
76
|
+
}): Promise<unknown>;
|
|
77
|
+
listSecrets(): Promise<unknown>;
|
|
78
|
+
getSecret(name: string): Promise<unknown>;
|
|
79
|
+
readSecret(name: string, version?: number): Promise<unknown>;
|
|
80
|
+
rotateSecret(name: string, value: string, graceSeconds?: number): Promise<unknown>;
|
|
81
|
+
revokeSecret(name: string, version?: number): Promise<unknown>;
|
|
82
|
+
deleteSecret(name: string): Promise<unknown>;
|
|
53
83
|
/**
|
|
54
84
|
* Fire a public inbound webhook through the gateway: `ANY /webhook/:path`.
|
|
55
85
|
* No auth is required; per-workflow auth/rate-limit/idempotency still apply.
|
package/dist/workflow.js
CHANGED
|
@@ -106,6 +106,63 @@ class WorkflowService {
|
|
|
106
106
|
deleteCredential(id) {
|
|
107
107
|
return this.http.req(`/v1/credentials/${encodeURIComponent(id)}`, { method: 'DELETE' });
|
|
108
108
|
}
|
|
109
|
+
// ---- durable human tasks (#44) ----
|
|
110
|
+
/** Create a standalone human task (workflow nodes create theirs on pause). */
|
|
111
|
+
createHumanTask(input) {
|
|
112
|
+
return this.http.req('/v1/human-tasks', { method: 'POST', body: JSON.stringify(input) });
|
|
113
|
+
}
|
|
114
|
+
listHumanTasks(query = {}) {
|
|
115
|
+
const allowed = ['status', 'executionId', 'workflowId', 'assignee', 'limit', 'offset'];
|
|
116
|
+
const params = new URLSearchParams();
|
|
117
|
+
for (const k of allowed) {
|
|
118
|
+
const v = query[k];
|
|
119
|
+
if (v !== undefined && v !== null && String(v) !== '')
|
|
120
|
+
params.set(k, String(v));
|
|
121
|
+
}
|
|
122
|
+
const s = params.toString();
|
|
123
|
+
return this.http.req(`/v1/human-tasks${s ? `?${s}` : ''}`);
|
|
124
|
+
}
|
|
125
|
+
getHumanTask(id) { return this.http.req(`/v1/human-tasks/${encodeURIComponent(id)}`); }
|
|
126
|
+
claimHumanTask(id) { return this.http.req(`/v1/human-tasks/${encodeURIComponent(id)}/claim`, { method: 'POST', body: '{}' }); }
|
|
127
|
+
completeHumanTask(id, decision = {}, note) {
|
|
128
|
+
return this.http.req(`/v1/human-tasks/${encodeURIComponent(id)}/complete`, {
|
|
129
|
+
method: 'POST', body: JSON.stringify({ decision, ...(note ? { note } : {}) }),
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
rejectHumanTask(id, note, decision = {}) {
|
|
133
|
+
return this.http.req(`/v1/human-tasks/${encodeURIComponent(id)}/reject`, {
|
|
134
|
+
method: 'POST', body: JSON.stringify({ note, decision }),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
expireHumanTask(id, force = false) {
|
|
138
|
+
return this.http.req(`/v1/human-tasks/${encodeURIComponent(id)}/expire`, {
|
|
139
|
+
method: 'POST', body: JSON.stringify({ force }),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
// ---- tenant secret vault (#47) ----
|
|
143
|
+
createSecret(name, value, opts = {}) {
|
|
144
|
+
return this.http.req('/v1/secrets', { method: 'POST', body: JSON.stringify({ name, value, ...opts }) });
|
|
145
|
+
}
|
|
146
|
+
listSecrets() { return this.http.req('/v1/secrets'); }
|
|
147
|
+
getSecret(name) { return this.http.req(`/v1/secrets/${encodeURIComponent(name)}`); }
|
|
148
|
+
readSecret(name, version) {
|
|
149
|
+
return this.http.req(`/v1/secrets/${encodeURIComponent(name)}/read`, {
|
|
150
|
+
method: 'POST', body: JSON.stringify(version ? { version } : {}),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
rotateSecret(name, value, graceSeconds = 86400) {
|
|
154
|
+
return this.http.req(`/v1/secrets/${encodeURIComponent(name)}/rotate`, {
|
|
155
|
+
method: 'POST', body: JSON.stringify({ value, graceSeconds }),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
revokeSecret(name, version) {
|
|
159
|
+
return this.http.req(`/v1/secrets/${encodeURIComponent(name)}/revoke`, {
|
|
160
|
+
method: 'POST', body: JSON.stringify(version ? { version } : {}),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
deleteSecret(name) {
|
|
164
|
+
return this.http.req(`/v1/secrets/${encodeURIComponent(name)}`, { method: 'DELETE' });
|
|
165
|
+
}
|
|
109
166
|
// ---- public inbound webhooks ----
|
|
110
167
|
/**
|
|
111
168
|
* Fire a public inbound webhook through the gateway: `ANY /webhook/:path`.
|