@dashai/sdk 0.9.0 → 2.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.
Files changed (52) hide show
  1. package/README.md +53 -13
  2. package/dist/auth/client.cjs +23 -1
  3. package/dist/auth/client.cjs.map +1 -1
  4. package/dist/auth/client.d.cts +30 -5
  5. package/dist/auth/client.d.ts +30 -5
  6. package/dist/auth/client.js +23 -1
  7. package/dist/auth/client.js.map +1 -1
  8. package/dist/auth/middleware.cjs +11 -1
  9. package/dist/auth/middleware.cjs.map +1 -1
  10. package/dist/auth/middleware.js +11 -1
  11. package/dist/auth/middleware.js.map +1 -1
  12. package/dist/auth/server.cjs +36 -7
  13. package/dist/auth/server.cjs.map +1 -1
  14. package/dist/auth/server.js +36 -7
  15. package/dist/auth/server.js.map +1 -1
  16. package/dist/auth/types.cjs.map +1 -1
  17. package/dist/auth/types.d.cts +13 -0
  18. package/dist/auth/types.d.ts +13 -0
  19. package/dist/auth/types.js.map +1 -1
  20. package/dist/deps/index.cjs +82 -7
  21. package/dist/deps/index.cjs.map +1 -1
  22. package/dist/deps/index.d.cts +28 -10
  23. package/dist/deps/index.d.ts +28 -10
  24. package/dist/deps/index.js +81 -8
  25. package/dist/deps/index.js.map +1 -1
  26. package/dist/index-BsSFz58g.d.cts +431 -0
  27. package/dist/index-BsSFz58g.d.ts +431 -0
  28. package/dist/index.cjs +318 -25
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +66 -53
  31. package/dist/index.d.ts +66 -53
  32. package/dist/index.js +313 -26
  33. package/dist/index.js.map +1 -1
  34. package/dist/query/index.cjs +158 -2
  35. package/dist/query/index.cjs.map +1 -1
  36. package/dist/query/index.d.cts +7 -7
  37. package/dist/query/index.d.ts +7 -7
  38. package/dist/query/index.js +158 -2
  39. package/dist/query/index.js.map +1 -1
  40. package/dist/react/index.d.cts +1 -1
  41. package/dist/react/index.d.ts +1 -1
  42. package/dist/{types-DXsbCVkb.d.cts → types-CkAfiS4k.d.cts} +106 -38
  43. package/dist/{types-DXsbCVkb.d.ts → types-CkAfiS4k.d.ts} +106 -38
  44. package/dist/uses/index.cjs +147 -0
  45. package/dist/uses/index.cjs.map +1 -0
  46. package/dist/uses/index.d.cts +1 -0
  47. package/dist/uses/index.d.ts +1 -0
  48. package/dist/uses/index.js +142 -0
  49. package/dist/uses/index.js.map +1 -0
  50. package/package.json +6 -1
  51. package/dist/errors-BV75u7b9.d.cts +0 -207
  52. package/dist/errors-BV75u7b9.d.ts +0 -207
package/dist/index.js CHANGED
@@ -32,23 +32,39 @@ function makeDeps(transport, providerSlug) {
32
32
  };
33
33
  }
