@dashai/sdk 0.7.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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +377 -0
  3. package/dist/auth/client.cjs +185 -0
  4. package/dist/auth/client.cjs.map +1 -0
  5. package/dist/auth/client.d.cts +137 -0
  6. package/dist/auth/client.d.ts +137 -0
  7. package/dist/auth/client.js +175 -0
  8. package/dist/auth/client.js.map +1 -0
  9. package/dist/auth/middleware.cjs +352 -0
  10. package/dist/auth/middleware.cjs.map +1 -0
  11. package/dist/auth/middleware.d.cts +90 -0
  12. package/dist/auth/middleware.d.ts +90 -0
  13. package/dist/auth/middleware.js +343 -0
  14. package/dist/auth/middleware.js.map +1 -0
  15. package/dist/auth/server.cjs +445 -0
  16. package/dist/auth/server.cjs.map +1 -0
  17. package/dist/auth/server.d.cts +170 -0
  18. package/dist/auth/server.d.ts +170 -0
  19. package/dist/auth/server.js +432 -0
  20. package/dist/auth/server.js.map +1 -0
  21. package/dist/auth/types.cjs +31 -0
  22. package/dist/auth/types.cjs.map +1 -0
  23. package/dist/auth/types.d.cts +163 -0
  24. package/dist/auth/types.d.ts +163 -0
  25. package/dist/auth/types.js +29 -0
  26. package/dist/auth/types.js.map +1 -0
  27. package/dist/deps/index.cjs +117 -0
  28. package/dist/deps/index.cjs.map +1 -0
  29. package/dist/deps/index.d.cts +93 -0
  30. package/dist/deps/index.d.ts +93 -0
  31. package/dist/deps/index.js +112 -0
  32. package/dist/deps/index.js.map +1 -0
  33. package/dist/errors-BV75u7b9.d.cts +207 -0
  34. package/dist/errors-BV75u7b9.d.ts +207 -0
  35. package/dist/index.cjs +721 -0
  36. package/dist/index.cjs.map +1 -0
  37. package/dist/index.d.cts +171 -0
  38. package/dist/index.d.ts +171 -0
  39. package/dist/index.js +703 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/query/index.cjs +621 -0
  42. package/dist/query/index.cjs.map +1 -0
  43. package/dist/query/index.d.cts +800 -0
  44. package/dist/query/index.d.ts +800 -0
  45. package/dist/query/index.js +617 -0
  46. package/dist/query/index.js.map +1 -0
  47. package/dist/react/index.cjs +199 -0
  48. package/dist/react/index.cjs.map +1 -0
  49. package/dist/react/index.d.cts +117 -0
  50. package/dist/react/index.d.ts +117 -0
  51. package/dist/react/index.js +195 -0
  52. package/dist/react/index.js.map +1 -0
  53. package/dist/types-BLNQ1S1C.d.cts +396 -0
  54. package/dist/types-BLNQ1S1C.d.ts +396 -0
  55. package/package.json +109 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,721 @@
