@synthigy/sdk 0.2.1 → 0.2.2

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 CHANGED
@@ -60,7 +60,9 @@ Run it with `synthigy exec -- node hello.ts`.
60
60
  `watchSqlTemplate` for live analytics, `watch` for raw record events.
61
61
 
62
62
  - **`actingAs` per call.** Every read and write can run as a specific user, with
63
- IAM / RBAC / row-level security enforced *server-side*. Tokens never have to
63
+ IAM / RBAC / row-level security enforced *server-side*; `whoami({ actingAs })`
64
+ shows who a call runs as — roles, superuser, whether this client may act as
65
+ users. Tokens never have to
64
66
  reach the browser. `client.login` runs the OIDC authorization-code + PKCE
65
67
  exchange for your BFF and leaves sessions to you; `createBrowserLogin` does
66
68
  the same for a browser app, as a public client with silent renew and tokens
@@ -2,7 +2,6 @@
2
2
  // Unified codegen tool:
3
3
  // node codegen.mjs <xsql...> [outDir] — describe + gen TS (saves ops.ir.json)
4
4
  // node codegen.mjs check <xsql...> — re-describe, diff, exit 1 on drift
5
- // node codegen.mjs pull [endpoint] [out] — pull schema.json (wraps pull.mjs)
6
5
  //
7
6
  // Config via env: SYNTHIGY_ENDPOINT, SYNTHIGY_CLIENT_ID, SYNTHIGY_CLIENT_SECRET
8
7
 
@@ -29,10 +28,9 @@ synthigy-codegen — generate TypeScript types from XSQL operations
29
28
  Usage:
30
29
  codegen.mjs [flags] <a.xsql> [b.xsql ...] [outDir] generate TS from one or more xsql files
31
30
  codegen.mjs check [flags] <a.xsql> [b.xsql ...] re-describe, diff IR, exit 1 on drift
32
- codegen.mjs pull [endpoint] [out] pull schema.json only
33
31
 
34
32
  Flags:
35
- --pull force schema refresh before generating
33
+ --pull refresh schema.json beside the .xsql before generating
36
34
  --keys snake|camel field key casing in generated types (default: snake)
37
35
  --no-writes omit sync / stack / delete methods
38
36
  --schema <path> explicit schema.json path (skips auto-pull)
@@ -47,7 +45,6 @@ Examples:
47
45
  node codegen.mjs movies.xsql src/generated/ first run auto-pulls schema
48
46
  node codegen.mjs --pull movies.xsql src/generated/ force schema refresh + generate
49
47
  node codegen.mjs check movies.xsql CI drift check
