kalup 0.4.0 → 0.6.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.
@@ -2,46 +2,81 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://kalup.dev/schemas/ir-1.schema.json",
4
4
  "title": "Kalup IR, version 1",
5
- "description": "What a Kalup project's config files mean, derived by `kalup ir`, or what a portal holds, captured by `kalup snapshot` with an observation block. Change inside a version is additive and readers keep unknown fields, so the document and each resource accept fields this schema does not list. Below a resource everything is closed except `x` and the definition of a resource type this schema does not describe, which stays open until a later ir/1 release describes that type.",
5
+ "description": "What a Kalup project's config files mean, derived by `kalup ir`, or what a portal holds, captured by `kalup snapshot` with an observation block. Open for additions within ir/1 (docs/compatibility.md): the document, each resource and everything below it accept fields this schema does not list, and readers keep or ignore them; a later 1.x may add a resource type, and a reader reports an address of a type it does not handle as unknown. Closed, because a new value changes what a reader may conclude: generator, a $ref, a tombstone, the read statuses in coverage, lifecycle.options, and a target's drift and adopt.",
6
6
  "type": "object",
7
7
  "required": ["irVersion", "project", "generator", "resources", "targets", "tombstones"],
8
8
  "properties": {
9
- "irVersion": { "const": 1 },
10
- "project": { "type": "string" },
9
+ "irVersion": {
10
+ "const": 1
11
+ },
12
+ "project": {
13
+ "type": "string"
14
+ },
11
15
  "generator": {
12
16
  "type": "object",
13
17
  "required": ["name", "version", "frontend"],
14
18
  "properties": {
15
- "name": { "type": "string" },
16
- "version": { "type": "string" },
17
- "frontend": { "enum": ["ts", "portal"] }
19
+ "name": {
20
+ "type": "string"
21
+ },
22
+ "version": {
23
+ "type": "string"
24
+ },
25
+ "frontend": {
26
+ "enum": ["ts", "portal"]
27
+ }
18
28
  },
19
29
  "additionalProperties": false
20
30
  },
21
31
  "resources": {
22
32
  "type": "object",
23
- "patternProperties": { "^[a-z]+:\\S+$": { "$ref": "#/$defs/resource" } },
33
+ "patternProperties": {
34
+ "^[a-z]+:\\S+$": {
35
+ "$ref": "#/$defs/resource"
36
+ }
37
+ },
24
38
  "additionalProperties": false
25
39
  },
26
40
  "targets": {
27
41
  "type": "object",
28
- "additionalProperties": { "$ref": "#/$defs/target" }
42
+ "additionalProperties": {
43
+ "$ref": "#/$defs/target"
44
+ }
29
45
  },
30
46
  "tombstones": {
31
47
  "type": "object",
32
- "patternProperties": { "^[a-z]+:\\S+$": { "$ref": "#/$defs/tombstone" } },
48
+ "patternProperties": {
49
+ "^[a-z]+:\\S+$": {
50
+ "$ref": "#/$defs/tombstone"
51
+ }
52
+ },
33
53
  "additionalProperties": false
34
54
  },
35
- "observation": { "$ref": "#/$defs/observation" },
36
- "x": { "type": "object" }
55
+ "observation": {
56
+ "$ref": "#/$defs/observation"
57
+ },
58
+ "x": {
59
+ "type": "object"
60
+ }
37
61
  },
38
62
  "allOf": [
39
63
  {
40
64
  "if": {
41
65
  "required": ["generator"],
42
- "properties": { "generator": { "required": ["frontend"], "properties": { "frontend": { "const": "portal" } } } }
66
+ "properties": {
67
+ "generator": {
68
+ "required": ["frontend"],
69
+ "properties": {
70
+ "frontend": {
71
+ "const": "portal"
72
+ }
73
+ }
74
+ }
75
+ }
43
76
  },
44
- "then": { "required": ["observation"] }
77
+ "then": {
78
+ "required": ["observation"]
79
+ }
45
80
  }
46
81
  ],
47
82
  "$defs": {
@@ -54,53 +89,180 @@
54
89
  "description": "A logical reference, allowed anywhere inside a definition where HubSpot wants an ID.",
55
90
  "type": "object",
56
91
  "required": ["$ref"],
57
- "properties": { "$ref": { "$ref": "#/$defs/address" } },
92
+ "properties": {
93
+ "$ref": {
94
+ "$ref": "#/$defs/address"
95
+ }
96
+ },
58
97
  "additionalProperties": false
59
98
  },
