@synapseone/sdk 0.0.0-stage → 0.7.0-dev.43

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.
@@ -0,0 +1,292 @@
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
+ /*
7
+ * Copyright 2026 SynapseOne Contributors
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * Offline SDK tests — local echo server, no platform needed.
10
+ */
11
+ const node_test_1 = require("node:test");
12
+ const strict_1 = __importDefault(require("node:assert/strict"));
13
+ const node_http_1 = __importDefault(require("node:http"));
14
+ const index_1 = require("./index");
15
+ let base = '';
16
+ let lastHeaders = {};
17
+ let lastPath = '';
18
+ let lastMethod = '';
19
+ let lastBody = '';
20
+ let server;
21
+ (0, node_test_1.before)(() => new Promise((resolve) => {
22
+ server = node_http_1.default
23
+ .createServer((req, res) => {
24
+ lastHeaders = { ...req.headers };
25
+ lastPath = req.url || '';
26
+ lastMethod = req.method || '';
27
+ let body = '';
28
+ req.on('data', (c) => (body += c));
29
+ req.on('end', () => {
30
+ lastBody = body;
31
+ res.setHeader('Content-Type', 'application/json');
32
+ res.end(JSON.stringify({ ok: true, path: req.url }));
33
+ });
34
+ })
35
+ .listen(0, '127.0.0.1', () => {
36
+ const a = server.address();
37
+ base = `http://127.0.0.1:${typeof a === 'object' && a ? a.port : 0}`;
38
+ resolve();
39
+ });
40
+ }));
41
+ (0, node_test_1.after)(() => new Promise((resolve) => server.close(() => resolve())));
42
+ (0, node_test_1.describe)('SynapseOneClient', () => {
43
+ (0, node_test_1.it)('keeps the SynapseDX alias identical during the rebrand window', () => {
44
+ strict_1.default.equal(index_1.SynapseDXClient, index_1.SynapseOneClient);
45
+ strict_1.default.equal(index_1.SynapseDXError, index_1.SynapseOneError);
46
+ });
47
+ (0, node_test_1.it)('trims trailing slash', () => {
48
+ const c = new index_1.SynapseOneClient({ baseUrl: 'http://x:8080/' });
49
+ strict_1.default.equal(c.baseUrl, 'http://x:8080');
50
+ });
51
+ (0, node_test_1.it)('sends Bearer token', async () => {
52
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
53
+ c.setToken('tok123');
54
+ await c.listOrgs();
55
+ strict_1.default.equal(lastHeaders['authorization'], 'Bearer tok123');
56
+ strict_1.default.equal(lastPath, '/v1/orgs');
57
+ });
58
+ (0, node_test_1.it)('sends X-API-Key', async () => {
59
+ const c = new index_1.SynapseOneClient({ baseUrl: base, apiKey: 'k1' });
60
+ await c.listTemplates();
61
+ strict_1.default.equal(lastHeaders['x-api-key'], 'k1');
62
+ });
63
+ (0, node_test_1.it)('throws rich error on non-2xx', async () => {
64
+ const bad = new index_1.SynapseOneClient({ baseUrl: 'http://127.0.0.1:1' });
65
+ await strict_1.default.rejects(() => bad.listOrgs(), /synapseone/);
66
+ });
67
+ (0, node_test_1.it)('encodes ids in paths', async () => {
68
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
69
+ await c.getWorkflow('a/b');
70
+ strict_1.default.equal(lastPath, '/v1/workflows/a%2Fb');
71
+ });
72
+ (0, node_test_1.it)('covers new endpoints', async () => {
73
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
74
+ await c.userPolicies('u1');
75
+ strict_1.default.equal(lastPath, '/v1/users/u1/policies');
76
+ await c.getTemplate('webhook-to-log');
77
+ strict_1.default.equal(lastPath, '/v1/templates/webhook-to-log');
78
+ await c.listExecutions('limit=5');
79
+ strict_1.default.equal(lastPath, '/v1/executions?limit=5');
80
+ await c.executeWorkflow('w1', {});
81
+ strict_1.default.equal(lastPath, '/v1/workflows/w1/execute');
82
+ await c.updateWorkflow('w1', { name: 'renamed' });
83
+ strict_1.default.equal(lastPath, '/v1/workflows/w1');
84
+ await c.deleteWorkflow('w1');
85
+ strict_1.default.equal(lastPath, '/v1/workflows/w1');
86
+ await c.detachPolicy('r1', 'p1');
87
+ strict_1.default.equal(lastPath, '/v1/roles/r1/policies/p1');
88
+ await c.rolePolicies('r1');
89
+ strict_1.default.equal(lastPath, '/v1/roles/r1/policies');
90
+ await c.unassignRole('u1', 'r1');
91
+ strict_1.default.equal(lastPath, '/v1/users/u1/roles/r1');
92
+ await c.userRoles('u1');
93
+ strict_1.default.equal(lastPath, '/v1/users/u1/roles');
94
+ await c.listApiKeys('a1');
95
+ strict_1.default.equal(lastPath, '/v1/accounts/a1/keys');
96
+ await c.verifyApiKey('k');
97
+ strict_1.default.equal(lastPath, '/v1/keys/verify');
98
+ await c.deactivateWorkflow('w1');
99
+ strict_1.default.equal(lastPath, '/v1/workflows/w1/deactivate');
100
+ });
101
+ (0, node_test_1.it)('serviceAccountToken omits scopes unless explicitly given', async () => {
102
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
103
+ await c.serviceAccountToken('sa1');
104
+ strict_1.default.equal(lastPath, '/v1/service-accounts/sa1/token');
105
+ strict_1.default.deepEqual(JSON.parse(lastBody), {});
106
+ await c.serviceAccountToken('sa1', ['workflow:Execute']);
107
+ strict_1.default.deepEqual(JSON.parse(lastBody), { scopes: ['workflow:Execute'] });
108
+ await c.serviceAccountToken('sa1', []);
109
+ strict_1.default.deepEqual(JSON.parse(lastBody), { scopes: [] });
110
+ });
111
+ (0, node_test_1.it)('testRun posts definition+input', async () => {
112
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
113
+ const def = { nodes: [], connections: {} };
114
+ await c.testRun(def, { value: 21 });
115
+ strict_1.default.equal(lastPath, '/v1/workflows/test-run');
116
+ strict_1.default.equal(lastMethod, 'POST');
117
+ strict_1.default.deepEqual(JSON.parse(lastBody), { definition: def, input: { value: 21 } });
118
+ });
119
+ (0, node_test_1.it)('listExecutions accepts the allowlisted dict form', async () => {
120
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
121
+ await c.listExecutions({ workflowId: 'w1', status: 'error', limit: 20, offset: 0, includeData: true });
122
+ strict_1.default.ok(lastPath.startsWith('/v1/executions?'), lastPath);
123
+ strict_1.default.ok(lastPath.includes('workflowId=w1'), lastPath);
124
+ strict_1.default.ok(lastPath.includes('status=error'), lastPath);
125
+ strict_1.default.ok(lastPath.includes('limit=20'), lastPath);
126
+ strict_1.default.ok(lastPath.includes('includeData=true'), lastPath);
127
+ });
128
+ (0, node_test_1.it)('getExecution supports includeData', async () => {
129
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
130
+ await c.getExecution('e1', true);
131
+ strict_1.default.equal(lastPath, '/v1/executions/e1?includeData=true');
132
+ });
133
+ (0, node_test_1.it)('iam usageSummary and usageEvents hit the right endpoints', async () => {
134
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
135
+ await c.iam.usageSummary({ feature: 'workflows' });
136
+ strict_1.default.equal(lastPath, '/v1/usage/summary?feature=workflows');
137
+ strict_1.default.equal(lastMethod, 'GET');
138
+ await c.iam.usageEvents({ limit: 25, offset: 50, q: 'test' });
139
+ strict_1.default.ok(lastPath.startsWith('/v1/usage/events?'));
140
+ strict_1.default.ok(lastPath.includes('limit=25'));
141
+ strict_1.default.ok(lastPath.includes('offset=50'));
142
+ strict_1.default.ok(lastPath.includes('q=test'));
143
+ strict_1.default.equal(lastMethod, 'GET');
144
+ });
145
+ (0, node_test_1.it)('unwrapExecutions accepts envelope and bare array', () => {
146
+ strict_1.default.deepEqual((0, index_1.unwrapExecutions)({ data: [{ id: 'e1' }] }), [{ id: 'e1' }]);
147
+ strict_1.default.deepEqual((0, index_1.unwrapExecutions)([{ id: 'e2' }]), [{ id: 'e2' }]);
148
+ strict_1.default.deepEqual((0, index_1.unwrapExecutions)(null), []);
149
+ });
150
+ (0, node_test_1.it)('triggerWebhook posts to /webhook/:path without auth', async () => {
151
+ const out = await (0, index_1.triggerWebhook)(base, 'transform', { value: 21 });
152
+ strict_1.default.equal(lastPath, '/webhook/transform');
153
+ strict_1.default.equal(lastMethod, 'POST');
154
+ strict_1.default.deepEqual(JSON.parse(lastBody), { value: 21 });
155
+ strict_1.default.equal(out.ok, true);
156
+ });
157
+ (0, node_test_1.it)('call() passes any method/path/body through', async () => {
158
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
159
+ await c.call('POST', '/v1/accounts/a1/credentials', { name: 'x' });
160
+ strict_1.default.equal(lastPath, '/v1/accounts/a1/credentials');
161
+ strict_1.default.equal(lastMethod, 'POST');
162
+ strict_1.default.deepEqual(JSON.parse(lastBody), { name: 'x' });
163
+ await c.call('get', 'v1/workflows');
164
+ strict_1.default.equal(lastPath, '/v1/workflows');
165
+ strict_1.default.equal(lastMethod, 'GET');
166
+ });
167
+ (0, node_test_1.it)('credentials CRUD hits the workflow credentials paths', async () => {
168
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
169
+ await c.createCredential('a1', { name: 'stripe-live', type: 'bearer', secret: 's3cr3t', expiresAt: '2027-01-01T00:00:00Z' });
170
+ strict_1.default.equal(lastPath, '/v1/credentials');
171
+ strict_1.default.equal(lastMethod, 'POST');
172
+ strict_1.default.deepEqual(JSON.parse(lastBody), { accountId: 'a1', name: 'stripe-live', kind: 'bearer', secret: 's3cr3t' });
173
+ await c.listCredentials('a1');
174
+ strict_1.default.equal(lastPath, '/v1/credentials?accountId=a1');
175
+ strict_1.default.equal(lastMethod, 'GET');
176
+ await c.getCredential('c1');
177
+ strict_1.default.equal(lastPath, '/v1/credentials/c1');
178
+ await c.rotateCredential('c1', 'n3w');
179
+ strict_1.default.equal(lastPath, '/v1/credentials/c1/rotate');
180
+ strict_1.default.equal(lastMethod, 'POST');
181
+ strict_1.default.deepEqual(JSON.parse(lastBody), { secret: 'n3w' });
182
+ await c.deleteCredential('c1');
183
+ strict_1.default.equal(lastPath, '/v1/credentials/c1');
184
+ strict_1.default.equal(lastMethod, 'DELETE');
185
+ });
186
+ (0, node_test_1.it)('ai agent posts question and history', async () => {
187
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
188
+ await c.ai.agent('how to create a workflow', [{ role: 'user', text: 'hi' }]);
189
+ strict_1.default.equal(lastPath, '/v1/ai/agent');
190
+ strict_1.default.equal(lastMethod, 'POST');
191
+ strict_1.default.deepEqual(JSON.parse(lastBody), {
192
+ question: 'how to create a workflow',
193
+ history: [{ role: 'user', text: 'hi' }],
194
+ });
195
+ });
196
+ (0, node_test_1.it)('ldsLicenses lists the license catalog', async () => {
197
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
198
+ await c.ldsLicenses();
199
+ strict_1.default.equal(lastPath, '/v1/lds/licenses');
200
+ strict_1.default.equal(lastMethod, 'GET');
201
+ });
202
+ (0, node_test_1.it)('ldsDatasources passes orgId/accountId filters', async () => {
203
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
204
+ await c.ldsDatasources({ orgId: 'o1', accountId: 'a1' });
205
+ strict_1.default.equal(lastPath, '/v1/lds/datasources?orgId=o1&accountId=a1');
206
+ await c.ldsDatasources();
207
+ strict_1.default.equal(lastPath, '/v1/lds/datasources');
208
+ });
209
+ (0, node_test_1.it)('ldsCreateDatasource posts the contract body', async () => {
210
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
211
+ const input = {
212
+ name: 'Weather', slug: 'weather', entityType: 'WeatherObserved', license: 'CC-BY-4.0',
213
+ licenseUrl: 'https://creativecommons.org/licenses/by/4.0/',
214
+ contexts: ['https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld'],
215
+ defaultVisibility: 'public', description: 'demo datasource', orgId: 'o1', accountId: 'a1',
216
+ };
217
+ await c.ldsCreateDatasource(input);
218
+ strict_1.default.equal(lastPath, '/v1/lds/datasources');
219
+ strict_1.default.equal(lastMethod, 'POST');
220
+ strict_1.default.deepEqual(JSON.parse(lastBody), input);
221
+ });
222
+ (0, node_test_1.it)('covers LDS datasource/attribute CRUD paths', async () => {
223
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
224
+ await c.ldsDatasource('ds1');
225
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1');
226
+ await c.ldsUpdateDatasource('ds1', { name: 'renamed' });
227
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1');
228
+ strict_1.default.equal(lastMethod, 'PATCH');
229
+ strict_1.default.deepEqual(JSON.parse(lastBody), { name: 'renamed' });
230
+ await c.ldsDeleteDatasource('ds1');
231
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1');
232
+ strict_1.default.equal(lastMethod, 'DELETE');
233
+ await c.ldsAttributes('ds1');
234
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1/attributes');
235
+ await c.ldsSetAttributes('ds1', [{ name: 'temperature', ngsiLdType: 'Property', visibility: 'public' }]);
236
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1/attributes');
237
+ strict_1.default.equal(lastMethod, 'PUT');
238
+ strict_1.default.deepEqual(JSON.parse(lastBody), { attributes: [{ name: 'temperature', ngsiLdType: 'Property', visibility: 'public' }] });
239
+ await c.ldsStats('ds1');
240
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1/stats');
241
+ await c.ldsEntity('ds1', 'urn:ngsi-ld:Thing:t1');
242
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1/entities/urn%3Angsi-ld%3AThing%3At1');
243
+ });
244
+ (0, node_test_1.it)('ldsIngest normalizes single/array/wrapped record bodies', async () => {
245
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
246
+ await c.ldsIngest('ds1', { sensor: 's1', temperature: 21 });
247
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1/records');
248
+ strict_1.default.equal(lastMethod, 'POST');
249
+ strict_1.default.deepEqual(JSON.parse(lastBody), { record: { sensor: 's1', temperature: 21 } });
250
+ await c.ldsIngest('ds1', [{ sensor: 's1' }, { sensor: 's2' }]);
251
+ strict_1.default.deepEqual(JSON.parse(lastBody), { records: [{ sensor: 's1' }, { sensor: 's2' }] });
252
+ await c.ldsIngest('ds1', { records: [{ sensor: 's3' }] });
253
+ strict_1.default.deepEqual(JSON.parse(lastBody), { records: [{ sensor: 's3' }] });
254
+ });
255
+ (0, node_test_1.it)('ldsEntities sends limit/offset/visibility query params', async () => {
256
+ const c = new index_1.SynapseOneClient({ baseUrl: base });
257
+ await c.ldsEntities('ds1', { limit: 50, offset: 10, visibility: 'public' });
258
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1/entities?limit=50&offset=10&visibility=public');
259
+ await c.ldsEntities('ds1');
260
+ strict_1.default.equal(lastPath, '/v1/lds/datasources/ds1/entities');
261
+ });
262
+ (0, node_test_1.it)('ldsSetAttributes surfaces the 400 reserved_attribute error', async () => {
263
+ let errMethod = '';
264
+ let errPath = '';
265
+ let errBody = '';
266
+ const errSrv = node_http_1.default.createServer((req, res) => {
267
+ errMethod = req.method || '';
268
+ errPath = req.url || '';
269
+ let body = '';
270
+ req.on('data', (ch) => (body += ch));
271
+ req.on('end', () => {
272
+ errBody = body;
273
+ res.statusCode = 400;
274
+ res.setHeader('Content-Type', 'application/json');
275
+ res.end(JSON.stringify({ error: 'reserved_attribute', message: 'attribute name "id" is reserved' }));
276
+ });
277
+ });
278
+ await new Promise((resolve) => errSrv.listen(0, '127.0.0.1', resolve));
279
+ const a = errSrv.address();
280
+ const errBase = `http://127.0.0.1:${typeof a === 'object' && a ? a.port : 0}`;
281
+ try {
282
+ const c = new index_1.SynapseOneClient({ baseUrl: errBase });
283
+ await strict_1.default.rejects(() => c.ldsSetAttributes('ds1', [{ name: 'id' }]), /synapseone 400 .*reserved_attribute/);
284
+ strict_1.default.equal(errMethod, 'PUT');
285
+ strict_1.default.equal(errPath, '/v1/lds/datasources/ds1/attributes');
286
+ strict_1.default.deepEqual(JSON.parse(errBody), { attributes: [{ name: 'id' }] });
287
+ }
288
+ finally {
289
+ await new Promise((resolve) => errSrv.close(() => resolve()));
290
+ }
291
+ });
292
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /*
4
+ * Copyright 2026 SynapseOne Contributors
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ */
7
+ const index_1 = require("./index");
8
+ async function main() {
9
+ const c = new index_1.SynapseOneClient({ baseUrl: process.env.SYNAPSEONE_BASE_URL || 'http://localhost:8080' });
10
+ const login = await c.login('demo@acme.local');
11
+ console.log('login ok:', login.user?.email);
12
+ c.setToken(login.accessToken);
13
+ console.log(await c.listOrgs());
14
+ console.log('lds datasources:', await c.ldsDatasources());
15
+ }
16
+ main().catch((e) => { console.error(e); process.exit(1); });
@@ -0,0 +1,108 @@
1
+ import { HttpClient } from './_http';
2
+ export declare class FaststoreService {
3
+ private readonly http;
4
+ constructor(http: HttpClient);
5
+ private key;
6
+ stats(): Promise<unknown>;
7
+ /** Scan keys; returns `{keys, cursor, truncated}` (pass `cursor` back to continue). */
8
+ listKeys(query?: {
9
+ prefix?: string;
10
+ limit?: number;
11
+ cursor?: string;
12
+ }): Promise<{
13
+ keys: any[];
14
+ cursor: string | null;
15
+ truncated: boolean;
16
+ }>;
17
+ exists(key: string): Promise<boolean>;
18
+ get(key: string): Promise<unknown>;
19
+ set(key: string, value: unknown, opts?: {
20
+ ttlSeconds?: number;
21
+ ifNotExists?: boolean;
22
+ ifExists?: boolean;
23
+ }): Promise<unknown>;
24
+ delete(key: string): Promise<unknown>;
25
+ ttl(key: string): Promise<unknown>;
26
+ expire(key: string, ttlSeconds: number): Promise<unknown>;
27
+ incr(key: string, opts?: {
28
+ by?: number;
29
+ ttlSeconds?: number;
30
+ }): Promise<unknown>;
31
+ batch(operations: Record<string, unknown>[]): Promise<{
32
+ results: any[];
33
+ ok: boolean;
34
+ }>;
35
+ hashGet(key: string): Promise<unknown>;
36
+ hashSet(key: string, values: Record<string, unknown>, opts?: {
37
+ ttlSeconds?: number;
38
+ }): Promise<unknown>;
39
+ hashDelete(key: string): Promise<unknown>;
40
+ hashLength(key: string): Promise<unknown>;
41
+ hashGetField(key: string, field: string): Promise<unknown>;
42
+ hashSetField(key: string, field: string, value: unknown, opts?: {
43
+ ttlSeconds?: number;
44
+ }): Promise<unknown>;
45
+ hashDeleteField(key: string, field: string): Promise<unknown>;
46
+ hashIncr(key: string, field: string, opts?: {
47
+ by?: number;
48
+ ttlSeconds?: number;
49
+ }): Promise<unknown>;
50
+ listRange(key: string, start?: number, stop?: number): Promise<unknown>;
51
+ listDelete(key: string): Promise<unknown>;
52
+ listPush(key: string, values: unknown[], opts?: {
53
+ side?: 'left' | 'right';
54
+ ttlSeconds?: number;
55
+ }): Promise<unknown>;
56
+ listPop(key: string, opts?: {
57
+ side?: 'left' | 'right';
58
+ count?: number;
59
+ }): Promise<unknown>;
60
+ listTrim(key: string, start: number, stop: number): Promise<unknown>;
61
+ listLength(key: string): Promise<unknown>;
62
+ setMembers(key: string): Promise<unknown>;
63
+ setDelete(key: string): Promise<unknown>;
64
+ setAdd(key: string, members: unknown[], opts?: {
65
+ ttlSeconds?: number;
66
+ }): Promise<unknown>;
67
+ setRemove(key: string, members: unknown[]): Promise<unknown>;
68
+ setContains(key: string, member: unknown): Promise<unknown>;
69
+ setCard(key: string): Promise<unknown>;
70
+ zsetRange(key: string, opts?: {
71
+ start?: number;
72
+ stop?: number;
73
+ rev?: boolean;
74
+ withScores?: boolean;
75
+ }): Promise<unknown>;
76
+ zsetDelete(key: string): Promise<unknown>;
77
+ zsetAdd(key: string, members: Array<{
78
+ member: unknown;
79
+ score: number;
80
+ }>, opts?: {
81
+ ttlSeconds?: number;
82
+ }): Promise<unknown>;
83
+ zsetIncr(key: string, member: unknown, opts?: {
84
+ by?: number;
85
+ ttlSeconds?: number;
86
+ }): Promise<unknown>;
87
+ zsetRemove(key: string, members: unknown[]): Promise<unknown>;
88
+ zsetScore(key: string, member: unknown): Promise<unknown>;
89
+ zsetRank(key: string, member: unknown, opts?: {
90
+ rev?: boolean;
91
+ }): Promise<unknown>;
92
+ zsetCard(key: string): Promise<unknown>;
93
+ lockAcquire(name: string, opts?: {
94
+ ttlSeconds?: number;
95
+ waitMs?: number;
96
+ token?: string;
97
+ }): Promise<{
98
+ acquired: boolean;
99
+ lock: string;
100
+ token?: string;
101
+ ttlSeconds?: number;
102
+ expiresAt?: string;
103
+ }>;
104
+ lockRelease(name: string, token: string): Promise<unknown>;
105
+ lockExtend(name: string, token: string, opts?: {
106
+ ttlSeconds?: number;
107
+ }): Promise<unknown>;
108
+ }
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright 2026 SynapseOne Contributors
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * Synapse Faststore client: Redis-backed cache/KV with strings, hashes, lists,
6
+ * sets, sorted sets, TTLs, counters, scans, batches and distributed locks.
7
+ *
8
+ * Every operation is scoped to the caller's tenant (org / account / user).
9
+ * Platform callers set `tenant` on the client (x-synapseone-tenant).
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.FaststoreService = void 0;
13
+ const _http_1 = require("./_http");
14
+ const P = '/v1/faststore';
15
+ class FaststoreService {
16
+ http;
17
+ constructor(http) {
18
+ this.http = http;
19
+ }
20
+ key(key) {
21
+ return encodeURIComponent(key);
22
+ }
23
+ // ---- stats / scans ----
24
+ stats() { return this.http.req(`${P}/stats`); }
25
+ /** Scan keys; returns `{keys, cursor, truncated}` (pass `cursor` back to continue). */
26
+ listKeys(query = {}) {
27
+ const p = new URLSearchParams();
28
+ if (query.prefix)
29
+ p.set('prefix', query.prefix);
30
+ if (query.limit !== undefined)
31
+ p.set('limit', String(query.limit));
32
+ if (query.cursor !== undefined)
33
+ p.set('cursor', query.cursor);
34
+ const s = p.toString();
35
+ return this.http.req(`${P}/keys${s ? `?${s}` : ''}`);
36
+ }
37
+ async exists(key) {
38
+ try {
39
+ await this.get(key);
40
+ return true;
41
+ }
42
+ catch (e) {
43
+ if (e instanceof _http_1.SynapseOneError && e.status === 404)
44
+ return false;
45
+ throw e;
46
+ }
47
+ }
48
+ // ---- key/value ----
49
+ get(key) { return this.http.req(`${P}/keys/${this.key(key)}`); }
50
+ set(key, value, opts = {}) {
51
+ return this.http.req(`${P}/keys/${this.key(key)}`, {
52
+ method: 'PUT',
53
+ body: JSON.stringify({
54
+ value,
55
+ ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}),
56
+ ...(opts.ifNotExists ? { ifNotExists: true } : {}),
57
+ ...(opts.ifExists ? { ifExists: true } : {}),
58
+ }),
59
+ });
60
+ }
61
+ delete(key) { return this.http.req(`${P}/keys/${this.key(key)}`, { method: 'DELETE' }); }
62
+ ttl(key) { return this.http.req(`${P}/keys/${this.key(key)}/ttl`); }
63
+ expire(key, ttlSeconds) {
64
+ return this.http.req(`${P}/keys/${this.key(key)}/expire`, { method: 'POST', body: JSON.stringify({ ttlSeconds }) });
65
+ }
66
+ incr(key, opts = {}) {
67
+ return this.http.req(`${P}/keys/${this.key(key)}/incr`, {
68
+ method: 'POST',
69
+ body: JSON.stringify({
70
+ by: opts.by ?? 1,
71
+ ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}),
72
+ }),
73
+ });
74
+ }
75
+ batch(operations) {
76
+ return this.http.req(`${P}/batch`, { method: 'POST', body: JSON.stringify({ operations }) });
77
+ }
78
+ // ---- hashes ----
79
+ hashGet(key) { return this.http.req(`${P}/hashes/${this.key(key)}`); }
80
+ hashSet(key, values, opts = {}) {
81
+ return this.http.req(`${P}/hashes/${this.key(key)}`, {
82
+ method: 'PUT',
83
+ body: JSON.stringify({ values, ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}) }),
84
+ });
85
+ }
86
+ hashDelete(key) { return this.http.req(`${P}/hashes/${this.key(key)}`, { method: 'DELETE' }); }
87
+ hashLength(key) { return this.http.req(`${P}/hashes/${this.key(key)}/length`); }
88
+ hashGetField(key, field) {
89
+ return this.http.req(`${P}/hashes/${this.key(key)}/${encodeURIComponent(field)}`);
90
+ }
91
+ hashSetField(key, field, value, opts = {}) {
92
+ return this.http.req(`${P}/hashes/${this.key(key)}/${encodeURIComponent(field)}`, {
93
+ method: 'PUT',
94
+ body: JSON.stringify({ value, ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}) }),
95
+ });
96
+ }
97
+ hashDeleteField(key, field) {
98
+ return this.http.req(`${P}/hashes/${this.key(key)}/${encodeURIComponent(field)}`, { method: 'DELETE' });
99
+ }
100
+ hashIncr(key, field, opts = {}) {
101
+ return this.http.req(`${P}/hashes/${this.key(key)}/incr`, {
102
+ method: 'POST',
103
+ body: JSON.stringify({ field, by: opts.by ?? 1, ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}) }),
104
+ });
105
+ }
106
+ // ---- lists ----
107
+ listRange(key, start = 0, stop = -1) {
108
+ return this.http.req(`${P}/lists/${this.key(key)}?start=${start}&stop=${stop}`);
109
+ }
110
+ listDelete(key) { return this.http.req(`${P}/lists/${this.key(key)}`, { method: 'DELETE' }); }
111
+ listPush(key, values, opts = {}) {
112
+ return this.http.req(`${P}/lists/${this.key(key)}/push`, {
113
+ method: 'POST',
114
+ body: JSON.stringify({ values, side: opts.side ?? 'right', ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}) }),
115
+ });
116
+ }
117
+ listPop(key, opts = {}) {
118
+ return this.http.req(`${P}/lists/${this.key(key)}/pop`, {
119
+ method: 'POST',
120
+ body: JSON.stringify({ side: opts.side ?? 'left', count: opts.count ?? 1 }),
121
+ });
122
+ }
123
+ listTrim(key, start, stop) {
124
+ return this.http.req(`${P}/lists/${this.key(key)}/trim`, { method: 'POST', body: JSON.stringify({ start, stop }) });
125
+ }
126
+ listLength(key) { return this.http.req(`${P}/lists/${this.key(key)}/length`); }
127
+ // ---- sets ----
128
+ setMembers(key) { return this.http.req(`${P}/sets/${this.key(key)}`); }
129
+ setDelete(key) { return this.http.req(`${P}/sets/${this.key(key)}`, { method: 'DELETE' }); }
130
+ setAdd(key, members, opts = {}) {
131
+ return this.http.req(`${P}/sets/${this.key(key)}/add`, {
132
+ method: 'POST',
133
+ body: JSON.stringify({ members, ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}) }),
134
+ });
135
+ }
136
+ setRemove(key, members) {
137
+ return this.http.req(`${P}/sets/${this.key(key)}/remove`, { method: 'POST', body: JSON.stringify({ members }) });
138
+ }
139
+ setContains(key, member) {
140
+ return this.http.req(`${P}/sets/${this.key(key)}/contains`, { method: 'POST', body: JSON.stringify({ member }) });
141
+ }
142
+ setCard(key) { return this.http.req(`${P}/sets/${this.key(key)}/card`); }
143
+ // ---- sorted sets ----
144
+ zsetRange(key, opts = {}) {
145
+ const p = new URLSearchParams();
146
+ p.set('start', String(opts.start ?? 0));
147
+ p.set('stop', String(opts.stop ?? -1));
148
+ if (opts.rev)
149
+ p.set('rev', 'true');
150
+ if (opts.withScores)
151
+ p.set('withScores', 'true');
152
+ return this.http.req(`${P}/zsets/${this.key(key)}?${p.toString()}`);
153
+ }
154
+ zsetDelete(key) { return this.http.req(`${P}/zsets/${this.key(key)}`, { method: 'DELETE' }); }
155
+ zsetAdd(key, members, opts = {}) {
156
+ return this.http.req(`${P}/zsets/${this.key(key)}/add`, {
157
+ method: 'POST',
158
+ body: JSON.stringify({ members, ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}) }),
159
+ });
160
+ }
161
+ zsetIncr(key, member, opts = {}) {
162
+ return this.http.req(`${P}/zsets/${this.key(key)}/incr`, {
163
+ method: 'POST',
164
+ body: JSON.stringify({ member, by: opts.by ?? 1, ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}) }),
165
+ });
166
+ }
167
+ zsetRemove(key, members) {
168
+ return this.http.req(`${P}/zsets/${this.key(key)}/remove`, { method: 'POST', body: JSON.stringify({ members }) });
169
+ }
170
+ zsetScore(key, member) {
171
+ return this.http.req(`${P}/zsets/${this.key(key)}/score`, { method: 'POST', body: JSON.stringify({ member }) });
172
+ }
173
+ zsetRank(key, member, opts = {}) {
174
+ return this.http.req(`${P}/zsets/${this.key(key)}/rank`, {
175
+ method: 'POST',
176
+ body: JSON.stringify({ member, ...(opts.rev ? { rev: true } : {}) }),
177
+ });
178
+ }
179
+ zsetCard(key) { return this.http.req(`${P}/zsets/${this.key(key)}/card`); }
180
+ // ---- distributed locks ----
181
+ lockAcquire(name, opts = {}) {
182
+ return this.http.req(`${P}/locks/${encodeURIComponent(name)}/acquire`, {
183
+ method: 'POST',
184
+ body: JSON.stringify({
185
+ waitMs: opts.waitMs ?? 0,
186
+ ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}),
187
+ ...(opts.token !== undefined ? { token: opts.token } : {}),
188
+ }),
189
+ });
190
+ }
191
+ lockRelease(name, token) {
192
+ return this.http.req(`${P}/locks/${encodeURIComponent(name)}/release`, { method: 'POST', body: JSON.stringify({ token }) });
193
+ }
194
+ lockExtend(name, token, opts = {}) {
195
+ return this.http.req(`${P}/locks/${encodeURIComponent(name)}/extend`, {
196
+ method: 'POST',
197
+ body: JSON.stringify({ token, ...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}) }),
198
+ });
199
+ }
200
+ }
201
+ exports.FaststoreService = FaststoreService;