@withloops.ai/contracts 0.3.1 → 0.4.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/dist/api.d.ts +153 -0
- package/dist/api.js +86 -0
- package/dist/fields.d.ts +6 -0
- package/dist/fields.js +11 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/manifest.d.ts +516 -3
- package/dist/manifest.js +161 -3
- package/dist/registry.d.ts +151 -1
- package/dist/sync.d.ts +338 -0
- package/dist/sync.js +123 -0
- package/dist/trust.d.ts +1 -1
- package/examples/attio-sync.manifest.json +146 -0
- package/package.json +1 -1
- package/src/api.ts +110 -0
- package/src/fields.ts +11 -0
- package/src/index.ts +2 -0
- package/src/manifest.ts +161 -3
- package/src/sync.ts +229 -0
package/dist/manifest.js
CHANGED
|
@@ -2,6 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { AppId, HttpsUrl, SemVer } from "./ids.js";
|
|
3
3
|
import { EventTypeSchema, scopeForEvent } from "./events.js";
|
|
4
4
|
import { ScopeSchema, expandScopes } from "./scopes.js";
|
|
5
|
+
import { LOOPS_FIELD_NAMES } from "./fields.js";
|
|
5
6
|
/**
|
|
6
7
|
* App manifest v1 (`loops.manifest.json`). Everything is a Loops App: one manifest, two optional halves —
|
|
7
8
|
* `sync` (declarative CRM connector, run by the one Loops sync engine) and `ui` (LoopKit). Skill §2 #1–#3, §3.
|
|
@@ -22,6 +23,45 @@ const RECORD_SCOPE = {
|
|
|
22
23
|
loop: { read: 'loops:read', write: 'loops:write' },
|
|
23
24
|
};
|
|
24
25
|
const PathTemplate = z.string().regex(/^\/[A-Za-z0-9_\-./{}:]*$/, 'A path starting with /, e.g. /crm/v3/objects/contacts');
|
|
26
|
+
/**
|
|
27
|
+
* Added in 0.4.0 (L2). A JSON body template. A string that is exactly `{{name}}` takes the value as it is (type kept);
|
|
28
|
+
* `{{name}}` inside longer text is written as text. A key whose value comes out null or missing is left out, so is a null
|
|
29
|
+
* array item and an object left empty. Names: see `TEMPLATE_VARIABLES` in sync.ts. Pure: no code, no loops, no conditions.
|
|
30
|
+
*/
|
|
31
|
+
export const BodyTemplate = z.json();
|
|
32
|
+
/** Added in 0.4.0. A dotted path into a JSON answer: `data`, `values.name[0].first_name`, `values.associated_people[*].target_record_id`. */
|
|
33
|
+
export const JsonPath = z.string().regex(/^[A-Za-z0-9_$-]+(\[(\d+|\*)\])?(\.[A-Za-z0-9_$-]+(\[(\d+|\*)\])?)*$/, 'A dotted path like data.items or values.name[0].first_name');
|
|
34
|
+
/** Added in 0.4.0. Small pure value transforms, applied in order when reading their value. */
|
|
35
|
+
export const ValueTransform = z.enum(['trim', 'lower', 'upper', 'string', 'number', 'boolean', 'isoDate', 'first', 'domainFromUrl']);
|
|
36
|
+
/** Added in 0.4.0. How a list call pages. `cursor`: their answer holds the next cursor; `offset`/`page`: count up until a short page. */
|
|
37
|
+
export const Paging = z.discriminatedUnion('style', [
|
|
38
|
+
z.object({ style: z.literal('cursor'), param: z.string().min(1), nextPath: JsonPath, in: z.enum(['query', 'body']).default('query') }),
|
|
39
|
+
z.object({
|
|
40
|
+
style: z.literal('offset'),
|
|
41
|
+
param: z.string().min(1),
|
|
42
|
+
sizeParam: z.string().min(1),
|
|
43
|
+
size: z.number().int().min(1).max(1000).default(100),
|
|
44
|
+
in: z.enum(['query', 'body']).default('query'),
|
|
45
|
+
}),
|
|
46
|
+
z.object({
|
|
47
|
+
style: z.literal('page'),
|
|
48
|
+
param: z.string().min(1),
|
|
49
|
+
sizeParam: z.string().min(1),
|
|
50
|
+
size: z.number().int().min(1).max(1000).default(100),
|
|
51
|
+
startAt: z.number().int().min(0).max(1).default(1),
|
|
52
|
+
in: z.enum(['query', 'body']).default('query'),
|
|
53
|
+
}),
|
|
54
|
+
]);
|
|
55
|
+
/** Added in 0.4.0. One HTTP call against their API. `{id}` in the path is their record id. */
|
|
56
|
+
export const RecordCall = z.object({
|
|
57
|
+
method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']).default('GET'),
|
|
58
|
+
path: PathTemplate,
|
|
59
|
+
body: BodyTemplate.optional(),
|
|
60
|
+
/** Where the record sits in the answer (`data`); the whole answer when left out. */
|
|
61
|
+
itemPath: JsonPath.optional(),
|
|
62
|
+
/** Where their id sits in the answer of a create (`data.id.record_id`); defaults to the object's idPath under itemPath. */
|
|
63
|
+
idPath: JsonPath.optional(),
|
|
64
|
+
});
|
|
25
65
|
// ── sync: the connector half ────────────────────────────────────────────────────
|
|
26
66
|
export const SyncAuth = z.discriminatedUnion('type', [
|
|
27
67
|
z.object({
|
|
@@ -37,14 +77,21 @@ export const SyncAuth = z.discriminatedUnion('type', [
|
|
|
37
77
|
type: z.literal('apiKey'),
|
|
38
78
|
header: z.string().min(1).default('Authorization'),
|
|
39
79
|
prefix: z.string().optional(),
|
|
80
|
+
/** Added in 0.4.0. What the admin is asked for at install ("Attio access token"), and where to find it. */
|
|
81
|
+
label: z.string().min(1).max(80).optional(),
|
|
82
|
+
helpUrl: HttpsUrl.optional(),
|
|
40
83
|
}),
|
|
41
84
|
]);
|
|
42
85
|
/** Who owns a field. The customer's CRM owns its fields (locked in Loops); Loops owns its own. Owner wins, never last-write-wins. */
|
|
43
86
|
export const FieldOwner = z.enum(['theirs', 'ours']);
|
|
44
87
|
export const SyncField = z.object({
|
|
88
|
+
/** Where the value sits in their record: a field name or a JsonPath (`values.email_addresses[0].email_address`). */
|
|
45
89
|
theirs: z.string().min(1),
|
|
90
|
+
/** The Loops field (`LOOPS_FIELDS` in sync.ts) or `custom.<key>` for a custom field. */
|
|
46
91
|
ours: z.string().min(1),
|
|
47
92
|
owner: FieldOwner,
|
|
93
|
+
/** Added in 0.4.0. Applied in order to their value when reading it. */
|
|
94
|
+
transform: z.array(ValueTransform).optional(),
|
|
48
95
|
});
|
|
49
96
|
export const SyncObject = z.object({
|
|
50
97
|
theirs: z.string().min(1),
|
|
@@ -55,30 +102,95 @@ export const SyncObject = z.object({
|
|
|
55
102
|
cursorParam: z.string().optional(),
|
|
56
103
|
nextCursorPath: z.string().optional(),
|
|
57
104
|
updatedSinceParam: z.string().optional(),
|
|
105
|
+
/** Added in 0.4.0. GET by default; POST for APIs that query with a body. */
|
|
106
|
+
method: z.enum(['GET', 'POST']).optional(),
|
|
107
|
+
/** Added in 0.4.0. Body for a POST list (`{{limit}}`, `{{offset}}`, `{{cursor}}`, `{{updatedSince}}` fill in). */
|
|
108
|
+
body: BodyTemplate.optional(),
|
|
109
|
+
/** Added in 0.4.0. Replaces cursorParam/nextCursorPath when set. */
|
|
110
|
+
paging: Paging.optional(),
|
|
58
111
|
}),
|
|
59
112
|
fields: z.array(SyncField).min(1),
|
|
60
113
|
/** Dedupe keys, in order: e.g. ["email"] for contacts, ["domain"] for companies. External id always matches first. */
|
|
61
114
|
match: z.array(z.string().min(1)).default([]),
|
|
115
|
+
/** Added in 0.4.0. Where their id sits in one item (default `id`). */
|
|
116
|
+
idPath: JsonPath.optional(),
|
|
117
|
+
/** Added in 0.4.0. Where their last-changed time sits; without it, polling compares each record with what it saw last. */
|
|
118
|
+
updatedAtPath: JsonPath.optional(),
|
|
119
|
+
/** Added in 0.4.0. Read one record (`/v1/people/{id}`); needed when their webhook sends only ids. */
|
|
120
|
+
get: RecordCall.optional(),
|
|
121
|
+
/** Added in 0.4.0. Create a record Loops made (all mapped fields are filled). Without it, Loops never creates records there. */
|
|
122
|
+
create: RecordCall.optional(),
|
|
123
|
+
/** Added in 0.4.0. Update a record: only fields owned by Loops (`owner: ours`) are filled; their fields are left out. */
|
|
124
|
+
update: RecordCall.optional(),
|
|
62
125
|
});
|
|
63
126
|
export const SyncLink = z.object({
|
|
64
127
|
from: RecordKind,
|
|
65
128
|
to: RecordKind,
|
|
129
|
+
/** Where the other record's id sits on `from`'s item: a field or a JsonPath; `[*]` for many (`values.associated_people[*].target_record_id`). */
|
|
66
130
|
theirs: z.string().min(1),
|
|
131
|
+
/** The role on the Loops record link (`recordLinks`), e.g. `decision maker`, `employee`. */
|
|
67
132
|
role: z.string().optional(),
|
|
68
133
|
});
|
|
69
134
|
export const ChangeFeed = z
|
|
70
135
|
.object({
|
|
71
136
|
webhook: z
|
|
72
137
|
.object({
|
|
73
|
-
signature: z.object({
|
|
138
|
+
signature: z.object({
|
|
139
|
+
scheme: z.enum(['hmac-sha256', 'hmac-sha1']),
|
|
140
|
+
header: z.string().min(1),
|
|
141
|
+
/** Added in 0.4.0. How the signature is written (default hex). */
|
|
142
|
+
encoding: z.enum(['hex', 'base64']).optional(),
|
|
143
|
+
/** Added in 0.4.0. Text before the signature in the header, e.g. `sha256=`. */
|
|
144
|
+
prefix: z.string().max(40).optional(),
|
|
145
|
+
}),
|
|
146
|
+
/** Added in 0.4.0. Where the events sit in one delivery (`events`); the body is one event when left out. */
|
|
147
|
+
eventsPath: JsonPath.optional(),
|
|
148
|
+
/** Added in 0.4.0. Where an event says what happened (`event_type`). */
|
|
149
|
+
typePath: JsonPath.optional(),
|
|
150
|
+
/** Added in 0.4.0. Where an event names the record (`id.record_id`). */
|
|
151
|
+
idPath: JsonPath.optional(),
|
|
152
|
+
/** Added in 0.4.0. Where an event names the object; when it matches no object's `theirs`, the engine asks each object's `get`. */
|
|
153
|
+
objectPath: JsonPath.optional(),
|
|
154
|
+
/** Added in 0.4.0. Their event names for each change. A created or updated record is read again with the object's `get`. */
|
|
155
|
+
types: z
|
|
156
|
+
.object({
|
|
157
|
+
created: z.array(z.string().min(1)).default([]),
|
|
158
|
+
updated: z.array(z.string().min(1)).default([]),
|
|
159
|
+
deleted: z.array(z.string().min(1)).default([]),
|
|
160
|
+
})
|
|
161
|
+
.optional(),
|
|
162
|
+
/** Added in 0.4.0. Register the webhook through their API at install (`{{hookUrl}}` in the body); the secret is kept in the vault. */
|
|
163
|
+
register: z
|
|
164
|
+
.object({
|
|
165
|
+
call: RecordCall,
|
|
166
|
+
/** Where the signing secret sits in the answer (`data.secret`). */
|
|
167
|
+
secretPath: JsonPath,
|
|
168
|
+
/** Where the webhook's id sits in the answer, to remove it at uninstall. */
|
|
169
|
+
idPath: JsonPath.optional(),
|
|
170
|
+
/** Remove it at uninstall; `{id}` is the webhook id. */
|
|
171
|
+
unregister: RecordCall.optional(),
|
|
172
|
+
})
|
|
173
|
+
.optional(),
|
|
74
174
|
})
|
|
75
175
|
.optional(),
|
|
76
|
-
polling: z.object({
|
|
176
|
+
polling: z.object({
|
|
177
|
+
everyMinutes: z.number().int().min(5).max(1440),
|
|
178
|
+
/** Added in 0.4.0. `updatedSince` asks only for changed records (needs list.updatedSinceParam); `full` reads every record and keeps the changed ones. Default: updatedSince when the object has the param, else full. */
|
|
179
|
+
mode: z.enum(['updatedSince', 'full']).optional(),
|
|
180
|
+
}).optional(),
|
|
77
181
|
})
|
|
78
182
|
.refine((f) => f.webhook || f.polling, 'Declare a webhook, polling, or both');
|
|
79
183
|
/** What Loops writes back to the CRM timeline (Loops owns these). */
|
|
80
184
|
export const WriteBackKind = z.enum(['call', 'transcript', 'meeting', 'note', 'action', 'campaignReply']);
|
|
81
|
-
export const WriteBack = z.partialRecord(WriteBackKind, z.object({
|
|
185
|
+
export const WriteBack = z.partialRecord(WriteBackKind, z.object({
|
|
186
|
+
method: z.enum(['POST', 'PUT', 'PATCH']),
|
|
187
|
+
/** `{id}` = their id of the record the item belongs to, `{object}` = their object name. */
|
|
188
|
+
path: PathTemplate,
|
|
189
|
+
/** Added in 0.4.0. Body template; `{{item.*}}` and `{{record.*}}` fill in (sync.ts TEMPLATE_VARIABLES). */
|
|
190
|
+
body: BodyTemplate.optional(),
|
|
191
|
+
/** Added in 0.4.0. Where their id of the written item sits in the answer, so Loops can find it again. */
|
|
192
|
+
idPath: JsonPath.optional(),
|
|
193
|
+
}));
|
|
82
194
|
export const SyncLimits = z.object({
|
|
83
195
|
requestsPerSecond: z.number().positive().max(1000),
|
|
84
196
|
burst: z.number().int().positive().max(10000).optional(),
|
|
@@ -92,6 +204,8 @@ export const SyncManifest = z.object({
|
|
|
92
204
|
changeFeed: ChangeFeed,
|
|
93
205
|
writeBack: WriteBack.default({}),
|
|
94
206
|
limits: SyncLimits,
|
|
207
|
+
/** Added in 0.4.0. A cheap call that proves the credentials work (`GET /v2/self`). `loops test` and the health check use it. */
|
|
208
|
+
test: RecordCall.optional(),
|
|
95
209
|
});
|
|
96
210
|
// ── ui: the LoopKit half ────────────────────────────────────────────────────────
|
|
97
211
|
export const SLOTS = [
|
|
@@ -176,6 +290,8 @@ export const ManifestV1 = z
|
|
|
176
290
|
if (new Set(m.scopes).size !== m.scopes.length)
|
|
177
291
|
ctx.addIssue({ code: 'custom', path: ['scopes'], message: 'Scopes are listed twice' });
|
|
178
292
|
m.sync?.objects.forEach((o, i) => need(RECORD_SCOPE[o.ours].write, ['sync', 'objects', i, 'ours'], `Syncing ${o.ours}`));
|
|
293
|
+
if (m.sync)
|
|
294
|
+
checkSync(m.sync, ctx);
|
|
179
295
|
if (m.ui) {
|
|
180
296
|
m.ui.uses.forEach((f, i) => need(RECORD_SCOPE[f.split('.')[0]].read, ['ui', 'uses', i], `Reading ${f}`));
|
|
181
297
|
m.ui.does.forEach((d, i) => need(DOES[d], ['ui', 'does', i], `Doing ${d}`));
|
|
@@ -206,6 +322,48 @@ export const ManifestV1 = z
|
|
|
206
322
|
}
|
|
207
323
|
}
|
|
208
324
|
});
|
|
325
|
+
/** Connector checks added in 0.4.0: Loops field names, `{id}` where a record is named, webhook pieces that need each other. */
|
|
326
|
+
function checkSync(sync, ctx) {
|
|
327
|
+
const issue = (path, message) => ctx.addIssue({ code: 'custom', path: ['sync', ...path], message });
|
|
328
|
+
const seen = new Set();
|
|
329
|
+
sync.objects.forEach((o, i) => {
|
|
330
|
+
if (seen.has(o.theirs))
|
|
331
|
+
issue(['objects', i, 'theirs'], `${o.theirs} is listed twice`);
|
|
332
|
+
seen.add(o.theirs);
|
|
333
|
+
const known = LOOPS_FIELD_NAMES[o.ours];
|
|
334
|
+
o.fields.forEach((f, j) => {
|
|
335
|
+
if (!f.ours.startsWith('custom.') && !known.includes(f.ours))
|
|
336
|
+
issue(['objects', i, 'fields', j, 'ours'], `${f.ours} is not a Loops ${o.ours} field (use one of ${known.join(', ')}, or custom.<key>)`);
|
|
337
|
+
});
|
|
338
|
+
o.match.forEach((k, j) => {
|
|
339
|
+
// A match key names a Loops field (preferred) or, as in 0.3.x manifests, their field; either must be mapped.
|
|
340
|
+
if (!o.fields.some((f) => f.ours === k || f.theirs === k))
|
|
341
|
+
issue(['objects', i, 'match', j], `Matching on ${k} needs a field mapped to ${k}`);
|
|
342
|
+
});
|
|
343
|
+
for (const call of ['get', 'update']) {
|
|
344
|
+
if (o[call] && !o[call].path.includes('{id}'))
|
|
345
|
+
issue(['objects', i, call, 'path'], `The ${call} path needs {id}`);
|
|
346
|
+
}
|
|
347
|
+
if (o.list.paging && (o.list.paging.in === 'body') !== (o.list.method === 'POST'))
|
|
348
|
+
issue(['objects', i, 'list', 'paging', 'in'], 'Paging in the body needs list.method POST, and a POST list pages in the body');
|
|
349
|
+
});
|
|
350
|
+
sync.links.forEach((l, i) => {
|
|
351
|
+
for (const end of ['from', 'to'])
|
|
352
|
+
if (!sync.objects.some((o) => o.ours === l[end]))
|
|
353
|
+
issue(['links', i, end], `${l[end]} is linked but no object syncs it`);
|
|
354
|
+
});
|
|
355
|
+
const hook = sync.changeFeed.webhook;
|
|
356
|
+
if (hook?.types && !hook.idPath)
|
|
357
|
+
issue(['changeFeed', 'webhook', 'idPath'], 'Webhook event types need idPath');
|
|
358
|
+
if (hook?.types && (hook.types.created.length || hook.types.updated.length))
|
|
359
|
+
sync.objects.forEach((o, i) => { if (!o.get)
|
|
360
|
+
issue(['objects', i, 'get'], 'Webhooks that send ids need a get call to read the record'); });
|
|
361
|
+
if (sync.changeFeed.polling?.mode === 'updatedSince')
|
|
362
|
+
sync.objects.forEach((o, i) => {
|
|
363
|
+
if (!o.list.updatedSinceParam)
|
|
364
|
+
issue(['objects', i, 'list', 'updatedSinceParam'], 'Polling by updatedSince needs list.updatedSinceParam');
|
|
365
|
+
});
|
|
366
|
+
}
|
|
209
367
|
/** The manifest file name in an app folder. */
|
|
210
368
|
export const MANIFEST_FILE = 'loops.manifest.json';
|
|
211
369
|
/** Parse a manifest; errors come back as plain lines ("ui.uses.0: Reading contact.email needs the contacts:read scope"). */
|
package/dist/registry.d.ts
CHANGED
|
@@ -81,6 +81,8 @@ export declare const AppVersionRecord: z.ZodObject<{
|
|
|
81
81
|
type: z.ZodLiteral<"apiKey">;
|
|
82
82
|
header: z.ZodDefault<z.ZodString>;
|
|
83
83
|
prefix: z.ZodOptional<z.ZodString>;
|
|
84
|
+
label: z.ZodOptional<z.ZodString>;
|
|
85
|
+
helpUrl: z.ZodOptional<z.ZodURL>;
|
|
84
86
|
}, z.core.$strip>], "type">;
|
|
85
87
|
objects: z.ZodArray<z.ZodObject<{
|
|
86
88
|
theirs: z.ZodString;
|
|
@@ -96,6 +98,39 @@ export declare const AppVersionRecord: z.ZodObject<{
|
|
|
96
98
|
cursorParam: z.ZodOptional<z.ZodString>;
|
|
97
99
|
nextCursorPath: z.ZodOptional<z.ZodString>;
|
|
98
100
|
updatedSinceParam: z.ZodOptional<z.ZodString>;
|
|
101
|
+
method: z.ZodOptional<z.ZodEnum<{
|
|
102
|
+
GET: "GET";
|
|
103
|
+
POST: "POST";
|
|
104
|
+
}>>;
|
|
105
|
+
body: z.ZodOptional<z.ZodJSONSchema>;
|
|
106
|
+
paging: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
107
|
+
style: z.ZodLiteral<"cursor">;
|
|
108
|
+
param: z.ZodString;
|
|
109
|
+
nextPath: z.ZodString;
|
|
110
|
+
in: z.ZodDefault<z.ZodEnum<{
|
|
111
|
+
query: "query";
|
|
112
|
+
body: "body";
|
|
113
|
+
}>>;
|
|
114
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
115
|
+
style: z.ZodLiteral<"offset">;
|
|
116
|
+
param: z.ZodString;
|
|
117
|
+
sizeParam: z.ZodString;
|
|
118
|
+
size: z.ZodDefault<z.ZodNumber>;
|
|
119
|
+
in: z.ZodDefault<z.ZodEnum<{
|
|
120
|
+
query: "query";
|
|
121
|
+
body: "body";
|
|
122
|
+
}>>;
|
|
123
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
124
|
+
style: z.ZodLiteral<"page">;
|
|
125
|
+
param: z.ZodString;
|
|
126
|
+
sizeParam: z.ZodString;
|
|
127
|
+
size: z.ZodDefault<z.ZodNumber>;
|
|
128
|
+
startAt: z.ZodDefault<z.ZodNumber>;
|
|
129
|
+
in: z.ZodDefault<z.ZodEnum<{
|
|
130
|
+
query: "query";
|
|
131
|
+
body: "body";
|
|
132
|
+
}>>;
|
|
133
|
+
}, z.core.$strip>], "style">>;
|
|
99
134
|
}, z.core.$strip>;
|
|
100
135
|
fields: z.ZodArray<z.ZodObject<{
|
|
101
136
|
theirs: z.ZodString;
|
|
@@ -104,8 +139,60 @@ export declare const AppVersionRecord: z.ZodObject<{
|
|
|
104
139
|
theirs: "theirs";
|
|
105
140
|
ours: "ours";
|
|
106
141
|
}>;
|
|
142
|
+
transform: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
143
|
+
string: "string";
|
|
144
|
+
number: "number";
|
|
145
|
+
boolean: "boolean";
|
|
146
|
+
trim: "trim";
|
|
147
|
+
lower: "lower";
|
|
148
|
+
upper: "upper";
|
|
149
|
+
isoDate: "isoDate";
|
|
150
|
+
first: "first";
|
|
151
|
+
domainFromUrl: "domainFromUrl";
|
|
152
|
+
}>>>;
|
|
107
153
|
}, z.core.$strip>>;
|
|
108
154
|
match: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
155
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
156
|
+
updatedAtPath: z.ZodOptional<z.ZodString>;
|
|
157
|
+
get: z.ZodOptional<z.ZodObject<{
|
|
158
|
+
method: z.ZodDefault<z.ZodEnum<{
|
|
159
|
+
GET: "GET";
|
|
160
|
+
POST: "POST";
|
|
161
|
+
PUT: "PUT";
|
|
162
|
+
PATCH: "PATCH";
|
|
163
|
+
DELETE: "DELETE";
|
|
164
|
+
}>>;
|
|
165
|
+
path: z.ZodString;
|
|
166
|
+
body: z.ZodOptional<z.ZodJSONSchema>;
|
|
167
|
+
itemPath: z.ZodOptional<z.ZodString>;
|
|
168
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
169
|
+
}, z.core.$strip>>;
|
|
170
|
+
create: z.ZodOptional<z.ZodObject<{
|
|
171
|
+
method: z.ZodDefault<z.ZodEnum<{
|
|
172
|
+
GET: "GET";
|
|
173
|
+
POST: "POST";
|
|
174
|
+
PUT: "PUT";
|
|
175
|
+
PATCH: "PATCH";
|
|
176
|
+
DELETE: "DELETE";
|
|
177
|
+
}>>;
|
|
178
|
+
path: z.ZodString;
|
|
179
|
+
body: z.ZodOptional<z.ZodJSONSchema>;
|
|
180
|
+
itemPath: z.ZodOptional<z.ZodString>;
|
|
181
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
182
|
+
}, z.core.$strip>>;
|
|
183
|
+
update: z.ZodOptional<z.ZodObject<{
|
|
184
|
+
method: z.ZodDefault<z.ZodEnum<{
|
|
185
|
+
GET: "GET";
|
|
186
|
+
POST: "POST";
|
|
187
|
+
PUT: "PUT";
|
|
188
|
+
PATCH: "PATCH";
|
|
189
|
+
DELETE: "DELETE";
|
|
190
|
+
}>>;
|
|
191
|
+
path: z.ZodString;
|
|
192
|
+
body: z.ZodOptional<z.ZodJSONSchema>;
|
|
193
|
+
itemPath: z.ZodOptional<z.ZodString>;
|
|
194
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
195
|
+
}, z.core.$strip>>;
|
|
109
196
|
}, z.core.$strip>>;
|
|
110
197
|
links: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
111
198
|
from: z.ZodEnum<{
|
|
@@ -131,10 +218,58 @@ export declare const AppVersionRecord: z.ZodObject<{
|
|
|
131
218
|
"hmac-sha1": "hmac-sha1";
|
|
132
219
|
}>;
|
|
133
220
|
header: z.ZodString;
|
|
221
|
+
encoding: z.ZodOptional<z.ZodEnum<{
|
|
222
|
+
hex: "hex";
|
|
223
|
+
base64: "base64";
|
|
224
|
+
}>>;
|
|
225
|
+
prefix: z.ZodOptional<z.ZodString>;
|
|
134
226
|
}, z.core.$strip>;
|
|
227
|
+
eventsPath: z.ZodOptional<z.ZodString>;
|
|
228
|
+
typePath: z.ZodOptional<z.ZodString>;
|
|
229
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
230
|
+
objectPath: z.ZodOptional<z.ZodString>;
|
|
231
|
+
types: z.ZodOptional<z.ZodObject<{
|
|
232
|
+
created: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
233
|
+
updated: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
234
|
+
deleted: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
235
|
+
}, z.core.$strip>>;
|
|
236
|
+
register: z.ZodOptional<z.ZodObject<{
|
|
237
|
+
call: z.ZodObject<{
|
|
238
|
+
method: z.ZodDefault<z.ZodEnum<{
|
|
239
|
+
GET: "GET";
|
|
240
|
+
POST: "POST";
|
|
241
|
+
PUT: "PUT";
|
|
242
|
+
PATCH: "PATCH";
|
|
243
|
+
DELETE: "DELETE";
|
|
244
|
+
}>>;
|
|
245
|
+
path: z.ZodString;
|
|
246
|
+
body: z.ZodOptional<z.ZodJSONSchema>;
|
|
247
|
+
itemPath: z.ZodOptional<z.ZodString>;
|
|
248
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
249
|
+
}, z.core.$strip>;
|
|
250
|
+
secretPath: z.ZodString;
|
|
251
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
252
|
+
unregister: z.ZodOptional<z.ZodObject<{
|
|
253
|
+
method: z.ZodDefault<z.ZodEnum<{
|
|
254
|
+
GET: "GET";
|
|
255
|
+
POST: "POST";
|
|
256
|
+
PUT: "PUT";
|
|
257
|
+
PATCH: "PATCH";
|
|
258
|
+
DELETE: "DELETE";
|
|
259
|
+
}>>;
|
|
260
|
+
path: z.ZodString;
|
|
261
|
+
body: z.ZodOptional<z.ZodJSONSchema>;
|
|
262
|
+
itemPath: z.ZodOptional<z.ZodString>;
|
|
263
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
264
|
+
}, z.core.$strip>>;
|
|
265
|
+
}, z.core.$strip>>;
|
|
135
266
|
}, z.core.$strip>>;
|
|
136
267
|
polling: z.ZodOptional<z.ZodObject<{
|
|
137
268
|
everyMinutes: z.ZodNumber;
|
|
269
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
270
|
+
updatedSince: "updatedSince";
|
|
271
|
+
full: "full";
|
|
272
|
+
}>>;
|
|
138
273
|
}, z.core.$strip>>;
|
|
139
274
|
}, z.core.$strip>;
|
|
140
275
|
writeBack: z.ZodDefault<z.ZodRecord<z.ZodEnum<{
|
|
@@ -151,12 +286,27 @@ export declare const AppVersionRecord: z.ZodObject<{
|
|
|
151
286
|
PATCH: "PATCH";
|
|
152
287
|
}>;
|
|
153
288
|
path: z.ZodString;
|
|
289
|
+
body: z.ZodOptional<z.ZodJSONSchema>;
|
|
290
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
154
291
|
}, z.core.$strip>>>;
|
|
155
292
|
limits: z.ZodObject<{
|
|
156
293
|
requestsPerSecond: z.ZodNumber;
|
|
157
294
|
burst: z.ZodOptional<z.ZodNumber>;
|
|
158
295
|
retryAfterHeader: z.ZodDefault<z.ZodString>;
|
|
159
296
|
}, z.core.$strip>;
|
|
297
|
+
test: z.ZodOptional<z.ZodObject<{
|
|
298
|
+
method: z.ZodDefault<z.ZodEnum<{
|
|
299
|
+
GET: "GET";
|
|
300
|
+
POST: "POST";
|
|
301
|
+
PUT: "PUT";
|
|
302
|
+
PATCH: "PATCH";
|
|
303
|
+
DELETE: "DELETE";
|
|
304
|
+
}>>;
|
|
305
|
+
path: z.ZodString;
|
|
306
|
+
body: z.ZodOptional<z.ZodJSONSchema>;
|
|
307
|
+
itemPath: z.ZodOptional<z.ZodString>;
|
|
308
|
+
idPath: z.ZodOptional<z.ZodString>;
|
|
309
|
+
}, z.core.$strip>>;
|
|
160
310
|
}, z.core.$strip>>;
|
|
161
311
|
ui: z.ZodOptional<z.ZodObject<{
|
|
162
312
|
apiVersion: z.ZodLiteral<1>;
|
|
@@ -213,10 +363,10 @@ export declare const AppVersionRecord: z.ZodObject<{
|
|
|
213
363
|
}, z.core.$strip>], "type">>>;
|
|
214
364
|
endpoints: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
215
365
|
method: z.ZodEnum<{
|
|
366
|
+
GET: "GET";
|
|
216
367
|
POST: "POST";
|
|
217
368
|
PUT: "PUT";
|
|
218
369
|
PATCH: "PATCH";
|
|
219
|
-
GET: "GET";
|
|
220
370
|
DELETE: "DELETE";
|
|
221
371
|
}>;
|
|
222
372
|
url: z.ZodURL;
|