60
99
  "resource": {
61
100
  "type": "object",
62
101
  "required": ["type", "managed"],
63
102
  "properties": {
64
- "type": { "type": "string" },
65
- "managed": { "type": "boolean" },
66
- "definition": { "type": "object" },
67
- "lookup": { "type": "object", "additionalProperties": { "type": "string" } },
68
- "binding": { "$ref": "#/$defs/binding" },
69
- "lifecycle": { "$ref": "#/$defs/lifecycle" },
70
- "provenance": { "$ref": "#/$defs/provenance" },
71
- "x": { "type": "object" }
103
+ "type": {
104
+ "type": "string"
105
+ },
106
+ "managed": {
107
+ "type": "boolean"
108
+ },
109
+ "definition": {
110
+ "type": "object"
111
+ },
112
+ "lookup": {
113
+ "type": "object",
114
+ "additionalProperties": {
115
+ "type": "string"
116
+ }
117
+ },
118
+ "binding": {
119
+ "$ref": "#/$defs/binding"
120
+ },
121
+ "lifecycle": {
122
+ "$ref": "#/$defs/lifecycle"
123
+ },
124
+ "provenance": {
125
+ "$ref": "#/$defs/provenance"
126
+ },
127
+ "x": {
128
+ "type": "object"
129
+ }
72
130
  },
73
131
  "allOf": [
74
132
  {
75
- "if": { "required": ["managed"], "properties": { "managed": { "const": true } } },
76
- "then": { "required": ["definition"] }
133
+ "if": {
134
+ "required": ["managed"],
135
+ "properties": {
136
+ "managed": {
137
+ "const": true
138
+ }
139
+ }
140
+ },
141
+ "then": {
142
+ "required": ["definition"]
143
+ }
77
144
  },
78
145
  {
79
- "if": { "required": ["type"], "properties": { "type": { "const": "property" } } },
80
- "then": { "properties": { "definition": { "$ref": "#/$defs/propertyFields" } } }
146
+ "if": {
147
+ "required": ["type"],
148
+ "properties": {
149
+ "type": {
150
+ "const": "property"
151
+ }
152
+ }
153
+ },
154
+ "then": {
155
+ "properties": {
156
+ "definition": {
157
+ "$ref": "#/$defs/propertyFields"
158
+ }
159
+ }
160
+ }
81
161
  },
82
162
  {
83
163
  "if": {
84
164
  "required": ["type", "managed"],
85
- "properties": { "type": { "const": "property" }, "managed": { "const": true } }
165
+ "properties": {
166
+ "type": {
167
+ "const": "property"
168
+ },
169
+ "managed": {
170
+ "const": true
171
+ }
172
+ }
86
173
  },
87
- "then": { "properties": { "definition": { "required": ["label", "group", "type", "fieldType"] } } }
174
+ "then": {
175
+ "properties": {
176
+ "definition": {
177
+ "required": ["label", "group", "type", "fieldType"]
178
+ }
179
+ }
180
+ }
88
181
  },
89
182
  {
90
- "if": { "required": ["type"], "properties": { "type": { "const": "group" } } },
91
- "then": { "properties": { "definition": { "$ref": "#/$defs/groupDefinition" } } }
183
+ "if": {
184
+ "required": ["type"],
185
+ "properties": {
186
+ "type": {
187
+ "const": "group"
188
+ }
189
+ }
190
+ },
191
+ "then": {
192
+ "properties": {
193
+ "definition": {
194
+ "$ref": "#/$defs/groupDefinition"
195
+ }
196
+ }
197
+ }
198
+ },
199
+ {
200
+ "if": {
201
+ "required": ["type"],
202
+ "properties": {
203
+ "type": {
204
+ "const": "object"
205
+ }
206
+ }
207
+ },
208
+ "then": {
209
+ "properties": {
210
+ "definition": {
211
+ "$ref": "#/$defs/objectDefinition"
212
+ }
213
+ }
214
+ }
92
215
  },
93
216
  {
94
- "if": { "required": ["type"], "properties": { "type": { "const": "object" } } },
95
- "then": { "properties": { "definition": { "$ref": "#/$defs/objectDefinition" } } }
217
+ "if": {
218
+ "required": ["type"],
219
+ "properties": {
220
+ "type": {
221
+ "const": "pipeline"
222
+ }
223
+ }
224
+ },
225
+ "then": {
226
+ "properties": {
227
+ "definition": {
228
+ "$ref": "#/$defs/pipelineDefinition"
229
+ }
230
+ }
231
+ }
96
232
  },
97
233
  {
98
- "if": { "required": ["type"], "properties": { "type": { "const": "pipeline" } } },
99
- "then": { "properties": { "definition": { "$ref": "#/$defs/pipelineDefinition" } } }
234
+ "if": {
235
+ "required": ["type"],
236
+ "properties": {
237
+ "type": {
238
+ "const": "stage"
239
+ }
240
+ }
241
+ },
242
+ "then": {
243
+ "properties": {
244
+ "definition": {
245
+ "$ref": "#/$defs/stageDefinition"
246
+ }
247
+ }
248
+ }
100
249
  },
101
250
  {
102
- "if": { "required": ["type"], "properties": { "type": { "const": "stage" } } },
103
- "then": { "properties": { "definition": { "$ref": "#/$defs/stageDefinition" } } }
251
+ "if": {
252
+ "required": ["type"],
253
+ "properties": {
254
+ "type": {
255
+ "const": "association"
256
+ }
257
+ }
258
+ },
259
+ "then": {
260
+ "properties": {
261
+ "definition": {
262
+ "$ref": "#/$defs/associationDefinition"
263
+ }
264
+ }
265
+ }
104
266
  }
105
267
  ]
106
268
  },
