@proteos/sdk 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-33EULWIM.cjs → chunk-F5DHWOGW.cjs} +195 -27
- package/dist/chunk-F5DHWOGW.cjs.map +1 -0
- package/dist/{chunk-IGIAJVX6.js → chunk-Y4CEHIRX.js} +191 -28
- package/dist/chunk-Y4CEHIRX.js.map +1 -0
- package/dist/index.cjs +428 -178
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +643 -11
- package/dist/index.d.ts +643 -11
- package/dist/index.js +330 -96
- package/dist/index.js.map +1 -1
- package/dist/meta/index.cjs +69 -53
- package/dist/meta/index.d.cts +1 -1
- package/dist/meta/index.d.ts +1 -1
- package/dist/meta/index.js +1 -1
- package/dist/{types-BTdBFq34.d.cts → types-D1PRIsSO.d.cts} +406 -14
- package/dist/{types-BTdBFq34.d.ts → types-D1PRIsSO.d.ts} +406 -14
- package/package.json +1 -1
- package/src/auth/index.ts +58 -1
- package/src/auth/me.ts +14 -1
- package/src/auth/platform-entities.ts +27 -0
- package/src/auth/roles.ts +3 -1
- package/src/auth/shares.ts +181 -0
- package/src/auth/teams.ts +135 -0
- package/src/auth/types.ts +192 -4
- package/src/auth/user-role-assignments.ts +65 -0
- package/src/index.ts +36 -0
- package/src/knowledge/graph.ts +6 -2
- package/src/knowledge/index.ts +15 -0
- package/src/knowledge/nodes.ts +4 -1
- package/src/knowledge/spaces.ts +86 -0
- package/src/knowledge/types.ts +89 -0
- package/src/meta/index.ts +11 -0
- package/src/meta/layout/control-registry.json +151 -26
- package/src/meta/types.ts +186 -4
- package/src/workflow/types.ts +20 -3
- package/dist/chunk-33EULWIM.cjs.map +0 -1
- package/dist/chunk-IGIAJVX6.js.map +0 -1
package/src/knowledge/types.ts
CHANGED
|
@@ -56,6 +56,12 @@ export interface KnowledgeNodeMetadata extends AuditFields {
|
|
|
56
56
|
/** Embedding provenance (null until ingestion runs). */
|
|
57
57
|
embedding_model?: string | null
|
|
58
58
|
embedded_at?: string | null
|
|
59
|
+
/**
|
|
60
|
+
* The space this node lives in, or null when UNASSIGNED. An unassigned node
|
|
61
|
+
* is visible to anyone holding knowledge-nodes:read — the behaviour every
|
|
62
|
+
* node had before spaces existed.
|
|
63
|
+
*/
|
|
64
|
+
space_slug?: string | null
|
|
59
65
|
/** Source pointer for `file` nodes (storage-service file id). */
|
|
60
66
|
file_id?: string | null
|
|
61
67
|
/** Source pointer for `url` nodes. */
|
|
@@ -148,6 +154,8 @@ export interface CreateNodeRequest {
|
|
|
148
154
|
type: NodeType
|
|
149
155
|
status: NodeStatus
|
|
150
156
|
content?: string
|
|
157
|
+
/** File the node into a space. Omitted = unassigned. */
|
|
158
|
+
space_slug?: string
|
|
151
159
|
file_id?: string
|
|
152
160
|
url?: string
|
|
153
161
|
summary?: string
|
|
@@ -170,6 +178,12 @@ export interface UpdateNodeRequest {
|
|
|
170
178
|
*/
|
|
171
179
|
valid_from?: string | null
|
|
172
180
|
valid_until?: string | null
|
|
181
|
+
/**
|
|
182
|
+
* Move the node between spaces, tri-state like the validity window: omit to
|
|
183
|
+
* leave it where it is, pass `null` to move it back to unassigned, or a slug
|
|
184
|
+
* to file it into that space.
|
|
185
|
+
*/
|
|
186
|
+
space_slug?: string | null
|
|
173
187
|
}
|
|
174
188
|
|
|
175
189
|
/** Filters for listing nodes. */
|
|
@@ -180,6 +194,11 @@ export interface ListNodesOptions extends ListOptions {
|
|
|
180
194
|
'title[contains]'?: string
|
|
181
195
|
/** Keep only nodes carrying ANY of these labels (union). */
|
|
182
196
|
label_ids?: string[]
|
|
197
|
+
/**
|
|
198
|
+
* Keep only nodes living in ANY of these spaces (union). Use
|
|
199
|
+
* `UNASSIGNED_SPACE_SLUG` to ask for nodes belonging to no space.
|
|
200
|
+
*/
|
|
201
|
+
space_slugs?: string[]
|
|
183
202
|
/** Created on/after this RFC3339 timestamp (inclusive). */
|
|
184
203
|
created_after?: string
|
|
185
204
|
/** Created on/before this RFC3339 timestamp (inclusive). */
|
|
@@ -298,6 +317,11 @@ export interface SearchNodesRequest {
|
|
|
298
317
|
status?: NodeStatus
|
|
299
318
|
/** Match nodes carrying ANY of these labels. */
|
|
300
319
|
label_ids?: string[]
|
|
320
|
+
/**
|
|
321
|
+
* Match nodes living in ANY of these spaces (union). Use
|
|
322
|
+
* `UNASSIGNED_SPACE_SLUG` for nodes belonging to no space.
|
|
323
|
+
*/
|
|
324
|
+
space_slugs?: string[]
|
|
301
325
|
/** Match nodes connected (either direction) to this node. */
|
|
302
326
|
linked_to_id?: string
|
|
303
327
|
/**
|
|
@@ -365,6 +389,8 @@ export interface KnowledgeGraphNode {
|
|
|
365
389
|
type: NodeType
|
|
366
390
|
status: NodeStatus
|
|
367
391
|
label_ids: string[]
|
|
392
|
+
/** The node's space, or null when unassigned. */
|
|
393
|
+
space_slug?: string | null
|
|
368
394
|
degree: number
|
|
369
395
|
}
|
|
370
396
|
|
|
@@ -386,6 +412,12 @@ export interface KnowledgeGraph {
|
|
|
386
412
|
nodes: KnowledgeGraphNode[]
|
|
387
413
|
links: KnowledgeGraphLink[]
|
|
388
414
|
labels: KnowledgeLabel[]
|
|
415
|
+
/**
|
|
416
|
+
* The full org space set, sent once for the same reason as `labels`: the
|
|
417
|
+
* client renders the space navigator and filters by space without a second
|
|
418
|
+
* request, even when the graph is pruned to one space.
|
|
419
|
+
*/
|
|
420
|
+
spaces: KnowledgeSpace[]
|
|
389
421
|
total: number
|
|
390
422
|
}
|
|
391
423
|
|
|
@@ -395,6 +427,8 @@ export interface KnowledgeGraph {
|
|
|
395
427
|
*/
|
|
396
428
|
export interface GetGraphOptions {
|
|
397
429
|
label_ids?: string[]
|
|
430
|
+
/** Prune to nodes in ANY of these spaces (union). */
|
|
431
|
+
space_slugs?: string[]
|
|
398
432
|
}
|
|
399
433
|
|
|
400
434
|
// ============================================================================
|
|
@@ -443,6 +477,61 @@ export interface ListRecordLinksOptions extends ListOptions {
|
|
|
443
477
|
record_id?: string
|
|
444
478
|
}
|
|
445
479
|
|
|
480
|
+
// ============================================================================
|
|
481
|
+
// Spaces
|
|
482
|
+
// ============================================================================
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* A knowledge space: the container a node lives in. A node belongs to at most
|
|
486
|
+
* one space; a node with no space is unassigned.
|
|
487
|
+
*
|
|
488
|
+
* A space is NOT a label. Labels are many-per-node, overlapping, non-security
|
|
489
|
+
* tags; a space is the single place a node lives, and it is what instance-level
|
|
490
|
+
* access is evaluated against.
|
|
491
|
+
*
|
|
492
|
+
* Keyed by `slug`, which is IMMUTABLE — it is half the primary key, node rows
|
|
493
|
+
* reference it and access grants name it, so renaming would orphan both. There
|
|
494
|
+
* is no id.
|
|
495
|
+
*/
|
|
496
|
+
export interface KnowledgeSpace extends AuditFields {
|
|
497
|
+
org_id: string
|
|
498
|
+
slug: string
|
|
499
|
+
name: string
|
|
500
|
+
description?: string | null
|
|
501
|
+
color?: string | null
|
|
502
|
+
icon?: string | null
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* The reserved filter value meaning "nodes that belong to no space at all".
|
|
507
|
+
* Deliberately not a legal slug (slugs are kebab-case), so it can never collide
|
|
508
|
+
* with a space an org creates.
|
|
509
|
+
*/
|
|
510
|
+
export const UNASSIGNED_SPACE_SLUG = '__unassigned__'
|
|
511
|
+
|
|
512
|
+
export interface CreateSpaceRequest {
|
|
513
|
+
/** Permanent — it is half the primary key and cannot be changed later. */
|
|
514
|
+
slug: string
|
|
515
|
+
name: string
|
|
516
|
+
description?: string
|
|
517
|
+
color?: string
|
|
518
|
+
icon?: string
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/** Partial update. `slug` is absent because it is immutable. */
|
|
522
|
+
export interface UpdateSpaceRequest {
|
|
523
|
+
name?: string
|
|
524
|
+
description?: string
|
|
525
|
+
color?: string
|
|
526
|
+
icon?: string
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
export interface ListSpacesOptions extends ListOptions {
|
|
530
|
+
slug?: string
|
|
531
|
+
name?: string
|
|
532
|
+
'name[contains]'?: string
|
|
533
|
+
}
|
|
534
|
+
|
|
446
535
|
// ============================================================================
|
|
447
536
|
// Label requests
|
|
448
537
|
// ============================================================================
|
package/src/meta/index.ts
CHANGED
|
@@ -123,6 +123,8 @@ export type {
|
|
|
123
123
|
ArrayAttributeMeta,
|
|
124
124
|
Attribute,
|
|
125
125
|
AttributeMeta,
|
|
126
|
+
AttributeAccessRule,
|
|
127
|
+
AttributeRestrictions,
|
|
126
128
|
AttributeType,
|
|
127
129
|
Column,
|
|
128
130
|
ComparisonOperator,
|
|
@@ -184,6 +186,7 @@ export type {
|
|
|
184
186
|
// Page types
|
|
185
187
|
Page,
|
|
186
188
|
PageAction,
|
|
189
|
+
PageActionKind,
|
|
187
190
|
PageType,
|
|
188
191
|
PublicAccessOperation,
|
|
189
192
|
PublicPageComponent,
|
|
@@ -204,6 +207,10 @@ export type {
|
|
|
204
207
|
UpdatePageRequest,
|
|
205
208
|
UpdateVariableRequest,
|
|
206
209
|
// User attribute meta
|
|
210
|
+
PrincipalAttributeMeta,
|
|
211
|
+
CurrentUserDefault,
|
|
212
|
+
PrincipalRef,
|
|
213
|
+
PrincipalType,
|
|
207
214
|
UserAttributeMeta,
|
|
208
215
|
// Variable types
|
|
209
216
|
Variable,
|
|
@@ -233,7 +240,11 @@ export {
|
|
|
233
240
|
PageActionSchema,
|
|
234
241
|
PageSchema,
|
|
235
242
|
PLATFORM_ATTRIBUTE_NAMES,
|
|
243
|
+
CURRENT_USER_DEFAULT,
|
|
244
|
+
acceptsCurrentUserDefault,
|
|
245
|
+
isCurrentUserDefault,
|
|
236
246
|
parseCurrencyMeta,
|
|
247
|
+
parsePrincipalMeta,
|
|
237
248
|
parseFileMeta,
|
|
238
249
|
parseRelationMeta,
|
|
239
250
|
parseUserMeta,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "SOURCE OF TRUTH for the page-layout control registry. Each entry under `controls` declares the primary control slug and the full compatible list for one (type[+format|+items.type]) combination. Renderer dispatches off `primary`; inspector picker dispatches off `compatible`. Edit this file then run `go run ./scripts/codegen/page-layout-registry` from the repo root to regenerate packages/go/model/page_layout_registry_gen.go.",
|
|
3
|
-
"_attributeTypes": "Top-level keys MUST match the Go canonical AttributeType union in packages/go/model/meta/attribute.go (string
|
|
4
|
-
"_slugRoster": "v1 ships only lib-backed slugs. Slugs without a backing @proteos/ui component (markdown
|
|
3
|
+
"_attributeTypes": "Top-level keys MUST match the Go canonical AttributeType union in packages/go/model/meta/attribute.go (string \u00b7 number \u00b7 integer \u00b7 boolean \u00b7 array \u00b7 object \u00b7 datetime \u00b7 enum \u00b7 relation \u00b7 user \u00b7 currency \u00b7 knowledge-text \u00b7 file). `byFormat` keys for `string` MUST match StringFormat (email \u00b7 uri \u00b7 uuid \u00b7 hostname \u00b7 ipv4 \u00b7 ipv6). `byFormat` keys for `datetime` MUST match DatetimeFormat (date-time \u00b7 date \u00b7 time \u00b7 duration). `byItemsType` for `array` keys on the item Attribute's type. A null `primary` with empty `compatible` means \"render-only fallback\" \u2014 see plan \u00a73.2.5.",
|
|
4
|
+
"_slugRoster": "v1 ships only lib-backed slugs. Slugs without a backing @proteos/ui component (markdown \u00b7 json-editor \u00b7 slider \u00b7 stepper \u00b7 percent \u00b7 user-card) are intentionally omitted; they return when the matching lib primitive ships. See plan \u00a73.2.4 / \u00a77.3. The `user-picker` slug is backed by the web client's UserCombobox (account/user-service people picker). The `currency` slug is backed by the web client's currency control (CurrencyInput: decimal amount + ISO-4217 picker).",
|
|
5
5
|
"builtInControls": [
|
|
6
6
|
"text",
|
|
7
7
|
"textarea",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"tag-input",
|
|
22
22
|
"entity-picker",
|
|
23
23
|
"user-picker",
|
|
24
|
+
"principal-picker",
|
|
24
25
|
"currency",
|
|
25
26
|
"knowledge-text",
|
|
26
27
|
"file",
|
|
@@ -29,43 +30,167 @@
|
|
|
29
30
|
"controls": {
|
|
30
31
|
"string": {
|
|
31
32
|
"primary": "text",
|
|
32
|
-
"compatible": [
|
|
33
|
+
"compatible": [
|
|
34
|
+
"text",
|
|
35
|
+
"textarea",
|
|
36
|
+
"password"
|
|
37
|
+
],
|
|
33
38
|
"byFormat": {
|
|
34
|
-
"email": {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
"email": {
|
|
40
|
+
"primary": "email",
|
|
41
|
+
"compatible": [
|
|
42
|
+
"email",
|
|
43
|
+
"text"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"uri": {
|
|
47
|
+
"primary": "url",
|
|
48
|
+
"compatible": [
|
|
49
|
+
"url",
|
|
50
|
+
"text"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"uuid": {
|
|
54
|
+
"primary": "text",
|
|
55
|
+
"compatible": [
|
|
56
|
+
"text"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"hostname": {
|
|
60
|
+
"primary": "text",
|
|
61
|
+
"compatible": [
|
|
62
|
+
"text"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
"ipv4": {
|
|
66
|
+
"primary": "text",
|
|
67
|
+
"compatible": [
|
|
68
|
+
"text"
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"ipv6": {
|
|
72
|
+
"primary": "text",
|
|
73
|
+
"compatible": [
|
|
74
|
+
"text"
|
|
75
|
+
]
|
|
76
|
+
}
|
|
40
77
|
}
|
|
41
78
|
},
|
|
42
|
-
"number": {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
79
|
+
"number": {
|
|
80
|
+
"primary": "number",
|
|
81
|
+
"compatible": [
|
|
82
|
+
"number"
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
"integer": {
|
|
86
|
+
"primary": "number",
|
|
87
|
+
"compatible": [
|
|
88
|
+
"number"
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
"boolean": {
|
|
92
|
+
"primary": "switch",
|
|
93
|
+
"compatible": [
|
|
94
|
+
"switch",
|
|
95
|
+
"checkbox"
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
"enum": {
|
|
99
|
+
"primary": "select",
|
|
100
|
+
"compatible": [
|
|
101
|
+
"select",
|
|
102
|
+
"radio-group",
|
|
103
|
+
"chip-group"
|
|
104
|
+
]
|
|
105
|
+
},
|
|
46
106
|
"array": {
|
|
47
107
|
"primary": "tag-input",
|
|
48
|
-
"compatible": [
|
|
108
|
+
"compatible": [
|
|
109
|
+
"tag-input"
|
|
110
|
+
],
|
|
49
111
|
"byItemsType": {
|
|
50
|
-
"string": {
|
|
51
|
-
|
|
112
|
+
"string": {
|
|
113
|
+
"primary": "tag-input",
|
|
114
|
+
"compatible": [
|
|
115
|
+
"tag-input"
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
"enum": {
|
|
119
|
+
"primary": "multi-select",
|
|
120
|
+
"compatible": [
|
|
121
|
+
"multi-select"
|
|
122
|
+
]
|
|
123
|
+
}
|
|
52
124
|
}
|
|
53
125
|
},
|
|
54
126
|
"datetime": {
|
|
55
127
|
"primary": null,
|
|
56
128
|
"compatible": [],
|
|
57
129
|
"byFormat": {
|
|
58
|
-
"date": {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
130
|
+
"date": {
|
|
131
|
+
"primary": "date-picker",
|
|
132
|
+
"compatible": [
|
|
133
|
+
"date-picker"
|
|
134
|
+
]
|
|
135
|
+
},
|
|
136
|
+
"date-time": {
|
|
137
|
+
"primary": "datetime-picker",
|
|
138
|
+
"compatible": [
|
|
139
|
+
"datetime-picker"
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
"time": {
|
|
143
|
+
"primary": "time-picker",
|
|
144
|
+
"compatible": [
|
|
145
|
+
"time-picker"
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
"duration": {
|
|
149
|
+
"primary": null,
|
|
150
|
+
"compatible": []
|
|
151
|
+
}
|
|
62
152
|
}
|
|
63
153
|
},
|
|
64
|
-
"object": {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
|
|
154
|
+
"object": {
|
|
155
|
+
"primary": null,
|
|
156
|
+
"compatible": []
|
|
157
|
+
},
|
|
158
|
+
"relation": {
|
|
159
|
+
"primary": "entity-picker",
|
|
160
|
+
"compatible": [
|
|
161
|
+
"entity-picker"
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
"user": {
|
|
165
|
+
"primary": "user-picker",
|
|
166
|
+
"compatible": [
|
|
167
|
+
"user-picker"
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
"currency": {
|
|
171
|
+
"primary": "currency",
|
|
172
|
+
"compatible": [
|
|
173
|
+
"currency"
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
"knowledge-text": {
|
|
177
|
+
"primary": "knowledge-text",
|
|
178
|
+
"compatible": [
|
|
179
|
+
"knowledge-text"
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
"file": {
|
|
183
|
+
"primary": "file",
|
|
184
|
+
"compatible": [
|
|
185
|
+
"file",
|
|
186
|
+
"file-viewer"
|
|
187
|
+
]
|
|
188
|
+
},
|
|
189
|
+
"principal": {
|
|
190
|
+
"primary": "principal-picker",
|
|
191
|
+
"compatible": [
|
|
192
|
+
"principal-picker"
|
|
193
|
+
]
|
|
194
|
+
}
|
|
70
195
|
}
|
|
71
196
|
}
|
package/src/meta/types.ts
CHANGED
|
@@ -38,10 +38,52 @@ export type AttributeType =
|
|
|
38
38
|
| 'enum'
|
|
39
39
|
| 'relation'
|
|
40
40
|
| 'user'
|
|
41
|
+
| 'principal'
|
|
41
42
|
| 'currency'
|
|
42
43
|
| 'knowledge-text'
|
|
43
44
|
| 'file'
|
|
44
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Attribute-level permissions: restricting a FIELD rather than a record — a
|
|
48
|
+
* salary column readable only by the people team, a margin column writable only
|
|
49
|
+
* by finance. Mirror of the Go `metamodel.AttributeRestrictions`.
|
|
50
|
+
*
|
|
51
|
+
* Orthogonal to instance-level access: a caller who may see a record may still
|
|
52
|
+
* be blocked from one of its fields.
|
|
53
|
+
*
|
|
54
|
+
* Absent means unrestricted. Both arms FAIL CLOSED — an empty rule matches
|
|
55
|
+
* nobody rather than everybody, and an unknown role or team slug never matches,
|
|
56
|
+
* so a typo removes access rather than granting it.
|
|
57
|
+
*/
|
|
58
|
+
export interface AttributeAccessRule {
|
|
59
|
+
/** Role slugs, matched against the caller's roles. */
|
|
60
|
+
roles?: string[]
|
|
61
|
+
/**
|
|
62
|
+
* Team slugs. Matched through the caller's team closure, so a member of a
|
|
63
|
+
* CHILD team is matched by a rule naming an ancestor.
|
|
64
|
+
*/
|
|
65
|
+
teams?: string[]
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const AttributeAccessRuleSchema = z.object({
|
|
69
|
+
roles: z.array(z.string()).optional(),
|
|
70
|
+
teams: z.array(z.string()).optional(),
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Read and write are gated independently, so `write` alone yields a field
|
|
75
|
+
* everyone can see and only some can change.
|
|
76
|
+
*/
|
|
77
|
+
export interface AttributeRestrictions {
|
|
78
|
+
read?: AttributeAccessRule
|
|
79
|
+
write?: AttributeAccessRule
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const AttributeRestrictionsSchema = z.object({
|
|
83
|
+
read: AttributeAccessRuleSchema.optional(),
|
|
84
|
+
write: AttributeAccessRuleSchema.optional(),
|
|
85
|
+
})
|
|
86
|
+
|
|
45
87
|
// ── Attribute meta (sub-discriminators) ──────────────────────────────
|
|
46
88
|
// Mirrors the Go `*AttributeMeta` types in
|
|
47
89
|
// packages/go/model/attribute-{string,number,datetime,array,object,enum}.go.
|
|
@@ -88,6 +130,10 @@ export interface EnumValue {
|
|
|
88
130
|
value: string
|
|
89
131
|
label?: string
|
|
90
132
|
description?: string
|
|
133
|
+
/** Lucide icon name, canonical PascalCase (e.g. `CircleCheck`). Replaces the badge dot. */
|
|
134
|
+
icon?: string
|
|
135
|
+
/** Tint as `#rrggbb`. Renderers derive dot/border/background from it; text stays ink. */
|
|
136
|
+
color?: string
|
|
91
137
|
}
|
|
92
138
|
|
|
93
139
|
export interface EnumAttributeMeta {
|
|
@@ -144,6 +190,68 @@ export const UserAttributeMetaSchema = z.object({
|
|
|
144
190
|
description: z.string().optional(),
|
|
145
191
|
})
|
|
146
192
|
|
|
193
|
+
/**
|
|
194
|
+
* The stored value of a `principal`-typed attribute: a {@link PrincipalRef}
|
|
195
|
+
* `{ type, id }` naming anything that can HOLD ACCESS — a user (person, agent
|
|
196
|
+
* or api client), a team, or the whole organization. Mirror of the Go
|
|
197
|
+
* `metamodel.PrincipalAttributeMeta`.
|
|
198
|
+
*
|
|
199
|
+
* Distinct from `user` on purpose. `user` means "a person did this" — it is
|
|
200
|
+
* authorship, and its value can never be a team. `principal` means "this party
|
|
201
|
+
* may be granted access", a different question with a strictly larger
|
|
202
|
+
* vocabulary. Widening `user` would have made every existing user attribute
|
|
203
|
+
* silently accept a team, including the created_by / updated_by audit columns.
|
|
204
|
+
*/
|
|
205
|
+
export interface PrincipalAttributeMeta {
|
|
206
|
+
description?: string
|
|
207
|
+
/**
|
|
208
|
+
* Turns the attribute into a GRANTING attribute: the verbs its value confers
|
|
209
|
+
* on the record. `deals.account_manager` with `["read","write"]` means setting
|
|
210
|
+
* it gives that principal access with no share call — the business field IS
|
|
211
|
+
* the ACL.
|
|
212
|
+
*
|
|
213
|
+
* `share` is the right to hand access on — share the record, set other
|
|
214
|
+
* granting attributes, revoke shares. `["read","write","delete","share"]` is
|
|
215
|
+
* full ownership: there is no separate owner field on the platform, the
|
|
216
|
+
* business field that grants `share` IS the owner. `share` must accompany
|
|
217
|
+
* at least one of read/write/delete, and an attribute granting it never
|
|
218
|
+
* accepts an `org` principal.
|
|
219
|
+
*
|
|
220
|
+
* Empty (the default) means an ordinary reference that confers nothing, so an
|
|
221
|
+
* existing principal attribute cannot start granting access by accident.
|
|
222
|
+
*/
|
|
223
|
+
grants?: Array<'read' | 'write' | 'delete' | 'share'>
|
|
224
|
+
/**
|
|
225
|
+
* Narrows which principal kinds this attribute accepts; empty means all
|
|
226
|
+
* (except that an attribute granting `share` refuses `org` regardless —
|
|
227
|
+
* an org-wide right to re-grant would hand record management to every
|
|
228
|
+
* member).
|
|
229
|
+
*/
|
|
230
|
+
allowed_types?: PrincipalType[]
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export const PrincipalAttributeMetaSchema = z.object({
|
|
234
|
+
description: z.string().optional(),
|
|
235
|
+
grants: z.array(z.enum(['read', 'write', 'delete', 'share'])).optional(),
|
|
236
|
+
allowed_types: z.array(z.enum(['person', 'agent', 'api', 'team', 'org'])).optional(),
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
/** The kinds a principal reference may name. */
|
|
240
|
+
export type PrincipalType = 'person' | 'agent' | 'api' | 'team' | 'org'
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* The stored value of a `principal`-typed attribute.
|
|
244
|
+
*/
|
|
245
|
+
export interface PrincipalRef {
|
|
246
|
+
type: PrincipalType
|
|
247
|
+
id: string
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export const PrincipalRefSchema = z.object({
|
|
251
|
+
type: z.enum(['person', 'agent', 'api', 'team', 'org']),
|
|
252
|
+
id: z.string(),
|
|
253
|
+
})
|
|
254
|
+
|
|
147
255
|
/**
|
|
148
256
|
* The stored value of a `currency`-typed attribute: an exact decimal `amount`
|
|
149
257
|
* (a STRING, never a JS number — preserves financial-system precision and
|
|
@@ -236,6 +344,7 @@ export type AttributeMeta =
|
|
|
236
344
|
| EnumAttributeMeta
|
|
237
345
|
| RelationAttributeMeta
|
|
238
346
|
| UserAttributeMeta
|
|
347
|
+
| PrincipalAttributeMeta
|
|
239
348
|
| CurrencyAttributeMeta
|
|
240
349
|
| KnowledgeTextAttributeMeta
|
|
241
350
|
| FileAttributeMeta
|
|
@@ -259,6 +368,17 @@ export interface Attribute {
|
|
|
259
368
|
* Mirrors `IsPlatformManaged` in the Go `metamodel.Attribute`.
|
|
260
369
|
*/
|
|
261
370
|
is_platform_managed?: boolean
|
|
371
|
+
/**
|
|
372
|
+
* Attribute-level permissions. Absent means unrestricted (today's behaviour).
|
|
373
|
+
* Platform-managed attributes cannot carry restrictions.
|
|
374
|
+
*/
|
|
375
|
+
restrictions?: AttributeRestrictions
|
|
376
|
+
/**
|
|
377
|
+
* Literal default, or — on a `user` / `principal` attribute only — the
|
|
378
|
+
* current-user sentinel `{ type: 'current_user' }` (see
|
|
379
|
+
* `CURRENT_USER_DEFAULT`), which data-service resolves to the writer at
|
|
380
|
+
* record-write time.
|
|
381
|
+
*/
|
|
262
382
|
default_value?: unknown
|
|
263
383
|
/**
|
|
264
384
|
* Type-specific metadata. The concrete shape is determined by `type`
|
|
@@ -365,6 +485,7 @@ export const AttributeSchema = z.object({
|
|
|
365
485
|
is_nullable: z.boolean().optional(),
|
|
366
486
|
is_unique: z.boolean(),
|
|
367
487
|
is_read_only: z.boolean().optional(),
|
|
488
|
+
restrictions: AttributeRestrictionsSchema.optional(),
|
|
368
489
|
default_value: z.unknown().optional(),
|
|
369
490
|
meta: z.unknown().optional(),
|
|
370
491
|
options: z.record(z.unknown()).optional(),
|
|
@@ -393,6 +514,18 @@ export function parseCurrencyMeta(attr: Attribute): CurrencyAttributeMeta | null
|
|
|
393
514
|
return parsed.success ? parsed.data : null
|
|
394
515
|
}
|
|
395
516
|
|
|
517
|
+
/**
|
|
518
|
+
* Returns the typed `PrincipalAttributeMeta` when `attr` is a principal
|
|
519
|
+
* attribute; null otherwise. Principal meta is optional, so an attribute with
|
|
520
|
+
* no meta resolves to an empty `{}` rather than null.
|
|
521
|
+
*/
|
|
522
|
+
export function parsePrincipalMeta(attr: Attribute): PrincipalAttributeMeta | null {
|
|
523
|
+
if (attr.type !== 'principal') return null
|
|
524
|
+
if (attr.meta == null) return {}
|
|
525
|
+
const parsed = PrincipalAttributeMetaSchema.safeParse(attr.meta)
|
|
526
|
+
return parsed.success ? parsed.data : {}
|
|
527
|
+
}
|
|
528
|
+
|
|
396
529
|
export function parseUserMeta(attr: Attribute): UserAttributeMeta | null {
|
|
397
530
|
if (attr.type !== 'user') return null
|
|
398
531
|
if (attr.meta == null) return {}
|
|
@@ -915,19 +1048,41 @@ export interface UpdateListViewRequest {
|
|
|
915
1048
|
// ============================================================================
|
|
916
1049
|
|
|
917
1050
|
/**
|
|
918
|
-
*
|
|
919
|
-
*
|
|
1051
|
+
* What a page toolbar button invokes. Absent normalizes to `action` (pages
|
|
1052
|
+
* persisted before `kind` existed).
|
|
1053
|
+
*/
|
|
1054
|
+
export type PageActionKind = 'action' | 'workflow'
|
|
1055
|
+
|
|
1056
|
+
/**
|
|
1057
|
+
* Page action definition — one toolbar button. `kind: action` invokes a
|
|
1058
|
+
* function-service Action by slug (`action`) and may prefill its params;
|
|
1059
|
+
* `kind: workflow` starts a manual run of a workflow by key (`workflow`) and
|
|
1060
|
+
* may prefill its manual-trigger inputs. `params` / `inputs` map target field
|
|
1061
|
+
* names to Liquid templates rendered against the page scope
|
|
1062
|
+
* `{ record, entity, params, user }`; a resolved field is locked in the invoke
|
|
1063
|
+
* dialog. `skip_confirmation` fires the target immediately when every required
|
|
1064
|
+
* field resolved from the templates.
|
|
920
1065
|
*/
|
|
921
1066
|
export interface PageAction {
|
|
922
1067
|
label: string
|
|
923
1068
|
icon: string
|
|
924
|
-
|
|
1069
|
+
kind?: PageActionKind
|
|
1070
|
+
action?: string
|
|
1071
|
+
workflow?: string
|
|
1072
|
+
params?: Record<string, string>
|
|
1073
|
+
inputs?: Record<string, string>
|
|
1074
|
+
skip_confirmation?: boolean
|
|
925
1075
|
}
|
|
926
1076
|
|
|
927
1077
|
export const PageActionSchema = z.object({
|
|
928
1078
|
label: z.string(),
|
|
929
1079
|
icon: z.string(),
|
|
930
|
-
|
|
1080
|
+
kind: z.enum(['action', 'workflow']).optional(),
|
|
1081
|
+
action: z.string().optional(),
|
|
1082
|
+
workflow: z.string().optional(),
|
|
1083
|
+
params: z.record(z.string()).optional(),
|
|
1084
|
+
inputs: z.record(z.string()).optional(),
|
|
1085
|
+
skip_confirmation: z.boolean().optional(),
|
|
931
1086
|
})
|
|
932
1087
|
|
|
933
1088
|
/**
|
|
@@ -1252,3 +1407,30 @@ export interface UpdateDesignReferenceRequest {
|
|
|
1252
1407
|
export interface DesignReferenceContent {
|
|
1253
1408
|
content: string
|
|
1254
1409
|
}
|
|
1410
|
+
|
|
1411
|
+
/* -------------------------------------------------------------------------
|
|
1412
|
+
Default-value sentinel
|
|
1413
|
+
------------------------------------------------------------------------- */
|
|
1414
|
+
|
|
1415
|
+
/**
|
|
1416
|
+
* The one non-literal `default_value`: "whoever is writing the record".
|
|
1417
|
+
* Meaningful only on `user` and `principal` attributes, where data-service
|
|
1418
|
+
* resolves it to the caller's `{ type, id }` at write time — an owner field
|
|
1419
|
+
* granting `share`, an `assignee`, a `requested_by` fill themselves without a
|
|
1420
|
+
* hook. An object rather than a bare string because a bare string IS a valid
|
|
1421
|
+
* user value (clients send bare ids). Mirrors `metamodel.CurrentUserDefault`.
|
|
1422
|
+
*/
|
|
1423
|
+
export const CURRENT_USER_DEFAULT = { type: 'current_user' } as const
|
|
1424
|
+
export type CurrentUserDefault = { type: 'current_user' }
|
|
1425
|
+
|
|
1426
|
+
/** True when a `default_value` is the current-user sentinel (and nothing else). */
|
|
1427
|
+
export function isCurrentUserDefault(value: unknown): value is CurrentUserDefault {
|
|
1428
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false
|
|
1429
|
+
const keys = Object.keys(value)
|
|
1430
|
+
return keys.length === 1 && (value as { type?: unknown }).type === 'current_user'
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
/** Only the identity-valued attribute types can carry the sentinel. */
|
|
1434
|
+
export function acceptsCurrentUserDefault(type: AttributeType): boolean {
|
|
1435
|
+
return type === 'user' || type === 'principal'
|
|
1436
|
+
}
|