@graph8/sdk 0.13.0 → 0.13.1
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 +62 -6
- package/dist/index.d.mts +23 -7
- package/dist/index.d.ts +23 -7
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +12 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +23 -7
- package/dist/react.d.ts +23 -7
- package/dist/react.js +12 -2
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +12 -2
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -251,6 +251,28 @@ export const CTA = () => {
|
|
|
251
251
|
| `g8.webhooks.constructEvent(body, sig, ts, secret, opts?)` | Verify a delivery's HMAC signature and return the parsed event (throws `WebhookSignatureError`) |
|
|
252
252
|
| `g8.webhooks.knownEvents` | The known event-type catalog |
|
|
253
253
|
|
|
254
|
+
## Native custom objects
|
|
255
|
+
|
|
256
|
+
Use an organization API key with explicit `objects:read` for schema/record/history
|
|
257
|
+
reads, `objects:write` for create/PATCH, and `objects:delete` for archive. Unscoped
|
|
258
|
+
keys receive 403. `objects:*` grants all three; grant only the operations the
|
|
259
|
+
integration needs.
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import { g8 } from '@graph8/sdk';
|
|
263
|
+
|
|
264
|
+
g8.init({ apiKey: process.env.G8_API_KEY! });
|
|
265
|
+
const { data: objects } = await g8.objects.list();
|
|
266
|
+
const { data: attributes } = await g8.objects.listAttributes('invoices');
|
|
267
|
+
// Assumes this workspace defines an invoices object with a reference attribute.
|
|
268
|
+
const invoice = await g8.objects.createRecord('invoices', { reference: 'INV-1042' });
|
|
269
|
+
const history = await g8.objects.history('invoices', invoice.id);
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
PATCH preserves omitted attributes. Enabled defaults apply only on create;
|
|
273
|
+
unknown fields return 422 and unique-value collisions return 409. Standard
|
|
274
|
+
contacts, companies, and deals continue using their existing SDK resources.
|
|
275
|
+
|
|
254
276
|
## App Platform
|
|
255
277
|
|
|
256
278
|
Hosted apps do not carry a permanent org API key. Instead they **exchange** a
|
|
@@ -275,8 +297,8 @@ const appClient = createGraph8AppClient({
|
|
|
275
297
|
});
|
|
276
298
|
|
|
277
299
|
// Reach the existing resources with the app token via request():
|
|
278
|
-
const { data:
|
|
279
|
-
'/api/v1/
|
|
300
|
+
const { data: objects } = await appClient.request<{ data: unknown[] }>(
|
|
301
|
+
'/api/v1/app/objects',
|
|
280
302
|
{ query: { limit: 10 } },
|
|
281
303
|
);
|
|
282
304
|
```
|
|
@@ -295,12 +317,12 @@ const service = createGraph8ServiceClient({
|
|
|
295
317
|
scopes: ['objects:read', 'objects:write'],
|
|
296
318
|
});
|
|
297
319
|
|
|
298
|
-
const { data:
|
|
320
|
+
const { data: objects } = await service.request<{ data: unknown[] }>('/api/v1/app/objects');
|
|
299
321
|
```
|
|
300
322
|
|
|
301
|
-
>
|
|
302
|
-
>
|
|
303
|
-
>
|
|
323
|
+
> App-token clients use `request()` for their consented app-owned objects.
|
|
324
|
+
> The `g8.objects` resource above uses an API key for native workspace objects;
|
|
325
|
+
> it does not substitute for app-token authorization.
|
|
304
326
|
|
|
305
327
|
## Auth Modes
|
|
306
328
|
|
|
@@ -315,3 +337,37 @@ Get your API key at [app.graph8.com/settings](https://app.graph8.com/settings) u
|
|
|
315
337
|
## License
|
|
316
338
|
|
|
317
339
|
MIT
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
### Conditional custom-record updates
|
|
343
|
+
|
|
344
|
+
Custom-record responses expose `revision`. Pass it when saving an interactive edit:
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
import { g8 } from "@graph8/sdk";
|
|
348
|
+
|
|
349
|
+
g8.init({ apiKey: "YOUR_API_KEY" });
|
|
350
|
+
const projectId = "your-project-record-id";
|
|
351
|
+
const record = await g8.objects.getRecord("projects", projectId);
|
|
352
|
+
const updated = await g8.objects.updateRecord(
|
|
353
|
+
"projects", record.id, { name: "Updated project" },
|
|
354
|
+
{ expectedRevision: record.revision },
|
|
355
|
+
);
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
A stale revision returns HTTP 409 with code `revision_conflict`; reload the record
|
|
359
|
+
and reconcile the edit before retrying. Native and app APIs accept
|
|
360
|
+
`expected_revision` in the PATCH body, and the MCP update tool accepts the same
|
|
361
|
+
argument. Omitting it retains unconditional PATCH behavior. Older servers may
|
|
362
|
+
omit `revision`; deploy the revision-enabled backend before relying on this
|
|
363
|
+
precondition. This applies to custom-object records.
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
Restore a custom record with `g8.objects.restoreRecord(objectSlug, recordId)`.
|
|
367
|
+
The native API uses `POST /api/v1/objects/{objectSlug}/records/{recordId}/restore`;
|
|
368
|
+
MCP exposes `g8_object_record_restore`. Restoration preserves the original ID and
|
|
369
|
+
old history, validates the current schema and references, and returns 409 if a
|
|
370
|
+
unique value has been reused. Validation failures leave the record archived.
|
|
371
|
+
Ambiguous legacy history returns 422 with `archive_snapshot_unavailable` rather
|
|
372
|
+
than guessing its prior values. Repeating a successful restore adds no revision
|
|
373
|
+
or history entry.
|
package/dist/index.d.mts
CHANGED
|
@@ -1765,6 +1765,10 @@ interface CustomObjectAttribute {
|
|
|
1765
1765
|
/** No two ACTIVE records may hold the same value. A collision returns 409. */
|
|
1766
1766
|
is_unique: boolean;
|
|
1767
1767
|
is_multiselect: boolean;
|
|
1768
|
+
/** Apply a non-null default to omitted create fields, never PATCH. Absent on older servers. */
|
|
1769
|
+
is_default_value_enabled?: boolean;
|
|
1770
|
+
/** Configured default; validated like an explicit value when enabled. */
|
|
1771
|
+
default_value?: unknown;
|
|
1768
1772
|
/** Type-specific configuration, e.g. the allowed options for a `select`. */
|
|
1769
1773
|
config: Record<string, unknown>;
|
|
1770
1774
|
}
|
|
@@ -1780,6 +1784,8 @@ interface CustomObjectRecord {
|
|
|
1780
1784
|
*/
|
|
1781
1785
|
values: Record<string, unknown>;
|
|
1782
1786
|
is_archived: boolean;
|
|
1787
|
+
/** Revision for conditional updates; absent on older servers. */
|
|
1788
|
+
revision?: number;
|
|
1783
1789
|
created_at: string | null;
|
|
1784
1790
|
updated_at: string | null;
|
|
1785
1791
|
}
|
|
@@ -1824,10 +1830,7 @@ interface ObjectPagination {
|
|
|
1824
1830
|
* Requires an API key (server-side). On the hardened HTTP core: throws a typed
|
|
1825
1831
|
* `G8Error` on failure and retries transient errors.
|
|
1826
1832
|
*
|
|
1827
|
-
*
|
|
1828
|
-
* custom-objects surface is switched on for the platform. It is off by default,
|
|
1829
|
-
* so a call fails fast rather than returning an empty list that reads as "you
|
|
1830
|
-
* have no objects".
|
|
1833
|
+
* Access requires an authenticated credential with the applicable object scope.
|
|
1831
1834
|
*
|
|
1832
1835
|
* HOW THIS DIFFERS FROM `g8.fields`. A FIELD adds a column to an existing
|
|
1833
1836
|
* contact or company. A CUSTOM OBJECT is a whole new record type with its own
|
|
@@ -1840,10 +1843,16 @@ interface ObjectPagination {
|
|
|
1840
1843
|
* lose your data, and the response lists every problem at once so a payload
|
|
1841
1844
|
* with three mistakes takes one round trip to fix.
|
|
1842
1845
|
* 2. `update` is a PARTIAL write. Attributes you omit are left alone; sending
|
|
1843
|
-
* an explicit `null`
|
|
1846
|
+
* an explicit `null` clears an optional attribute. Required attributes
|
|
1847
|
+
* cannot be cleared with `null` or an empty multivalue list (422).
|
|
1844
1848
|
* 3. `archive` does not destroy anything. The record leaves listings, stays
|
|
1845
1849
|
* readable by id, and keeps its history.
|
|
1846
1850
|
*
|
|
1851
|
+
* Record references must resolve to an active record of `config.target_object`
|
|
1852
|
+
* within the same organization and app. Unavailable targets return a 422 with
|
|
1853
|
+
* `invalid_reference` in the field error's `reason`, without disclosing whether
|
|
1854
|
+
* a target exists outside the caller's scope.
|
|
1855
|
+
*
|
|
1847
1856
|
* Backed by:
|
|
1848
1857
|
* GET /api/v1/objects
|
|
1849
1858
|
* GET /api/v1/objects/{slug}
|
|
@@ -1887,12 +1896,16 @@ declare const createObjectsClient: (apiKey: string, apiUrl?: string) => {
|
|
|
1887
1896
|
* Values are versioned rather than overwritten, so the previous value stays
|
|
1888
1897
|
* readable through `history`.
|
|
1889
1898
|
*/
|
|
1890
|
-
updateRecord(objectSlug: string, recordId: string, values: Record<string, unknown
|
|
1899
|
+
updateRecord(objectSlug: string, recordId: string, values: Record<string, unknown>, options?: {
|
|
1900
|
+
expectedRevision?: number;
|
|
1901
|
+
}): Promise<CustomObjectRecord>;
|
|
1891
1902
|
/**
|
|
1892
1903
|
* Archive a record. It leaves listings, stays readable by id, and keeps its
|
|
1893
1904
|
* history and associations. Nothing is destroyed.
|
|
1894
1905
|
*/
|
|
1895
1906
|
archiveRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
1907
|
+
/** Restore archived values under current constraints. Conflicts leave the record archived. */
|
|
1908
|
+
restoreRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
1896
1909
|
/**
|
|
1897
1910
|
* A record's value timeline, newest first. An entry whose `active_until` is
|
|
1898
1911
|
* null is the value currently in force.
|
|
@@ -3809,8 +3822,11 @@ declare class G8 {
|
|
|
3809
3822
|
}>;
|
|
3810
3823
|
createRecord(objectSlug: string, values: Record<string, unknown>): Promise<CustomObjectRecord>;
|
|
3811
3824
|
getRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
3812
|
-
updateRecord(objectSlug: string, recordId: string, values: Record<string, unknown
|
|
3825
|
+
updateRecord(objectSlug: string, recordId: string, values: Record<string, unknown>, options?: {
|
|
3826
|
+
expectedRevision?: number;
|
|
3827
|
+
}): Promise<CustomObjectRecord>;
|
|
3813
3828
|
archiveRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
3829
|
+
restoreRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
3814
3830
|
history(objectSlug: string, recordId: string, limit?: number): Promise<CustomObjectHistory>;
|
|
3815
3831
|
};
|
|
3816
3832
|
/** Deals and pipelines (requires API key). */
|
package/dist/index.d.ts
CHANGED
|
@@ -1765,6 +1765,10 @@ interface CustomObjectAttribute {
|
|
|
1765
1765
|
/** No two ACTIVE records may hold the same value. A collision returns 409. */
|
|
1766
1766
|
is_unique: boolean;
|
|
1767
1767
|
is_multiselect: boolean;
|
|
1768
|
+
/** Apply a non-null default to omitted create fields, never PATCH. Absent on older servers. */
|
|
1769
|
+
is_default_value_enabled?: boolean;
|
|
1770
|
+
/** Configured default; validated like an explicit value when enabled. */
|
|
1771
|
+
default_value?: unknown;
|
|
1768
1772
|
/** Type-specific configuration, e.g. the allowed options for a `select`. */
|
|
1769
1773
|
config: Record<string, unknown>;
|
|
1770
1774
|
}
|
|
@@ -1780,6 +1784,8 @@ interface CustomObjectRecord {
|
|
|
1780
1784
|
*/
|
|
1781
1785
|
values: Record<string, unknown>;
|
|
1782
1786
|
is_archived: boolean;
|
|
1787
|
+
/** Revision for conditional updates; absent on older servers. */
|
|
1788
|
+
revision?: number;
|
|
1783
1789
|
created_at: string | null;
|
|
1784
1790
|
updated_at: string | null;
|
|
1785
1791
|
}
|
|
@@ -1824,10 +1830,7 @@ interface ObjectPagination {
|
|
|
1824
1830
|
* Requires an API key (server-side). On the hardened HTTP core: throws a typed
|
|
1825
1831
|
* `G8Error` on failure and retries transient errors.
|
|
1826
1832
|
*
|
|
1827
|
-
*
|
|
1828
|
-
* custom-objects surface is switched on for the platform. It is off by default,
|
|
1829
|
-
* so a call fails fast rather than returning an empty list that reads as "you
|
|
1830
|
-
* have no objects".
|
|
1833
|
+
* Access requires an authenticated credential with the applicable object scope.
|
|
1831
1834
|
*
|
|
1832
1835
|
* HOW THIS DIFFERS FROM `g8.fields`. A FIELD adds a column to an existing
|
|
1833
1836
|
* contact or company. A CUSTOM OBJECT is a whole new record type with its own
|
|
@@ -1840,10 +1843,16 @@ interface ObjectPagination {
|
|
|
1840
1843
|
* lose your data, and the response lists every problem at once so a payload
|
|
1841
1844
|
* with three mistakes takes one round trip to fix.
|
|
1842
1845
|
* 2. `update` is a PARTIAL write. Attributes you omit are left alone; sending
|
|
1843
|
-
* an explicit `null`
|
|
1846
|
+
* an explicit `null` clears an optional attribute. Required attributes
|
|
1847
|
+
* cannot be cleared with `null` or an empty multivalue list (422).
|
|
1844
1848
|
* 3. `archive` does not destroy anything. The record leaves listings, stays
|
|
1845
1849
|
* readable by id, and keeps its history.
|
|
1846
1850
|
*
|
|
1851
|
+
* Record references must resolve to an active record of `config.target_object`
|
|
1852
|
+
* within the same organization and app. Unavailable targets return a 422 with
|
|
1853
|
+
* `invalid_reference` in the field error's `reason`, without disclosing whether
|
|
1854
|
+
* a target exists outside the caller's scope.
|
|
1855
|
+
*
|
|
1847
1856
|
* Backed by:
|
|
1848
1857
|
* GET /api/v1/objects
|
|
1849
1858
|
* GET /api/v1/objects/{slug}
|
|
@@ -1887,12 +1896,16 @@ declare const createObjectsClient: (apiKey: string, apiUrl?: string) => {
|
|
|
1887
1896
|
* Values are versioned rather than overwritten, so the previous value stays
|
|
1888
1897
|
* readable through `history`.
|
|
1889
1898
|
*/
|
|
1890
|
-
updateRecord(objectSlug: string, recordId: string, values: Record<string, unknown
|
|
1899
|
+
updateRecord(objectSlug: string, recordId: string, values: Record<string, unknown>, options?: {
|
|
1900
|
+
expectedRevision?: number;
|
|
1901
|
+
}): Promise<CustomObjectRecord>;
|
|
1891
1902
|
/**
|
|
1892
1903
|
* Archive a record. It leaves listings, stays readable by id, and keeps its
|
|
1893
1904
|
* history and associations. Nothing is destroyed.
|
|
1894
1905
|
*/
|
|
1895
1906
|
archiveRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
1907
|
+
/** Restore archived values under current constraints. Conflicts leave the record archived. */
|
|
1908
|
+
restoreRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
1896
1909
|
/**
|
|
1897
1910
|
* A record's value timeline, newest first. An entry whose `active_until` is
|
|
1898
1911
|
* null is the value currently in force.
|
|
@@ -3809,8 +3822,11 @@ declare class G8 {
|
|
|
3809
3822
|
}>;
|
|
3810
3823
|
createRecord(objectSlug: string, values: Record<string, unknown>): Promise<CustomObjectRecord>;
|
|
3811
3824
|
getRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
3812
|
-
updateRecord(objectSlug: string, recordId: string, values: Record<string, unknown
|
|
3825
|
+
updateRecord(objectSlug: string, recordId: string, values: Record<string, unknown>, options?: {
|
|
3826
|
+
expectedRevision?: number;
|
|
3827
|
+
}): Promise<CustomObjectRecord>;
|
|
3813
3828
|
archiveRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
3829
|
+
restoreRecord(objectSlug: string, recordId: string): Promise<CustomObjectRecord>;
|
|
3814
3830
|
history(objectSlug: string, recordId: string, limit?: number): Promise<CustomObjectHistory>;
|
|
3815
3831
|
};
|
|
3816
3832
|
/** Deals and pipelines (requires API key). */
|
package/dist/index.js
CHANGED
|
@@ -1366,12 +1366,12 @@ var createObjectsClient = (apiKey, apiUrl) => {
|
|
|
1366
1366
|
* Values are versioned rather than overwritten, so the previous value stays
|
|
1367
1367
|
* readable through `history`.
|
|
1368
1368
|
*/
|
|
1369
|
-
async updateRecord(objectSlug, recordId, values) {
|
|
1369
|
+
async updateRecord(objectSlug, recordId, values, options) {
|
|
1370
1370
|
const resp = await request(
|
|
1371
1371
|
baseUrl,
|
|
1372
1372
|
`/api/v1/objects/${encode(objectSlug)}/records/${encode(recordId)}`,
|
|
1373
1373
|
apiKey,
|
|
1374
|
-
{ method: "PATCH", body: { values } }
|
|
1374
|
+
{ method: "PATCH", body: { values, ...options?.expectedRevision === void 0 ? {} : { expected_revision: options.expectedRevision } } }
|
|
1375
1375
|
);
|
|
1376
1376
|
return resp.data ?? resp;
|
|
1377
1377
|
},
|
|
@@ -1388,6 +1388,16 @@ var createObjectsClient = (apiKey, apiUrl) => {
|
|
|
1388
1388
|
);
|
|
1389
1389
|
return resp.data ?? resp;
|
|
1390
1390
|
},
|
|
1391
|
+
/** Restore archived values under current constraints. Conflicts leave the record archived. */
|
|
1392
|
+
async restoreRecord(objectSlug, recordId) {
|
|
1393
|
+
const resp = await request(
|
|
1394
|
+
baseUrl,
|
|
1395
|
+
`/api/v1/objects/${encode(objectSlug)}/records/${encode(recordId)}/restore`,
|
|
1396
|
+
apiKey,
|
|
1397
|
+
{ method: "POST" }
|
|
1398
|
+
);
|
|
1399
|
+
return resp.data ?? resp;
|
|
1400
|
+
},
|
|
1391
1401
|
/**
|
|
1392
1402
|
* A record's value timeline, newest first. An entry whose `active_until` is
|
|
1393
1403
|
* null is the value currently in force.
|