@@ -108,72 +270,104 @@
108
270
  "description": "A property definition in HubSpot terms. A managed property needs label, group, type and fieldType; an unmanaged one may carry any subset, such as the options of a HubSpot-defined enumeration.",
109
271
  "type": "object",
110
272
  "properties": {
111
- "label": { "type": "string" },
112
- "group": { "$ref": "#/$defs/ref" },
113
- "type": { "enum": ["string", "number", "bool", "date", "datetime", "enumeration", "phone_number"] },
273
+ "label": {
274
+ "type": "string"
275
+ },
276
+ "group": {
277
+ "$ref": "#/$defs/ref"
278
+ },
279
+ "type": {
280
+ "type": "string",
281
+ "description": "A value HubSpot defines; known values: string, number, bool, date, datetime, enumeration, phone_number. A later version may record one HubSpot adds."
282
+ },
114
283
  "fieldType": {
115
- "enum": [
116
- "text",
117
- "textarea",
118
- "file",
119
- "phonenumber",
120
- "number",
121
- "booleancheckbox",
122
- "select",
123
- "radio",
124
- "checkbox",
125
- "date",
126
- "html",
127
- "calculation_equation"
128
- ]
129
- },
130
- "description": { "type": "string" },
131
- "options": { "type": "array", "items": { "$ref": "#/$defs/option" } },
132
- "hasUniqueValue": { "type": "boolean" },
133
- "formField": { "type": "boolean" },
134
- "hidden": { "type": "boolean" },
135
- "displayOrder": { "type": "integer", "minimum": -1 },
284
+ "type": "string",
285
+ "description": "A value HubSpot defines; known values: text, textarea, file, phonenumber, number, booleancheckbox, select, radio, checkbox, date, html, calculation_equation. A later version may record one HubSpot adds."
286
+ },
287
+ "description": {
288
+ "type": "string"
289
+ },
290
+ "options": {
291
+ "type": "array",
292
+ "items": {
293
+ "$ref": "#/$defs/option"
294
+ }
295
+ },
296
+ "hasUniqueValue": {
297
+ "type": "boolean"
298
+ },
299
+ "formField": {
300
+ "type": "boolean"
301
+ },
302
+ "hidden": {
303
+ "type": "boolean"
304
+ },
305
+ "displayOrder": {
306
+ "type": "integer",
307
+ "minimum": -1
308
+ },
136
309
  "numberDisplayHint": {
137
- "enum": ["currency", "duration", "formatted", "percentage", "probability", "unformatted"]
310
+ "type": "string",
311
+ "description": "A value HubSpot defines; known values: currency, duration, formatted, percentage, probability, unformatted. A later version may record one HubSpot adds."
312
+ },
313
+ "showCurrencySymbol": {
314
+ "type": "boolean"
315
+ },
316
+ "currencyPropertyName": {
317
+ "type": "string"
138
318
  },
139
- "showCurrencySymbol": { "type": "boolean" },
140
- "currencyPropertyName": { "type": "string" },
141
319
  "textDisplayHint": {
142
- "enum": [
143
- "domain_name",
144
- "email",
145
- "ip_address",
146
- "multi_line",
147
- "phone_number",
148
- "physical_address",
149
- "postal_code",
150
- "unformatted_single_line"
151
- ]
152
- },
153
- "calculationFormula": { "type": "string" },
154
- "dataSensitivity": { "enum": ["non_sensitive", "sensitive", "highly_sensitive"] },
155
- "externalOptions": { "const": true },
156
- "referencedObjectType": { "const": "OWNER" }
320
+ "type": "string",
321
+ "description": "A value HubSpot defines; known values: domain_name, email, ip_address, multi_line, phone_number, physical_address, postal_code, unformatted_single_line. A later version may record one HubSpot adds."
322
+ },
323
+ "calculationFormula": {
324
+ "type": "string"
325
+ },
326
+ "dataSensitivity": {
327
+ "type": "string",
328
+ "description": "A value HubSpot defines; known values: non_sensitive, sensitive, highly_sensitive. A later version may record one HubSpot adds."
329
+ },
330
+ "externalOptions": {
331
+ "const": true
332
+ },
333
+ "referencedObjectType": {
334
+ "const": "OWNER"
335
+ }
157
336
  },
158
- "additionalProperties": false
337
+ "additionalProperties": true
159
338
  },
