@synap-core/sdk 0.1.0 → 1.0.0
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/README.md +40 -140
- package/dist/index.cjs +115 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +80 -0
- package/dist/index.d.ts +72 -29
- package/dist/index.js +80 -33
- package/dist/index.js.map +1 -1
- package/package.json +28 -24
- package/src/client.ts +193 -0
- package/src/index.ts +2 -0
- package/dist/client.d.ts +0 -67
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -58
- package/dist/client.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/resources/entities.d.ts +0 -141
- package/dist/resources/entities.d.ts.map +0 -1
- package/dist/resources/entities.js +0 -126
- package/dist/resources/entities.js.map +0 -1
- package/dist/resources/events.d.ts +0 -51
- package/dist/resources/events.d.ts.map +0 -1
- package/dist/resources/events.js +0 -92
- package/dist/resources/events.js.map +0 -1
- package/dist/resources/relations.d.ts +0 -71
- package/dist/resources/relations.d.ts.map +0 -1
- package/dist/resources/relations.js +0 -121
- package/dist/resources/relations.js.map +0 -1
- package/dist/types/events.d.ts +0 -24
- package/dist/types/events.d.ts.map +0 -1
- package/dist/types/events.js +0 -5
- package/dist/types/events.js.map +0 -1
- package/dist/types/relations.d.ts +0 -26
- package/dist/types/relations.d.ts.map +0 -1
- package/dist/types/relations.js +0 -5
- package/dist/types/relations.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["/**\n * @synap-core/sdk — Type-safe tRPC client for Synap data pods.\n *\n * Usage:\n * ```typescript\n * import { createSynapClient } from \"@synap-core/sdk\";\n *\n * const synap = createSynapClient({\n * podUrl: \"https://pod.example.com\",\n * apiKey: \"sk_live_...\",\n * workspaceId: \"ws_...\",\n * });\n *\n * // Fully typed — autocomplete works on all 47+ routers\n * const entities = await synap.entities.list.query({ limit: 20 });\n * const workspace = await synap.workspaces.get.query();\n * ```\n */\n\nimport {\n createTRPCClient,\n httpBatchLink,\n type CreateTRPCClient,\n} from \"@trpc/client\";\nimport superjson from \"superjson\";\nimport type { AppRouter } from \"@synap-core/api-types\";\n\nexport interface SynapClientOptions {\n /**\n * Base URL of the data pod (no trailing slash, no `/trpc` suffix).\n * @example \"https://pod.example.com\"\n */\n podUrl: string;\n\n /**\n * Ory Kratos session token (for example, from the Pod's\n * `/api/federation/exchange` endpoint).\n * Sent as `X-Session-Token` header — preferred for non-browser clients\n * like extensions, CLI tools, and mobile apps.\n * @example \"oathkeeper_token_...\"\n */\n sessionToken?: string;\n\n /**\n * API key for authentication (Bearer token).\n * Generate one in your workspace developer settings.\n * If omitted, the client falls back to cookie-based Kratos session auth.\n * @example \"sk_live_abc123...\"\n */\n apiKey?: string;\n\n /**\n * Workspace ID to scope all requests to.\n * Pass empty string for procedures that don't require workspace context\n * (e.g. workspaces.list, which is protectedProcedure only).\n * @example \"ws_01jk...\"\n */\n workspaceId: string;\n\n /**\n * Additional headers to include in every request.\n */\n extraHeaders?: Record<string, string>;\n\n /**\n * Called when the pod returns a `401 Unauthorized` (expired/invalid session\n * or API key). The app should sign out and re-authenticate (re-handshake).\n *\n * The pod's auth middleware can reply with a plain-JSON body\n * (`{\"error\":\"Invalid session\"}`) that is NOT in tRPC batch format and would\n * otherwise crash the superjson transformer; when an `onAuthError` handler is\n * provided the client rewrites such responses into a well-formed tRPC error so\n * the query rejects gracefully instead of throwing a parse error.\n */\n onAuthError?: (error: { status: number; message: string }) => void;\n}\n\n/**\n * Creates a fully-typed tRPC client connected to a Synap data pod.\n *\n * All 47+ tRPC routers are available with full TypeScript autocomplete\n * and compile-time safety. Auth is handled via Bearer token + workspace header.\n */\nexport function createSynapClient(\n options: SynapClientOptions,\n): CreateTRPCClient<AppRouter> {\n const { podUrl, apiKey, workspaceId, extraHeaders, onAuthError } = options;\n\n const url = `${podUrl.replace(/\\/$/, \"\")}/trpc`;\n\n // Base fetch: always include credentials so session cookies are sent in\n // cookie-auth mode. When apiKey is present, the Bearer token takes precedence\n // on the pod.\n const baseFetch: typeof fetch = (input, init) =>\n fetch(input, { ...init, credentials: \"include\" });\n\n // When an onAuthError handler is provided, wrap fetch to catch 401 (and other\n // non-tRPC error) responses. The pod's auth middleware replies with a plain\n // JSON body that is not a tRPC batch array; left untouched it crashes the\n // superjson transformer. We notify the handler and rewrite the body into a\n // valid tRPC error envelope so the query rejects cleanly.\n const wrappedFetch: typeof fetch = onAuthError\n ? async (input, init) => {\n const response = await baseFetch(input, init);\n if (response.ok) return response;\n\n const cloned = response.clone();\n let body = \"\";\n try {\n body = await cloned.text();\n } catch {\n body = \"\";\n }\n\n let isTrpcFormat = false;\n try {\n isTrpcFormat = Array.isArray(JSON.parse(body));\n } catch {\n isTrpcFormat = false;\n }\n if (isTrpcFormat) return response;\n\n const parsedMessage = (() => {\n try {\n const parsed = JSON.parse(body) as {\n error?: string;\n message?: string;\n };\n return parsed.error ?? parsed.message ?? null;\n } catch {\n return null;\n }\n })();\n // Never forward a server-controlled string as user-facing copy — map by\n // status. The raw server detail is preserved (untrusted) on `data.detail`.\n const message =\n response.status === 401\n ? \"Session expired. Please sign in again.\"\n : `Request failed (${response.status}).`;\n\n if (response.status === 401) {\n onAuthError({ status: 401, message });\n }\n\n const trpcError = [\n {\n error: {\n message,\n code: response.status === 401 ? -32001 : -32000,\n data: {\n code:\n response.status === 401\n ? \"UNAUTHORIZED\"\n : \"INTERNAL_SERVER_ERROR\",\n httpStatus: response.status,\n // Server-supplied detail — untrusted; consumers must escape it\n // before rendering (never inject as HTML).\n detail: parsedMessage ?? undefined,\n },\n\n },\n },\n ];\n return new Response(JSON.stringify(trpcError), {\n status: response.status,\n headers: { \"content-type\": \"application/json\" },\n });\n }\n : baseFetch;\n\n return createTRPCClient<AppRouter>({\n links: [\n httpBatchLink({\n url,\n transformer: superjson,\n fetch: wrappedFetch,\n headers: () => ({\n // Session token mode (Kratos, preferred for non-browser clients)\n ...(options.sessionToken ? { \"x-session-token\": options.sessionToken } : {}),\n // API key mode (Bearer, for legacy SDK usage)\n ...(apiKey && !options.sessionToken ? { Authorization: `Bearer ${apiKey}` } : {}),\n ...(workspaceId ? { \"x-workspace-id\": workspaceId } : {}),\n ...extraHeaders,\n }),\n }),\n ],\n });\n}\n\nexport type SynapClient = ReturnType<typeof createSynapClient>;\n\n// Re-export type helpers so consumers don't need @trpc/server\nexport type { AppRouter };\n"],"mappings":";AAmBA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,OAAO,eAAe;AA2Df,SAAS,kBACd,SAC6B;AAC7B,QAAM,EAAE,QAAQ,QAAQ,aAAa,cAAc,YAAY,IAAI;AAEnE,QAAM,MAAM,GAAG,OAAO,QAAQ,OAAO,EAAE,CAAC;AAKxC,QAAM,YAA0B,CAAC,OAAO,SACtC,MAAM,OAAO,EAAE,GAAG,MAAM,aAAa,UAAU,CAAC;AAOlD,QAAM,eAA6B,cAC/B,OAAO,OAAO,SAAS;AACrB,UAAM,WAAW,MAAM,UAAU,OAAO,IAAI;AAC5C,QAAI,SAAS,GAAI,QAAO;AAExB,UAAM,SAAS,SAAS,MAAM;AAC9B,QAAI,OAAO;AACX,QAAI;AACF,aAAO,MAAM,OAAO,KAAK;AAAA,IAC3B,QAAQ;AACN,aAAO;AAAA,IACT;AAEA,QAAI,eAAe;AACnB,QAAI;AACF,qBAAe,MAAM,QAAQ,KAAK,MAAM,IAAI,CAAC;AAAA,IAC/C,QAAQ;AACN,qBAAe;AAAA,IACjB;AACA,QAAI,aAAc,QAAO;AAEzB,UAAM,iBAAiB,MAAM;AAC3B,UAAI;AACF,cAAM,SAAS,KAAK,MAAM,IAAI;AAI9B,eAAO,OAAO,SAAS,OAAO,WAAW;AAAA,MAC3C,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,GAAG;AAGH,UAAM,UACJ,SAAS,WAAW,MAChB,2CACA,mBAAmB,SAAS,MAAM;AAExC,QAAI,SAAS,WAAW,KAAK;AAC3B,kBAAY,EAAE,QAAQ,KAAK,QAAQ,CAAC;AAAA,IACtC;AAEA,UAAM,YAAY;AAAA,MAChB;AAAA,QACE,OAAO;AAAA,UACL;AAAA,UACA,MAAM,SAAS,WAAW,MAAM,SAAS;AAAA,UACzC,MAAM;AAAA,YACJ,MACE,SAAS,WAAW,MAChB,iBACA;AAAA,YACN,YAAY,SAAS;AAAA;AAAA;AAAA,YAGrB,QAAQ,iBAAiB;AAAA,UAC3B;AAAA,QAEF;AAAA,MACF;AAAA,IACF;AACA,WAAO,IAAI,SAAS,KAAK,UAAU,SAAS,GAAG;AAAA,MAC7C,QAAQ,SAAS;AAAA,MACjB,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAChD,CAAC;AAAA,EACH,IACA;AAEJ,SAAO,iBAA4B;AAAA,IACjC,OAAO;AAAA,MACL,cAAc;AAAA,QACZ;AAAA,QACA,aAAa;AAAA,QACb,OAAO;AAAA,QACP,SAAS,OAAO;AAAA;AAAA,UAEd,GAAI,QAAQ,eAAe,EAAE,mBAAmB,QAAQ,aAAa,IAAI,CAAC;AAAA;AAAA,UAE1E,GAAI,UAAU,CAAC,QAAQ,eAAe,EAAE,eAAe,UAAU,MAAM,GAAG,IAAI,CAAC;AAAA,UAC/E,GAAI,cAAc,EAAE,kBAAkB,YAAY,IAAI,CAAC;AAAA,UACvD,GAAG;AAAA,QACL;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synap-core/sdk",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"access": "public"
|
|
6
|
-
},
|
|
7
|
-
"description": "High-level SDK for Synap - Event-sourced personal data platform",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Type-safe tRPC client SDK for Synap data pods",
|
|
8
5
|
"type": "module",
|
|
9
|
-
"main": "./dist/index.
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
10
7
|
"module": "./dist/index.js",
|
|
11
8
|
"types": "./dist/index.d.ts",
|
|
12
9
|
"exports": {
|
|
@@ -16,37 +13,44 @@
|
|
|
16
13
|
"require": "./dist/index.cjs"
|
|
17
14
|
}
|
|
18
15
|
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
19
|
+
],
|
|
19
20
|
"keywords": [
|
|
20
21
|
"synap",
|
|
21
22
|
"sdk",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"knowledge-graph"
|
|
23
|
+
"trpc",
|
|
24
|
+
"data-pod"
|
|
25
25
|
],
|
|
26
|
-
"author": "Synap Team",
|
|
27
|
-
"license": "AGPL-3.0",
|
|
28
26
|
"dependencies": {
|
|
29
|
-
"@synap-core/
|
|
30
|
-
"@
|
|
27
|
+
"@synap-core/api-types": "^1.23.3",
|
|
28
|
+
"@trpc/client": "^11.10.0",
|
|
29
|
+
"superjson": "^2.2.6"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
|
-
"
|
|
34
|
-
"typescript": "^5.
|
|
32
|
+
"tsup": "^8.3.5",
|
|
33
|
+
"typescript": "^5.7.3"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@trpc/server": "^11.0.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependenciesMeta": {
|
|
39
|
+
"@trpc/server": {
|
|
40
|
+
"optional": true
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
35
45
|
},
|
|
36
|
-
"files": [
|
|
37
|
-
"dist",
|
|
38
|
-
"README.md"
|
|
39
|
-
],
|
|
40
46
|
"repository": {
|
|
41
47
|
"type": "git",
|
|
42
|
-
"url": "https://github.com/synap
|
|
48
|
+
"url": "https://github.com/synap/synap-app.git",
|
|
43
49
|
"directory": "packages/sdk"
|
|
44
50
|
},
|
|
45
|
-
"
|
|
51
|
+
"license": "MIT",
|
|
46
52
|
"scripts": {
|
|
47
|
-
"build": "
|
|
48
|
-
"dev": "tsc -p tsconfig.json --watch",
|
|
49
|
-
"clean": "rm -rf dist",
|
|
53
|
+
"build": "tsup",
|
|
50
54
|
"typecheck": "tsc --noEmit"
|
|
51
55
|
}
|
|
52
56
|
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @synap-core/sdk — Type-safe tRPC client for Synap data pods.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* ```typescript
|
|
6
|
+
* import { createSynapClient } from "@synap-core/sdk";
|
|
7
|
+
*
|
|
8
|
+
* const synap = createSynapClient({
|
|
9
|
+
* podUrl: "https://pod.example.com",
|
|
10
|
+
* apiKey: "sk_live_...",
|
|
11
|
+
* workspaceId: "ws_...",
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* // Fully typed — autocomplete works on all 47+ routers
|
|
15
|
+
* const entities = await synap.entities.list.query({ limit: 20 });
|
|
16
|
+
* const workspace = await synap.workspaces.get.query();
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
createTRPCClient,
|
|
22
|
+
httpBatchLink,
|
|
23
|
+
type CreateTRPCClient,
|
|
24
|
+
} from "@trpc/client";
|
|
25
|
+
import superjson from "superjson";
|
|
26
|
+
import type { AppRouter } from "@synap-core/api-types";
|
|
27
|
+
|
|
28
|
+
export interface SynapClientOptions {
|
|
29
|
+
/**
|
|
30
|
+
* Base URL of the data pod (no trailing slash, no `/trpc` suffix).
|
|
31
|
+
* @example "https://pod.example.com"
|
|
32
|
+
*/
|
|
33
|
+
podUrl: string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Ory Kratos session token (for example, from the Pod's
|
|
37
|
+
* `/api/federation/exchange` endpoint).
|
|
38
|
+
* Sent as `X-Session-Token` header — preferred for non-browser clients
|
|
39
|
+
* like extensions, CLI tools, and mobile apps.
|
|
40
|
+
* @example "oathkeeper_token_..."
|
|
41
|
+
*/
|
|
42
|
+
sessionToken?: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* API key for authentication (Bearer token).
|
|
46
|
+
* Generate one in your workspace developer settings.
|
|
47
|
+
* If omitted, the client falls back to cookie-based Kratos session auth.
|
|
48
|
+
* @example "sk_live_abc123..."
|
|
49
|
+
*/
|
|
50
|
+
apiKey?: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Workspace ID to scope all requests to.
|
|
54
|
+
* Pass empty string for procedures that don't require workspace context
|
|
55
|
+
* (e.g. workspaces.list, which is protectedProcedure only).
|
|
56
|
+
* @example "ws_01jk..."
|
|
57
|
+
*/
|
|
58
|
+
workspaceId: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Additional headers to include in every request.
|
|
62
|
+
*/
|
|
63
|
+
extraHeaders?: Record<string, string>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Called when the pod returns a `401 Unauthorized` (expired/invalid session
|
|
67
|
+
* or API key). The app should sign out and re-authenticate (re-handshake).
|
|
68
|
+
*
|
|
69
|
+
* The pod's auth middleware can reply with a plain-JSON body
|
|
70
|
+
* (`{"error":"Invalid session"}`) that is NOT in tRPC batch format and would
|
|
71
|
+
* otherwise crash the superjson transformer; when an `onAuthError` handler is
|
|
72
|
+
* provided the client rewrites such responses into a well-formed tRPC error so
|
|
73
|
+
* the query rejects gracefully instead of throwing a parse error.
|
|
74
|
+
*/
|
|
75
|
+
onAuthError?: (error: { status: number; message: string }) => void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates a fully-typed tRPC client connected to a Synap data pod.
|
|
80
|
+
*
|
|
81
|
+
* All 47+ tRPC routers are available with full TypeScript autocomplete
|
|
82
|
+
* and compile-time safety. Auth is handled via Bearer token + workspace header.
|
|
83
|
+
*/
|
|
84
|
+
export function createSynapClient(
|
|
85
|
+
options: SynapClientOptions,
|
|
86
|
+
): CreateTRPCClient<AppRouter> {
|
|
87
|
+
const { podUrl, apiKey, workspaceId, extraHeaders, onAuthError } = options;
|
|
88
|
+
|
|
89
|
+
const url = `${podUrl.replace(/\/$/, "")}/trpc`;
|
|
90
|
+
|
|
91
|
+
// Base fetch: always include credentials so session cookies are sent in
|
|
92
|
+
// cookie-auth mode. When apiKey is present, the Bearer token takes precedence
|
|
93
|
+
// on the pod.
|
|
94
|
+
const baseFetch: typeof fetch = (input, init) =>
|
|
95
|
+
fetch(input, { ...init, credentials: "include" });
|
|
96
|
+
|
|
97
|
+
// When an onAuthError handler is provided, wrap fetch to catch 401 (and other
|
|
98
|
+
// non-tRPC error) responses. The pod's auth middleware replies with a plain
|
|
99
|
+
// JSON body that is not a tRPC batch array; left untouched it crashes the
|
|
100
|
+
// superjson transformer. We notify the handler and rewrite the body into a
|
|
101
|
+
// valid tRPC error envelope so the query rejects cleanly.
|
|
102
|
+
const wrappedFetch: typeof fetch = onAuthError
|
|
103
|
+
? async (input, init) => {
|
|
104
|
+
const response = await baseFetch(input, init);
|
|
105
|
+
if (response.ok) return response;
|
|
106
|
+
|
|
107
|
+
const cloned = response.clone();
|
|
108
|
+
let body = "";
|
|
109
|
+
try {
|
|
110
|
+
body = await cloned.text();
|
|
111
|
+
} catch {
|
|
112
|
+
body = "";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let isTrpcFormat = false;
|
|
116
|
+
try {
|
|
117
|
+
isTrpcFormat = Array.isArray(JSON.parse(body));
|
|
118
|
+
} catch {
|
|
119
|
+
isTrpcFormat = false;
|
|
120
|
+
}
|
|
121
|
+
if (isTrpcFormat) return response;
|
|
122
|
+
|
|
123
|
+
const parsedMessage = (() => {
|
|
124
|
+
try {
|
|
125
|
+
const parsed = JSON.parse(body) as {
|
|
126
|
+
error?: string;
|
|
127
|
+
message?: string;
|
|
128
|
+
};
|
|
129
|
+
return parsed.error ?? parsed.message ?? null;
|
|
130
|
+
} catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
})();
|
|
134
|
+
// Never forward a server-controlled string as user-facing copy — map by
|
|
135
|
+
// status. The raw server detail is preserved (untrusted) on `data.detail`.
|
|
136
|
+
const message =
|
|
137
|
+
response.status === 401
|
|
138
|
+
? "Session expired. Please sign in again."
|
|
139
|
+
: `Request failed (${response.status}).`;
|
|
140
|
+
|
|
141
|
+
if (response.status === 401) {
|
|
142
|
+
onAuthError({ status: 401, message });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const trpcError = [
|
|
146
|
+
{
|
|
147
|
+
error: {
|
|
148
|
+
message,
|
|
149
|
+
code: response.status === 401 ? -32001 : -32000,
|
|
150
|
+
data: {
|
|
151
|
+
code:
|
|
152
|
+
response.status === 401
|
|
153
|
+
? "UNAUTHORIZED"
|
|
154
|
+
: "INTERNAL_SERVER_ERROR",
|
|
155
|
+
httpStatus: response.status,
|
|
156
|
+
// Server-supplied detail — untrusted; consumers must escape it
|
|
157
|
+
// before rendering (never inject as HTML).
|
|
158
|
+
detail: parsedMessage ?? undefined,
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
return new Response(JSON.stringify(trpcError), {
|
|
165
|
+
status: response.status,
|
|
166
|
+
headers: { "content-type": "application/json" },
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
: baseFetch;
|
|
170
|
+
|
|
171
|
+
return createTRPCClient<AppRouter>({
|
|
172
|
+
links: [
|
|
173
|
+
httpBatchLink({
|
|
174
|
+
url,
|
|
175
|
+
transformer: superjson,
|
|
176
|
+
fetch: wrappedFetch,
|
|
177
|
+
headers: () => ({
|
|
178
|
+
// Session token mode (Kratos, preferred for non-browser clients)
|
|
179
|
+
...(options.sessionToken ? { "x-session-token": options.sessionToken } : {}),
|
|
180
|
+
// API key mode (Bearer, for legacy SDK usage)
|
|
181
|
+
...(apiKey && !options.sessionToken ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
182
|
+
...(workspaceId ? { "x-workspace-id": workspaceId } : {}),
|
|
183
|
+
...extraHeaders,
|
|
184
|
+
}),
|
|
185
|
+
}),
|
|
186
|
+
],
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export type SynapClient = ReturnType<typeof createSynapClient>;
|
|
191
|
+
|
|
192
|
+
// Re-export type helpers so consumers don't need @trpc/server
|
|
193
|
+
export type { AppRouter };
|
package/src/index.ts
ADDED
package/dist/client.d.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SynapSDK - Main SDK Client
|
|
3
|
-
*
|
|
4
|
-
* Provides high-level APIs for interacting with Synap Data Pod.
|
|
5
|
-
* All mutations go through event sourcing, all queries are direct reads.
|
|
6
|
-
*/
|
|
7
|
-
import { type SynapClient as TRPCClient } from '@synap/client';
|
|
8
|
-
import { EntitiesAPI } from './resources/entities.js';
|
|
9
|
-
import { RelationsAPI } from './resources/relations.js';
|
|
10
|
-
import { EventsAPI } from './resources/events.js';
|
|
11
|
-
/**
|
|
12
|
-
* SDK Configuration
|
|
13
|
-
*/
|
|
14
|
-
export interface SynapSDKConfig {
|
|
15
|
-
/**
|
|
16
|
-
* Base URL for the Synap API
|
|
17
|
-
* @example 'https://api.synap.app' or 'http://localhost:3000'
|
|
18
|
-
*/
|
|
19
|
-
url: string;
|
|
20
|
-
/**
|
|
21
|
-
* API key or authentication token
|
|
22
|
-
* Either provide apiKey OR headers function
|
|
23
|
-
*/
|
|
24
|
-
apiKey?: string;
|
|
25
|
-
/**
|
|
26
|
-
* Custom headers function for dynamic authentication
|
|
27
|
-
* @example () => ({ Authorization: `Bearer ${getToken()}` })
|
|
28
|
-
*/
|
|
29
|
-
headers?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
30
|
-
/**
|
|
31
|
-
* Custom fetch implementation (for React Native, etc.)
|
|
32
|
-
*/
|
|
33
|
-
fetch?: typeof globalThis.fetch;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Synap SDK - High-Level Client
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```typescript
|
|
40
|
-
* const synap = new SynapSDK({
|
|
41
|
-
* url: 'https://api.synap.app',
|
|
42
|
-
* apiKey: 'sk_...'
|
|
43
|
-
* });
|
|
44
|
-
*
|
|
45
|
-
* // Use resource APIs
|
|
46
|
-
* const task = await synap.entities.create({ type: 'task', title: 'Call Marie' });
|
|
47
|
-
* await synap.relations.create(task.id, personId, 'assigned_to');
|
|
48
|
-
* const history = await synap.events.getHistory(task.id);
|
|
49
|
-
* ```
|
|
50
|
-
*/
|
|
51
|
-
export declare class SynapSDK {
|
|
52
|
-
/** Internal tRPC client */
|
|
53
|
-
private readonly trpc;
|
|
54
|
-
/** Entities API - Generic entity operations */
|
|
55
|
-
readonly entities: EntitiesAPI;
|
|
56
|
-
/** Relations API - Relationship management */
|
|
57
|
-
readonly relations: RelationsAPI;
|
|
58
|
-
/** Events API - Event history and replay */
|
|
59
|
-
readonly events: EventsAPI;
|
|
60
|
-
constructor(config: SynapSDKConfig);
|
|
61
|
-
/**
|
|
62
|
-
* Get direct access to underlying tRPC client
|
|
63
|
-
* Use this for advanced operations not covered by SDK APIs
|
|
64
|
-
*/
|
|
65
|
-
get client(): TRPCClient;
|
|
66
|
-
}
|
|
67
|
-
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAqB,KAAK,WAAW,IAAI,UAAU,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAEzE;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,QAAQ;IACnB,2BAA2B;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAElC,+CAA+C;IAC/C,SAAgB,QAAQ,EAAE,WAAW,CAAC;IAEtC,8CAA8C;IAC9C,SAAgB,SAAS,EAAE,YAAY,CAAC;IAExC,4CAA4C;IAC5C,SAAgB,MAAM,EAAE,SAAS,CAAC;gBAEtB,MAAM,EAAE,cAAc;IAgBlC;;;OAGG;IACH,IAAI,MAAM,IAAI,UAAU,CAEvB;CACF"}
|
package/dist/client.js
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SynapSDK - Main SDK Client
|
|
3
|
-
*
|
|
4
|
-
* Provides high-level APIs for interacting with Synap Data Pod.
|
|
5
|
-
* All mutations go through event sourcing, all queries are direct reads.
|
|
6
|
-
*/
|
|
7
|
-
import { createSynapClient } from '@synap/client';
|
|
8
|
-
import { EntitiesAPI } from './resources/entities.js';
|
|
9
|
-
import { RelationsAPI } from './resources/relations.js';
|
|
10
|
-
import { EventsAPI } from './resources/events.js';
|
|
11
|
-
/**
|
|
12
|
-
* Synap SDK - High-Level Client
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```typescript
|
|
16
|
-
* const synap = new SynapSDK({
|
|
17
|
-
* url: 'https://api.synap.app',
|
|
18
|
-
* apiKey: 'sk_...'
|
|
19
|
-
* });
|
|
20
|
-
*
|
|
21
|
-
* // Use resource APIs
|
|
22
|
-
* const task = await synap.entities.create({ type: 'task', title: 'Call Marie' });
|
|
23
|
-
* await synap.relations.create(task.id, personId, 'assigned_to');
|
|
24
|
-
* const history = await synap.events.getHistory(task.id);
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
export class SynapSDK {
|
|
28
|
-
/** Internal tRPC client */
|
|
29
|
-
trpc;
|
|
30
|
-
/** Entities API - Generic entity operations */
|
|
31
|
-
entities;
|
|
32
|
-
/** Relations API - Relationship management */
|
|
33
|
-
relations;
|
|
34
|
-
/** Events API - Event history and replay */
|
|
35
|
-
events;
|
|
36
|
-
constructor(config) {
|
|
37
|
-
// Create underlying tRPC client
|
|
38
|
-
this.trpc = createSynapClient({
|
|
39
|
-
url: config.url,
|
|
40
|
-
headers: config.apiKey
|
|
41
|
-
? { Authorization: `Bearer ${config.apiKey}` }
|
|
42
|
-
: config.headers,
|
|
43
|
-
fetch: config.fetch,
|
|
44
|
-
});
|
|
45
|
-
// Initialize resource APIs
|
|
46
|
-
this.entities = new EntitiesAPI(this.trpc);
|
|
47
|
-
this.relations = new RelationsAPI(this.trpc);
|
|
48
|
-
this.events = new EventsAPI(this.trpc);
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Get direct access to underlying tRPC client
|
|
52
|
-
* Use this for advanced operations not covered by SDK APIs
|
|
53
|
-
*/
|
|
54
|
-
get client() {
|
|
55
|
-
return this.trpc;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAkC,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AA8BlD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,QAAQ;IACnB,2BAA2B;IACV,IAAI,CAAa;IAElC,+CAA+C;IAC/B,QAAQ,CAAc;IAEtC,8CAA8C;IAC9B,SAAS,CAAe;IAExC,4CAA4C;IAC5B,MAAM,CAAY;IAElC,YAAY,MAAsB;QAChC,gCAAgC;QAChC,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;YAC5B,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,OAAO,EAAE,MAAM,CAAC,MAAM;gBACpB,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE,EAAE;gBAC9C,CAAC,CAAC,MAAM,CAAC,OAAO;YAClB,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC,CAAC;QAEH,2BAA2B;QAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,SAAS,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAED;;;OAGG;IACH,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;CACF"}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,YAAY,EACV,UAAU,EACV,cAAc,EACd,MAAM,EACN,SAAS,EACT,YAAY,GACb,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,QAAQ,EACR,YAAY,GACb,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EACV,KAAK,EACL,WAAW,GACZ,MAAM,mBAAmB,CAAC"}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Entities API - Generic Entity Operations
|
|
3
|
-
*
|
|
4
|
-
* ALL MUTATIONS are event-sourced (go through events.log)
|
|
5
|
-
* ALL QUERIES are direct reads (fast)
|
|
6
|
-
*/
|
|
7
|
-
import type { SynapClient } from '@synap/client';
|
|
8
|
-
import type { EntityType } from '@synap/types/entities';
|
|
9
|
-
export interface CreateEntityInput<T extends EntityType = EntityType> {
|
|
10
|
-
type: T;
|
|
11
|
-
title: string;
|
|
12
|
-
preview?: string;
|
|
13
|
-
content?: string;
|
|
14
|
-
metadata?: Record<string, unknown>;
|
|
15
|
-
}
|
|
16
|
-
export interface UpdateEntityInput {
|
|
17
|
-
title?: string;
|
|
18
|
-
preview?: string;
|
|
19
|
-
content?: string;
|
|
20
|
-
metadata?: Record<string, unknown>;
|
|
21
|
-
}
|
|
22
|
-
export interface ListEntitiesOptions {
|
|
23
|
-
type?: EntityType;
|
|
24
|
-
limit?: number;
|
|
25
|
-
}
|
|
26
|
-
export interface SearchOptions {
|
|
27
|
-
query: string;
|
|
28
|
-
types?: EntityType[];
|
|
29
|
-
limit?: number;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Entities API
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```typescript
|
|
36
|
-
* // Create task (event-sourced)
|
|
37
|
-
* const task = await sdk.entities.create({
|
|
38
|
-
* type: 'task',
|
|
39
|
-
* title: 'Call Marie',
|
|
40
|
-
* metadata: { dueDate: '2024-12-20', priority: 'high' }
|
|
41
|
-
* });
|
|
42
|
-
*
|
|
43
|
-
* // Get entity (direct read)
|
|
44
|
-
* const entity = await sdk.entities.get(task.id);
|
|
45
|
-
*
|
|
46
|
-
* // List entities (direct read)
|
|
47
|
-
* const tasks = await sdk.entities.list({ type: 'task' });
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
|
-
export declare class EntitiesAPI {
|
|
51
|
-
private readonly client;
|
|
52
|
-
constructor(client: SynapClient);
|
|
53
|
-
/**
|
|
54
|
-
* Create entity (event-sourced)
|
|
55
|
-
*
|
|
56
|
-
* Publishes `entities.create.requested` event → entitiesWorker → DB
|
|
57
|
-
*/
|
|
58
|
-
create<T extends EntityType>(input: CreateEntityInput<T>): Promise<{
|
|
59
|
-
entityId: string;
|
|
60
|
-
}>;
|
|
61
|
-
/**
|
|
62
|
-
* Update entity (event-sourced)
|
|
63
|
-
*
|
|
64
|
-
* Publishes `entities.update.requested` event → entitiesWorker → DB
|
|
65
|
-
*/
|
|
66
|
-
update(id: string, input: UpdateEntityInput): Promise<{
|
|
67
|
-
success: boolean;
|
|
68
|
-
}>;
|
|
69
|
-
/**
|
|
70
|
-
* Delete entity (event-sourced soft delete)
|
|
71
|
-
*
|
|
72
|
-
* Publishes `entities.delete.requested` event → entitiesWorker → DB
|
|
73
|
-
*/
|
|
74
|
-
delete(id: string): Promise<{
|
|
75
|
-
success: boolean;
|
|
76
|
-
}>;
|
|
77
|
-
/**
|
|
78
|
-
* Get entity by ID (direct read)
|
|
79
|
-
*/
|
|
80
|
-
get(id: string): Promise<{
|
|
81
|
-
type: string;
|
|
82
|
-
userId: string;
|
|
83
|
-
version: number;
|
|
84
|
-
id: string;
|
|
85
|
-
title: string | null;
|
|
86
|
-
preview: string | null;
|
|
87
|
-
documentId: string | null;
|
|
88
|
-
fileUrl: string | null;
|
|
89
|
-
filePath: string | null;
|
|
90
|
-
fileSize: number | null;
|
|
91
|
-
fileType: string | null;
|
|
92
|
-
checksum: string | null;
|
|
93
|
-
createdAt: string;
|
|
94
|
-
updatedAt: string;
|
|
95
|
-
deletedAt: string | null;
|
|
96
|
-
metadata?: unknown;
|
|
97
|
-
}>;
|
|
98
|
-
/**
|
|
99
|
-
* List entities (direct read)
|
|
100
|
-
*/
|
|
101
|
-
list(options?: ListEntitiesOptions): Promise<{
|
|
102
|
-
type: string;
|
|
103
|
-
userId: string;
|
|
104
|
-
version: number;
|
|
105
|
-
id: string;
|
|
106
|
-
title: string | null;
|
|
107
|
-
preview: string | null;
|
|
108
|
-
documentId: string | null;
|
|
109
|
-
fileUrl: string | null;
|
|
110
|
-
filePath: string | null;
|
|
111
|
-
fileSize: number | null;
|
|
112
|
-
fileType: string | null;
|
|
113
|
-
checksum: string | null;
|
|
114
|
-
createdAt: string;
|
|
115
|
-
updatedAt: string;
|
|
116
|
-
deletedAt: string | null;
|
|
117
|
-
metadata?: unknown;
|
|
118
|
-
}[]>;
|
|
119
|
-
/**
|
|
120
|
-
* Search entities (direct read)
|
|
121
|
-
*/
|
|
122
|
-
search(options: SearchOptions): Promise<{
|
|
123
|
-
type: string;
|
|
124
|
-
userId: string;
|
|
125
|
-
version: number;
|
|
126
|
-
id: string;
|
|
127
|
-
title: string | null;
|
|
128
|
-
preview: string | null;
|
|
129
|
-
documentId: string | null;
|
|
130
|
-
fileUrl: string | null;
|
|
131
|
-
filePath: string | null;
|
|
132
|
-
fileSize: number | null;
|
|
133
|
-
fileType: string | null;
|
|
134
|
-
checksum: string | null;
|
|
135
|
-
createdAt: string;
|
|
136
|
-
updatedAt: string;
|
|
137
|
-
deletedAt: string | null;
|
|
138
|
-
metadata?: unknown;
|
|
139
|
-
}[]>;
|
|
140
|
-
}
|
|
141
|
-
//# sourceMappingURL=entities.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../../src/resources/entities.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAGxD,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,UAAU,GAAG,UAAU;IAClE,IAAI,EAAE,CAAC,CAAC;IACR,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,WAAW;IAEhD;;;;OAIG;IACG,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAwB9F;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAiBjF;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAgBvD;;OAEG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;IAKpB;;OAEG;IACG,IAAI,CAAC,OAAO,GAAE,mBAAwB;;;;;;;;;;;;;;;;;;IAQ5C;;OAEG;IACG,MAAM,CAAC,OAAO,EAAE,aAAa;;;;;;;;;;;;;;;;;;CAQpC"}
|