34
34
  function makeBorrowedTableClient(transport, providerSlug, tableSlug) {
35
- const root = `/deps/${providerSlug}/db/${tableSlug}`;
35
+ const tablesRoot = `/deps/${providerSlug}/tables/${tableSlug}`;
36
36
  return {
37
37
  async list(opts) {
38
- const body = opts ?? {};
39
- const result = await transport.request("POST", `${root}/list`, body);
38
+ const ast = {
39
+ v: 1,
40
+ from: { kind: "dep", module: providerSlug, slug: tableSlug }
41
+ };
42
+ if (opts?.filter !== void 0) ast.where = opts.filter;
43
+ if (opts?.sort !== void 0 && opts.sort.length > 0) {
44
+ ast.orderBy = opts.sort;
45
+ }
46
+ if (typeof opts?.limit === "number") ast.limit = opts.limit;
47
+ if (typeof opts?.offset === "number") ast.offset = opts.offset;
48
+ const result = await transport.request("POST", "/query", { ast });
40
49
  if (Array.isArray(result)) {
41
50
  return {
42
51
  rows: result,
43
52
  total: result.length,
44
- limit: body.limit ?? result.length,
45
- offset: body.offset ?? 0
53
+ limit: opts?.limit ?? result.length,
54
+ offset: opts?.offset ?? 0
46
55
  };
47
56
  }
48
57
  return result;
49
58
  },
50
59
  async get(id) {
51
- return transport.request("GET", `${root}/${id}`);
60
+ const result = await transport.request(
61
+ "GET",
62
+ `${tablesRoot}/${id}`
63
+ );
64
+ if (result && typeof result === "object" && "row" in result) {
65
+ return result.row;
66
+ }
67
+ return result;
52
68
  }
53
69
  };
54
70
  }
@@ -73,6 +89,44 @@ var DashwiseErrorCode = {
73
89
  TABLE_NOT_IN_CONTRACT: "TABLE_NOT_IN_CONTRACT",
74
90
  PROVIDER_TABLE_MISSING: "PROVIDER_TABLE_MISSING",
75
91
  OPERATION_NOT_ALLOWED_BY_PROVIDER: "OPERATION_NOT_ALLOWED_BY_PROVIDER",
92
+ // Cross-module dependency PARK state (Phase 3 modules-platform-v2 —
93
+ // dependency connect/bind lifecycle). Surfaced at RUNTIME (409) when a
94
+ // module reads a borrowed table (`client.deps(slug)` / `qb.deps.<slug>`)
95
+ // or invokes a dep action whose `module_dependencies` row is currently
96
+ // `status='unbound'` — the dependency is declared but not connected to a
97
+ // provider installation (no provider in the workspace, version mismatch,
98
+ // manually unbound, provider uninstalled, etc.). The consumer app should
99
+ // render a "connect your provider" state rather than treating this as a
100
+ // hard failure. `err.context` carries `{ provider, range, reason }`.
101
+ DEP_UNBOUND: "DEP_UNBOUND",
102
+ // Workspace-table `uses` plane (Phase 4 modules-platform-v2 — the
103
+ // declared/portable path for a module to read+write a WORKSPACE table
104
+ // the workspace already owns, as opposed to `deps` = another module's
105
+ // tables). Surfaced at RUNTIME against `client.uses(slug)` /
106
+ // `qb.uses.<slug>` / the `POST /api/module-api/uses/:slug/...` REST
107
+ // plane. The BINDING is the grant on this plane (for sandbox AND
108
+ // api_key auth alike — a kind-local key does NOT bypass it):
109
+ // - USES_UNBOUND 409 — the `uses` slot is declared but its
110
+ // `module_table_bindings` row isn't `status='bound'` (never bound,
111
+ // ambiguous match, no match, table trashed, ops widened pending
112
+ // re-consent, manually unbound). `err.context` carries
113
+ // `{ uses_slug, reason }`. Recoverable: a workspace admin binds a
114
+ // table (`dashwise bind <uses_slug>`), then the read succeeds.
115
+ // - USES_OP_NOT_ALLOWED 403 — the operation isn't in the binding's
116
+ // enforcement set (manifest `ops` ∩ `consented_ops`). `err.context`
117
+ // carries `{ uses_slug, op }`. Fix: widen the manifest ops +
118
+ // re-consent (re-bind), or the admin re-binds to consent.
119
+ // - CONTRACT_FIELD_MISSING 409 — a field the binding maps no longer
120
+ // exists on the physical table (schema drift). `err.context`
121
+ // carries `{ uses_slug, field }`. The binding is best-effort parked
122
+ // on detection; an admin re-binds to a table that has the field.
123
+ USES_UNBOUND: "USES_UNBOUND",
124
+ USES_OP_NOT_ALLOWED: "USES_OP_NOT_ALLOWED",
125
+ CONTRACT_FIELD_MISSING: "CONTRACT_FIELD_MISSING",
126
+ // `uses`-plane query joins are NOT supported in v1 — a
127
+ // `qb.uses.<slug>.join(...)` / cross-plane join is rejected with a
128
+ // typed 400. (Joins WITH a uses table as a target are v2 territory.)
129
+ USES_JOIN_UNSUPPORTED: "USES_JOIN_UNSUPPORTED",
76
130
  // Query-plane joins (Phase 3 — see
77
131
  // dashwise-devops-docs/plans/modules-sdk-query-v1-p3-execution.md).
78
132
  // Surfaced when `.join('<slug>')` / `.leftJoin('<slug>')` can't
@@ -85,8 +139,8 @@ var DashwiseErrorCode = {
85
139
  // Cross-module actions (Phase 7 slice 7.3a — see
86
140
  // dashwise-devops-docs/plans/modules-sdk-query-v1-p7-cross-module-writes.md).
87
141
  // Surfaced when `qb.deps.<dep>.actions.<name>(input)` (generated
88
- // factory) dispatches against the new backend endpoint
89
- // `POST :installationId/deps/:providerSlug/actions/:actionName`.
142
+ // factory) dispatches against the backend endpoint
143
+ // `POST /api/module-api/deps/:providerSlug/actions/:actionName`.
90
144
  // Slice 7.2b ships the backend emitter; slice 7.3a (this slice)
91
145
  // reserves the codes + maps them to DepActionError in the SDK.
92
146
  ACTION_NOT_EXPOSED: "ACTION_NOT_EXPOSED",
@@ -212,6 +266,132 @@ var OperationNotAllowedByProviderError = class extends DashwiseError {
212
266
  });
213
267
  }