160
339
  "option": {
161
340
  "description": "One enumeration option. Array index is display order. The app alias lives in binding.aliases, never here.",
162
341
  "type": "object",
163
342
  "required": ["value", "label"],
164
343
  "properties": {
165
- "value": { "type": "string" },
166
- "label": { "type": "string" },
167
- "hidden": { "type": "boolean" },
168
- "description": { "type": "string" }
344
+ "value": {
345
+ "type": "string"
346
+ },
347
+ "label": {
348
+ "type": "string"
349
+ },
350
+ "hidden": {
351
+ "type": "boolean"
352
+ },
353
+ "description": {
354
+ "type": "string"
355
+ }
169
356
  },
170
- "additionalProperties": false
357
+ "additionalProperties": true,
358
+ "patternProperties": {
359
+ "^as$": false
360
+ }
171
361
  },
172
362
  "groupDefinition": {
173
363
  "type": "object",
174
364
  "required": ["label"],
175
- "properties": { "label": { "type": "string" } },
176
- "additionalProperties": false
365
+ "properties": {
366
+ "label": {
367
+ "type": "string"
368
+ }
369
+ },
370
+ "additionalProperties": true
177
371
  },
178
372
  "objectDefinition": {
179
373
  "description": "A custom object schema. Its properties and groups are resources of their own.",
@@ -183,99 +377,197 @@
183
377
  "labels": {
184
378
  "type": "object",
185
379
  "required": ["singular", "plural"],
186
- "properties": { "singular": { "type": "string" }, "plural": { "type": "string" } },
187
- "additionalProperties": false
380
+ "properties": {
381
+ "singular": {
382
+ "type": "string"
383
+ },
384
+ "plural": {
385
+ "type": "string"
386
+ }
387
+ },
388
+ "additionalProperties": true
389
+ },
390
+ "description": {
391
+ "type": "string"
392
+ },
393
+ "primaryDisplayProperty": {
394
+ "type": "string"
395
+ },
396
+ "requiredProperties": {
397
+ "type": "array",
398
+ "items": {
399
+ "type": "string"
400
+ }
401
+ },
402
+ "searchableProperties": {
403
+ "type": "array",
404
+ "items": {
405
+ "type": "string"
406
+ }
188
407
  },
189
- "primaryDisplayProperty": { "type": "string" },
190
- "requiredProperties": { "type": "array", "items": { "type": "string" } },
191
- "searchableProperties": { "type": "array", "items": { "type": "string" } },
192
- "secondaryDisplayProperties": { "type": "array", "items": { "type": "string" } }
408
+ "secondaryDisplayProperties": {
409
+ "type": "array",
410
+ "items": {
411
+ "type": "string"
412
+ }
413
+ }
193
414
  },
194
- "additionalProperties": false
415
+ "additionalProperties": true
195
416
  },
196
417
  "pipelineDefinition": {
197
418
  "description": "A pipeline. Its stages are resources of their own; stages lists their IDs in display order.",
198
419
  "type": "object",
199
420
  "required": ["label", "displayOrder", "stages"],
200
421
  "properties": {
201
- "label": { "type": "string" },
202
- "displayOrder": { "type": "integer", "minimum": 0 },
203
- "stages": { "type": "array", "items": { "type": "string" } }
422
+ "label": {
423
+ "type": "string"
424
+ },
425
+ "displayOrder": {
426
+ "type": "integer",
427
+ "minimum": 0
428
+ },
429
+ "stages": {
430
+ "type": "array",
431
+ "items": {
432
+ "type": "string"
433
+ }
434
+ }
204
435
  },
205
- "additionalProperties": false
436
+ "additionalProperties": true
206
437
  },
207
438
  "stageDefinition": {
208
439
  "description": "A pipeline stage. Its metadata field depends on the object: probability on deals, ticketState on tickets, state on custom objects.",
209
440
  "type": "object",
210
441
  "required": ["label"],
211
442
  "properties": {
212
- "label": { "type": "string" },
213
- "probability": { "type": "number", "minimum": 0, "maximum": 1 },
214
- "ticketState": { "enum": ["OPEN", "CLOSED"] },
215
- "state": { "enum": ["OPEN", "CLOSED"] }
443
+ "label": {
444
+ "type": "string"
445
+ },
446
+ "probability": {
447
+ "type": "number",
448
+ "minimum": 0,
449
+ "maximum": 1
450
+ },
451
+ "ticketState": {
452
+ "type": "string",
453
+ "description": "A value HubSpot defines; known values: OPEN, CLOSED. A later version may record one HubSpot adds."
454
+ },
455
+ "state": {
456
+ "type": "string",
457
+ "description": "A value HubSpot defines; known values: OPEN, CLOSED. A later version may record one HubSpot adds."
458
+ }
216
459
  },
217
- "additionalProperties": false
460
+ "additionalProperties": true
461
+ },
462
+ "associationDefinition": {
463
+ "description": "An association label between two objects: label as the from object shows it, inverseLabel as the to object does. With neither, the plain association of a pair that has no HubSpot-defined one.",
464
+ "type": "object",
465
+ "properties": {
466
+ "label": {
467
+ "type": "string"
468
+ },
469
+ "inverseLabel": {
470
+ "type": "string"
471
+ }
472
+ },
473
+ "additionalProperties": true
218
474
  },
