@chatlychat/cli 0.1.4 → 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.
Files changed (73) hide show
  1. package/dist/commands/ai.d.ts +4 -0
  2. package/dist/commands/ai.d.ts.map +1 -0
  3. package/dist/commands/ai.js +149 -0
  4. package/dist/commands/ai.js.map +1 -0
  5. package/dist/commands/common.d.ts +79 -0
  6. package/dist/commands/common.d.ts.map +1 -0
  7. package/dist/commands/common.js +194 -0
  8. package/dist/commands/common.js.map +1 -0
  9. package/dist/commands/config.d.ts +40 -0
  10. package/dist/commands/config.d.ts.map +1 -0
  11. package/dist/commands/config.js +336 -0
  12. package/dist/commands/config.js.map +1 -0
  13. package/dist/commands/insights.d.ts +5 -0
  14. package/dist/commands/insights.d.ts.map +1 -0
  15. package/dist/commands/insights.js +277 -0
  16. package/dist/commands/insights.js.map +1 -0
  17. package/dist/commands/integrations.d.ts +15 -0
  18. package/dist/commands/integrations.d.ts.map +1 -0
  19. package/dist/commands/integrations.js +256 -0
  20. package/dist/commands/integrations.js.map +1 -0
  21. package/dist/commands/resources.d.ts +19 -7
  22. package/dist/commands/resources.d.ts.map +1 -1
  23. package/dist/commands/resources.js +92 -167
  24. package/dist/commands/resources.js.map +1 -1
  25. package/dist/commands/workspace-as-code.d.ts +27 -0
  26. package/dist/commands/workspace-as-code.d.ts.map +1 -0
  27. package/dist/commands/workspace-as-code.js +377 -0
  28. package/dist/commands/workspace-as-code.js.map +1 -0
  29. package/dist/help.d.ts +25 -1
  30. package/dist/help.d.ts.map +1 -1
  31. package/dist/help.js +104 -8
  32. package/dist/help.js.map +1 -1
  33. package/dist/run.d.ts +17 -0
  34. package/dist/run.d.ts.map +1 -1
  35. package/dist/run.js +88 -41
  36. package/dist/run.js.map +1 -1
  37. package/dist/wac/__tests__/wac-fixtures.d.ts +20 -0
  38. package/dist/wac/__tests__/wac-fixtures.d.ts.map +1 -0
  39. package/dist/wac/__tests__/wac-fixtures.js +38 -0
  40. package/dist/wac/__tests__/wac-fixtures.js.map +1 -0
  41. package/dist/wac/apply.d.ts +113 -0
  42. package/dist/wac/apply.d.ts.map +1 -0
  43. package/dist/wac/apply.js +265 -0
  44. package/dist/wac/apply.js.map +1 -0
  45. package/dist/wac/diff.d.ts +137 -0
  46. package/dist/wac/diff.d.ts.map +1 -0
  47. package/dist/wac/diff.js +413 -0
  48. package/dist/wac/diff.js.map +1 -0
  49. package/dist/wac/document.d.ts +110 -0
  50. package/dist/wac/document.d.ts.map +1 -0
  51. package/dist/wac/document.js +429 -0
  52. package/dist/wac/document.js.map +1 -0
  53. package/dist/wac/render.d.ts +52 -0
  54. package/dist/wac/render.d.ts.map +1 -0
  55. package/dist/wac/render.js +156 -0
  56. package/dist/wac/render.js.map +1 -0
  57. package/dist/wac/resource-def.d.ts +116 -0
  58. package/dist/wac/resource-def.d.ts.map +1 -0
  59. package/dist/wac/resource-def.js +44 -0
  60. package/dist/wac/resource-def.js.map +1 -0
  61. package/dist/wac/resources.d.ts +104 -0
  62. package/dist/wac/resources.d.ts.map +1 -0
  63. package/dist/wac/resources.js +541 -0
  64. package/dist/wac/resources.js.map +1 -0
  65. package/dist/wac/values.d.ts +16 -0
  66. package/dist/wac/values.d.ts.map +1 -0
  67. package/dist/wac/values.js +53 -0
  68. package/dist/wac/values.js.map +1 -0
  69. package/package.json +2 -1
  70. package/dist/cli.spec.d.ts +0 -2
  71. package/dist/cli.spec.d.ts.map +0 -1
  72. package/dist/cli.spec.js +0 -226
  73. 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.4",
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,6 +25,7 @@
25
25
  },
26
26
  "files": [
27
27
  "dist",
28
+ "!dist/**/*.spec.*",
28
29
  "README.md",
29
30
  "LICENSE"
30
31
  ],
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=cli.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.spec.d.ts","sourceRoot":"","sources":["../src/cli.spec.ts"],"names":[],"mappings":""}