@awesomate/sdk 0.1.0 → 0.2.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 CHANGED
@@ -30,6 +30,30 @@ const one = await db.get('contact', rows[0].id); // null if there is none
30
30
  const byPlan = await db.aggregate({ measures: [{ column: 'people', agg: 'count' }], dimensions: ['plan'] });
31
31
  ```
32
32
 
33
+ ## Writing app data (Support Plus and above)
34
+
35
+ Define the tables an app keeps, then write to them. There's no migration and no SQL; every value is
36
+ checked against the kind (types, choices, required attributes and links).
37
+
38
+ ```ts
39
+ await db.defineKind({
40
+ key: 'job', label: 'Job', label_plural: 'Jobs',
41
+ attributes: [
42
+ { key: 'title', type: 'text', required: true, readable_by_ai: true },
43
+ { key: 'status', type: 'choice', choices: ['open', 'booked', 'done'], readable_by_ai: true },
44
+ ],
45
+ links: [{ key: 'customer', to: 'contact' }],
46
+ });
47
+ const id = await db.write('job', { title: 'Possum in the roof', status: 'open' }, { links: { customer: contactId } });
48
+ await db.write('job', { status: 'booked' }, { id }); // values not given stay
49
+ const jobs = await db.query('job', { where: { customer_id: contactId } });
50
+ await db.archive('job', id);
51
+ ```
52
+
53
+ Only attributes marked `readable_by_ai` come back from `query` and `get`; a `sensitive` attribute
54
+ can never be readable. Contacts themselves are not written this way: the contact list keeps its
55
+ own consent rules.
56
+
33
57
  ## What you can read
34
58
 
35
59
  The built-in contact details (name, email, phone, company, tags, when they were added) and only
package/dist/index.d.ts CHANGED
@@ -7,9 +7,10 @@
7
7
  * const { rows, next } = await db.query('contact', { where: { created_at: { gte: '$YEAR_BEGIN' } }, limit: 50 });
8
8
  *
9
9
  * The account's token (a hosting PAT with crm:read) is a secret: use it on a server, never in a
10
- * browser. End-user sign-in for browser apps comes in a later version.
10
+ * browser. End-user sign-in for browser apps comes in a later version. Writing app data (kinds and
11
+ * their records) needs crm:write, Support Plus and above.
11
12
  */
12
- export declare const VERSION = "0.1.0";
13
+ export declare const VERSION = "0.2.0";
13
14
  /** Augmented by the generated awesomate.d.ts, so each kind's rows are typed. */
14
15
  export interface Kinds {
15
16
  }
@@ -151,6 +152,14 @@ export declare class AwesomateClient {
151
152
  get<K extends KindName>(kind: K, id: string, options?: {
152
153
  tz?: string;
153
154
  }): Promise<RowOf<K> | null>;
155
+ /** The app kinds this account has defined. */
156
+ kinds(): Promise<KindDescription[]>;
157
+ /** Define an app kind (a table an app keeps). No migration: registry rows and generated views. */
158
+ defineKind(spec: KindSpec): Promise<KindDescription>;
159
+ /** Create a record (returns its id), or change one with options.id. Every value is checked against the kind. */
160
+ write<K extends KindName>(kind: K, data: Partial<RowOf<K>> | Record<string, unknown>, options?: WriteOptions): Promise<string>;
161
+ /** Archive a record: it leaves every read and is kept for a restore. */
162
+ archive<K extends KindName>(kind: K, id: string): Promise<void>;
154
163
  /** Grouped numbers (counts, sums) in the Business Data API's shape. */
155
164
  aggregate(request: {
156
165
  measures: Array<{
@@ -178,5 +187,45 @@ export declare class AwesomateClient {
178
187
  limit?: number;
179
188
  }): Promise<Record<string, unknown>>;
180
189
  }
190
+ export interface AttributeSpec {
191
+ key: string;
192
+ label?: string;
193
+ type?: 'text' | 'long_text' | 'number' | 'money' | 'date' | 'datetime' | 'duration' | 'yes_no' | 'choice' | 'choices' | 'email' | 'phone' | 'address' | 'url' | 'file';
194
+ choices?: string[];
195
+ required?: boolean;
196
+ sensitivity?: 'ordinary' | 'personal' | 'sensitive';
197
+ /** Default false. Only readable attributes reach query(), get() and the generated types. */
198
+ readable_by_ai?: boolean;
199
+ }
200
+ export interface KindSpec {
201
+ key: string;
202
+ label?: string;
203
+ label_plural?: string;
204
+ attributes: AttributeSpec[];
205
+ /** to is 'contact' or a kind already defined; each link reads back as <key>_id. */
206
+ links?: Array<{
207
+ key: string;
208
+ to: string;
209
+ label?: string;
210
+ to_label?: string;
211
+ required?: boolean;
212
+ }>;
213
+ }
214
+ export interface KindDescription extends Omit<KindSpec, 'attributes'> {
215
+ storage: 'plain' | 'tracked';
216
+ attributes: Array<Required<Pick<AttributeSpec, 'key' | 'label' | 'type' | 'required' | 'sensitivity' | 'readable_by_ai'>> & {
217
+ choices: string[] | null;
218
+ }>;
219
+ views: {
220
+ all: string;
221
+ for_agents: string;
222
+ };
223
+ }
224
+ export interface WriteOptions {
225
+ /** Change this record instead of creating one; values not given stay. */
226
+ id?: string;
227
+ /** Set a link by its key ('<id>'), or end it (null). */
228
+ links?: Record<string, string | null>;
229
+ }
181
230
  export declare function createClient(options: ClientOptions): AwesomateClient;
182
231
  export {};
package/dist/index.js CHANGED
@@ -7,9 +7,10 @@
7
7
  * const { rows, next } = await db.query('contact', { where: { created_at: { gte: '$YEAR_BEGIN' } }, limit: 50 });
8
8
  *
9
9
  * The account's token (a hosting PAT with crm:read) is a secret: use it on a server, never in a
10
- * browser. End-user sign-in for browser apps comes in a later version.
10
+ * browser. End-user sign-in for browser apps comes in a later version. Writing app data (kinds and
11
+ * their records) needs crm:write, Support Plus and above.
11
12
  */
12
- export const VERSION = '0.1.0';
13
+ export const VERSION = '0.2.0';
13
14
  const DEFAULT_BASE = 'https://hub.awesomate.ai';
14
15
  export class AwesomateError extends Error {
15
16
  code;
@@ -124,6 +125,25 @@ export class AwesomateClient {
124
125
  throw err;
125
126
  }
126
127
  }
128
+ /** The app kinds this account has defined. */
129
+ async kinds() {
130
+ return (await this.call('GET', '/api/my-crm/v1/kinds')).kinds;
131
+ }
132
+ /** Define an app kind (a table an app keeps). No migration: registry rows and generated views. */
133
+ async defineKind(spec) {
134
+ return (await this.call('POST', '/api/my-crm/v1/kinds', spec)).kind;
135
+ }
136
+ /** Create a record (returns its id), or change one with options.id. Every value is checked against the kind. */
137
+ async write(kind, data, options = {}) {
138
+ const r = await this.call('POST', '/api/my-crm/v1/call', {
139
+ fn: 'write_record', args: { kind, data, links: options.links ?? {}, ...(options.id ? { id: options.id } : {}) },
140
+ }, false);
141
+ return r.result.id;
142
+ }
143
+ /** Archive a record: it leaves every read and is kept for a restore. */
144
+ async archive(kind, id) {
145
+ await this.call('POST', '/api/my-crm/v1/call', { fn: 'archive_record', args: { kind, id } }, false);
146
+ }
127
147
  /** Grouped numbers (counts, sums) in the Business Data API's shape. */
128
148
  aggregate(request) {
129
149
  return this.call('POST', '/api/my-crm/v1/data/query', request);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awesomate/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Read your own Awesomate data from Node: query and page through your contact list with types generated from your fields",
5
5
  "license": "MIT",
6
6
  "type": "module",