219
475
  "binding": {
220
476
  "description": "App terms, filled in by the loader. key and codec for properties, export for objects.",
221
477
  "type": "object",
222
478
  "properties": {
223
- "key": { "type": "string" },
479
+ "key": {
480
+ "type": "string"
481
+ },
224
482
  "codec": {
225
- "enum": [
226
- "string",
227
- "number",
228
- "boolean",
229
- "date",
230
- "datetime",
231
- "enum",
232
- "multiEnum",
233
- "stringArray",
234
- "json",
235
- "phoneNumber",
236
- "owner"
237
- ]
238
- },
239
- "aliases": { "type": "object", "additionalProperties": { "type": "string" } },
240
- "required": { "type": "boolean" },
241
- "readonly": { "type": "boolean" },
242
- "strict": { "type": "boolean" },
243
- "export": { "type": "string" }
483
+ "type": "string",
484
+ "pattern": "^[a-zA-Z]+$",
485
+ "description": "The builder. Known: string, number, boolean, date, datetime, enum, multiEnum, stringArray, json, phoneNumber, owner. A later version may add a builder."
486
+ },
487
+ "aliases": {
488
+ "type": "object",
489
+ "additionalProperties": {
490
+ "type": "string"
491
+ }
492
+ },
493
+ "required": {
494
+ "type": "boolean"
495
+ },
496
+ "readonly": {
497
+ "type": "boolean"
498
+ },
499
+ "strict": {
500
+ "type": "boolean"
501
+ },
502
+ "export": {
503
+ "type": "string"
504
+ }
244
505
  },
245
- "additionalProperties": false
506
+ "additionalProperties": true
246
507
  },
247
508
  "lifecycle": {
248
509
  "type": "object",
249
510
  "required": ["options"],
250
511
  "properties": {
251
- "options": { "enum": ["additive", "exact"] },
252
- "removedOptions": { "type": "array", "items": { "type": "string" } },
253
- "ignoreChanges": { "type": "array", "items": { "type": "string" } },
254
- "preventDestroy": { "type": "boolean" }
512
+ "options": {
513
+ "enum": ["additive", "exact"]
514
+ },
515
+ "removedOptions": {
516
+ "type": "array",
517
+ "items": {
518
+ "type": "string"
519
+ }
520
+ },
521
+ "ignoreChanges": {
522
+ "type": "array",
523
+ "items": {
524
+ "type": "string"
525
+ }
526
+ },
527
+ "preventDestroy": {
528
+ "type": "boolean"
529
+ }
255
530
  },
256
- "additionalProperties": false
531
+ "additionalProperties": true
257
532
  },
258
533
  "provenance": {
259
534
  "description": "Merged from blueprints.lock.json in the folder of object files by the loader. Absent means authored by hand.",
260
535
  "type": "object",
261
536
  "required": ["blueprint", "version", "sourceAddress", "prefix", "hash"],
262
537
  "properties": {
263
- "blueprint": { "type": "string" },
264
- "version": { "type": "string" },
265
- "sourceAddress": { "$ref": "#/$defs/address" },
266
- "prefix": { "type": "string" },
267
- "hash": { "type": "string" }
538
+ "blueprint": {
539
+ "type": "string"
540
+ },
541
+ "version": {
542
+ "type": "string"
543
+ },
544
+ "sourceAddress": {
545
+ "$ref": "#/$defs/address"
546
+ },
547
+ "prefix": {
548
+ "type": "string"
549
+ },
550
+ "hash": {
551
+ "type": "string"
552
+ }
268
553
  },
269
- "additionalProperties": false
554
+ "additionalProperties": true
270
555
  },
271
556
  "target": {
272
557
  "description": "One named portal. Credentials never enter the IR.",
273
558
  "type": "object",
274
559
  "required": ["portalId"],
275
560
  "properties": {
276
- "portalId": { "type": "integer", "minimum": 1 },
277
- "protected": { "type": "boolean" },
278
- "drift": { "enum": ["hold", "overwrite"] },
561
+ "portalId": {
562
+ "type": "integer",
563
+ "minimum": 1
564
+ },
565
+ "protected": {
566
+ "type": "boolean"
567
+ },
568
+ "drift": {
569
+ "enum": ["hold", "overwrite"]
570
+ },
279
571
  "adopt": {
280
572
  "description": "What a plan does with a unit that has no base and differs. Default hold.",
281
573
  "enum": ["hold", "overwrite"]
@@ -292,21 +584,39 @@
292
584
  },
293
585
  "overrides": {
294
586
  "type": "object",
295
- "patternProperties": { "^[a-z]+:\\S+$": { "$ref": "#/$defs/override" } },
587
+ "patternProperties": {
588
+ "^[a-z]+:\\S+$": {
589
+ "$ref": "#/$defs/override"
590
+ }
591
+ },
296
592
  "additionalProperties": false
297
593
  }
298
594
  },
299
- "additionalProperties": false
595
+ "additionalProperties": true,
596
+ "patternProperties": {
597
+ "^credentials$": false
598
+ }
300
599
  },
