@graph8/sdk 0.13.1 → 0.15.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.
- package/README.md +127 -2
- package/dist/index.d.mts +470 -18
- package/dist/index.d.ts +470 -18
- package/dist/index.js +434 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +431 -44
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +447 -12
- package/dist/react.d.ts +447 -12
- package/dist/react.js +426 -44
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +426 -44
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -251,11 +251,41 @@ 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
|
+
The unreleased CRM increment adds `crm.record.created`, `crm.record.updated`,
|
|
255
|
+
`crm.record.archived`, and `crm.record.restored`. Their `data` contains
|
|
256
|
+
`object_slug`, `record_id`, and `revision`, rather than private field values.
|
|
257
|
+
The envelope `id` is a stable event ID; `X-Studio-Delivery-Id` identifies a
|
|
258
|
+
subscription's delivery. Verify the original request bytes before processing,
|
|
259
|
+
and deduplicate by the stable identifiers because delivery is at least once.
|
|
260
|
+
CRM subscription creation, update, deletion and secret rotation through the API
|
|
261
|
+
require explicit `webhooks:write` and `objects:read` scopes. Removing CRM events
|
|
262
|
+
also requires these grants. Reading CRM subscriptions or their delivery history
|
|
263
|
+
requires explicit `webhooks:read` and `objects:read` scopes; a subscription list
|
|
264
|
+
containing CRM subscriptions enforces the same read grants before returning data.
|
|
265
|
+
These checks refresh credentials and apply even during compatibility scope soak.
|
|
266
|
+
The backend checks current credential, membership and record access again before
|
|
267
|
+
sending. Native custom
|
|
268
|
+
records currently follow workspace-level access; app-owned/delegated authority
|
|
269
|
+
and configurable Enterprise object grants remain incomplete.
|
|
270
|
+
|
|
254
271
|
## Native custom objects
|
|
255
272
|
|
|
256
273
|
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.
|
|
258
|
-
|
|
274
|
+
reads, `objects:write` for record create/PATCH, and `objects:delete` for record archive.
|
|
275
|
+
Schema create/update/archive require `objects:manage` and current Admin access through
|
|
276
|
+
a personal API key. `objects.update(slug, { is_archived: false })` restores an object.
|
|
277
|
+
Object create accepts `description` and a typed `icon`. Update also accepts
|
|
278
|
+
`display_attribute_slug` for an active, single-value label field. Omit presentation
|
|
279
|
+
properties to preserve them or pass `null` to clear them. The current display field
|
|
280
|
+
must be replaced or cleared before archiving it or making it multivalue.
|
|
281
|
+
Attribute administration in the unreleased increment uses `objects.createAttribute`,
|
|
282
|
+
`objects.updateAttribute`, and `objects.archiveAttribute` with the same scope and Admin requirement.
|
|
283
|
+
Restore with `objects.updateAttribute(objectSlug, attributeSlug, { is_archived: false })`.
|
|
284
|
+
Use `objects.listAttributes(objectSlug, { include_archived: true })` to find archived fields;
|
|
285
|
+
normal discovery and record validation use active fields only. Attribute PATCH preserves
|
|
286
|
+
omitted fields; `default_value: null` explicitly clears a default. Requires the matching backend.
|
|
287
|
+
|
|
288
|
+
Unscoped keys receive 403. `objects:*` grants all object scopes; grant only the operations the
|
|
259
289
|
integration needs.
|
|
260
290
|
|
|
261
291
|
```typescript
|
|
@@ -273,6 +303,36 @@ PATCH preserves omitted attributes. Enabled defaults apply only on create;
|
|
|
273
303
|
unknown fields return 422 and unique-value collisions return 409. Standard
|
|
274
304
|
contacts, companies, and deals continue using their existing SDK resources.
|
|
275
305
|
|
|
306
|
+
### Create or update by a unique key
|
|
307
|
+
|
|
308
|
+
Use an active, single-value unique attribute to match a native custom record.
|
|
309
|
+
Supply its nonempty value with the fields to write. Existing matches retain
|
|
310
|
+
their graph8 ID and omitted values; new records receive configured defaults.
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
import { g8 } from '@graph8/sdk';
|
|
314
|
+
|
|
315
|
+
g8.init({ apiKey: process.env.G8_API_KEY! });
|
|
316
|
+
// Assumes invoices.reference is a unique text attribute in this workspace.
|
|
317
|
+
const invoice = await g8.objects.upsertRecord('invoices', 'reference', {
|
|
318
|
+
reference: 'INV-1042',
|
|
319
|
+
});
|
|
320
|
+
// A conditional update fails with 409 if the record changed or no longer matches.
|
|
321
|
+
await g8.objects.upsertRecord('invoices', 'reference', {
|
|
322
|
+
reference: 'INV-1042',
|
|
323
|
+
}, { expectedRevision: invoice.revision });
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
The REST operation is `POST /api/v1/objects/{object_slug}/records/upsert` with
|
|
327
|
+
`{ "matching_attribute": "reference", "values": { "reference": "INV-1042" } }`.
|
|
328
|
+
It requires `objects:write`, returns 201 for creation or 200 for an update, and
|
|
329
|
+
accepts optional `expected_revision`. MCP exposes `g8_object_record_upsert`
|
|
330
|
+
with the same fields. Archived records do not match. Invalid or nonunique
|
|
331
|
+
matching attributes return 422; another unique-field collision returns 409.
|
|
332
|
+
Legacy values requiring a uniqueness backfill also return 409 rather than
|
|
333
|
+
creating a duplicate. Repeated upserts can create additional update history;
|
|
334
|
+
unique-key matching is not a promise of exactly-once side effects.
|
|
335
|
+
|
|
276
336
|
## App Platform
|
|
277
337
|
|
|
278
338
|
Hosted apps do not carry a permanent org API key. Instead they **exchange** a
|
|
@@ -371,3 +431,68 @@ unique value has been reused. Validation failures leave the record archived.
|
|
|
371
431
|
Ambiguous legacy history returns 422 with `archive_snapshot_unavailable` rather
|
|
372
432
|
than guessing its prior values. Repeating a successful restore adds no revision
|
|
373
433
|
or history entry.
|
|
434
|
+
|
|
435
|
+
### Append or remove multivalue items
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
import { g8 } from "@graph8/sdk";
|
|
439
|
+
|
|
440
|
+
g8.init({ apiKey: "YOUR_API_KEY" });
|
|
441
|
+
const projectId = "your-project-record-id";
|
|
442
|
+
const record = await g8.objects.getRecord("projects", projectId);
|
|
443
|
+
await g8.objects.updateRecord("projects", projectId, {}, {
|
|
444
|
+
appendValues: { tags: ["priority"] },
|
|
445
|
+
removeValues: { reviewers: ["former-reviewer-id"] },
|
|
446
|
+
expectedRevision: record.revision,
|
|
447
|
+
});
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
Native and app PATCH APIs use `append_values` and `remove_values`; the MCP
|
|
451
|
+
`g8_object_record_update` tool accepts those same names. Each field must occur
|
|
452
|
+
in exactly one of `values`, `append_values`, or `remove_values`. These operations
|
|
453
|
+
require a multivalue attribute; `values` still replaces the entire supplied field.
|
|
454
|
+
Append preserves existing order and adds only canonically distinct items. Remove
|
|
455
|
+
deletes all matching items. The resulting values must satisfy required, unique,
|
|
456
|
+
and reference constraints. Changes are atomic and read the current values under
|
|
457
|
+
a record lock, so concurrent appends do not discard each other.
|
|
458
|
+
|
|
459
|
+
Repeating an append can leave the values unchanged while still advancing the
|
|
460
|
+
record revision and history. This is not an idempotency guarantee for events.
|
|
461
|
+
Deploy the matching backend before using these optional request fields.
|
|
462
|
+
|
|
463
|
+
### Record mutation history
|
|
464
|
+
|
|
465
|
+
```ts
|
|
466
|
+
import { g8 } from "@graph8/sdk";
|
|
467
|
+
|
|
468
|
+
g8.init({ apiKey: "YOUR_API_KEY" });
|
|
469
|
+
const firstPage = await g8.objects.changes("projects", "your-project-record-id", { limit: 50 });
|
|
470
|
+
if (firstPage.next_cursor) {
|
|
471
|
+
const olderPage = await g8.objects.changes("projects", "your-project-record-id", {
|
|
472
|
+
limit: 50,
|
|
473
|
+
cursor: firstPage.next_cursor,
|
|
474
|
+
});
|
|
475
|
+
console.log(olderPage.entries);
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
The matching native and app APIs expose `/objects/{object_slug}/records/{record_id}/changes`
|
|
480
|
+
and `/app/objects/{object_slug}/records/{record_id}/changes`. The MCP tool is
|
|
481
|
+
`g8_object_record_changes`. These additions require the matching backend deployment.
|
|
482
|
+
Entries include the record revision, action, actor identity/type, source, time,
|
|
483
|
+
and changed values. Presence flags distinguish a cleared field from a present null.
|
|
484
|
+
An empty page means no mutation entries were recorded, not that the record never
|
|
485
|
+
changed; the existing value-history endpoint remains available for older facts.
|
|
486
|
+
Use the returned opaque cursor for older pages. A storage failure is an error,
|
|
487
|
+
not an empty history. This interface does not establish broader object/record ACL parity.
|
|
488
|
+
|
|
489
|
+
### Conditional deal updates (unreleased)
|
|
490
|
+
|
|
491
|
+
Read the canonical deal record through `GET /api/v1/objects/deals/records/{id}`
|
|
492
|
+
to obtain its CRM revision, then pass `expected_revision` to
|
|
493
|
+
`g8.deals.update(id, { name: "Updated", expected_revision: revision })`.
|
|
494
|
+
A stale edit returns HTTP 409; reload and reconcile before retrying. A successful
|
|
495
|
+
conditional update returns `revision`. If tenant revision tracking is unavailable,
|
|
496
|
+
the conditional write returns 503 before mutation. Omitting `expected_revision`
|
|
497
|
+
retains the existing PATCH contract. The MCP `g8_update_deal` tool accepts the same
|
|
498
|
+
field. Deal UI integration and deployed QA verification remain pending.
|