@chatlychat/cli 0.1.3 → 0.1.5
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/commands/ai.d.ts +4 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +149 -0
- package/dist/commands/ai.js.map +1 -0
- package/dist/commands/common.d.ts +79 -0
- package/dist/commands/common.d.ts.map +1 -0
- package/dist/commands/common.js +194 -0
- package/dist/commands/common.js.map +1 -0
- package/dist/commands/config.d.ts +40 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +336 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/insights.d.ts +5 -0
- package/dist/commands/insights.d.ts.map +1 -0
- package/dist/commands/insights.js +277 -0
- package/dist/commands/insights.js.map +1 -0
- package/dist/commands/integrations.d.ts +15 -0
- package/dist/commands/integrations.d.ts.map +1 -0
- package/dist/commands/integrations.js +256 -0
- package/dist/commands/integrations.js.map +1 -0
- package/dist/commands/resources.d.ts +19 -7
- package/dist/commands/resources.d.ts.map +1 -1
- package/dist/commands/resources.js +100 -191
- package/dist/commands/resources.js.map +1 -1
- package/dist/commands/workspace-as-code.d.ts +27 -0
- package/dist/commands/workspace-as-code.d.ts.map +1 -0
- package/dist/commands/workspace-as-code.js +377 -0
- package/dist/commands/workspace-as-code.js.map +1 -0
- package/dist/help.d.ts +25 -1
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +104 -8
- package/dist/help.js.map +1 -1
- package/dist/run.d.ts +17 -0
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +88 -41
- package/dist/run.js.map +1 -1
- package/dist/wac/__tests__/wac-fixtures.d.ts +20 -0
- package/dist/wac/__tests__/wac-fixtures.d.ts.map +1 -0
- package/dist/wac/__tests__/wac-fixtures.js +38 -0
- package/dist/wac/__tests__/wac-fixtures.js.map +1 -0
- package/dist/wac/apply.d.ts +113 -0
- package/dist/wac/apply.d.ts.map +1 -0
- package/dist/wac/apply.js +265 -0
- package/dist/wac/apply.js.map +1 -0
- package/dist/wac/diff.d.ts +137 -0
- package/dist/wac/diff.d.ts.map +1 -0
- package/dist/wac/diff.js +413 -0
- package/dist/wac/diff.js.map +1 -0
- package/dist/wac/document.d.ts +110 -0
- package/dist/wac/document.d.ts.map +1 -0
- package/dist/wac/document.js +429 -0
- package/dist/wac/document.js.map +1 -0
- package/dist/wac/render.d.ts +52 -0
- package/dist/wac/render.d.ts.map +1 -0
- package/dist/wac/render.js +156 -0
- package/dist/wac/render.js.map +1 -0
- package/dist/wac/resource-def.d.ts +116 -0
- package/dist/wac/resource-def.d.ts.map +1 -0
- package/dist/wac/resource-def.js +44 -0
- package/dist/wac/resource-def.js.map +1 -0
- package/dist/wac/resources.d.ts +104 -0
- package/dist/wac/resources.d.ts.map +1 -0
- package/dist/wac/resources.js +541 -0
- package/dist/wac/resources.js.map +1 -0
- package/dist/wac/values.d.ts +16 -0
- package/dist/wac/values.d.ts.map +1 -0
- package/dist/wac/values.js +53 -0
- package/dist/wac/values.js.map +1 -0
- package/package.json +3 -2
- package/dist/cli.spec.d.ts +0 -2
- package/dist/cli.spec.d.ts.map +0 -1
- package/dist/cli.spec.js +0 -226
- package/dist/cli.spec.js.map +0 -1
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The resource table `chatly plan` and `chatly apply` work from.
|
|
3
|
+
*
|
|
4
|
+
* ═══ WHY A TABLE ══════════════════════════════════════════════════════════
|
|
5
|
+
*
|
|
6
|
+
* The ask behind this feature, in the integrator's words: "we wrote ~600
|
|
7
|
+
* lines to idempotently upsert tools, bots, routes, cards and channel
|
|
8
|
+
* config." Those 600 lines are nine copies of the same four steps — list,
|
|
9
|
+
* index by some stable name, compare, write — differing only in a route and a
|
|
10
|
+
* field name. This file is those differences and nothing else; `diff.ts` is
|
|
11
|
+
* the four steps, once, and `apply.ts` is the writes.
|
|
12
|
+
*
|
|
13
|
+
* ═══ IDENTITY: THE DECISION EVERYTHING ELSE RESTS ON ═════════════════════
|
|
14
|
+
*
|
|
15
|
+
* A declarative file cannot refer to resources by the server's uuid. On a
|
|
16
|
+
* fresh checkout against a fresh workspace there are no uuids, and a file
|
|
17
|
+
* carrying them is a file you cannot apply to a second environment — which
|
|
18
|
+
* is the whole reason this exists ("teams that run more than one
|
|
19
|
+
* environment"). So every resource needs a NATURAL KEY: a field the author
|
|
20
|
+
* writes, that comes back on the list read, and that identifies one row.
|
|
21
|
+
*
|
|
22
|
+
* Read off the handlers and the migrations, the nine are:
|
|
23
|
+
*
|
|
24
|
+
* brands slug UNIQUE (workspace_id, slug)
|
|
25
|
+
* bots slug UNIQUE (workspace_id, slug) WHERE NOT NULL
|
|
26
|
+
* macros shortCode UNIQUE (workspace_id, lower(short_code))
|
|
27
|
+
* emailTemplates kind UNIQUE (workspace_id, kind) — and a path param
|
|
28
|
+
* customerCards key UNIQUE (workspace_id, key)
|
|
29
|
+
* botRoutes name NO CONSTRAINT
|
|
30
|
+
* triggers name NO CONSTRAINT
|
|
31
|
+
* webhooks url NO CONSTRAINT
|
|
32
|
+
* docsSources label NO CONSTRAINT
|
|
33
|
+
* channels publicId UNIQUE — but minted by the server
|
|
34
|
+
*
|
|
35
|
+
* The first five are real: the database refuses a second row, so matching on
|
|
36
|
+
* the key cannot pick the wrong one. The next four are a CONVENTION the
|
|
37
|
+
* document enforces rather than a constraint the server does — so `diff.ts`
|
|
38
|
+
* refuses to touch a key that appears twice on either side instead of
|
|
39
|
+
* guessing, which is the only honest thing to do with a key that can repeat.
|
|
40
|
+
*
|
|
41
|
+
* ── The resource with no natural key at all ──────────────────────────────
|
|
42
|
+
*
|
|
43
|
+
* CHANNELS. `publicId` is required on create but it is a RESERVATION, not a
|
|
44
|
+
* name you choose freely: `channels_public_id_unique` is global rather than
|
|
45
|
+
* workspace-scoped, so another tenant may already hold `web`. `type` and
|
|
46
|
+
* `publicId` are both immutable afterwards, `config` reads back with
|
|
47
|
+
* `__redacted__` in every credential key, and the create response carries
|
|
48
|
+
* per-provider webhook registration results that a diff cannot model. A
|
|
49
|
+
* `channels:` section is therefore REFUSED by `document.ts`, by name, with
|
|
50
|
+
* the reason — not half-supported. `chatly channels create|update` is the
|
|
51
|
+
* way, and that is what the refusal says.
|
|
52
|
+
*
|
|
53
|
+
* ═══ VERIFIED AGAINST HANDLERS, NOT AGAINST NAMES ════════════════════════
|
|
54
|
+
*
|
|
55
|
+
* Every path, key, `paged` flag, update field-set and projection below was
|
|
56
|
+
* read off `apps/api/src/modules/**` and `packages/db/migrations/**`.
|
|
57
|
+
* CLAUDE.md records why that is not optional: the SDK manifest's first
|
|
58
|
+
* version listed two routes that do not exist and had its `paged` flag wrong
|
|
59
|
+
* in BOTH directions, and a fake transport that answers every route with a
|
|
60
|
+
* page envelope agrees with whatever the manifest says. Seven of the nine
|
|
61
|
+
* list routes here are `@PaginationExempt` bare arrays; treating one as a
|
|
62
|
+
* page is the bug two SDKs shipped.
|
|
63
|
+
*
|
|
64
|
+
* Six things in this table exist only because a handler said so, and each
|
|
65
|
+
* would be a live bug if guessed:
|
|
66
|
+
*
|
|
67
|
+
* 1. `macros.shortCode` does not round-trip. `normaliseShortCode` strips a
|
|
68
|
+
* leading `/` and lowercases, so a document saying `/Refund` would never
|
|
69
|
+
* match the stored `refund`, would create on every run, and would then
|
|
70
|
+
* collide with the unique index forever. Hence `normalizeKey`.
|
|
71
|
+
* 2. `emailTemplates` keeps the customised copy under `override`, not at the
|
|
72
|
+
* top level, and the list always returns all five kinds with
|
|
73
|
+
* `override: null` for the ones on the built-in. A naive diff reads
|
|
74
|
+
* `row.subject` — which does not exist — and reports a change every run.
|
|
75
|
+
* Hence `project`.
|
|
76
|
+
* 3. A bot's external config comes back nested under `externalAgent` and is
|
|
77
|
+
* written to a DIFFERENT route (`PATCH /v1/bots/{id}/external`). Hence
|
|
78
|
+
* `project` plus a second update route.
|
|
79
|
+
* 4. `webhooks` has NO general PATCH. Only the pinned schema version can
|
|
80
|
+
* change; `url`, `eventTypes` and `description` are frozen at create.
|
|
81
|
+
* 5. `triggers` POST is a FULL REPLACE keyed on the body's `id`, and an
|
|
82
|
+
* unknown id is a 404 rather than a create. So the id must come from the
|
|
83
|
+
* live row, and an omitted field is RESET to its default — hence
|
|
84
|
+
* `fullReplace`, which makes `plan` say so out loud.
|
|
85
|
+
* 6. `docsSources` PATCH accepts six fields. `provider`, `spaceId`,
|
|
86
|
+
* `organizationId`, `includePaths` and `excludePaths` are create-only, so
|
|
87
|
+
* a change to one of them is reported as un-appliable rather than sent to
|
|
88
|
+
* a route that will strip it and answer 200.
|
|
89
|
+
*/
|
|
90
|
+
export { looksLikeCredential, normalizedKey, projected, routeForField } from './resource-def.js';
|
|
91
|
+
/** Fields every row carries that no write path accepts. */
|
|
92
|
+
const SERVER_OWNED = ['id', 'workspaceId', 'createdAt', 'updatedAt'];
|
|
93
|
+
function asRecord(value) {
|
|
94
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
95
|
+
? value
|
|
96
|
+
: undefined;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Dependency order, and it is the array order.
|
|
100
|
+
*
|
|
101
|
+
* `botRoutes` after `bots` because a route names a bot, and in a single
|
|
102
|
+
* `apply` that bot may not exist until this run creates it. Nothing else
|
|
103
|
+
* references anything else, so the rest is ordered by how likely somebody is
|
|
104
|
+
* to be looking for it.
|
|
105
|
+
*/
|
|
106
|
+
export const RESOURCES = [
|
|
107
|
+
{
|
|
108
|
+
type: 'brands',
|
|
109
|
+
label: 'brand',
|
|
110
|
+
naturalKey: 'slug',
|
|
111
|
+
keySource: 'authored',
|
|
112
|
+
keyEnforced: true,
|
|
113
|
+
list: { path: '/v1/brands', paged: false },
|
|
114
|
+
idField: 'id',
|
|
115
|
+
create: { path: '/v1/brands' },
|
|
116
|
+
update: [{ method: 'PATCH', path: '/v1/brands/{id}' }],
|
|
117
|
+
// A soft delete. 200 with `{ id }` — that id is the only confirmation.
|
|
118
|
+
remove: { path: '/v1/brands/{id}' },
|
|
119
|
+
removeBlocked: undefined,
|
|
120
|
+
opaque: [],
|
|
121
|
+
secrets: [],
|
|
122
|
+
/*
|
|
123
|
+
* `usage` is computed. The list route calls `listWithUsage`, so every row
|
|
124
|
+
* carries `{ channels, conversations, triggers, workflows }` counts that
|
|
125
|
+
* no write schema has ever heard of.
|
|
126
|
+
*/
|
|
127
|
+
unwritable: [...SERVER_OWNED, 'usage'],
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
type: 'bots',
|
|
131
|
+
label: 'bot',
|
|
132
|
+
naturalKey: 'slug',
|
|
133
|
+
keySource: 'authored',
|
|
134
|
+
keyEnforced: true,
|
|
135
|
+
list: { path: '/v1/bots', paged: true },
|
|
136
|
+
idField: 'id',
|
|
137
|
+
create: { path: '/v1/bots' },
|
|
138
|
+
update: [
|
|
139
|
+
/*
|
|
140
|
+
* The external agent's delivery config lives on its own route and comes
|
|
141
|
+
* back nested. Listed FIRST so these three fields are claimed before
|
|
142
|
+
* the catch-all sees them.
|
|
143
|
+
*/
|
|
144
|
+
{
|
|
145
|
+
method: 'PATCH',
|
|
146
|
+
path: '/v1/bots/{id}/external',
|
|
147
|
+
fields: ['webhookUrl', 'timeoutSeconds', 'fallbackMessage'],
|
|
148
|
+
},
|
|
149
|
+
{ method: 'PATCH', path: '/v1/bots/{id}' },
|
|
150
|
+
],
|
|
151
|
+
/*
|
|
152
|
+
* There IS a `DELETE /v1/bots/{id}` (204), and `--prune` uses it. The
|
|
153
|
+
* `slug` collision note below is the reason the create path is the
|
|
154
|
+
* dangerous one here, not the delete path.
|
|
155
|
+
*/
|
|
156
|
+
remove: { path: '/v1/bots/{id}' },
|
|
157
|
+
opaque: ['signingSecret', 'callbackToken', 'token', 'systemPrompt'],
|
|
158
|
+
/*
|
|
159
|
+
* `type: "external"` answers with a signing secret AND a `cb_` token,
|
|
160
|
+
* flattened onto the bot object, each shown once, with no route that
|
|
161
|
+
* reads either back. `config.ts` prints the whole create response for
|
|
162
|
+
* exactly this reason.
|
|
163
|
+
*/
|
|
164
|
+
secrets: ['signingSecret', 'token', 'callbackToken'],
|
|
165
|
+
/*
|
|
166
|
+
* `slug` and `type` are create-only — the PATCH schema has neither. A
|
|
167
|
+
* change of slug is a different bot (the old one becomes an orphan),
|
|
168
|
+
* which is the honest reading, so `slug` is not listed here: it is the
|
|
169
|
+
* natural key and `diff.ts` never diffs that.
|
|
170
|
+
*/
|
|
171
|
+
unwritable: [
|
|
172
|
+
...SERVER_OWNED,
|
|
173
|
+
'templateOrigin',
|
|
174
|
+
'externalAgent',
|
|
175
|
+
'signingSecretSet',
|
|
176
|
+
'credentialId',
|
|
177
|
+
],
|
|
178
|
+
project: (row) => {
|
|
179
|
+
/*
|
|
180
|
+
* Flatten `externalAgent`.
|
|
181
|
+
*
|
|
182
|
+
* The CREATE body takes `webhookUrl` / `timeoutSeconds` /
|
|
183
|
+
* `fallbackMessage` at the top level; the READ returns them under
|
|
184
|
+
* `externalAgent`, alongside a `signingSecretSet` boolean that stands
|
|
185
|
+
* in for the secret. Without this a document that sets `webhookUrl`
|
|
186
|
+
* reports a change on every single run, for ever.
|
|
187
|
+
*/
|
|
188
|
+
const external = asRecord(row['externalAgent']);
|
|
189
|
+
if (external === undefined) {
|
|
190
|
+
return row;
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
...row,
|
|
194
|
+
webhookUrl: external['webhookUrl'],
|
|
195
|
+
timeoutSeconds: external['timeoutSeconds'],
|
|
196
|
+
fallbackMessage: external['fallbackMessage'],
|
|
197
|
+
};
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
type: 'botRoutes',
|
|
202
|
+
label: 'routing rule',
|
|
203
|
+
/*
|
|
204
|
+
* `name`, which is both the only candidate and the weakest key here.
|
|
205
|
+
*
|
|
206
|
+
* `ai_bot_routes` carries no unique index at all — only an eval index and
|
|
207
|
+
* a bot index — so two rules may share a name. `keyEnforced: false` is
|
|
208
|
+
* what makes `diff.ts` refuse a duplicate rather than guess, and the plan
|
|
209
|
+
* says so on the line.
|
|
210
|
+
*/
|
|
211
|
+
naturalKey: 'name',
|
|
212
|
+
keySource: 'authored',
|
|
213
|
+
keyEnforced: false,
|
|
214
|
+
list: { path: '/v1/bot-routes', paged: false },
|
|
215
|
+
idField: 'id',
|
|
216
|
+
create: { path: '/v1/bot-routes' },
|
|
217
|
+
update: [{ method: 'PATCH', path: '/v1/bot-routes/{id}' }],
|
|
218
|
+
// 200 with `{ deleted: true }`.
|
|
219
|
+
remove: { path: '/v1/bot-routes/{id}' },
|
|
220
|
+
opaque: [],
|
|
221
|
+
secrets: [],
|
|
222
|
+
unwritable: [...SERVER_OWNED],
|
|
223
|
+
/*
|
|
224
|
+
* `bot: <slug>` instead of `botId: <uuid>`.
|
|
225
|
+
*
|
|
226
|
+
* The one reference this surface needs, and the one that decides whether
|
|
227
|
+
* the whole document is portable. `botId` is a uuid the author cannot
|
|
228
|
+
* know, which would pin the file to one environment — the exact thing it
|
|
229
|
+
* exists to avoid. `bot` resolves against the live bot list plus whatever
|
|
230
|
+
* this run is about to create, and an unresolvable one BLOCKS the route
|
|
231
|
+
* rather than sending a null that zod would strip.
|
|
232
|
+
*/
|
|
233
|
+
references: { bot: { type: 'bots', wire: 'botId' } },
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
type: 'triggers',
|
|
237
|
+
label: 'trigger',
|
|
238
|
+
naturalKey: 'name',
|
|
239
|
+
keySource: 'authored',
|
|
240
|
+
keyEnforced: false,
|
|
241
|
+
list: { path: '/v1/triggers', paged: true },
|
|
242
|
+
idField: 'id',
|
|
243
|
+
/*
|
|
244
|
+
* `POST /v1/triggers` is an upsert keyed on the body's `id`, and an id the
|
|
245
|
+
* workspace does not have is a 404 rather than a create — so there is no
|
|
246
|
+
* such thing as creating a trigger at an id you chose. The id comes from
|
|
247
|
+
* the live row this file matched by name; absent a match, the POST goes
|
|
248
|
+
* without one and the server mints it.
|
|
249
|
+
*/
|
|
250
|
+
create: { path: '/v1/triggers', upsert: true },
|
|
251
|
+
update: [],
|
|
252
|
+
/*
|
|
253
|
+
* And it REPLACES. Every settable field is written unconditionally, so a
|
|
254
|
+
* field the document omits reverts to its schema default — `priority`
|
|
255
|
+
* goes to 0, `debounceSeconds` to null. `plan` prints that on every
|
|
256
|
+
* trigger change rather than letting somebody discover it.
|
|
257
|
+
*/
|
|
258
|
+
fullReplace: true,
|
|
259
|
+
// 200 with `{ ok: true }`. A hard delete.
|
|
260
|
+
remove: { path: '/v1/triggers/{id}' },
|
|
261
|
+
opaque: [],
|
|
262
|
+
secrets: [],
|
|
263
|
+
/*
|
|
264
|
+
* `brandId` is RETURNED on a read and is not in the upsert body — so a
|
|
265
|
+
* document setting it would be silently stripped and the plan would
|
|
266
|
+
* report the same change for ever. Refused at parse time instead.
|
|
267
|
+
*/
|
|
268
|
+
unwritable: [...SERVER_OWNED, 'brandId'],
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
type: 'macros',
|
|
272
|
+
label: 'macro',
|
|
273
|
+
/*
|
|
274
|
+
* `shortCode`, not `name`. The short code is what an agent types, it is
|
|
275
|
+
* the field the database makes unique, and two macros may legitimately
|
|
276
|
+
* share a name across scopes.
|
|
277
|
+
*/
|
|
278
|
+
naturalKey: 'shortCode',
|
|
279
|
+
keySource: 'authored',
|
|
280
|
+
keyEnforced: true,
|
|
281
|
+
/*
|
|
282
|
+
* The server's own normalisation, applied to BOTH sides before matching.
|
|
283
|
+
*
|
|
284
|
+
* `normaliseShortCode` strips a leading `/` and lowercases, and the DB
|
|
285
|
+
* CHECK only permits `^[a-z0-9][a-z0-9_-]{0,63}$`. So `/Refund` in a
|
|
286
|
+
* document is stored and returned as `refund`. Without this, that row
|
|
287
|
+
* never matches, `apply` creates on every run, and the unique index
|
|
288
|
+
* refuses it for ever — a config file that is permanently broken by a
|
|
289
|
+
* capital letter.
|
|
290
|
+
*/
|
|
291
|
+
normalizeKey: (key) => key.replace(/^\//, '').toLowerCase(),
|
|
292
|
+
/*
|
|
293
|
+
* `@PaginationExempt`: a bare array, capped at 200 rows and ordered by
|
|
294
|
+
* language rank then usage. NOT a page — the shared manifest flagged it
|
|
295
|
+
* `paged` for a day and two SDKs built a paginator over it. The cap is
|
|
296
|
+
* also why `--prune` is refused when the answer comes back at full
|
|
297
|
+
* length: a macro past the cap is invisible, not absent.
|
|
298
|
+
*/
|
|
299
|
+
list: { path: '/v1/macros', paged: false },
|
|
300
|
+
idField: 'id',
|
|
301
|
+
create: { path: '/v1/macros' },
|
|
302
|
+
update: [{ method: 'PATCH', path: '/v1/macros/{id}' }],
|
|
303
|
+
// The only real 204 on the whole SDK surface: no body comes back.
|
|
304
|
+
remove: { path: '/v1/macros/{id}' },
|
|
305
|
+
opaque: [],
|
|
306
|
+
secrets: [],
|
|
307
|
+
unwritable: [...SERVER_OWNED, 'usageCount', 'userId', 'createdByUserId'],
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
type: 'emailTemplates',
|
|
311
|
+
label: 'email template',
|
|
312
|
+
/*
|
|
313
|
+
* `kind`, which is also the id: the write is
|
|
314
|
+
* `PUT /v1/email-templates/{kind}`. The one resource here whose key space
|
|
315
|
+
* is CLOSED — five kinds, all five always on the list read. So there is
|
|
316
|
+
* no such thing as an orphan and `--prune` has nothing to do; a kind the
|
|
317
|
+
* document omits is simply unmanaged.
|
|
318
|
+
*/
|
|
319
|
+
naturalKey: 'kind',
|
|
320
|
+
keySource: 'authored',
|
|
321
|
+
keyEnforced: true,
|
|
322
|
+
list: { path: '/v1/email-templates', paged: false },
|
|
323
|
+
idField: 'kind',
|
|
324
|
+
/*
|
|
325
|
+
* No POST exists, and none is needed: all five kinds are always there, so
|
|
326
|
+
* every write is an update of an existing row. A kind the catalogue does
|
|
327
|
+
* not offer is reported as un-creatable by name.
|
|
328
|
+
*/
|
|
329
|
+
create: null,
|
|
330
|
+
/*
|
|
331
|
+
* A PUT with a `.strict()` body of `{ subject, body }` — an unknown key
|
|
332
|
+
* is a 400 here, which is the lucky case and not one to rely on
|
|
333
|
+
* elsewhere. `kind` is a path segment and must NOT appear in the body;
|
|
334
|
+
* `diff.ts` drops the natural key from every update body for this reason
|
|
335
|
+
* among others.
|
|
336
|
+
*/
|
|
337
|
+
update: [{ method: 'PUT', path: '/v1/email-templates/{id}', fields: ['subject', 'body'] }],
|
|
338
|
+
updateBlocked: 'the PUT body is `.strict()` and takes only `subject` and `body`. Everything else on a ' +
|
|
339
|
+
'template row is the catalogue describing itself.',
|
|
340
|
+
fullReplace: true,
|
|
341
|
+
/*
|
|
342
|
+
* DELETE here does not delete a template. It drops the workspace's
|
|
343
|
+
* OVERRIDE and puts the built-in copy back, answering 200 with
|
|
344
|
+
* `{ restored: false }` when there was nothing to drop. `--prune` does
|
|
345
|
+
* not call it: reverting a kind the document merely does not mention is
|
|
346
|
+
* not what "prune" means to anybody.
|
|
347
|
+
*/
|
|
348
|
+
remove: null,
|
|
349
|
+
removeBlocked: 'DELETE /v1/email-templates/{kind} reverts to the built-in copy rather than deleting ' +
|
|
350
|
+
'anything, and all five kinds always exist. Use `chatly email-templates reset <kind>`.',
|
|
351
|
+
opaque: [],
|
|
352
|
+
secrets: [],
|
|
353
|
+
unwritable: ['label', 'whenSent', 'audience', 'builtInSummary', 'tokens', 'override'],
|
|
354
|
+
project: (row) => {
|
|
355
|
+
/*
|
|
356
|
+
* The customised copy lives under `override`, or `override` is null and
|
|
357
|
+
* this kind is on the built-in. A diff against `row.subject` compares
|
|
358
|
+
* against a field that does not exist, so it reports a change on every
|
|
359
|
+
* run — and `override: null` is precisely the state a first `apply`
|
|
360
|
+
* is meant to leave behind.
|
|
361
|
+
*/
|
|
362
|
+
const override = asRecord(row['override']);
|
|
363
|
+
return {
|
|
364
|
+
kind: row['kind'],
|
|
365
|
+
subject: override?.['subject'],
|
|
366
|
+
body: override?.['body'],
|
|
367
|
+
};
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
type: 'customerCards',
|
|
372
|
+
label: 'customer card',
|
|
373
|
+
naturalKey: 'key',
|
|
374
|
+
keySource: 'authored',
|
|
375
|
+
keyEnforced: true,
|
|
376
|
+
list: { path: '/v1/customer-cards', paged: false },
|
|
377
|
+
idField: 'id',
|
|
378
|
+
create: { path: '/v1/customer-cards' },
|
|
379
|
+
/*
|
|
380
|
+
* `position` is on the PATCH schema and NOT on the create schema, which
|
|
381
|
+
* is `.strict()` — so a document that sets `position` on a card that does
|
|
382
|
+
* not exist yet gets a 400 on the create and the right answer on the next
|
|
383
|
+
* run. Left as it is rather than papered over: the API's 400 names the
|
|
384
|
+
* key, and a CLI that silently dropped it would be the second renaming
|
|
385
|
+
* layer `bodyFrom` refuses to add.
|
|
386
|
+
*/
|
|
387
|
+
update: [{ method: 'PATCH', path: '/v1/customer-cards/{id}' }],
|
|
388
|
+
// 200 with `{ ok: true }`.
|
|
389
|
+
remove: { path: '/v1/customer-cards/{id}' },
|
|
390
|
+
/*
|
|
391
|
+
* `headers` is WRITE-ONLY by design. The read shape has no `headers`
|
|
392
|
+
* field at all — it returns `headerNames: string[]`, names and never
|
|
393
|
+
* values, because that is where a card's bearer token lives. A diff on it
|
|
394
|
+
* would say "changed" on every single run, which is a diff nobody reads.
|
|
395
|
+
*/
|
|
396
|
+
opaque: ['headers'],
|
|
397
|
+
/*
|
|
398
|
+
* The create answers `{ card: {...}, secret: "cc_…" }` — the secret
|
|
399
|
+
* BESIDE the card rather than inside it, which is why `apply.ts` sweeps
|
|
400
|
+
* the whole response envelope and not just the resource object.
|
|
401
|
+
*/
|
|
402
|
+
secrets: ['secret'],
|
|
403
|
+
unwritable: ['id', 'headerNames'],
|
|
404
|
+
project: (row) => ({ ...row, headers: undefined }),
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
type: 'webhooks',
|
|
408
|
+
label: 'webhook endpoint',
|
|
409
|
+
/*
|
|
410
|
+
* The URL. A webhook endpoint has no name and no key, and the URL is the
|
|
411
|
+
* thing that is actually unique about it in practice — two subscriptions
|
|
412
|
+
* to one URL is a double delivery, not a configuration. The database does
|
|
413
|
+
* NOT enforce it (`webhook_endpoints` has no index block at all), hence
|
|
414
|
+
* `keyEnforced: false`.
|
|
415
|
+
*
|
|
416
|
+
* Compared byte for byte, so a trailing slash is a different endpoint
|
|
417
|
+
* here because it is a different endpoint there.
|
|
418
|
+
*/
|
|
419
|
+
naturalKey: 'url',
|
|
420
|
+
keySource: 'authored',
|
|
421
|
+
keyEnforced: false,
|
|
422
|
+
list: { path: '/v1/webhooks', paged: false },
|
|
423
|
+
idField: 'id',
|
|
424
|
+
create: { path: '/v1/webhooks' },
|
|
425
|
+
/*
|
|
426
|
+
* There is NO general PATCH on a webhook endpoint. The only field that
|
|
427
|
+
* can change in place is the pinned schema version, through a `.strict()`
|
|
428
|
+
* `{ schemaVersion }` body. No catch-all route is listed, so `diff.ts`
|
|
429
|
+
* reports a change to `eventTypes` as un-appliable and says what it would
|
|
430
|
+
* cost — which is the honest answer, and better than a PATCH that 404s.
|
|
431
|
+
*/
|
|
432
|
+
update: [
|
|
433
|
+
{
|
|
434
|
+
method: 'PATCH',
|
|
435
|
+
path: '/v1/webhooks/{id}/schema-version',
|
|
436
|
+
fields: ['schemaVersion'],
|
|
437
|
+
},
|
|
438
|
+
],
|
|
439
|
+
updateBlocked: 'a webhook endpoint is frozen at create except for its pinned schema version: `url`, ' +
|
|
440
|
+
'`eventTypes`, `description` and `enabled` have no PATCH. Changing one means delete and ' +
|
|
441
|
+
'recreate, which mints a NEW `whsec_` signing secret and breaks your verifier until you ' +
|
|
442
|
+
'deploy it — so this CLI will not do it behind a diff. Change the url in the document ' +
|
|
443
|
+
'instead: the new one is created and the old one is reported as an orphan.',
|
|
444
|
+
// 200 with `{ ok: true }`. A hard delete.
|
|
445
|
+
remove: { path: '/v1/webhooks/{id}' },
|
|
446
|
+
/*
|
|
447
|
+
* `secret` is never read back: the list selects six columns precisely to
|
|
448
|
+
* exclude it, there is no reveal route and no rotate route. Lose it and
|
|
449
|
+
* the only recovery is delete plus recreate.
|
|
450
|
+
*/
|
|
451
|
+
opaque: ['secret'],
|
|
452
|
+
secrets: ['secret'],
|
|
453
|
+
unwritable: ['id', 'workspaceId', 'createdAt', 'updatedAt', 'missingEventTypes'],
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
type: 'docsSources',
|
|
457
|
+
label: 'documentation source',
|
|
458
|
+
/*
|
|
459
|
+
* `label`. The alternatives are worse: `provider` repeats, `spaceId` is
|
|
460
|
+
* provider-specific, and the id is a uuid. It carries no constraint
|
|
461
|
+
* (`docs_sources` has only a workspace index and a due index) and it
|
|
462
|
+
* DEFAULTS to the generated collection name when omitted — so a document
|
|
463
|
+
* must set it explicitly, and `keyEnforced: false` makes a duplicate a
|
|
464
|
+
* refusal rather than a guess.
|
|
465
|
+
*/
|
|
466
|
+
naturalKey: 'label',
|
|
467
|
+
keySource: 'authored',
|
|
468
|
+
keyEnforced: false,
|
|
469
|
+
list: { path: '/v1/docs-sources', paged: false },
|
|
470
|
+
idField: 'id',
|
|
471
|
+
create: { path: '/v1/docs-sources' },
|
|
472
|
+
/*
|
|
473
|
+
* Six fields, and that is all. `provider`, `spaceId`, `organizationId`,
|
|
474
|
+
* `includePaths` and `excludePaths` are create-only — a change to one is
|
|
475
|
+
* reported rather than sent to a route that strips it and answers 200.
|
|
476
|
+
*/
|
|
477
|
+
update: [
|
|
478
|
+
{
|
|
479
|
+
method: 'PATCH',
|
|
480
|
+
path: '/v1/docs-sources/{id}',
|
|
481
|
+
fields: ['label', 'status', 'publishOnSync', 'syncIntervalMinutes', 'token', 'baseUrl'],
|
|
482
|
+
},
|
|
483
|
+
],
|
|
484
|
+
updateBlocked: '`provider`, `spaceId`, `organizationId`, `includePaths` and `excludePaths` are fixed at ' +
|
|
485
|
+
'create. Disconnect and reconnect the source (`chatly docs-sources delete <id>` keeps ' +
|
|
486
|
+
'the articles it imported) or give the new one a different `label`.',
|
|
487
|
+
// Disconnects the source and KEEPS the articles, re-labelled `manual`.
|
|
488
|
+
// 200 with `{ kept: n }`. Safe enough to prune when asked.
|
|
489
|
+
remove: { path: '/v1/docs-sources/{id}' },
|
|
490
|
+
// The provider token is write-only; no DTO field carries it back.
|
|
491
|
+
opaque: ['token'],
|
|
492
|
+
secrets: [],
|
|
493
|
+
unwritable: [
|
|
494
|
+
'id',
|
|
495
|
+
'spaceTitle',
|
|
496
|
+
'spaceKind',
|
|
497
|
+
'lastSyncedAt',
|
|
498
|
+
'lastError',
|
|
499
|
+
'lastArticleCount',
|
|
500
|
+
'articleCount',
|
|
501
|
+
'syncStatus',
|
|
502
|
+
'unreadableCount',
|
|
503
|
+
'staleCount',
|
|
504
|
+
'webhookSubscribed',
|
|
505
|
+
'webhookLastEventAt',
|
|
506
|
+
'webhookCapable',
|
|
507
|
+
'collectionId',
|
|
508
|
+
],
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
type: 'channels',
|
|
512
|
+
label: 'channel',
|
|
513
|
+
/*
|
|
514
|
+
* Server-owned. See the header: `publicId` is a GLOBALLY unique
|
|
515
|
+
* reservation rather than a name, `type` and `publicId` are immutable,
|
|
516
|
+
* `config` reads back redacted, and the create response carries
|
|
517
|
+
* provider-webhook registration results a diff cannot model. A
|
|
518
|
+
* `channels:` section is refused by `document.ts`. The row stays here so
|
|
519
|
+
* the refusal can name the type, the routes and the reason.
|
|
520
|
+
*/
|
|
521
|
+
naturalKey: 'publicId',
|
|
522
|
+
keySource: 'server',
|
|
523
|
+
keyEnforced: true,
|
|
524
|
+
list: { path: '/v1/channels', paged: false },
|
|
525
|
+
idField: 'id',
|
|
526
|
+
create: null,
|
|
527
|
+
update: [{ method: 'PATCH', path: '/v1/channels/{id}' }],
|
|
528
|
+
// There IS a DELETE, on its own controller — 200 with
|
|
529
|
+
// `{ deleted, id, type, detachedConversations }`.
|
|
530
|
+
remove: { path: '/v1/channels/{id}' },
|
|
531
|
+
opaque: ['config'],
|
|
532
|
+
secrets: ['secret'],
|
|
533
|
+
unwritable: [...SERVER_OWNED, 'type', 'publicId', 'originsRestricted', 'embed', 'brandId'],
|
|
534
|
+
},
|
|
535
|
+
];
|
|
536
|
+
export const RESOURCE_TYPES = RESOURCES.map((r) => r.type);
|
|
537
|
+
const BY_TYPE = new Map(RESOURCES.map((r) => [r.type, r]));
|
|
538
|
+
export function resourceDef(type) {
|
|
539
|
+
return BY_TYPE.get(type);
|
|
540
|
+
}
|
|
541
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../src/wac/resources.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comparing two JSON values, and spotting one the server would not show us.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `diff.ts` to keep both under the 650-line ceiling
|
|
5
|
+
* (`scripts/check-file-size.mjs`). These two functions carry two of the four
|
|
6
|
+
* rules in `diff.ts`'s header and are worth reading on their own: rule 3
|
|
7
|
+
* (absent and `undefined` are one state, and only `null` is a value) lives in
|
|
8
|
+
* `sameValue`, and the runtime half of rule 2 lives in `isRedacted`.
|
|
9
|
+
*/
|
|
10
|
+
/** The sentinel the API substitutes for a credential-bearing value. */
|
|
11
|
+
export declare const REDACTED = "__redacted__";
|
|
12
|
+
/** Deep structural equality over JSON values. */
|
|
13
|
+
export declare function sameValue(a: unknown, b: unknown): boolean;
|
|
14
|
+
/** Does this value carry the redaction sentinel anywhere inside it? */
|
|
15
|
+
export declare function isRedacted(value: unknown): boolean;
|
|
16
|
+
//# sourceMappingURL=values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.d.ts","sourceRoot":"","sources":["../../src/wac/values.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,uEAAuE;AACvE,eAAO,MAAM,QAAQ,iBAAiB,CAAC;AAIvC,iDAAiD;AACjD,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAyBzD;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAWlD"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comparing two JSON values, and spotting one the server would not show us.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `diff.ts` to keep both under the 650-line ceiling
|
|
5
|
+
* (`scripts/check-file-size.mjs`). These two functions carry two of the four
|
|
6
|
+
* rules in `diff.ts`'s header and are worth reading on their own: rule 3
|
|
7
|
+
* (absent and `undefined` are one state, and only `null` is a value) lives in
|
|
8
|
+
* `sameValue`, and the runtime half of rule 2 lives in `isRedacted`.
|
|
9
|
+
*/
|
|
10
|
+
/** The sentinel the API substitutes for a credential-bearing value. */
|
|
11
|
+
export const REDACTED = '__redacted__';
|
|
12
|
+
/* ── Value comparison ─────────────────────────────────────────────────── */
|
|
13
|
+
/** Deep structural equality over JSON values. */
|
|
14
|
+
export function sameValue(a, b) {
|
|
15
|
+
if (a === b) {
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
// Rule 3: absent and `undefined` are one state; `null` is a value.
|
|
19
|
+
if ((a === undefined || a === null) && (b === undefined || b === null)) {
|
|
20
|
+
return (a === null) === (b === null);
|
|
21
|
+
}
|
|
22
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
23
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return a.every((v, i) => sameValue(v, b[i]));
|
|
27
|
+
}
|
|
28
|
+
if (typeof a === 'object' && typeof b === 'object' && a !== null && b !== null) {
|
|
29
|
+
const ao = a;
|
|
30
|
+
const bo = b;
|
|
31
|
+
for (const k of new Set([...Object.keys(ao), ...Object.keys(bo)])) {
|
|
32
|
+
if (!sameValue(ao[k], bo[k])) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/** Does this value carry the redaction sentinel anywhere inside it? */
|
|
41
|
+
export function isRedacted(value) {
|
|
42
|
+
if (value === REDACTED) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(value)) {
|
|
46
|
+
return value.some(isRedacted);
|
|
47
|
+
}
|
|
48
|
+
if (typeof value === 'object' && value !== null) {
|
|
49
|
+
return Object.values(value).some(isRedacted);
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=values.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.js","sourceRoot":"","sources":["../../src/wac/values.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,uEAAuE;AACvE,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC;AAEvC,6EAA6E;AAE7E,iDAAiD;AACjD,MAAM,UAAU,SAAS,CAAC,CAAU,EAAE,CAAU;IAC9C,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IACD,mEAAmE;IACnE,IAAI,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;QACvE,OAAO,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IACvC,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;YACpE,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/E,MAAM,EAAE,GAAG,CAA4B,CAAC;QACxC,MAAM,EAAE,GAAG,CAA4B,CAAC;QACxC,KAAK,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC7B,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QAChD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAgC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatlychat/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "The Chatly command line — inspect conversations, send replies, read reports and call any API route from a terminal.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/chatlychat/chatly-cli#readme",
|
|
@@ -25,11 +25,12 @@
|
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
|
+
"!dist/**/*.spec.*",
|
|
28
29
|
"README.md",
|
|
29
30
|
"LICENSE"
|
|
30
31
|
],
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"@chatlychat/sdk-node": "0.
|
|
33
|
+
"@chatlychat/sdk-node": "0.3.0"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
36
|
"@types/node": "20.14.10",
|
package/dist/cli.spec.d.ts
DELETED
package/dist/cli.spec.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.spec.d.ts","sourceRoot":"","sources":["../src/cli.spec.ts"],"names":[],"mappings":""}
|