301
600
  "override": {
302
601
  "type": "object",
303
602
  "properties": {
304
- "skip": { "const": true },
305
- "name": { "type": "string" },
306
- "definition": { "type": "object" },
307
- "lookup": { "type": "object", "additionalProperties": { "type": "string" } }
603
+ "skip": {
604
+ "const": true
605
+ },
606
+ "name": {
607
+ "type": "string"
608
+ },
609
+ "definition": {
610
+ "type": "object"
611
+ },
612
+ "lookup": {
613
+ "type": "object",
614
+ "additionalProperties": {
615
+ "type": "string"
616
+ }
617
+ }
308
618
  },
309
- "additionalProperties": false
619
+ "additionalProperties": true
310
620
  },
311
621
  "observation": {
312
622
  "description": "What a snapshot read: the target, when, and how completely. A portal-frontend document requires it. observedAt is the one timestamp an ir/1 document carries.",
@@ -316,7 +626,15 @@
316
626
  "target": {
317
627
  "type": "object",
318
628
  "required": ["name", "portalId"],
319
- "properties": { "name": { "type": "string" }, "portalId": { "type": "integer", "minimum": 1 } },
629
+ "properties": {
630
+ "name": {
631
+ "type": "string"
632
+ },
633
+ "portalId": {
634
+ "type": "integer",
635
+ "minimum": 1
636
+ }
637
+ },
320
638
  "additionalProperties": false
321
639
  },
322
640
  "observedAt": {
@@ -324,68 +642,121 @@
324
642
  "type": "string",
325
643
  "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}([.][0-9]+)?Z$"
326
644
  },
327
- "coverage": { "$ref": "#/$defs/coverage" }
645
+ "coverage": {
646
+ "$ref": "#/$defs/coverage"
647
+ }
328
648
  },
329
- "additionalProperties": false
649
+ "additionalProperties": true
330
650
  },
331
651
  "coverage": {
332
652
  "description": "What the read covered. Only a complete read proves that a resource is absent.",
333
653
  "type": "object",
334
654
  "required": ["complete", "objects", "otherObjects", "notCaptured"],
335
655
  "properties": {
336
- "complete": { "type": "boolean" },
656
+ "complete": {
657
+ "type": "boolean"
658
+ },
337
659
  "objects": {
338
660
  "description": "One entry per config object key.",
339
661
  "type": "object",
340
- "additionalProperties": { "$ref": "#/$defs/objectCoverage" }
662
+ "additionalProperties": {
663
+ "$ref": "#/$defs/objectCoverage"
664
+ }
341
665
  },
342
666
  "otherObjects": {
343
667
  "description": "Custom objects in the portal that config does not name, or unknown when the schemas list was not read.",
344
668
  "type": ["array", "string"],
345
- "items": { "type": "string" },
346
- "if": { "type": "string" },
347
- "then": { "const": "unknown" }
669
+ "items": {
670
+ "type": "string"
671
+ },
672
+ "if": {
673
+ "type": "string"
674
+ },
675
+ "then": {
676
+ "const": "unknown"
677
+ }
678
+ },
679
+ "settling": {
680
+ "description": "Resources the read cannot be trusted on yet, by address: apply wrote them minutes ago and HubSpot still serves an older copy (stale), or does not list one Kalup created (missing). Unknown until the time given, never absent or drifted.",
681
+ "type": "object",
682
+ "additionalProperties": {
683
+ "type": "object",
684
+ "required": ["reason", "until"],
685
+ "properties": {
686
+ "reason": {
687
+ "type": "string",
688
+ "description": "Why it settles. Known: stale, missing. A later version may add a reason."
689
+ },
690
+ "until": {
691
+ "type": "string"
692
+ }
693
+ },
694
+ "additionalProperties": true
695
+ }
348
696
  },
349
697
  "notCaptured": {
350
- "description": "Documented response fields Kalup does not capture, per resource type.",
698
+ "description": "Documented response fields Kalup drops, by resource type. A later version may add a type.",
351
699
  "type": "object",
352
700
  "required": ["property", "group", "object"],
353
- "properties": {
354
- "property": { "type": "array", "items": { "type": "string" } },
355
- "group": { "type": "array", "items": { "type": "string" } },
356
- "object": { "type": "array", "items": { "type": "string" } },
357
- "pipeline": { "type": "array", "items": { "type": "string" } },
358
- "stage": { "type": "array", "items": { "type": "string" } }
359
- },
360
- "additionalProperties": false
701
+ "additionalProperties": false,
702
+ "patternProperties": {
703
+ "^[a-z]+$": {
704
+ "type": "array",
705
+ "items": {
706
+ "type": "string"
707
+ }
708
+ }
709
+ }
361
710
  }
362
711
  },
363
- "additionalProperties": false
712
+ "additionalProperties": true
364
713
  },