214
268
  };
269
+ var DepUnboundReason = {
270
+ MISSING_DEPENDENCY: "MISSING_DEPENDENCY",
271
+ DEPENDENCY_VERSION_MISMATCH: "DEPENDENCY_VERSION_MISMATCH",
272
+ PROVIDER_VERSION_RECORD_MISSING: "PROVIDER_VERSION_RECORD_MISSING",
273
+ EXPOSES_MISSING: "EXPOSES_MISSING",
274
+ EXPOSES_PRIVATE: "EXPOSES_PRIVATE",
275
+ ACTION_NOT_EXPOSED: "ACTION_NOT_EXPOSED",
276
+ PROVIDER_NOT_PRODUCTION: "PROVIDER_NOT_PRODUCTION",
277
+ MANUALLY_UNBOUND: "MANUALLY_UNBOUND",
278
+ PROVIDER_UPGRADE_BROKE_CONTRACT: "PROVIDER_UPGRADE_BROKE_CONTRACT",
279
+ PROVIDER_UNINSTALLED: "PROVIDER_UNINSTALLED"
280
+ };
281
+ var DepUnboundError = class extends DashwiseError {
282
+ constructor(message, context, requestId = null) {
283
+ super(DashwiseErrorCode.DEP_UNBOUND, message, {
284
+ status: 409,
285
+ context,
286
+ requestId
287
+ });
288
+ }
289
+ /**
290
+ * The provider module slug the parked dependency points at (kebab-case,
291
+ * e.g. `crm`). Read from `context.provider`; `undefined` if the backend
292
+ * omitted it.
293
+ */
294
+ get provider() {
295
+ const v = this.context?.provider;
296
+ return typeof v === "string" ? v : void 0;
297
+ }
298
+ /**
299
+ * The SemVer range the consumer's manifest declared for this dependency
300
+ * (e.g. `^1.2.0`). Read from `context.range`; `undefined` if omitted.
301
+ */
302
+ get range() {
303
+ const v = this.context?.range;
304
+ return typeof v === "string" ? v : void 0;
305
+ }
306
+ /**
307
+ * Why the dependency is unbound — one of {@link DepUnboundReason} (but
308
+ * typed as `string` for forward-compat with reasons the backend may add).
309
+ * Read from `context.reason`; `undefined` if omitted.
310
+ */
311
+ get reason() {
312
+ const v = this.context?.reason;
313
+ return typeof v === "string" ? v : void 0;
314
+ }
315
+ };
316
+ var UsesUnboundReason = {
317
+ NOT_BOUND_YET: "NOT_BOUND_YET",
318
+ AMBIGUOUS_MATCH: "AMBIGUOUS_MATCH",
319
+ NO_MATCH: "NO_MATCH",
320
+ TABLE_DELETED: "TABLE_DELETED",
321
+ OPS_WIDENED_PENDING_CONSENT: "OPS_WIDENED_PENDING_CONSENT",
322
+ MANUALLY_UNBOUND: "MANUALLY_UNBOUND"
323
+ };
324
+ var UsesUnboundError = class extends DashwiseError {
325
+ constructor(message, context, requestId = null) {
326
+ super(DashwiseErrorCode.USES_UNBOUND, message, {
327
+ status: 409,
328
+ context,
329
+ requestId
330
+ });
331
+ }
332
+ /**
333
+ * The manifest `uses[].tables[].slug` of the unbound slot (kebab-case,
334
+ * e.g. `employees`). Read from `context.uses_slug`; `undefined` if the
335
+ * backend omitted it.
336
+ */
337
+ get usesSlug() {
338
+ const v = this.context?.uses_slug;
339
+ return typeof v === "string" ? v : void 0;
340
+ }
341
+ /**
342
+ * Why the slot is unbound — one of {@link UsesUnboundReason} (typed as
343
+ * `string` for forward-compat with reasons the backend may add). Read
344
+ * from `context.reason`; `undefined` if omitted.
345
+ */
346
+ get reason() {
347
+ const v = this.context?.reason;
348
+ return typeof v === "string" ? v : void 0;
349
+ }
350
+ };
351
+ var UsesOpNotAllowedError = class extends DashwiseError {
352
+ constructor(message, context, requestId = null) {
353
+ super(DashwiseErrorCode.USES_OP_NOT_ALLOWED, message, {
354
+ status: 403,
355
+ context,
356
+ requestId
357
+ });
358
+ }
359
+ /** The `uses` slot slug the rejected op targeted. Read from `context.uses_slug`. */
360
+ get usesSlug() {
361
+ const v = this.context?.uses_slug;
362
+ return typeof v === "string" ? v : void 0;
363
+ }
364
+ /**
365
+ * The operation that was rejected — one of `create` / `read` /
366
+ * `update` / `delete`. Read from `context.op`; `undefined` if omitted.
367
+ */
368
+ get op() {
369
+ const v = this.context?.op;
370
+ return typeof v === "string" ? v : void 0;
371
+ }
372
+ };
373
+ var ContractFieldMissingError = class extends DashwiseError {
374
+ constructor(message, context, requestId = null) {
375
+ super(DashwiseErrorCode.CONTRACT_FIELD_MISSING, message, {
376
+ status: 409,
377
+ context,
378
+ requestId
379
+ });
380
+ }
381
+ /** The `uses` slot slug whose contract broke. Read from `context.uses_slug`. */
382
+ get usesSlug() {
383
+ const v = this.context?.uses_slug;
384
+ return typeof v === "string" ? v : void 0;
385
+ }
386
+ /**
387
+ * The declared field slug (the `uses` side name) whose mapped physical
388
+ * field is gone. Read from `context.field`; `undefined` if omitted.
389
+ */
390
+ get field() {
391
+ const v = this.context?.field;
392
+ return typeof v === "string" ? v : void 0;
393
+ }
394
+ };
215
395
  var JoinError = class extends DashwiseError {
216
396
  constructor(code, message, context, requestId = null) {
217
397
  super(code, message, { status: 400, context, requestId });
@@ -253,9 +433,21 @@ function fromBackendEnvelope(status, envelope, requestId = null) {
253
433
  return new ProviderTableMissingError(message, context, requestId);
254
434
  case DashwiseErrorCode.OPERATION_NOT_ALLOWED_BY_PROVIDER:
255
435
  return new OperationNotAllowedByProviderError(message, context, requestId);
436
+ case DashwiseErrorCode.DEP_UNBOUND:
437
+ return new DepUnboundError(message, context, requestId);
438
+ case DashwiseErrorCode.USES_UNBOUND:
439
+ return new UsesUnboundError(message, context, requestId);
440
+ case DashwiseErrorCode.USES_OP_NOT_ALLOWED:
441
+ return new UsesOpNotAllowedError(message, context, requestId);
442
+ case DashwiseErrorCode.CONTRACT_FIELD_MISSING:
443
+ return new ContractFieldMissingError(message, context, requestId);
256
444
  case DashwiseErrorCode.LINK_FIELD_NOT_FOUND:
257
445
  case DashwiseErrorCode.NOT_A_LINK_FIELD:
258
446
  case DashwiseErrorCode.JOIN_NOT_LINKED:
447
+ // `uses`-plane joins are unsupported in v1; the backend emits a 400
448
+ // with this code. Map to JoinError so it lands in the same
449
+ // "your join can't be resolved" family (code preserved for `err.code`).
450
+ case DashwiseErrorCode.USES_JOIN_UNSUPPORTED:
259
451
  return new JoinError(code, message, context, requestId);
260
452
  case DashwiseErrorCode.ACTION_NOT_EXPOSED:
261
453
  case DashwiseErrorCode.ACTION_NOT_DECLARED:
@@ -290,12 +482,13 @@ var DEFAULT_TIMEOUT_MS = 3e4;
290
482
  var DEFAULT_SLOW_QUERY_THRESHOLD_MS = 500;
291
483
  var TRAILING_SLASH = /\/+$/;
292
484
  var LEADING_SLASH = /^\/+/;
293
- function buildBaseUrl(baseUrl, installationId) {
294
- if (!baseUrl) {
295
- throw new Error("@dashai/sdk: `baseUrl` is required");
485
+ var MODULE_API_PREFIX = "/api/module-api";
486
+ function buildBaseUrl(apiUrl) {
487
+ if (!apiUrl) {
488
+ throw new Error("@dashai/sdk: `apiUrl` is required");
296
489
  }
297
- const trimmed = baseUrl.replace(TRAILING_SLASH, "");
298
- return `${trimmed}/api/modules/${installationId}`;
490
+ const trimmed = apiUrl.replace(TRAILING_SLASH, "");
491
+ return `${trimmed}${MODULE_API_PREFIX}`;
299
492
  }
300
493
  function resolveFetch(custom) {
301
494
  if (custom) return custom;
@@ -323,7 +516,7 @@ async function readBody(res) {
323
516
  }
324
517
  }
325
518
  function createHttp(config) {
326
- const base = buildBaseUrl(config.baseUrl, config.installationId);
519
+ const base = buildBaseUrl(config.apiUrl ?? config.baseUrl);
327
520
  const doFetch = resolveFetch(config.fetch);
328
521
  const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
329
522
  const staticHeaders = {
@@ -342,7 +535,7 @@ function createHttp(config) {
342
535
  }
343
536
  async function request(method, path, body) {
344
537
  const normalizedPath = `/${path.replace(LEADING_SLASH, "")}`;
345
- const url = normalizedPath.startsWith("/api/") ? `${config.baseUrl.replace(/\/+$/, "")}${normalizedPath}` : `${base}${normalizedPath}`;
538
+ const url = `${base}${normalizedPath}`;
346
539
  const token = (config.getToken ? await config.getToken() : null) ?? config.apiKey ?? null;
347
540
  const headers = { ...staticHeaders };
348
541
  if (body !== void 0) {
@@ -537,9 +730,7 @@ function createClient(config) {
537
730
  async _callAction(providerSlug, actionName, input, opts) {
538
731
  assertValidModuleSlug(providerSlug);
539
732
  assertValidActionName(actionName);
540
- const path = `/api/modules/runtime/installations/${config.installationId}/deps/${encodeURIComponent(
541
- providerSlug
542
- )}/actions/${encodeURIComponent(actionName)}`;
733
+ const path = `/deps/${encodeURIComponent(providerSlug)}/actions/${encodeURIComponent(actionName)}`;
543
734
  const body = { input };
544
735
  if (opts?.idempotencyKey !== void 0) {
545
736
  body.idempotency_key = opts.idempotencyKey;
@@ -598,8 +789,12 @@ function makeDatahubClient(transport) {
598
789
  assertValidTableId(tableId);
599
790
  const root = `/datahub/tables/${tableId}/rows`;
600
791
  return {
601
- async list(query) {
602
- const qs = query ? new URLSearchParams(query).toString() : "";
792
+ async list(opts) {
793
+ const arg = opts;
794
+ const flat = isDatahubListOpts(
795
+ arg
796
+ ) ? compileDatahubListOpts(arg) : arg;
797
+ const qs = flat ? new URLSearchParams(flat).toString() : "";
603
798
  const path = qs ? `${root}?${qs}` : root;
604
799
  return transport.request("GET", path);
605
800
  },
@@ -636,6 +831,100 @@ function assertValidTableId(tableId) {
636
831
  );
637
832
  }
638
833
  }
834
+ var DATAHUB_LIST_OPT_KEYS = /* @__PURE__ */ new Set([
835
+ "filter",
836
+ "sort",
837
+ "search",
838
+ "limit",
839
+ "page"
840
+ ]);
841
+ var FILTER_GROUP_KEYS = /* @__PURE__ */ new Set(["AND", "OR"]);
842
+ function isDatahubListOpts(opts) {
843
+ if (opts === void 0 || opts === null || typeof opts !== "object") {
844
+ return false;
845
+ }
846
+ return Object.keys(opts).some((k) => DATAHUB_LIST_OPT_KEYS.has(k));
847
+ }
848
+ function compileDatahubListOpts(opts) {
849
+ const out = {};
850
+ if (opts.filter !== void 0) {
851
+ const where = opts.filter;
852
+ if (hasFilterGrouping(where)) {
853
+ out.filters = JSON.stringify(whereToBackendTree(where));
854
+ } else {
855
+ for (const [field, value] of Object.entries(where)) {
856
+ if (value === void 0) continue;
857
+ if (isFilterOpsObject(value)) {
858
+ for (const [op, opValue] of Object.entries(value)) {
859
+ if (opValue === void 0) continue;
860
+ out[`filter__${field}__${op}`] = stringifyFilterValue(opValue);
861
+ }
862
+ } else {
863
+ out[`filter__${field}__equal`] = stringifyFilterValue(value);
864
+ }
865
+ }
866
+ }
867
+ }
868
+ if (opts.sort !== void 0 && opts.sort.length > 0) {
869
+ out.order_by = opts.sort.map(
870
+ (s) => s.dir === "desc" ? `-${s.field}` : s.field
871
+ ).join(",");
872
+ }
873
+ if (opts.search !== void 0) out.search = opts.search;
874
+ if (typeof opts.limit === "number") out.size = String(opts.limit);
875
+ if (typeof opts.page === "number") out.page = String(opts.page);
876
+ if (opts.filter !== void 0 || opts.sort !== void 0 && opts.sort.length > 0) {
877
+ out.user_field_names = "true";
878
+ }
879
+ return out;
880
+ }
881
+ function hasFilterGrouping(where) {
882
+ return Object.keys(where).some((k) => FILTER_GROUP_KEYS.has(k));
883
+ }
884
+ function isFilterGroupNode(node) {
885
+ return Object.keys(node).some((k) => FILTER_GROUP_KEYS.has(k));
886
+ }
887
+ function fieldLeaves(node) {
888
+ const leaves = [];
889
+ for (const [field, value] of Object.entries(node)) {
890
+ if (FILTER_GROUP_KEYS.has(field) || value === void 0) continue;
891
+ if (isFilterOpsObject(value)) {
892
+ for (const [op, opValue] of Object.entries(value)) {
893
+ if (opValue === void 0) continue;
894
+ leaves.push({ field, type: op, value: stringifyFilterValue(opValue) });
895
+ }
896
+ } else {
897
+ leaves.push({ field, type: "equal", value: stringifyFilterValue(value) });
898
+ }
899
+ }
900
+ return leaves;
901
+ }
902
+ function whereToBackendTree(where, defaultType = "AND") {
903
+ const obj = where;
904
+ const groupKey = Object.keys(obj).find((k) => FILTER_GROUP_KEYS.has(k));
905
+ if (groupKey) {
906
+ const children = obj[groupKey] ?? [];
907
+ const filters = [];
908
+ const filter_groups = [];
909
+ for (const child of children) {
910
+ const childObj = child;
911
+ if (isFilterGroupNode(childObj)) {
912
+ filter_groups.push(whereToBackendTree(child));
913
+ } else {
914
+ filters.push(...fieldLeaves(childObj));
915
+ }
916
+ }
917
+ return { filter_type: groupKey, filters, filter_groups };
918
+ }
919
+ return { filter_type: defaultType, filters: fieldLeaves(obj), filter_groups: [] };
920
+ }
921
+ function isFilterOpsObject(value) {
922
+ return typeof value === "object" && value !== null && !Array.isArray(value);
923
+ }
924
+ function stringifyFilterValue(value) {
925
+ if (value === null) return "";
926
+ return String(value);
927
+ }
639
928
  function makeTableClient(transport, tableSlug) {
640
929
  const root = `/db/${tableSlug}`;
641
930
  return {
@@ -686,14 +975,12 @@ function createDevClient(overrides = {}) {
686
975
  );
687
976
  }
688
977
  const moduleEntry = overrides.moduleSlug ? fileConfig?.modules?.[overrides.moduleSlug] : void 0;
689
- const runtimeToken = readEnv("DASHWISE_RUNTIME_TOKEN") ?? moduleEntry?.runtimeToken ?? null;
690
- const installationId = overrides.installationId ?? readEnv("DASHWISE_INSTALLATION_ID") ?? (runtimeToken !== null ? "sandbox" : "local");
691
- const snapshotToken = runtimeToken ?? readEnv("DASHWISE_API_KEY") ?? readEnv("DASHWISE_API_TOKEN") ?? fileConfig?.token ?? null;
978
+ const devModuleToken = moduleEntry?.apiKey ?? moduleEntry?.runtimeToken ?? null;
979
+ const snapshotToken = devModuleToken ?? readEnv("DASHWISE_API_KEY") ?? fileConfig?.token ?? null;
692
980
  const resolvedGetToken = overrides.getToken ?? (() => snapshotToken);
693
981
  return createClient({
694
982
  ...overrides,
695
983
  baseUrl,
696
- installationId,
697
984
  getToken: resolvedGetToken
698
985
  });
699
986
  }
@@ -746,8 +1033,8 @@ function isPlausibleFileShape(v) {
746
1033
  }
747
1034
 
748
1035
  // src/index.ts
749
- var VERSION = "0.9.0" ;
1036
+ var VERSION = "2.0.0" ;
750
1037
 
751
- export { ContractViolationError, DashwiseError, DashwiseErrorCode, DependencyContractError, ForbiddenError, JoinError, NetworkError, OperationNotAllowedByProviderError, ProviderTableMissingError, RowNotFoundError, TimeoutError, UnauthenticatedError, VERSION, ValidationError, createClient, createDevClient, fromBackendEnvelope };
1038
+ export { ContractFieldMissingError, ContractViolationError, DashwiseError, DashwiseErrorCode, DepUnboundError, DepUnboundReason, DependencyContractError, ForbiddenError, JoinError, NetworkError, OperationNotAllowedByProviderError, ProviderTableMissingError, RowNotFoundError, TimeoutError, UnauthenticatedError, UsesOpNotAllowedError, UsesUnboundError, UsesUnboundReason, VERSION, ValidationError, createClient, createDevClient, fromBackendEnvelope };
752
1039
  //# sourceMappingURL=index.js.map
753
1040
  //# sourceMappingURL=index.js.map