1
+ 'use strict';
2
+
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+
10
+ // src/data/deps.ts
11
+ var MODULE_SLUG_REGEX = /^[a-z][a-z0-9-]*[a-z0-9]$/;
12
+ var TABLE_SLUG_REGEX = /^[a-z][a-z0-9_]*[a-z0-9]$/;
13
+ function assertValidProviderSlug(slug) {
14
+ if (typeof slug !== "string" || !MODULE_SLUG_REGEX.test(slug)) {
15
+ throw new Error(
16
+ `@dashai/sdk: invalid provider slug "${slug}". Provider slugs are the dependency module's slug (kebab-case, e.g. "crm-app"); must match /^[a-z][a-z0-9-]*[a-z0-9]$/.`
17
+ );
18
+ }
19
+ }
20
+ function assertValidTableSlug(slug) {
21
+ if (typeof slug !== "string" || !TABLE_SLUG_REGEX.test(slug)) {
22
+ throw new Error(
23
+ `@dashai/sdk: invalid table slug "${slug}". Table slugs must match /^[a-z][a-z0-9_]*[a-z0-9]$/ (snake_case).`
24
+ );
25
+ }
26
+ }
27
+ function makeDeps(transport, providerSlug) {
28
+ assertValidProviderSlug(providerSlug);
29
+ return {
30
+ db(tableSlug) {
31
+ assertValidTableSlug(tableSlug);
32
+ return makeBorrowedTableClient(transport, providerSlug, tableSlug);
33
+ }
34
+ };
35
+ }
36
+ function makeBorrowedTableClient(transport, providerSlug, tableSlug) {
37
+ const root = `/deps/${providerSlug}/db/${tableSlug}`;
38
+ return {
39
+ async list(opts) {
40
+ const body = opts ?? {};
41
+ const result = await transport.request("POST", `${root}/list`, body);
42
+ if (Array.isArray(result)) {
43
+ return {
44
+ rows: result,
45
+ total: result.length,
46
+ limit: body.limit ?? result.length,
47
+ offset: body.offset ?? 0
48
+ };
49
+ }
50
+ return result;
51
+ },
52
+ async get(id) {
53
+ return transport.request("GET", `${root}/${id}`);
54
+ }
55
+ };
56
+ }
57
+
58
+ // src/data/errors.ts
59
+ var DashwiseErrorCode = {
60
+ // Auth / authz
61
+ UNAUTHENTICATED: "UNAUTHENTICATED",
62
+ FORBIDDEN: "FORBIDDEN",
63
+ TOKEN_EXPIRED: "TOKEN_EXPIRED",
64
+ INSTALLATION_NOT_FOUND: "INSTALLATION_NOT_FOUND",
65
+ INSTALLATION_MODE_UNSUPPORTED: "INSTALLATION_MODE_UNSUPPORTED",
66
+ // Contract enforcement
67
+ CONTRACT_VIOLATION: "CONTRACT_VIOLATION",
68
+ FIELD_NOT_READABLE: "FIELD_NOT_READABLE",
69
+ FILTER_OP_UNKNOWN: "FILTER_OP_UNKNOWN",
70
+ OPERATION_NOT_ALLOWED: "OPERATION_NOT_ALLOWED",
71
+ // Cross-module dependencies (Phase 1 of the SDK query plane —
72
+ // see dashwise-devops-docs/plans/modules-sdk-query-v1.md).
73
+ // Surfaced when reading borrowed tables via `client.deps(slug)`.
74
+ DEPENDENCY_NOT_DECLARED: "DEPENDENCY_NOT_DECLARED",
75
+ TABLE_NOT_IN_CONTRACT: "TABLE_NOT_IN_CONTRACT",
76
+ PROVIDER_TABLE_MISSING: "PROVIDER_TABLE_MISSING",
77
+ OPERATION_NOT_ALLOWED_BY_PROVIDER: "OPERATION_NOT_ALLOWED_BY_PROVIDER",
78
+ // Query-plane joins (Phase 3 — see
79
+ // dashwise-devops-docs/plans/modules-sdk-query-v1-p3-execution.md).
80
+ // Surfaced when `.join('<slug>')` / `.leftJoin('<slug>')` can't
81
+ // resolve the target. Pre-declared in slice 3.1 so slice 3.2's
82
+ // backend translator can emit them through fromBackendEnvelope
83
+ // without an SDK roundtrip.
84
+ LINK_FIELD_NOT_FOUND: "LINK_FIELD_NOT_FOUND",
85
+ NOT_A_LINK_FIELD: "NOT_A_LINK_FIELD",
86
+ JOIN_NOT_LINKED: "JOIN_NOT_LINKED",
87
+ // Cross-module actions (Phase 7 slice 7.3a — see
88
+ // dashwise-devops-docs/plans/modules-sdk-query-v1-p7-cross-module-writes.md).
89
+ // Surfaced when `qb.deps.<dep>.actions.<name>(input)` (generated
90
+ // factory) dispatches against the new backend endpoint
91
+ // `POST :installationId/deps/:providerSlug/actions/:actionName`.
92
+ // Slice 7.2b ships the backend emitter; slice 7.3a (this slice)
93
+ // reserves the codes + maps them to DepActionError in the SDK.
94
+ ACTION_NOT_EXPOSED: "ACTION_NOT_EXPOSED",
95
+ ACTION_NOT_DECLARED: "ACTION_NOT_DECLARED",
96
+ ACTION_INPUT_INVALID: "ACTION_INPUT_INVALID",
97
+ ACTION_OUTPUT_INVALID: "ACTION_OUTPUT_INVALID",
98
+ ACTION_RATE_LIMITED: "ACTION_RATE_LIMITED",
99
+ ACTION_EXECUTION_FAILED: "ACTION_EXECUTION_FAILED",
100
+ // Data plane
101
+ ROW_NOT_FOUND: "ROW_NOT_FOUND",
102
+ TABLE_NOT_FOUND: "TABLE_NOT_FOUND",
103
+ VALIDATION_FAILED: "VALIDATION_FAILED",
104
+ ROW_LIMIT_EXCEEDED: "ROW_LIMIT_EXCEEDED",
105
+ STORAGE_LIMIT_EXCEEDED: "STORAGE_LIMIT_EXCEEDED",
106
+ // Outbound / runtime
107
+ OUTBOUND_NOT_ALLOWED: "OUTBOUND_NOT_ALLOWED",
108
+ OUTBOUND_CONCURRENCY_LIMITED: "OUTBOUND_CONCURRENCY_LIMITED",
109
+ // Transport
110
+ NETWORK_ERROR: "NETWORK_ERROR",
111
+ TIMEOUT: "TIMEOUT",
112
+ // Server
113
+ INTERNAL_ERROR: "INTERNAL_ERROR"
114
+ };
115
+ var DashwiseError = class extends Error {
116
+ code;
117
+ status;
118
+ retriable;
119
+ context;
120
+ /**
121
+ * Backend-issued trace anchor (Phase 6 slice 6.2, 2026-05-19).
122
+ * Mirrors the `x-request-id` response header. Populated whenever
123
+ * the backend's `RuntimeQueryController` (or any future endpoint
124
+ * that echoes the header) is the origin of this error. `null` when
125
+ * the failure is client-side (NetworkError / TimeoutError — the
126
+ * request never reached the server, so there's no server-issued
127
+ * ID to surface).
128
+ *
129
+ * Use this as a debugging trace anchor when filing a bug against a
130
+ * specific failed query — the matching row in `module_query_log`
131
+ * carries the full backend context (ast_hash, error_code,
132
+ * duration_ms, etc.).
133
+ */
134
+ requestId;
135
+ constructor(code, message, options = {}) {
136
+ super(message);
137
+ this.name = this.constructor.name;
138
+ this.code = code;
139
+ this.status = options.status ?? 0;
140
+ this.retriable = options.retriable ?? false;
141
+ this.context = options.context;
142
+ this.requestId = options.requestId ?? null;
143
+ if (options.cause !== void 0) {
144
+ this.cause = options.cause;
145
+ }
146
+ }
147
+ };
148
+ var NetworkError = class extends DashwiseError {
149
+ constructor(message, cause) {
150
+ super(DashwiseErrorCode.NETWORK_ERROR, message, { retriable: true, cause });
151
+ }
152
+ };
153
+ var TimeoutError = class extends DashwiseError {
154
+ constructor(message, timeoutMs) {
155
+ super(DashwiseErrorCode.TIMEOUT, message, {
156
+ retriable: true,
157
+ context: { timeout_ms: timeoutMs }
158
+ });
159
+ }
160
+ };
161
+ var UnauthenticatedError = class extends DashwiseError {
162
+ constructor(message = "Authentication required", requestId = null) {
163
+ super(DashwiseErrorCode.UNAUTHENTICATED, message, { status: 401, requestId });
164
+ }
165
+ };
166
+ var ForbiddenError = class extends DashwiseError {
167
+ constructor(message, context, requestId = null) {
168
+ super(DashwiseErrorCode.FORBIDDEN, message, { status: 403, context, requestId });
169
+ }
170
+ };
171
+ var RowNotFoundError = class extends DashwiseError {
172
+ constructor(message, context, requestId = null) {
173
+ super(DashwiseErrorCode.ROW_NOT_FOUND, message, { status: 404, context, requestId });
174
+ }
175
+ };
176
+ var ContractViolationError = class extends DashwiseError {
177
+ constructor(message, context, requestId = null) {
178
+ super(DashwiseErrorCode.CONTRACT_VIOLATION, message, {
179
+ status: 403,
180
+ context,
181
+ requestId
182
+ });
183
+ }
184
+ };
185
+ var ValidationError = class extends DashwiseError {
186
+ constructor(message, context, requestId = null) {
187
+ super(DashwiseErrorCode.VALIDATION_FAILED, message, {
188
+ status: 400,
189
+ context,
190
+ requestId
191
+ });
192
+ }
193
+ };
194
+ var DependencyContractError = class extends DashwiseError {
195
+ constructor(code, message, context, requestId = null) {
196
+ super(code, message, { status: 404, context, requestId });
197
+ }
198
+ };
199
+ var ProviderTableMissingError = class extends DashwiseError {
200
+ constructor(message, context, requestId = null) {
201
+ super(DashwiseErrorCode.PROVIDER_TABLE_MISSING, message, {
202
+ status: 404,
203
+ context,
204
+ requestId
205
+ });
206
+ }
207
+ };
208
+ var OperationNotAllowedByProviderError = class extends DashwiseError {
209
+ constructor(message, context, requestId = null) {
210
+ super(DashwiseErrorCode.OPERATION_NOT_ALLOWED_BY_PROVIDER, message, {
211
+ status: 403,
212
+ context,
213
+ requestId
214
+ });
215
+ }
216
+ };
217
+ var JoinError = class extends DashwiseError {
218
+ constructor(code, message, context, requestId = null) {
219
+ super(code, message, { status: 400, context, requestId });
220
+ }
221
+ };
222
+ var DepActionError = class extends DashwiseError {
223
+ constructor(code, message, status, context, requestId = null) {
224
+ super(code, message, {
225
+ status,
226
+ retriable: code === DashwiseErrorCode.ACTION_RATE_LIMITED,
227
+ context,
228
+ requestId
229
+ });
230
+ }
231
+ };
232
+ function fromBackendEnvelope(status, envelope, requestId = null) {
233
+ const code = envelope?.code ?? codeFromStatus(status);
234
+ const message = envelope?.message ?? `HTTP ${status}`;
235
+ const context = envelope?.context;
236
+ switch (code) {
237
+ case DashwiseErrorCode.UNAUTHENTICATED:
238
+ case DashwiseErrorCode.TOKEN_EXPIRED:
239
+ return new UnauthenticatedError(message, requestId);
240
+ case DashwiseErrorCode.FORBIDDEN:
241
+ return new ForbiddenError(message, context, requestId);
242
+ case DashwiseErrorCode.ROW_NOT_FOUND:
243
+ return new RowNotFoundError(message, context, requestId);
244
+ case DashwiseErrorCode.CONTRACT_VIOLATION:
245
+ case DashwiseErrorCode.FIELD_NOT_READABLE:
246
+ case DashwiseErrorCode.FILTER_OP_UNKNOWN:
247
+ case DashwiseErrorCode.OPERATION_NOT_ALLOWED:
248
+ return new ContractViolationError(message, context, requestId);
249
+ case DashwiseErrorCode.VALIDATION_FAILED:
250
+ return new ValidationError(message, context, requestId);
251
+ case DashwiseErrorCode.DEPENDENCY_NOT_DECLARED:
252
+ case DashwiseErrorCode.TABLE_NOT_IN_CONTRACT:
253
+ return new DependencyContractError(code, message, context, requestId);
254
+ case DashwiseErrorCode.PROVIDER_TABLE_MISSING:
255
+ return new ProviderTableMissingError(message, context, requestId);
256
+ case DashwiseErrorCode.OPERATION_NOT_ALLOWED_BY_PROVIDER:
257
+ return new OperationNotAllowedByProviderError(message, context, requestId);
258
+ case DashwiseErrorCode.LINK_FIELD_NOT_FOUND:
259
+ case DashwiseErrorCode.NOT_A_LINK_FIELD:
260
+ case DashwiseErrorCode.JOIN_NOT_LINKED:
261
+ return new JoinError(code, message, context, requestId);
262
+ case DashwiseErrorCode.ACTION_NOT_EXPOSED:
263
+ case DashwiseErrorCode.ACTION_NOT_DECLARED:
264
+ return new DepActionError(code, message, 403, context, requestId);
265
+ case DashwiseErrorCode.ACTION_INPUT_INVALID:
266
+ return new DepActionError(code, message, 400, context, requestId);
267
+ case DashwiseErrorCode.ACTION_OUTPUT_INVALID:
268
+ return new DepActionError(code, message, 500, context, requestId);
269
+ case DashwiseErrorCode.ACTION_RATE_LIMITED:
270
+ return new DepActionError(code, message, 429, context, requestId);
271
+ case DashwiseErrorCode.ACTION_EXECUTION_FAILED:
272
+ return new DepActionError(code, message, 200, context, requestId);
273
+ default:
274
+ return new DashwiseError(code, message, {
275
+ status,
276
+ retriable: envelope?.retriable ?? false,
277
+ context,
278
+ requestId
279
+ });
280
+ }
281
+ }
282
+ function codeFromStatus(status) {
283
+ if (status === 401) return DashwiseErrorCode.UNAUTHENTICATED;
284
+ if (status === 403) return DashwiseErrorCode.FORBIDDEN;
285
+ if (status === 404) return DashwiseErrorCode.ROW_NOT_FOUND;
286
+ if (status >= 500) return DashwiseErrorCode.INTERNAL_ERROR;
287
+ return "HTTP_ERROR";
288
+ }
289
+
290
+ // src/data/http.ts
291
+ var DEFAULT_TIMEOUT_MS = 3e4;
292
+ var DEFAULT_SLOW_QUERY_THRESHOLD_MS = 500;
293
+ var TRAILING_SLASH = /\/+$/;
294
+ var LEADING_SLASH = /^\/+/;
295
+ function buildBaseUrl(baseUrl, installationId) {
296
+ if (!baseUrl) {
297
+ throw new Error("@dashai/sdk: `baseUrl` is required");
298
+ }
299
+ const trimmed = baseUrl.replace(TRAILING_SLASH, "");
300
+ return `${trimmed}/api/modules/${installationId}`;
301
+ }
302
+ function resolveFetch(custom) {
303
+ if (custom) return custom;
304
+ if (typeof globalThis.fetch !== "function") {
305
+ throw new Error(
306
+ "@dashai/sdk: no `fetch` available. On Node < 18, pass an explicit `fetch` in `createClient({...})`."
307
+ );
308
+ }
309
+ return globalThis.fetch.bind(globalThis);
310
+ }
311
+ async function readBody(res) {
312
+ if (res.status === 204) return void 0;
313
+ const contentType = res.headers.get("content-type") ?? "";
314
+ if (!contentType.includes("application/json")) {
315
+ try {
316
+ return await res.text();
317
+ } catch {
318
+ return null;
319
+ }
320
+ }
321
+ try {
322
+ return await res.json();
323
+ } catch {
324
+ return null;
325
+ }
326
+ }
327
+ function createHttp(config) {
328
+ const base = buildBaseUrl(config.baseUrl, config.installationId);
329
+ const doFetch = resolveFetch(config.fetch);
330
+ const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
331
+ const staticHeaders = {
332
+ Accept: "application/json",
333
+ ...config.headers ?? {}
334
+ };
335
+ const onSlowQuery = config.onSlowQuery;
336
+ const slowQueryThresholdMs = config.slowQueryThresholdMs ?? DEFAULT_SLOW_QUERY_THRESHOLD_MS;
337
+ function maybeFireSlowQuery(info) {
338
+ if (!onSlowQuery) return;
339
+ if (info.durationMs <= slowQueryThresholdMs) return;
340
+ try {
341
+ onSlowQuery(info);
342
+ } catch {
343
+ }
344
+ }
345
+ async function request(method, path, body) {
346
+ const normalizedPath = `/${path.replace(LEADING_SLASH, "")}`;
347
+ const url = normalizedPath.startsWith("/api/") ? `${config.baseUrl.replace(/\/+$/, "")}${normalizedPath}` : `${base}${normalizedPath}`;
348
+ const token = config.getToken ? await config.getToken() : null;
349
+ const headers = { ...staticHeaders };
350
+ if (body !== void 0) {
351
+ headers["Content-Type"] = "application/json";
352
+ }
353
+ if (token) {
354
+ headers["Authorization"] = `Bearer ${token}`;
355
+ }
356
+ const controller = new AbortController();
357
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
358
+ const start = Date.now();
359
+ let res;
360
+ try {
361
+ res = await doFetch(url, {
362
+ method,
363
+ headers,
364
+ body: body === void 0 ? void 0 : JSON.stringify(body),
365
+ signal: controller.signal
366
+ });
367
+ } catch (err) {
368
+ clearTimeout(timer);
369
+ const durationMs2 = Date.now() - start;
370
+ if (isAbortError(err)) {
371
+ maybeFireSlowQuery({
372
+ method,
373
+ path: normalizedPath,
374
+ durationMs: durationMs2,
375
+ status: 0,
376
+ success: false,
377
+ requestId: null
378
+ });
379
+ throw new TimeoutError(`Request to ${method} ${normalizedPath} timed out`, timeoutMs);
380
+ }
381
+ maybeFireSlowQuery({
382
+ method,
383
+ path: normalizedPath,
384
+ durationMs: durationMs2,
385
+ status: 0,
386
+ success: false,
387
+ requestId: null
388
+ });
389
+ throw new NetworkError(
390
+ `Network failure on ${method} ${normalizedPath}: ${describeError(err)}`,
391
+ err
392
+ );
393
+ }
394
+ clearTimeout(timer);
395
+ const parsed = await readBody(res);
396
+ const durationMs = Date.now() - start;
397
+ const requestId = res.headers.get("x-request-id");
398
+ if (!res.ok) {
399
+ maybeFireSlowQuery({
400
+ method,
401
+ path: normalizedPath,
402
+ durationMs,
403
+ status: res.status,
404
+ success: false,
405
+ requestId
406
+ });
407
+ const envelope = isEnvelope(parsed) ? parsed : null;
408
+ throw fromBackendEnvelope(res.status, envelope, requestId);
409
+ }
410
+ maybeFireSlowQuery({
411
+ method,
412
+ path: normalizedPath,
413
+ durationMs,
414
+ status: res.status,
415
+ success: true,
416
+ requestId
417
+ });
418
+ return parsed;
419
+ }
420
+ async function streamRaw(method, path, body, signal) {
421
+ const normalizedPath = `/${path.replace(LEADING_SLASH, "")}`;
422
+ const url = `${base}${normalizedPath}`;
423
+ const token = config.getToken ? await config.getToken() : null;
424
+ const headers = { ...staticHeaders };
425
+ if (body !== void 0) {
426
+ headers["Content-Type"] = "application/json";
427
+ }
428
+ if (token) {
429
+ headers["Authorization"] = `Bearer ${token}`;
430
+ }
431
+ const timeoutController = new AbortController();
432
+ const timer = setTimeout(() => timeoutController.abort(), timeoutMs);
433
+ const combinedController = new AbortController();
434
+ if (signal) {
435
+ if (signal.aborted) combinedController.abort();
436
+ else signal.addEventListener("abort", () => combinedController.abort(), { once: true });
437
+ }
438
+ timeoutController.signal.addEventListener(
439
+ "abort",
440
+ () => combinedController.abort(),
441
+ { once: true }
442
+ );
443
+ const start = Date.now();
444
+ let res;
445
+ try {
446
+ res = await doFetch(url, {
447
+ method,
448
+ headers,
449
+ body: body === void 0 ? void 0 : JSON.stringify(body),
450
+ signal: combinedController.signal
451
+ });
452
+ } catch (err) {
453
+ clearTimeout(timer);
454
+ const durationMs = Date.now() - start;
455
+ if (isAbortError(err)) {
456
+ maybeFireSlowQuery({
457
+ method,
458
+ path: normalizedPath,
459
+ durationMs,
460
+ status: 0,
461
+ success: false,
462
+ requestId: null
463
+ });
464
+ if (signal?.aborted) {
465
+ const e = new Error("Aborted by caller");
466
+ e.name = "AbortError";
467
+ throw e;
468
+ }
469
+ throw new TimeoutError(
470
+ `Streaming request to ${method} ${normalizedPath} timed out before headers arrived`,
471
+ timeoutMs
472
+ );
473
+ }
474
+ maybeFireSlowQuery({
475
+ method,
476
+ path: normalizedPath,
477
+ durationMs,
478
+ status: 0,
479
+ success: false,
480
+ requestId: null
481
+ });
482
+ throw new NetworkError(
483
+ `Network failure on ${method} ${normalizedPath}: ${describeError(err)}`,
484
+ err
485
+ );
486
+ }
487
+ clearTimeout(timer);
488
+ const requestId = res.headers.get("x-request-id");
489
+ maybeFireSlowQuery({
490
+ method,
491
+ path: normalizedPath,
492
+ durationMs: Date.now() - start,
493
+ status: res.status,
494
+ success: res.ok,
495
+ requestId
496
+ });
497
+ return res;
498
+ }
499
+ return { request, streamRaw };
500
+ }
501
+ function isAbortError(err) {
502
+ if (!err || typeof err !== "object") return false;
503
+ const e = err;
504
+ return e.name === "AbortError" || e.code === "ABORT_ERR";
505
+ }
506
+ function describeError(err) {
507
+ if (err instanceof Error) return err.message;
508
+ if (typeof err === "string") return err;
509
+ try {
510
+ return JSON.stringify(err);
511
+ } catch {
512
+ return "<unknown error>";
513
+ }
514
+ }
515
+ function isEnvelope(value) {
516
+ if (!value || typeof value !== "object") return false;
517
+ const v = value;
518
+ return typeof v.code === "string" || typeof v.message === "string";
519
+ }
520
+
521
+ // src/data/client.ts
522
+ function createClient(config) {
523
+ const transport = createHttp(config);
524
+ return {
525
+ db(tableSlug) {
526
+ assertValidTableSlug2(tableSlug);
527
+ return makeTableClient(transport, tableSlug);
528
+ },
529
+ deps(providerSlug) {
530
+ return makeDeps(transport, providerSlug);
531
+ },
532
+ request(method, path, body) {
533
+ return transport.request(method, path, body);
534
+ },
535
+ streamRaw(method, path, body, signal) {
536
+ return transport.streamRaw(method, path, body, signal);
537
+ },
538
+ async _callAction(providerSlug, actionName, input, opts) {
539
+ assertValidModuleSlug(providerSlug);
540
+ assertValidActionName(actionName);
541
+ const path = `/api/modules/runtime/installations/${config.installationId}/deps/${encodeURIComponent(
542
+ providerSlug
543
+ )}/actions/${encodeURIComponent(actionName)}`;
544
+ const body = { input };
545
+ if (opts?.idempotencyKey !== void 0) {
546
+ body.idempotency_key = opts.idempotencyKey;
547
+ }
548
+ if (opts?.timeoutMs !== void 0) {
549
+ body.timeout_ms = opts.timeoutMs;
550
+ }
551
+ const envelope = await transport.request(
552
+ "POST",
553
+ path,
554
+ body
555
+ );
556
+ if (envelope.ok === false) {
557
+ const requestId = envelope.cross_module?.request_id ?? null;
558
+ throw fromBackendEnvelope(
559
+ 200,
560
+ {
561
+ code: envelope.error.code,
562
+ message: envelope.error.message,
563
+ context: envelope.error.trace ? { trace: envelope.error.trace } : void 0
564
+ },
565
+ requestId
566
+ );
567
+ }
568
+ return envelope.result;
569
+ }
570
+ };
571
+ }
572
+ var ACTION_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]{0,63}$/;
573
+ var MODULE_SLUG_REGEX2 = /^[a-z][a-z0-9-]*[a-z0-9]$/;
574
+ function assertValidModuleSlug(slug) {
575
+ if (!MODULE_SLUG_REGEX2.test(slug)) {
576
+ throw new Error(
577
+ `Invalid provider module slug "${slug}" \u2014 must be kebab-case (^[a-z][a-z0-9-]*[a-z0-9]$).`
578
+ );
579
+ }
580
+ }
581
+ function assertValidActionName(name) {
582
+ if (!ACTION_NAME_REGEX.test(name)) {
583
+ throw new Error(
584
+ `Invalid action name "${name}" \u2014 must be a JS identifier (letters/digits/underscore/$, starts non-digit, \u226464 chars).`
585
+ );
586
+ }
587
+ }
588
+ var TABLE_SLUG_REGEX2 = /^[a-z][a-z0-9_]*$/;
589
+ function assertValidTableSlug2(slug) {
590
+ if (typeof slug !== "string" || !TABLE_SLUG_REGEX2.test(slug)) {
591
+ throw new Error(
592
+ `@dashai/sdk: invalid table slug "${slug}". Slugs must match /^[a-z][a-z0-9_]*$/.`
593
+ );
594
+ }
595
+ }
596
+ function makeTableClient(transport, tableSlug) {
597
+ const root = `/db/${tableSlug}`;
598
+ return {
599
+ async list(opts) {
600
+ const ast = {
601
+ v: 1,
602
+ from: { kind: "owned", slug: tableSlug }
603
+ };
604
+ if (opts?.filter !== void 0) ast.where = opts.filter;
605
+ if (opts?.sort !== void 0 && opts.sort.length > 0) {
606
+ ast.orderBy = opts.sort;
607
+ }
608
+ if (typeof opts?.limit === "number") ast.limit = opts.limit;
609
+ if (typeof opts?.offset === "number") ast.offset = opts.offset;
610
+ const result = await transport.request("POST", "/query", { ast });
611
+ if (Array.isArray(result)) {
612
+ return {
613
+ rows: result,
614
+ total: result.length,
615
+ limit: opts?.limit ?? result.length,
616
+ offset: opts?.offset ?? 0
617
+ };
618
+ }
619
+ return result;
620
+ },
621
+ async get(id) {
622
+ return transport.request("GET", `${root}/${id}`);
623
+ },
624
+ async create(body) {
625
+ return transport.request("POST", root, body);
626
+ },
627
+ async update(id, patch) {
628
+ return transport.request("PATCH", `${root}/${id}`, patch);
629
+ },
630
+ async delete(id) {
631
+ await transport.request("DELETE", `${root}/${id}`);
632
+ }
633
+ };
634
+ }
635
+
636
+ // src/data/dev-client.ts
637
+ function createDevClient(overrides = {}) {
638
+ const fileConfig = readCliConfigFile();
639
+ const baseUrl = overrides.baseUrl ?? readEnv("DASHWISE_API_URL") ?? fileConfig?.apiUrl ?? null;
640
+ if (!baseUrl) {
641
+ throw new Error(
642
+ "@dashai/sdk: createDevClient() could not resolve a baseUrl. Pass `{ baseUrl }` explicitly, set `DASHWISE_API_URL`, or run `dashwise login` to create the CLI config file."
643
+ );
644
+ }
645
+ const installationId = overrides.installationId ?? readEnv("DASHWISE_INSTALLATION_ID") ?? "local";
646
+ const snapshotToken = readEnv("DASHWISE_API_TOKEN") ?? fileConfig?.token ?? null;
647
+ const resolvedGetToken = overrides.getToken ?? (() => snapshotToken);
648
+ return createClient({
649
+ ...overrides,
650
+ baseUrl,
651
+ installationId,
652
+ getToken: resolvedGetToken
653
+ });
654
+ }
655
+ function readEnv(key) {
656
+ if (typeof process === "undefined" || !process.env) return void 0;
657
+ const v = process.env[key];
658
+ return typeof v === "string" && v.length > 0 ? v : void 0;
659
+ }
660
+ function isNodeRuntime() {
661
+ if (typeof process === "undefined") return false;
662
+ if (!process.versions || typeof process.versions.node !== "string") {
663
+ return false;
664
+ }
665
+ return true;
666
+ }
667
+ function readCliConfigFile() {
668
+ if (!isNodeRuntime()) return null;
669
+ if (readEnv("NODE_ENV") === "production") return null;
670
+ try {
671
+ const fs = __require("fs");
672
+ const path = __require("path");
673
+ const os = __require("os");
674
+ const dir = resolveConfigDir(path, os);
675
+ const file = path.join(dir, "auth.json");
676
+ if (!fs.existsSync(file)) return null;
677
+ const raw = fs.readFileSync(file, "utf-8");
678
+ const parsed = JSON.parse(raw);
679
+ if (!isPlausibleFileShape(parsed)) return null;
680
+ return parsed;
681
+ } catch {
682
+ return null;
683
+ }
684
+ }
685
+ function resolveConfigDir(path, os) {
686
+ const xdg = readEnv("XDG_CONFIG_HOME");
687
+ if (xdg) return path.join(xdg, "dashwise");
688
+ if (os.platform() === "win32") {
689
+ const appdata = readEnv("APPDATA");
690
+ if (appdata) return path.join(appdata, "dashwise");
691
+ }
692
+ return path.join(os.homedir(), ".config", "dashwise");
693
+ }
694
+ function isPlausibleFileShape(v) {
695
+ if (!v || typeof v !== "object") return false;
696
+ const o = v;
697
+ return (o.apiUrl === void 0 || typeof o.apiUrl === "string") && (o.token === void 0 || typeof o.token === "string");
698
+ }
699
+
700
+ // src/index.ts
701
+ var VERSION = "0.7.0" ;
702
+
703
+ exports.ContractViolationError = ContractViolationError;
704
+ exports.DashwiseError = DashwiseError;
705
+ exports.DashwiseErrorCode = DashwiseErrorCode;
706
+ exports.DependencyContractError = DependencyContractError;
707
+ exports.ForbiddenError = ForbiddenError;
708
+ exports.JoinError = JoinError;
709
+ exports.NetworkError = NetworkError;
710
+ exports.OperationNotAllowedByProviderError = OperationNotAllowedByProviderError;
711
+ exports.ProviderTableMissingError = ProviderTableMissingError;
712
+ exports.RowNotFoundError = RowNotFoundError;
713
+ exports.TimeoutError = TimeoutError;
714
+ exports.UnauthenticatedError = UnauthenticatedError;
715
+ exports.VERSION = VERSION;
716
+ exports.ValidationError = ValidationError;
717
+ exports.createClient = createClient;
718
+ exports.createDevClient = createDevClient;
719
+ exports.fromBackendEnvelope = fromBackendEnvelope;
720
+ //# sourceMappingURL=index.cjs.map
721
+ //# sourceMappingURL=index.cjs.map