365
714
  "objectCoverage": {
366
715
  "type": "object",
367
716
  "required": ["status"],
368
717
  "properties": {
369
- "status": { "enum": ["read", "unreadable", "absent", "excluded"] },
370
- "missingScope": { "description": "Unreadable only.", "type": "string" },
371
- "issue": { "description": "Unreadable only.", "type": "string" },
372
- "objectTypeId": { "description": "A custom object that exists.", "type": "string" },
718
+ "status": {
719
+ "enum": ["read", "unreadable", "absent", "excluded"]
720
+ },
721
+ "missingScope": {
722
+ "description": "Unreadable only.",
723
+ "type": "string"
724
+ },
725
+ "issue": {
726
+ "description": "Unreadable only.",
727
+ "type": "string"
728
+ },
729
+ "objectTypeId": {
730
+ "description": "A custom object that exists.",
731
+ "type": "string"
732
+ },
373
733
  "outOfScope": {
374
734
  "description": "Present properties outside the pull scope that config does not name.",
375
735
  "type": "array",
376
- "items": { "type": "string" }
736
+ "items": {
737
+ "type": "string"
738
+ }
377
739
  },
378
740
  "shadowed": {
379
741
  "description": "Portal names equal to the local name of a renamed address, so not reported at it.",
380
742
  "type": "array",
381
- "items": { "type": "string" }
743
+ "items": {
744
+ "type": "string"
745
+ }
382
746
  },
383
747
  "unaddressable": {
384
748
  "description": "Present properties config names that are in a group whose name no address can hold, so not captured. What they hold is unknown.",
385
749
  "type": "array",
386
- "items": { "type": "string" }
750
+ "items": {
751
+ "type": "string"
752
+ }
753
+ },
754
+ "unsupported": {
755
+ "type": "array",
756
+ "items": {
757
+ "$ref": "#/$defs/unsupportedProperty"
758
+ }
387
759
  },
388
- "unsupported": { "type": "array", "items": { "$ref": "#/$defs/unsupportedProperty" } },
389
760
  "unsupportedSchema": {
390
761
  "description": "A custom object HubSpot returned without a singular or plural label, its fields as returned. It is present but not a resource.",
391
762
  "type": "object",
@@ -393,64 +764,187 @@
393
764
  "properties": {
394
765
  "labels": {
395
766
  "type": "object",
396
- "properties": { "singular": { "type": "string" }, "plural": { "type": "string" } },
767
+ "properties": {
768
+ "singular": {
769
+ "type": "string"
770
+ },
771
+ "plural": {
772
+ "type": "string"
773
+ }
774
+ },
397
775
  "additionalProperties": false
398
776
  },
399
- "primaryDisplayProperty": { "type": "string" },
400
- "requiredProperties": { "type": "array", "items": { "type": "string" } },
401
- "searchableProperties": { "type": "array", "items": { "type": "string" } },
402
- "secondaryDisplayProperties": { "type": "array", "items": { "type": "string" } }
777
+ "description": {
778
+ "type": "string"
779
+ },
780
+ "primaryDisplayProperty": {
781
+ "type": "string"
782
+ },
783
+ "requiredProperties": {
784
+ "type": "array",
785
+ "items": {
786
+ "type": "string"
787
+ }
788
+ },
789
+ "searchableProperties": {
790
+ "type": "array",
791
+ "items": {
792
+ "type": "string"
793
+ }
794
+ },
795
+ "secondaryDisplayProperties": {
796
+ "type": "array",
797
+ "items": {
798
+ "type": "string"
799
+ }
800
+ }
403
801
  },
404
- "additionalProperties": false
802
+ "additionalProperties": true
405
803
  },
406
804
  "excluded": {
407
805
  "description": "Addresses a skip override leaves out.",
408
806
  "type": "array",
409
- "items": { "$ref": "#/$defs/address" }
807
+ "items": {
808
+ "$ref": "#/$defs/address"
809
+ }
410
810
  },
411
811
  "renamed": {
412
812
  "description": "Addresses a name override points at another portal name.",
413
813
  "type": "object",
414
- "patternProperties": { "^[a-z]+:\\S+$": { "type": "string" } },
814
+ "patternProperties": {
815
+ "^[a-z]+:\\S+$": {
816
+ "type": "string"
817
+ }
818
+ },
415
819
  "additionalProperties": false
416
820
  },
417
821
  "pipelines": {
418
822
  "description": "Whether the object's pipelines list was read. Absent when its pipelines are not in scope.",
419
823
  "type": "object",
420
824
  "required": ["status"],
421
- "properties": { "status": { "enum": ["read", "unreadable"] }, "missingScope": { "type": "string" } },
422
- "additionalProperties": false
825
+ "properties": {
826
+ "status": {
827
+ "enum": ["read", "unreadable"]
828
+ },
829
+ "missingScope": {
830
+ "type": "string"
831
+ }
832
+ },
833
+ "additionalProperties": true
834
+ },
835
+ "associations": {
836
+ "description": "The associations of the pairs this object is in, pair by pair: per other object, whether the pair was read, and the user-defined types of this direction no name reached; and the HubSpot type IDs of each association addressed from this object. Absent when no pair with this object is in scope.",
837
+ "type": "object",
838
+ "required": ["with"],
839
+ "properties": {
840
+ "with": {
841
+ "type": "object",
842
+ "additionalProperties": {
843
+ "$ref": "#/$defs/pairCoverage"
844
+ }
845
+ },
846
+ "typeIds": {
847
+ "type": "object",
848
+ "additionalProperties": {
849
+ "type": "array",
850
+ "items": {
851
+ "type": "integer"
852
+ }
853
+ }
854
+ }
855
+ },
856
+ "additionalProperties": true
423
857
  }
424
858
  },
425
- "additionalProperties": false
859
+ "additionalProperties": true
426
860
  },
