@dashai/sdk 0.10.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 +218 -23
  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 +213 -24
  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-BwlzFHbq.d.cts → types-CkAfiS4k.d.cts} +37 -31
  43. package/dist/{types-BwlzFHbq.d.ts → types-CkAfiS4k.d.ts} +37 -31
  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.cjs CHANGED
@@ -34,23 +34,39 @@ function makeDeps(transport, providerSlug) {
34
34
  };
35
35
  }
36
36
  function makeBorrowedTableClient(transport, providerSlug, tableSlug) {
37
- const root = `/deps/${providerSlug}/db/${tableSlug}`;
37
+ const tablesRoot = `/deps/${providerSlug}/tables/${tableSlug}`;
38
38
  return {
39
39
  async list(opts) {
40
- const body = opts ?? {};
41
- const result = await transport.request("POST", `${root}/list`, body);
40
+ const ast = {
41
+ v: 1,
42
+ from: { kind: "dep", module: providerSlug, slug: tableSlug }
43
+ };
44
+ if (opts?.filter !== void 0) ast.where = opts.filter;
45
+ if (opts?.sort !== void 0 && opts.sort.length > 0) {
46
+ ast.orderBy = opts.sort;
47
+ }
48
+ if (typeof opts?.limit === "number") ast.limit = opts.limit;
49
+ if (typeof opts?.offset === "number") ast.offset = opts.offset;
50
+ const result = await transport.request("POST", "/query", { ast });
42
51
  if (Array.isArray(result)) {
43
52
  return {
44
53
  rows: result,
45
54
  total: result.length,
46
- limit: body.limit ?? result.length,
47
- offset: body.offset ?? 0
55
+ limit: opts?.limit ?? result.length,
56
+ offset: opts?.offset ?? 0
48
57
  };
49
58
  }
50
59
  return result;
51
60
  },
52
61
  async get(id) {
53
- return transport.request("GET", `${root}/${id}`);
62
+ const result = await transport.request(
63
+ "GET",
64
+ `${tablesRoot}/${id}`
65
+ );
66
+ if (result && typeof result === "object" && "row" in result) {
67
+ return result.row;
68
+ }
69
+ return result;
54
70
  }
55
71
  };
56
72
  }