50
- node codegen.mjs pull http://localhost:7887 pull schema only
51
48
  `.trim())
52
49
  process.exit(0)
53
50
  }
@@ -71,13 +68,6 @@ if (!VALID_KEYS.has(flags.keys)) {
71
68
  }
72
69
 
73
70
  const checkMode = pos[0] === 'check'
74
- const pullMode = pos[0] === 'pull'
75
-
76
- if (pullMode) {
77
- execFileSync(process.execPath, [path.join(here, 'pull.mjs'), ...pos.slice(1)],
78
- { stdio: 'inherit', env: process.env })
79
- process.exit(0)
80
- }
81
71
 
82
72
  // Positionals: last non-.xsql arg is outDir; everything before it (files or dirs)
83
73
  // is input. check mode has no outDir — every positional is input.
@@ -90,7 +80,6 @@ const xsqlArgs = hasExplicitOut ? rawPos.slice(0, -1) : rawPos
90
80
  if (!xsqlArgs.length) {
91
81
  console.error('usage: node codegen.mjs [flags] <file.xsql|dir> [...] [outDir] (dirs searched recursively)')
92
82
  console.error(' node codegen.mjs check <file.xsql|dir> [...]')
93
- console.error(' node codegen.mjs pull [endpoint] [schema.json]')
94
83
  console.error('flags: --pull force schema refresh')
95
84
  console.error(' --keys snake|camel field casing (default: snake)')
96
85
  console.error(' --no-writes omit sync/stack/delete methods')
@@ -99,6 +88,8 @@ if (!xsqlArgs.length) {
99
88
  }
100
89
 
101
90
  const isDir = p => fs.existsSync(p) && fs.statSync(p).isDirectory()
91
+ const missing = xsqlArgs.filter(a => !fs.existsSync(path.resolve(a)))
92
+ if (missing.length) { console.error(`no such .xsql file or directory: ${missing.join(', ')}`); process.exit(1) }
102
93
  const xsqlPaths = xsqlArgs.flatMap(a => {
103
94
  const p = path.resolve(a)
104
95
  if (isDir(p))
package/codegen/pull.mjs CHANGED
@@ -21,8 +21,9 @@ import path from 'node:path'
21
21
  import { createClient } from '../src/index.js'
22
22
 
23
23
  const endpoint = process.argv[2] ?? process.env.SYNTHIGY_ENDPOINT
24
- if (!endpoint) {
25
- console.error('usage: node pull.mjs <endpoint> (or set SYNTHIGY_ENDPOINT)')
24
+ const out = process.argv[3]
25
+ if (!endpoint || !out) {
26
+ console.error('usage: node pull.mjs <endpoint> <schema.json>')
26
27
  process.exit(1)
27
28
  }
28
29
 
@@ -41,8 +42,7 @@ if (SYNTHIGY_CLIENT_ID && SYNTHIGY_CLIENT_SECRET) {
41
42
  config.token = SYNTHIGY_TOKEN ?? '' // '' = authless (bare server)
42
43
  }
43
44
 
44
- const here = path.dirname(new URL(import.meta.url).pathname)
45
- const outPath = process.argv[3] ? path.resolve(process.argv[3]) : path.join(here, 'schema.json')
45
+ const outPath = path.resolve(out)
46
46
 
47
47
  const client = createClient(config)
48
48
  const schema = await client.schema()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synthigy/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Zero-dependency client for Synthigy's /data endpoint",
5
5
  "author": "Robert Geršak",
6
6
  "license": "MIT",
package/src/index.d.ts CHANGED
@@ -324,11 +324,50 @@ export type SynthigyErrorCode =
324
324
  | 'HTTP_ERROR' | 'OPERATION_ERROR' | 'INTERNAL_ERROR'
325
325
  | (string & {})
326
326
 
327
+ /** `whoami()` — the identity a call runs as. `client` is null in-process (no OAuth client). */
328
+ export interface WhoAmI {
329
+ xid: string | null
330
+ name: string | null
331
+ active: boolean
332
+ superuser: boolean
333
+ roles: string[]
334
+ groups: string[]
335
+ /** `trusted`: this client may act as users (confidential, active, flagged trusted). */
336
+ client: { id: string; trusted: boolean } | null
337
+ }
338
+
339
+ export type SynthigyErrorCategory =
340
+ | 'auth' | 'iam' | 'validation' | 'not_found'
341
+ | 'conflict' | 'rate_limit' | 'network' | 'internal'
342
+
343
+ /** 1-based source position (XSQL_PARSE_ERROR, TEMPLATE_*). */
344
+ export interface SourcePosition { line: number; col: number }
345
+
327
346
  export class SynthigyError extends Error {
328
347
  name: 'SynthigyError'
329
348
  code: SynthigyErrorCode
349
+ category: SynthigyErrorCategory
350
+ /** True for known network/rate_limit/internal codes, or when the server marked the error retryable. */
351
+ retryable: boolean
330
352
  details?: unknown
331
- constructor(message: string, code: string, details?: unknown)
353
+ hint?: string
354
+ available?: string[]
355
+ path?: unknown
356
+ entity?: string
357
+ relation?: string
358
+ operator?: string
359
+ requestId?: string
360
+ status?: number
361
+ line?: number
362
+ col?: number
363
+ start?: SourcePosition
364
+ end?: SourcePosition
365
+ diagnostics?: unknown[]
366
+ constructor(message: string, code: string, details?: unknown, extras?: {
367
+ hint?: string; available?: string[]; path?: unknown; entity?: string; relation?: string
368
+ operator?: string; requestId?: string; status?: number; retryable?: boolean
369
+ line?: number; col?: number; start?: SourcePosition; end?: SourcePosition; diagnostics?: unknown[]
370
+ })
332
371
  }
333
372
 
334
373
  // ============================================================================
@@ -789,6 +828,9 @@ export class SynthigyClient {
789
828
  */
790
829
  deployedModel(opts?: ExecOpts): Promise<Record<string, unknown>>
791
830
 
831
+ /** Who a call runs as, after `actingAs` — roles, superuser, and whether this client may act as users. */
832
+ whoami(opts?: ExecOpts): Promise<WhoAmI>
833
+
792
834
  /**
793
835
  * Deploy a dataset version from a modeler export — pass the export file's
794
836
  * contents verbatim, the server decodes it. Requires `dataset:deploy`.
@@ -1210,6 +1252,7 @@ export const op: {
1210
1252
  query(xsql: string, params?: Record<string, unknown>, verb?: string): Operation
1211
1253
  deployedModel(): Operation
1212
1254
  runtimeModel(): Operation
1255
+ whoami(): Operation
1213
1256
  deploy(exportContents: string): Operation
1214
1257
  destroy(datasetXid: string): Operation
1215
1258
  }
@@ -1291,6 +1334,7 @@ export const onboardComplete: SynthigyClient['onboardComplete']
1291
1334
  export const deploy: SynthigyClient['deploy']
1292
1335
  export const destroy: SynthigyClient['destroy']
1293
1336
  export const deployedModel: SynthigyClient['deployedModel']
1337
+ export const whoami: SynthigyClient['whoami']
1294
1338
  export const runtimeModel: SynthigyClient['runtimeModel']
1295
1339
  export const token: SynthigyClient['token']
1296
1340
  export function history(): SynthigyClient['history']
package/src/index.js CHANGED
@@ -2003,6 +2003,19 @@ class SynthigyClient {
2003
2003
  return result.data
2004
2004
  }
2005
2005
 
2006
+ /**
2007
+ * Who a call runs as, after `actingAs`: xid, name, active, superuser, roles,
2008
+ * groups, and `client` ({ id, trusted }) — trusted means it may act as users.
2009
+ *
2010
+ * @param {Object} [opts] - Options ({ actingAs })
2011
+ * @returns {Promise<Object>}
2012
+ */
2013
+ async whoami(opts) {
2014
+ const [result] = await this.exec([{ op: 'whoami' }], opts)
2015
+ if (!result.ok) throw _errorFromServer(result.error, undefined, result._requestId)
2016
+ return result.data
2017
+ }
2018
+
2006
2019
  /**
2007
2020
  * Deploy a dataset version from a modeler export. Pass the export file's
2008
2021
  * contents verbatim — the server decodes it. Requires `dataset:deploy`.
@@ -2561,6 +2574,7 @@ export const op = {
2561
2574
  query: (xsql, params, verb = 'search') => ({ op: 'xsql', xsql: xsqlDocument(xsql, verb), ...(params !== undefined && { params }) }),
2562
2575
  deployedModel: () => ({ op: 'deployed-model' }),
2563
2576
  runtimeModel: () => ({ op: 'runtime-model' }),
2577
+ whoami: () => ({ op: 'whoami' }),
2564
2578
  deploy: (exportContents) => ({ op: 'deploy', data: exportContents }),
2565
2579
  destroy: (datasetXid) => ({ op: 'delete', entity: 'dataset', data: { xid: datasetXid } }),
2566
2580
  }
@@ -2692,6 +2706,7 @@ export const onboardComplete = (...a) => _dflt().onboardComplete(...a)
2692
2706
  export const deploy = (...a) => _dflt().deploy(...a)
2693
2707
  export const destroy = (...a) => _dflt().destroy(...a)
2694
2708
  export const deployedModel = (...a) => _dflt().deployedModel(...a)
2709
+ export const whoami = (...a) => _dflt().whoami(...a)
2695
2710
  export const runtimeModel = (...a) => _dflt().runtimeModel(...a)
2696
2711
  export const token = (...a) => _dflt().token(...a)
2697
2712
  export const history = () => _dflt().history