427
861
  "unsupportedProperty": {
428
862
  "description": "A present property Kalup does not write: no builder carries its type or fieldType, or HubSpot fills its options (owner or externalOptions). It is compared like any property but is not a resource.",
429
863
  "type": "object",
430
864
  "required": ["name", "type", "fieldType", "label", "group", "hubspotDefined"],
431
865
  "properties": {
432
- "name": { "type": "string" },
433
- "type": { "type": "string" },
434
- "fieldType": { "type": "string" },
435
- "label": { "type": "string" },
436
- "group": { "$ref": "#/$defs/ref" },
437
- "description": { "type": "string" },
438
- "options": { "type": "array", "items": { "$ref": "#/$defs/option" } },
439
- "hubspotDefined": { "type": "boolean" },
440
- "externalOptions": { "type": "boolean" },
441
- "referencedObjectType": { "type": "string" }
866
+ "name": {
867
+ "type": "string"
868
+ },
869
+ "type": {
870
+ "type": "string"
871
+ },
872
+ "fieldType": {
873
+ "type": "string"
874
+ },
875
+ "label": {
876
+ "type": "string"
877
+ },
878
+ "group": {
879
+ "$ref": "#/$defs/ref"
880
+ },
881
+ "description": {
882
+ "type": "string"
883
+ },
884
+ "options": {
885
+ "type": "array",
886
+ "items": {
887
+ "$ref": "#/$defs/option"
888
+ }
889
+ },
890
+ "hubspotDefined": {
891
+ "type": "boolean"
892
+ },
893
+ "externalOptions": {
894
+ "type": "boolean"
895
+ },
896
+ "referencedObjectType": {
897
+ "type": "string"
898
+ }
442
899
  },
443
- "additionalProperties": false
900
+ "additionalProperties": true
444
901
  },
445
902
  "tombstone": {
446
903
  "description": "Written by `kalup rm`. destroy archives or deletes in the portal; release stops managing and leaves it.",
447
904
  "type": "object",
448
905
  "required": ["action"],
449
906
  "properties": {
450
- "action": { "enum": ["destroy", "release"] },
451
- "reason": { "type": "string" }
907
+ "action": {
908
+ "enum": ["destroy", "release"]
909
+ },
910
+ "reason": {
911
+ "type": "string"
912
+ }
452
913
  },
453
914
  "additionalProperties": false
915
+ },
916
+ "pairCoverage": {
917
+ "description": "One pair read with an object, from that object's side.",
918
+ "type": "object",
919
+ "required": ["status"],
920
+ "properties": {
921
+ "status": {
922
+ "enum": ["read", "unreadable"]
923
+ },
924
+ "missingScope": {
925
+ "type": "string"
926
+ },
927
+ "issue": {
928
+ "type": "string"
929
+ },
930
+ "unnamed": {
931
+ "type": "array",
932
+ "items": {
933
+ "type": "object",
934
+ "required": ["typeId"],
935
+ "properties": {
936
+ "typeId": {
937
+ "type": "integer"
938
+ },
939
+ "label": {
940
+ "type": "string"
941
+ }
942
+ },
943
+ "additionalProperties": false
944
+ }
945
+ }
946
+ },
947
+ "additionalProperties": true
454
948
  }
455
949
  }
456
950
  }