@@ -75,6 +91,44 @@ var DashwiseErrorCode = {
75
91
  TABLE_NOT_IN_CONTRACT: "TABLE_NOT_IN_CONTRACT",
76
92
  PROVIDER_TABLE_MISSING: "PROVIDER_TABLE_MISSING",
77
93
  OPERATION_NOT_ALLOWED_BY_PROVIDER: "OPERATION_NOT_ALLOWED_BY_PROVIDER",
94
+ // Cross-module dependency PARK state (Phase 3 modules-platform-v2 —
95
+ // dependency connect/bind lifecycle). Surfaced at RUNTIME (409) when a
96
+ // module reads a borrowed table (`client.deps(slug)` / `qb.deps.<slug>`)
97
+ // or invokes a dep action whose `module_dependencies` row is currently
98
+ // `status='unbound'` — the dependency is declared but not connected to a
99
+ // provider installation (no provider in the workspace, version mismatch,
100
+ // manually unbound, provider uninstalled, etc.). The consumer app should
101
+ // render a "connect your provider" state rather than treating this as a
102
+ // hard failure. `err.context` carries `{ provider, range, reason }`.
103
+ DEP_UNBOUND: "DEP_UNBOUND",
104
+ // Workspace-table `uses` plane (Phase 4 modules-platform-v2 — the
105
+ // declared/portable path for a module to read+write a WORKSPACE table
106
+ // the workspace already owns, as opposed to `deps` = another module's
107
+ // tables). Surfaced at RUNTIME against `client.uses(slug)` /
108
+ // `qb.uses.<slug>` / the `POST /api/module-api/uses/:slug/...` REST
109
+ // plane. The BINDING is the grant on this plane (for sandbox AND
110
+ // api_key auth alike — a kind-local key does NOT bypass it):
111
+ // - USES_UNBOUND 409 — the `uses` slot is declared but its
112
+ // `module_table_bindings` row isn't `status='bound'` (never bound,
113
+ // ambiguous match, no match, table trashed, ops widened pending
114
+ // re-consent, manually unbound). `err.context` carries
115
+ // `{ uses_slug, reason }`. Recoverable: a workspace admin binds a
116
+ // table (`dashwise bind <uses_slug>`), then the read succeeds.
117
+ // - USES_OP_NOT_ALLOWED 403 — the operation isn't in the binding's
118
+ // enforcement set (manifest `ops` ∩ `consented_ops`). `err.context`
119
+ // carries `{ uses_slug, op }`. Fix: widen the manifest ops +
120
+ // re-consent (re-bind), or the admin re-binds to consent.
121
+ // - CONTRACT_FIELD_MISSING 409 — a field the binding maps no longer
122
+ // exists on the physical table (schema drift). `err.context`
123
+ // carries `{ uses_slug, field }`. The binding is best-effort parked
124
+ // on detection; an admin re-binds to a table that has the field.
125
+ USES_UNBOUND: "USES_UNBOUND",
126
+ USES_OP_NOT_ALLOWED: "USES_OP_NOT_ALLOWED",
127
+ CONTRACT_FIELD_MISSING: "CONTRACT_FIELD_MISSING",
128
+ // `uses`-plane query joins are NOT supported in v1 — a
129
+ // `qb.uses.<slug>.join(...)` / cross-plane join is rejected with a
130
+ // typed 400. (Joins WITH a uses table as a target are v2 territory.)
131
+ USES_JOIN_UNSUPPORTED: "USES_JOIN_UNSUPPORTED",
78
132
  // Query-plane joins (Phase 3 — see
79
133
  // dashwise-devops-docs/plans/modules-sdk-query-v1-p3-execution.md).
80
134
  // Surfaced when `.join('<slug>')` / `.leftJoin('<slug>')` can't
@@ -87,8 +141,8 @@ var DashwiseErrorCode = {
87
141
  // Cross-module actions (Phase 7 slice 7.3a — see
88
142
  // dashwise-devops-docs/plans/modules-sdk-query-v1-p7-cross-module-writes.md).
89
143
  // Surfaced when `qb.deps.<dep>.actions.<name>(input)` (generated
90
- // factory) dispatches against the new backend endpoint
91
- // `POST :installationId/deps/:providerSlug/actions/:actionName`.
144
+ // factory) dispatches against the backend endpoint
145
+ // `POST /api/module-api/deps/:providerSlug/actions/:actionName`.
92
146
  // Slice 7.2b ships the backend emitter; slice 7.3a (this slice)
93
147
  // reserves the codes + maps them to DepActionError in the SDK.
94
148
  ACTION_NOT_EXPOSED: "ACTION_NOT_EXPOSED",
@@ -214,6 +268,132 @@ var OperationNotAllowedByProviderError = class extends DashwiseError {
214
268
  });
215
269
  }
216
270
  };
271
+ var DepUnboundReason = {
272
+ MISSING_DEPENDENCY: "MISSING_DEPENDENCY",
273
+ DEPENDENCY_VERSION_MISMATCH: "DEPENDENCY_VERSION_MISMATCH",
274
+ PROVIDER_VERSION_RECORD_MISSING: "PROVIDER_VERSION_RECORD_MISSING",
275
+ EXPOSES_MISSING: "EXPOSES_MISSING",
276
+ EXPOSES_PRIVATE: "EXPOSES_PRIVATE",
277
+ ACTION_NOT_EXPOSED: "ACTION_NOT_EXPOSED",
278
+ PROVIDER_NOT_PRODUCTION: "PROVIDER_NOT_PRODUCTION",
279
+ MANUALLY_UNBOUND: "MANUALLY_UNBOUND",
280
+ PROVIDER_UPGRADE_BROKE_CONTRACT: "PROVIDER_UPGRADE_BROKE_CONTRACT",
281
+ PROVIDER_UNINSTALLED: "PROVIDER_UNINSTALLED"
282
+ };
283
+ var DepUnboundError = class extends DashwiseError {
284
+ constructor(message, context, requestId = null) {
285
+ super(DashwiseErrorCode.DEP_UNBOUND, message, {
286
+ status: 409,
287
+ context,
288
+ requestId
289
+ });
290
+ }
291
+ /**
292
+ * The provider module slug the parked dependency points at (kebab-case,
293
+ * e.g. `crm`). Read from `context.provider`; `undefined` if the backend
294
+ * omitted it.
295
+ */
296
+ get provider() {
297
+ const v = this.context?.provider;
298
+ return typeof v === "string" ? v : void 0;
299
+ }
300
+ /**
301
+ * The SemVer range the consumer's manifest declared for this dependency
302
+ * (e.g. `^1.2.0`). Read from `context.range`; `undefined` if omitted.
303
+ */
304
+ get range() {
305
+ const v = this.context?.range;
306
+ return typeof v === "string" ? v : void 0;
307
+ }
308
+ /**
309
+ * Why the dependency is unbound — one of {@link DepUnboundReason} (but
310
+ * typed as `string` for forward-compat with reasons the backend may add).
311
+ * Read from `context.reason`; `undefined` if omitted.
312
+ */
313
+ get reason() {
314
+ const v = this.context?.reason;
315
+ return typeof v === "string" ? v : void 0;
316
+ }
317
+ };
318
+ var UsesUnboundReason = {
319
+ NOT_BOUND_YET: "NOT_BOUND_YET",
320
+ AMBIGUOUS_MATCH: "AMBIGUOUS_MATCH",
321
+ NO_MATCH: "NO_MATCH",
322
+ TABLE_DELETED: "TABLE_DELETED",
323
+ OPS_WIDENED_PENDING_CONSENT: "OPS_WIDENED_PENDING_CONSENT",
324
+ MANUALLY_UNBOUND: "MANUALLY_UNBOUND"
325
+ };
326
+ var UsesUnboundError = class extends DashwiseError {
327
+ constructor(message, context, requestId = null) {
328
+ super(DashwiseErrorCode.USES_UNBOUND, message, {
329
+ status: 409,
330
+ context,
331
+ requestId
332
+ });
333
+ }
334
+ /**
335
+ * The manifest `uses[].tables[].slug` of the unbound slot (kebab-case,
336
+ * e.g. `employees`). Read from `context.uses_slug`; `undefined` if the
337
+ * backend omitted it.
338
+ */
339
+ get usesSlug() {
340
+ const v = this.context?.uses_slug;
341
+ return typeof v === "string" ? v : void 0;
342
+ }
343
+ /**
344
+ * Why the slot is unbound — one of {@link UsesUnboundReason} (typed as
345
+ * `string` for forward-compat with reasons the backend may add). Read
346
+ * from `context.reason`; `undefined` if omitted.
347
+ */
348
+ get reason() {
349
+ const v = this.context?.reason;
350
+ return typeof v === "string" ? v : void 0;
351
+ }
352
+ };
353
+ var UsesOpNotAllowedError = class extends DashwiseError {
354
+ constructor(message, context, requestId = null) {
355
+ super(DashwiseErrorCode.USES_OP_NOT_ALLOWED, message, {
356
+ status: 403,
357
+ context,
358
+ requestId
359
+ });
360
+ }
361
+ /** The `uses` slot slug the rejected op targeted. Read from `context.uses_slug`. */
362
+ get usesSlug() {
363
+ const v = this.context?.uses_slug;
364
+ return typeof v === "string" ? v : void 0;
365
+ }
366
+ /**
367
+ * The operation that was rejected — one of `create` / `read` /
368
+ * `update` / `delete`. Read from `context.op`; `undefined` if omitted.
369
+ */
370
+ get op() {
371
+ const v = this.context?.op;
372
+ return typeof v === "string" ? v : void 0;
373
+ }
374
+ };
375
+ var ContractFieldMissingError = class extends DashwiseError {
376
+ constructor(message, context, requestId = null) {
377
+ super(DashwiseErrorCode.CONTRACT_FIELD_MISSING, message, {
378
+ status: 409,
379
+ context,
380
+ requestId
381
+ });
382
+ }
383
+ /** The `uses` slot slug whose contract broke. Read from `context.uses_slug`. */
384
+ get usesSlug() {
385
+ const v = this.context?.uses_slug;
386
+ return typeof v === "string" ? v : void 0;
387
+ }
388
+ /**
389
+ * The declared field slug (the `uses` side name) whose mapped physical
390
+ * field is gone. Read from `context.field`; `undefined` if omitted.
391
+ */
392
+ get field() {
393
+ const v = this.context?.field;
394
+ return typeof v === "string" ? v : void 0;
395
+ }
396
+ };
217
397
  var JoinError = class extends DashwiseError {
218
398
  constructor(code, message, context, requestId = null) {
219
399
  super(code, message, { status: 400, context, requestId });
@@ -255,9 +435,21 @@ function fromBackendEnvelope(status, envelope, requestId = null) {
255
435
  return new ProviderTableMissingError(message, context, requestId);
256
436
  case DashwiseErrorCode.OPERATION_NOT_ALLOWED_BY_PROVIDER:
257
437
  return new OperationNotAllowedByProviderError(message, context, requestId);
438
+ case DashwiseErrorCode.DEP_UNBOUND:
439
+ return new DepUnboundError(message, context, requestId);
440
+ case DashwiseErrorCode.USES_UNBOUND:
441
+ return new UsesUnboundError(message, context, requestId);
442
+ case DashwiseErrorCode.USES_OP_NOT_ALLOWED:
443
+ return new UsesOpNotAllowedError(message, context, requestId);
444
+ case DashwiseErrorCode.CONTRACT_FIELD_MISSING:
445
+ return new ContractFieldMissingError(message, context, requestId);
258
446
  case DashwiseErrorCode.LINK_FIELD_NOT_FOUND:
259
447
  case DashwiseErrorCode.NOT_A_LINK_FIELD:
260
448
  case DashwiseErrorCode.JOIN_NOT_LINKED:
449
+ // `uses`-plane joins are unsupported in v1; the backend emits a 400
450
+ // with this code. Map to JoinError so it lands in the same
451
+ // "your join can't be resolved" family (code preserved for `err.code`).
452
+ case DashwiseErrorCode.USES_JOIN_UNSUPPORTED:
261
453
  return new JoinError(code, message, context, requestId);
262
454
  case DashwiseErrorCode.ACTION_NOT_EXPOSED:
263
455
  case DashwiseErrorCode.ACTION_NOT_DECLARED:
@@ -292,12 +484,13 @@ var DEFAULT_TIMEOUT_MS = 3e4;
292
484
  var DEFAULT_SLOW_QUERY_THRESHOLD_MS = 500;
293
485
  var TRAILING_SLASH = /\/+$/;
294
486
  var LEADING_SLASH = /^\/+/;
295
- function buildBaseUrl(baseUrl, installationId) {
296
- if (!baseUrl) {
297
- throw new Error("@dashai/sdk: `baseUrl` is required");
487
+ var MODULE_API_PREFIX = "/api/module-api";
488
+ function buildBaseUrl(apiUrl) {
489
+ if (!apiUrl) {
490
+ throw new Error("@dashai/sdk: `apiUrl` is required");
298
491
  }
299
- const trimmed = baseUrl.replace(TRAILING_SLASH, "");
300
- return `${trimmed}/api/modules/${installationId}`;
492
+ const trimmed = apiUrl.replace(TRAILING_SLASH, "");
493
+ return `${trimmed}${MODULE_API_PREFIX}`;
301
494
  }
302
495
  function resolveFetch(custom) {
303
496
  if (custom) return custom;
@@ -325,7 +518,7 @@ async function readBody(res) {
325
518
  }
326
519
  }
327
520
  function createHttp(config) {
328
- const base = buildBaseUrl(config.baseUrl, config.installationId);
521
+ const base = buildBaseUrl(config.apiUrl ?? config.baseUrl);
329
522
  const doFetch = resolveFetch(config.fetch);
330
523
  const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
331
524
  const staticHeaders = {
@@ -344,7 +537,7 @@ function createHttp(config) {
344
537
  }
345
538
  async function request(method, path, body) {
346
539
  const normalizedPath = `/${path.replace(LEADING_SLASH, "")}`;
347
- const url = normalizedPath.startsWith("/api/") ? `${config.baseUrl.replace(/\/+$/, "")}${normalizedPath}` : `${base}${normalizedPath}`;
540
+ const url = `${base}${normalizedPath}`;
348
541
  const token = (config.getToken ? await config.getToken() : null) ?? config.apiKey ?? null;
349
542
  const headers = { ...staticHeaders };
350
543
  if (body !== void 0) {
@@ -539,9 +732,7 @@ function createClient(config) {
539
732
  async _callAction(providerSlug, actionName, input, opts) {
540
733
  assertValidModuleSlug(providerSlug);
541
734
  assertValidActionName(actionName);
542
- const path = `/api/modules/runtime/installations/${config.installationId}/deps/${encodeURIComponent(
543
- providerSlug
544
- )}/actions/${encodeURIComponent(actionName)}`;
735
+ const path = `/deps/${encodeURIComponent(providerSlug)}/actions/${encodeURIComponent(actionName)}`;
545
736
  const body = { input };
546
737
  if (opts?.idempotencyKey !== void 0) {
547
738
  body.idempotency_key = opts.idempotencyKey;
@@ -786,14 +977,12 @@ function createDevClient(overrides = {}) {
786
977
  );
787
978
  }
788
979
  const moduleEntry = overrides.moduleSlug ? fileConfig?.modules?.[overrides.moduleSlug] : void 0;
789
- const runtimeToken = readEnv("DASHWISE_RUNTIME_TOKEN") ?? moduleEntry?.runtimeToken ?? null;
790
- const installationId = overrides.installationId ?? readEnv("DASHWISE_INSTALLATION_ID") ?? (runtimeToken !== null ? "sandbox" : "local");
791
- const snapshotToken = runtimeToken ?? readEnv("DASHWISE_API_KEY") ?? readEnv("DASHWISE_API_TOKEN") ?? fileConfig?.token ?? null;
980
+ const devModuleToken = moduleEntry?.apiKey ?? moduleEntry?.runtimeToken ?? null;
981
+ const snapshotToken = devModuleToken ?? readEnv("DASHWISE_API_KEY") ?? fileConfig?.token ?? null;
792
982
  const resolvedGetToken = overrides.getToken ?? (() => snapshotToken);
793
983
  return createClient({
794
984
  ...overrides,
795
985
  baseUrl,
796
- installationId,
797
986
  getToken: resolvedGetToken
798
987
  });
799
988
  }
@@ -846,11 +1035,14 @@ function isPlausibleFileShape(v) {
846
1035
  }
847
1036
 
848
1037
  // src/index.ts
849
- var VERSION = "0.10.0" ;
1038
+ var VERSION = "2.0.0" ;
850
1039
 
1040
+ exports.ContractFieldMissingError = ContractFieldMissingError;
851
1041
  exports.ContractViolationError = ContractViolationError;
852
1042
  exports.DashwiseError = DashwiseError;
853
1043
  exports.DashwiseErrorCode = DashwiseErrorCode;
1044
+ exports.DepUnboundError = DepUnboundError;
1045
+ exports.DepUnboundReason = DepUnboundReason;
854
1046
  exports.DependencyContractError = DependencyContractError;
855
1047
  exports.ForbiddenError = ForbiddenError;
856
1048
  exports.JoinError = JoinError;
@@ -860,6 +1052,9 @@ exports.ProviderTableMissingError = ProviderTableMissingError;
860
1052
  exports.RowNotFoundError = RowNotFoundError;
861
1053
  exports.TimeoutError = TimeoutError;
862
1054
  exports.UnauthenticatedError = UnauthenticatedError;
1055
+ exports.UsesOpNotAllowedError = UsesOpNotAllowedError;
1056
+ exports.UsesUnboundError = UsesUnboundError;
1057
+ exports.UsesUnboundReason = UsesUnboundReason;
863
1058
  exports.VERSION = VERSION;
864
1059
  exports.ValidationError = ValidationError;
865
1060
  exports.createClient = createClient;