@stndrds/schema 0.1.0-alpha.14
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-3ABIOLKO.mjs +4624 -0
- package/dist/chunk-3IRX2BDY.mjs +3970 -0
- package/dist/chunk-4OTLPWSP.mjs +4448 -0
- package/dist/chunk-54ODQBUN.mjs +3867 -0
- package/dist/chunk-6HIA3FR2.mjs +4230 -0
- package/dist/chunk-6P3XHNLD.mjs +4171 -0
- package/dist/chunk-7LJECNAS.mjs +4167 -0
- package/dist/chunk-A2WNLUKV.mjs +4475 -0
- package/dist/chunk-AA3234RM.mjs +4475 -0
- package/dist/chunk-ADNXDLLD.mjs +3136 -0
- package/dist/chunk-B4DCDQUI.mjs +4695 -0
- package/dist/chunk-B4PSXY6I.mjs +4527 -0
- package/dist/chunk-BJHJBZCM.mjs +4228 -0
- package/dist/chunk-C3ZWTO6G.mjs +4474 -0
- package/dist/chunk-CLOGNKDD.mjs +4040 -0
- package/dist/chunk-EW4V63PA.mjs +3053 -0
- package/dist/chunk-FR2LCO6R.mjs +2485 -0
- package/dist/chunk-GJSF2RKL.mjs +2786 -0
- package/dist/chunk-GO5NPP2X.mjs +4726 -0
- package/dist/chunk-H3ZYJUDS.mjs +3050 -0
- package/dist/chunk-IDDLSFSK.mjs +4230 -0
- package/dist/chunk-JRADUJQ7.mjs +4726 -0
- package/dist/chunk-NEDR6N7R.mjs +3118 -0
- package/dist/chunk-NESPRMDF.mjs +2482 -0
- package/dist/chunk-NWFGRJBW.mjs +4612 -0
- package/dist/chunk-NXJ57GSN.mjs +2918 -0
- package/dist/chunk-O4C5FCTS.mjs +3961 -0
- package/dist/chunk-O4PRB27Q.mjs +2513 -0
- package/dist/chunk-OJDFNUCR.mjs +4463 -0
- package/dist/chunk-OSEKVBHC.mjs +4627 -0
- package/dist/chunk-QX4U6U6K.mjs +2484 -0
- package/dist/chunk-RMDQ6LKV.mjs +3046 -0
- package/dist/chunk-SBXKDATH.mjs +2673 -0
- package/dist/chunk-SKMP3AP3.mjs +2918 -0
- package/dist/chunk-STMS7WZD.mjs +2623 -0
- package/dist/chunk-T3T6PTFG.mjs +3057 -0
- package/dist/chunk-TPW72RAH.mjs +4624 -0
- package/dist/chunk-TUQEGNGV.mjs +2534 -0
- package/dist/chunk-TVKFS3YN.mjs +2449 -0
- package/dist/chunk-TZTH3BHG.mjs +3110 -0
- package/dist/chunk-W6MU3XPG.mjs +4612 -0
- package/dist/chunk-WL7Z3YFR.mjs +4603 -0
- package/dist/chunk-XNVVYHH3.mjs +4602 -0
- package/dist/chunk-XTA3WY64.mjs +2918 -0
- package/dist/chunk-YV7DEZFZ.mjs +2528 -0
- package/dist/chunk-ZLJPJND6.mjs +4474 -0
- package/dist/chunk-ZNZXTCEX.mjs +4234 -0
- package/dist/index.d.mts +1222 -0
- package/dist/index.d.ts +1222 -0
- package/dist/index.js +5320 -0
- package/dist/index.mjs +635 -0
- package/dist/runtime-2iKarXtl.d.mts +1924 -0
- package/dist/runtime-2iKarXtl.d.ts +1924 -0
- package/dist/runtime-4l2ddHZ7.d.mts +2242 -0
- package/dist/runtime-4l2ddHZ7.d.ts +2243 -0
- package/dist/runtime-8hKS6zAv.d.mts +2226 -0
- package/dist/runtime-8hKS6zAv.d.ts +2226 -0
- package/dist/runtime-B6yjtoR3.d.mts +4142 -0
- package/dist/runtime-B6yjtoR3.d.ts +4142 -0
- package/dist/runtime-BGCShrZB.d.mts +2001 -0
- package/dist/runtime-BGCShrZB.d.ts +2001 -0
- package/dist/runtime-BRW4NGAk.d.mts +1668 -0
- package/dist/runtime-BRW4NGAk.d.ts +1668 -0
- package/dist/runtime-BnfBr314.d.mts +1683 -0
- package/dist/runtime-BnfBr314.d.ts +1683 -0
- package/dist/runtime-BrqhiJUF.d.mts +4151 -0
- package/dist/runtime-BrqhiJUF.d.ts +4151 -0
- package/dist/runtime-Bvj8c-BE.d.mts +4277 -0
- package/dist/runtime-Bvj8c-BE.d.ts +4277 -0
- package/dist/runtime-C03qT4qU.d.mts +4267 -0
- package/dist/runtime-C03qT4qU.d.ts +4267 -0
- package/dist/runtime-CaCZ7mSf.d.mts +2974 -0
- package/dist/runtime-CaCZ7mSf.d.ts +2974 -0
- package/dist/runtime-CaIzNX0Z.d.mts +4091 -0
- package/dist/runtime-CaIzNX0Z.d.ts +4091 -0
- package/dist/runtime-ChPTgmLP.d.mts +4320 -0
- package/dist/runtime-ChPTgmLP.d.ts +4320 -0
- package/dist/runtime-CnImZ1Vv.d.mts +4267 -0
- package/dist/runtime-CnImZ1Vv.d.ts +4267 -0
- package/dist/runtime-Cp-B26Nj.d.mts +2890 -0
- package/dist/runtime-Cp-B26Nj.d.ts +2890 -0
- package/dist/runtime-Cq8jfk3c.d.mts +4277 -0
- package/dist/runtime-Cq8jfk3c.d.ts +4277 -0
- package/dist/runtime-CqDFXhhP.d.mts +1685 -0
- package/dist/runtime-CqDFXhhP.d.ts +1685 -0
- package/dist/runtime-CqtpZLdL.d.mts +4280 -0
- package/dist/runtime-CqtpZLdL.d.ts +4280 -0
- package/dist/runtime-D-4DblaZ.d.mts +4147 -0
- package/dist/runtime-D-4DblaZ.d.ts +4147 -0
- package/dist/runtime-D59sSqNl.d.mts +4146 -0
- package/dist/runtime-D59sSqNl.d.ts +4146 -0
- package/dist/runtime-DEfPk3wT.d.mts +1840 -0
- package/dist/runtime-DEfPk3wT.d.ts +1840 -0
- package/dist/runtime-DGV-7vES.d.mts +1685 -0
- package/dist/runtime-DGV-7vES.d.ts +1685 -0
- package/dist/runtime-DNacghqc.d.mts +3971 -0
- package/dist/runtime-DNacghqc.d.ts +3971 -0
- package/dist/runtime-DPLsUHYK.d.mts +3977 -0
- package/dist/runtime-DPLsUHYK.d.ts +3977 -0
- package/dist/runtime-DTxCw60F.d.mts +2973 -0
- package/dist/runtime-DTxCw60F.d.ts +2973 -0
- package/dist/runtime-DUXJ-zNS.d.mts +2788 -0
- package/dist/runtime-DUXJ-zNS.d.ts +2788 -0
- package/dist/runtime-DbljInhV.d.mts +2237 -0
- package/dist/runtime-DbljInhV.d.ts +2237 -0
- package/dist/runtime-DcH3y6Yu.d.mts +4272 -0
- package/dist/runtime-DcH3y6Yu.d.ts +4272 -0
- package/dist/runtime-DdBFz85g.d.mts +4229 -0
- package/dist/runtime-DdBFz85g.d.ts +4229 -0
- package/dist/runtime-DjMWhjkm.d.mts +4321 -0
- package/dist/runtime-DjMWhjkm.d.ts +4321 -0
- package/dist/runtime-Djz3fOBE.d.mts +2078 -0
- package/dist/runtime-Djz3fOBE.d.ts +2078 -0
- package/dist/runtime-Dli8g3Aq.d.mts +2082 -0
- package/dist/runtime-Dli8g3Aq.d.ts +2082 -0
- package/dist/runtime-a8J378im.d.mts +4123 -0
- package/dist/runtime-a8J378im.d.ts +4123 -0
- package/dist/runtime-dp3rb3Lf.d.mts +2968 -0
- package/dist/runtime-dp3rb3Lf.d.ts +2968 -0
- package/dist/runtime-iWXlSN_H.d.mts +1683 -0
- package/dist/runtime-iWXlSN_H.d.ts +1683 -0
- package/dist/runtime-yMql0npY.d.mts +4321 -0
- package/dist/runtime-yMql0npY.d.ts +4321 -0
- package/dist/runtime.d.mts +3 -0
- package/dist/runtime.d.ts +3 -0
- package/dist/runtime.js +3626 -0
- package/dist/runtime.mjs +48 -0
- package/package.json +58 -0
|
@@ -0,0 +1,2237 @@
|
|
|
1
|
+
import { ColorId, IconName, CountryIso3, CurrencyCode, MimeType } from '@stndrds/constants';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* UUID string type for all identifiers
|
|
6
|
+
*/
|
|
7
|
+
type Uuid = string;
|
|
8
|
+
/**
|
|
9
|
+
* Tenant identifier for multi-tenant isolation
|
|
10
|
+
* Phase 1: Type defined but not yet used in interfaces
|
|
11
|
+
* Phase 2+: Will be added to ObjectRecord and services for SaaS mode
|
|
12
|
+
*/
|
|
13
|
+
type TenantId = string;
|
|
14
|
+
/**
|
|
15
|
+
* Generate a unique UUID v4
|
|
16
|
+
* Uses crypto.randomUUID() when available (Node.js 19+, modern browsers)
|
|
17
|
+
* Falls back to a manual implementation for older environments
|
|
18
|
+
*
|
|
19
|
+
* @returns A UUID v4 string
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const id = generateId();
|
|
24
|
+
* // "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
declare function generateId(): Uuid;
|
|
28
|
+
/**
|
|
29
|
+
* Generate a prefixed ID for better debugging and readability
|
|
30
|
+
*
|
|
31
|
+
* @param prefix - Prefix for the ID (e.g., "obj", "attr", "rec")
|
|
32
|
+
* @returns A prefixed UUID string
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const objectId = generatePrefixedId("obj");
|
|
37
|
+
* // "obj_a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
|
|
38
|
+
*
|
|
39
|
+
* const attrId = generatePrefixedId("attr");
|
|
40
|
+
* // "attr_a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare function generatePrefixedId(prefix: string): Uuid;
|
|
44
|
+
|
|
45
|
+
type AttributeType = "text" | "textarea" | "number" | "checkbox" | "date" | "phone" | "currency" | "status" | "location" | "timestamp" | "select" | "multiselect" | "file" | "user" | "relation" | "rating";
|
|
46
|
+
/**
|
|
47
|
+
* Status group categorization
|
|
48
|
+
*/
|
|
49
|
+
type StatusGroup = "idle" | "in_progress" | "finished";
|
|
50
|
+
/**
|
|
51
|
+
* Unified option type for select-like fields
|
|
52
|
+
*/
|
|
53
|
+
interface Option {
|
|
54
|
+
id: string;
|
|
55
|
+
label: string;
|
|
56
|
+
value: string;
|
|
57
|
+
color?: ColorId;
|
|
58
|
+
icon?: IconName;
|
|
59
|
+
description?: string;
|
|
60
|
+
group?: StatusGroup;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Attribute grouping for UI organization
|
|
64
|
+
*/
|
|
65
|
+
interface AttributeGroup {
|
|
66
|
+
id: string;
|
|
67
|
+
label: string;
|
|
68
|
+
description?: string;
|
|
69
|
+
attributeIds: string[];
|
|
70
|
+
collapsible?: boolean;
|
|
71
|
+
collapsed?: boolean;
|
|
72
|
+
order?: number;
|
|
73
|
+
}
|
|
74
|
+
interface BaseAttribute<DefaultValueType = unknown> {
|
|
75
|
+
id: Uuid;
|
|
76
|
+
name: string;
|
|
77
|
+
label: string;
|
|
78
|
+
type: AttributeType;
|
|
79
|
+
required: boolean;
|
|
80
|
+
disabled?: boolean;
|
|
81
|
+
placeholder?: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
defaultValue?: DefaultValueType;
|
|
84
|
+
icon?: IconName;
|
|
85
|
+
order?: number;
|
|
86
|
+
hidden?: boolean;
|
|
87
|
+
archived?: boolean;
|
|
88
|
+
deprecated?: boolean;
|
|
89
|
+
system?: boolean;
|
|
90
|
+
metadata?: Record<string, unknown>;
|
|
91
|
+
}
|
|
92
|
+
interface TextAttribute extends BaseAttribute<string> {
|
|
93
|
+
type: "text";
|
|
94
|
+
minLength?: number;
|
|
95
|
+
maxLength?: number;
|
|
96
|
+
pattern?: string;
|
|
97
|
+
}
|
|
98
|
+
type NumberUnit = "integer" | "decimal" | "percentage";
|
|
99
|
+
interface NumberAttribute extends BaseAttribute<number> {
|
|
100
|
+
type: "number";
|
|
101
|
+
min?: number;
|
|
102
|
+
max?: number;
|
|
103
|
+
unit?: NumberUnit;
|
|
104
|
+
decimals?: number;
|
|
105
|
+
}
|
|
106
|
+
interface CheckboxAttribute extends BaseAttribute<boolean> {
|
|
107
|
+
type: "checkbox";
|
|
108
|
+
}
|
|
109
|
+
type DateFormat = "short" | "long" | "full" | "relative";
|
|
110
|
+
type DateValue = string | "today";
|
|
111
|
+
interface DateAttribute extends BaseAttribute<string> {
|
|
112
|
+
type: "date";
|
|
113
|
+
dateFormat?: DateFormat;
|
|
114
|
+
minDate?: DateValue;
|
|
115
|
+
maxDate?: DateValue;
|
|
116
|
+
}
|
|
117
|
+
interface Phone {
|
|
118
|
+
countryCode: CountryIso3;
|
|
119
|
+
phoneNumber: string;
|
|
120
|
+
}
|
|
121
|
+
interface PhoneAttribute extends BaseAttribute<Phone> {
|
|
122
|
+
type: "phone";
|
|
123
|
+
defaultCountryCode?: CountryIso3;
|
|
124
|
+
}
|
|
125
|
+
interface Currency {
|
|
126
|
+
code: CurrencyCode;
|
|
127
|
+
value: number;
|
|
128
|
+
}
|
|
129
|
+
interface CurrencyAttribute extends BaseAttribute<Currency> {
|
|
130
|
+
type: "currency";
|
|
131
|
+
defaultCurrency?: CurrencyCode;
|
|
132
|
+
allowedCurrencies?: CurrencyCode[];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* StatusAttribute - For workflow states with semantic grouping (idle/in_progress/finished)
|
|
136
|
+
* Use this for: Task status, Order status, Project phases, Process states
|
|
137
|
+
* Use SelectAttribute for: Categories, Types, simple choices without workflow
|
|
138
|
+
*/
|
|
139
|
+
interface StatusAttribute extends BaseAttribute<string> {
|
|
140
|
+
type: "status";
|
|
141
|
+
options: Option[];
|
|
142
|
+
}
|
|
143
|
+
interface Location {
|
|
144
|
+
address?: string;
|
|
145
|
+
address2?: string;
|
|
146
|
+
city?: string;
|
|
147
|
+
state?: string;
|
|
148
|
+
postalCode?: string;
|
|
149
|
+
country?: CountryIso3;
|
|
150
|
+
latitude?: number;
|
|
151
|
+
longitude?: number;
|
|
152
|
+
}
|
|
153
|
+
type LocationGranularity = "full" | "address" | "city" | "state" | "country" | "coordinates";
|
|
154
|
+
interface LocationAttribute extends BaseAttribute<Location> {
|
|
155
|
+
type: "location";
|
|
156
|
+
granularity: LocationGranularity;
|
|
157
|
+
enableAutocomplete?: boolean;
|
|
158
|
+
enableMap?: boolean;
|
|
159
|
+
defaultCountry?: CountryIso3;
|
|
160
|
+
allowedCountries?: CountryIso3[];
|
|
161
|
+
displayFormat?: "single_line" | "multi_line" | "compact";
|
|
162
|
+
}
|
|
163
|
+
interface TimestampAttribute extends BaseAttribute<number> {
|
|
164
|
+
type: "timestamp";
|
|
165
|
+
autoUpdate?: boolean;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* SelectAttribute - For simple single-choice selection
|
|
169
|
+
* Use this for: Categories, Document types, Departments, Priorities
|
|
170
|
+
* Options can be grouped (e.g., countries by continent) but no workflow logic
|
|
171
|
+
*/
|
|
172
|
+
interface SelectAttribute extends BaseAttribute<string> {
|
|
173
|
+
type: "select";
|
|
174
|
+
options: Option[];
|
|
175
|
+
}
|
|
176
|
+
interface MultiselectAttribute extends BaseAttribute<string[]> {
|
|
177
|
+
type: "multiselect";
|
|
178
|
+
options: Option[];
|
|
179
|
+
}
|
|
180
|
+
type DocumentType = "id_card" | "passport" | "incorporation_certificate" | "driver_license" | "birth_certificate" | "residence_permit" | "bank_statement" | "proof_of_address" | "custom";
|
|
181
|
+
type DocumentFace = "front" | "back" | "single";
|
|
182
|
+
interface DocumentTypeConfig {
|
|
183
|
+
type: DocumentType;
|
|
184
|
+
label: string;
|
|
185
|
+
faces: DocumentFace[];
|
|
186
|
+
attributeMapping?: {
|
|
187
|
+
attributeId: string;
|
|
188
|
+
extractedKey: string;
|
|
189
|
+
face?: DocumentFace;
|
|
190
|
+
required?: boolean;
|
|
191
|
+
}[];
|
|
192
|
+
}
|
|
193
|
+
interface FileVerificationConfig {
|
|
194
|
+
enabled: boolean;
|
|
195
|
+
documentTypes: DocumentTypeConfig[];
|
|
196
|
+
autoExtract?: boolean;
|
|
197
|
+
autoValidate?: boolean;
|
|
198
|
+
}
|
|
199
|
+
interface FileAttribute extends BaseAttribute<string> {
|
|
200
|
+
type: "file";
|
|
201
|
+
maxFiles?: number;
|
|
202
|
+
maxSize?: number;
|
|
203
|
+
allowedTypes?: MimeType[] | readonly MimeType[];
|
|
204
|
+
verification?: FileVerificationConfig;
|
|
205
|
+
}
|
|
206
|
+
interface UserAttribute extends BaseAttribute<string> {
|
|
207
|
+
type: "user";
|
|
208
|
+
allowedRoles?: string[];
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Target object for a relation - defines which objects can be linked
|
|
212
|
+
*/
|
|
213
|
+
interface RelationTarget {
|
|
214
|
+
/** Object name (e.g., "companies", "contacts") */
|
|
215
|
+
object: string;
|
|
216
|
+
/**
|
|
217
|
+
* Display template for the label using mustache-like syntax
|
|
218
|
+
* @example "{name}" or "{firstName} {lastName} — {email}"
|
|
219
|
+
*/
|
|
220
|
+
displayTemplate?: string;
|
|
221
|
+
/**
|
|
222
|
+
* Optional filter to restrict available records
|
|
223
|
+
* @example { status: "active" }
|
|
224
|
+
*/
|
|
225
|
+
filter?: Record<string, unknown>;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Strategy when a target record is deleted
|
|
229
|
+
* - "restrict": Prevent deletion if relations exist (default)
|
|
230
|
+
* - "cascade": Delete this record too
|
|
231
|
+
* - "set_null": Set the relation value to null
|
|
232
|
+
*/
|
|
233
|
+
type RelationOnDelete = "restrict" | "cascade" | "set_null";
|
|
234
|
+
/**
|
|
235
|
+
* Base properties shared by both single and multi relation attributes
|
|
236
|
+
*/
|
|
237
|
+
interface RelationAttributeBase extends Omit<BaseAttribute<unknown>, "defaultValue"> {
|
|
238
|
+
type: "relation";
|
|
239
|
+
/** Target objects that can be linked */
|
|
240
|
+
targets: RelationTarget[];
|
|
241
|
+
/** Deletion strategy when target record is deleted */
|
|
242
|
+
onDelete?: RelationOnDelete;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Single relation attribute (one-to-one or many-to-one)
|
|
246
|
+
* Stores a single record ID or null
|
|
247
|
+
*/
|
|
248
|
+
interface SingleRelationAttribute extends RelationAttributeBase {
|
|
249
|
+
cardinality: "one";
|
|
250
|
+
defaultValue?: string | null;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Multi relation attribute (one-to-many or many-to-many)
|
|
254
|
+
* Stores an array of record IDs
|
|
255
|
+
*/
|
|
256
|
+
interface MultiRelationAttribute extends RelationAttributeBase {
|
|
257
|
+
cardinality: "many";
|
|
258
|
+
defaultValue?: string[];
|
|
259
|
+
/** Minimum number of relations required */
|
|
260
|
+
minItems?: number;
|
|
261
|
+
/** Maximum number of relations allowed */
|
|
262
|
+
maxItems?: number;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* RelationAttribute links to other objects/records
|
|
266
|
+
* Discriminated union by cardinality for type-safe value handling
|
|
267
|
+
*
|
|
268
|
+
* @example Single relation (many-to-one)
|
|
269
|
+
* ```typescript
|
|
270
|
+
* relation({ name: "company", label: "Company" })
|
|
271
|
+
* .to("companies")
|
|
272
|
+
* .required()
|
|
273
|
+
* // → Value: "rec-uuid-123" | null
|
|
274
|
+
* ```
|
|
275
|
+
*
|
|
276
|
+
* @example Multi relation (many-to-many)
|
|
277
|
+
* ```typescript
|
|
278
|
+
* relation({ name: "contacts", label: "Contacts" })
|
|
279
|
+
* .to("contacts", { displayTemplate: "{firstName} {lastName}" })
|
|
280
|
+
* .many()
|
|
281
|
+
* .maxItems(5)
|
|
282
|
+
* // → Value: ["rec-1", "rec-2", ...]
|
|
283
|
+
* ```
|
|
284
|
+
*
|
|
285
|
+
* @example Polymorphic relation (multiple target objects)
|
|
286
|
+
* ```typescript
|
|
287
|
+
* relation({ name: "linked", label: "Linked Items" })
|
|
288
|
+
* .to("companies")
|
|
289
|
+
* .to("contacts")
|
|
290
|
+
* .to("deals")
|
|
291
|
+
* .many()
|
|
292
|
+
* // → Can link to records from any of these objects
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
type RelationAttribute = SingleRelationAttribute | MultiRelationAttribute;
|
|
296
|
+
interface TextAreaAttribute extends BaseAttribute<string> {
|
|
297
|
+
type: "textarea";
|
|
298
|
+
}
|
|
299
|
+
interface RatingAttribute extends BaseAttribute<number> {
|
|
300
|
+
type: "rating";
|
|
301
|
+
max?: number;
|
|
302
|
+
iconType?: "star" | "heart" | "thumbs" | "number";
|
|
303
|
+
}
|
|
304
|
+
type Attribute = TextAttribute | TextAreaAttribute | NumberAttribute | CheckboxAttribute | DateAttribute | PhoneAttribute | CurrencyAttribute | StatusAttribute | LocationAttribute | TimestampAttribute | SelectAttribute | MultiselectAttribute | FileAttribute | UserAttribute | RelationAttribute | RatingAttribute;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Timestamps for tracking creation and updates
|
|
308
|
+
*/
|
|
309
|
+
interface Timestamps {
|
|
310
|
+
createdAt: Date;
|
|
311
|
+
updatedAt: Date;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Object definition - Represents a database table/entity
|
|
315
|
+
*/
|
|
316
|
+
interface ObjectDefinition {
|
|
317
|
+
id?: Uuid;
|
|
318
|
+
name: string;
|
|
319
|
+
label: string;
|
|
320
|
+
description?: string;
|
|
321
|
+
icon?: IconName;
|
|
322
|
+
/**
|
|
323
|
+
* Name of the text attribute used as the object's title/display name.
|
|
324
|
+
* This attribute is used to represent the record in lists, relations, etc.
|
|
325
|
+
* Must reference an existing text attribute.
|
|
326
|
+
*/
|
|
327
|
+
titleAttribute: string;
|
|
328
|
+
attributes: Attribute[];
|
|
329
|
+
system?: boolean;
|
|
330
|
+
metadata?: Record<string, unknown>;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Links an attribute to an object
|
|
334
|
+
*/
|
|
335
|
+
interface ObjectAttribute {
|
|
336
|
+
objectId: Uuid;
|
|
337
|
+
attributeId: Uuid;
|
|
338
|
+
order?: number;
|
|
339
|
+
required?: boolean;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Completion status of a record based on data completeness.
|
|
343
|
+
*
|
|
344
|
+
* - `draft`: Record is missing one or more required attribute values.
|
|
345
|
+
* Can be saved but is considered incomplete.
|
|
346
|
+
* - `complete`: All required attribute values are present and valid.
|
|
347
|
+
* Record is ready for use.
|
|
348
|
+
*
|
|
349
|
+
* This is different from workflow status (e.g., "pending", "approved").
|
|
350
|
+
* Completion status is computed dynamically based on the object schema.
|
|
351
|
+
*/
|
|
352
|
+
type CompletionStatus = "draft" | "complete";
|
|
353
|
+
/**
|
|
354
|
+
* Record - Instance of an Object (a row in the database)
|
|
355
|
+
*/
|
|
356
|
+
interface ObjectRecord extends Timestamps {
|
|
357
|
+
id: Uuid;
|
|
358
|
+
objectId: Uuid;
|
|
359
|
+
/**
|
|
360
|
+
* Completion status of the record.
|
|
361
|
+
* - `draft`: Missing required values, record is incomplete
|
|
362
|
+
* - `complete`: All required values present and valid
|
|
363
|
+
*
|
|
364
|
+
* Computed dynamically based on the object's schema.
|
|
365
|
+
*/
|
|
366
|
+
completionStatus: CompletionStatus;
|
|
367
|
+
values: Record<string, unknown>;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Storage provider type
|
|
372
|
+
*/
|
|
373
|
+
type StorageProvider = "s3" | "gcs" | "azure" | "local" | "cloudflare-r2" | string;
|
|
374
|
+
/**
|
|
375
|
+
* File visibility level
|
|
376
|
+
*/
|
|
377
|
+
type FileVisibility = "public" | "private" | "restricted";
|
|
378
|
+
/**
|
|
379
|
+
* File - Represents uploaded file metadata and storage info
|
|
380
|
+
*
|
|
381
|
+
* ARCHITECTURE:
|
|
382
|
+
* - Fixed table (no custom attributes)
|
|
383
|
+
* - Manages file storage, permissions, and metadata
|
|
384
|
+
* - uploadedBy links to user_profiles table
|
|
385
|
+
* - Supports soft delete via deletedAt
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```typescript
|
|
389
|
+
* const file: File = {
|
|
390
|
+
* id: "file-123",
|
|
391
|
+
* tenantId: "tenant-456",
|
|
392
|
+
* name: "contract-2025.pdf",
|
|
393
|
+
* originalName: "Contract Acme Corp 2025.pdf",
|
|
394
|
+
* mimeType: "application/pdf",
|
|
395
|
+
* size: 2458624,
|
|
396
|
+
* storageProvider: "s3",
|
|
397
|
+
* storagePath: "tenants/456/files/2025/11/contract-2025.pdf",
|
|
398
|
+
* storageBucket: "my-app-files",
|
|
399
|
+
* url: "https://cdn.example.com/files/file-123",
|
|
400
|
+
* uploadedBy: "profile-789",
|
|
401
|
+
* folderPath: "/contracts/2025",
|
|
402
|
+
* tags: ["contract", "legal"],
|
|
403
|
+
* visibility: "restricted",
|
|
404
|
+
* allowedUsers: ["profile-789", "profile-456"],
|
|
405
|
+
* createdAt: new Date(),
|
|
406
|
+
* updatedAt: new Date(),
|
|
407
|
+
* };
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
interface File extends Timestamps {
|
|
411
|
+
id: Uuid;
|
|
412
|
+
tenantId: Uuid;
|
|
413
|
+
/**
|
|
414
|
+
* File name (sanitized for storage)
|
|
415
|
+
*/
|
|
416
|
+
name: string;
|
|
417
|
+
/**
|
|
418
|
+
* Original file name (as uploaded by user)
|
|
419
|
+
*/
|
|
420
|
+
originalName: string;
|
|
421
|
+
/**
|
|
422
|
+
* MIME type (e.g., "application/pdf", "image/jpeg")
|
|
423
|
+
*/
|
|
424
|
+
mimeType: MimeType | string;
|
|
425
|
+
/**
|
|
426
|
+
* File size in bytes
|
|
427
|
+
*/
|
|
428
|
+
size: number;
|
|
429
|
+
/**
|
|
430
|
+
* Storage provider (s3, gcs, azure, local, etc.)
|
|
431
|
+
*/
|
|
432
|
+
storageProvider: StorageProvider;
|
|
433
|
+
/**
|
|
434
|
+
* Path in the storage bucket
|
|
435
|
+
*/
|
|
436
|
+
storagePath: string;
|
|
437
|
+
/**
|
|
438
|
+
* Storage bucket name (if applicable)
|
|
439
|
+
*/
|
|
440
|
+
storageBucket?: string;
|
|
441
|
+
/**
|
|
442
|
+
* Public or signed URL to access the file
|
|
443
|
+
*/
|
|
444
|
+
url: string;
|
|
445
|
+
/**
|
|
446
|
+
* User who uploaded the file (FK to user_profiles)
|
|
447
|
+
*/
|
|
448
|
+
uploadedBy: Uuid;
|
|
449
|
+
/**
|
|
450
|
+
* Folder path for organization (e.g., "/contracts/2025")
|
|
451
|
+
*/
|
|
452
|
+
folderPath?: string;
|
|
453
|
+
/**
|
|
454
|
+
* Tags for search and categorization
|
|
455
|
+
*/
|
|
456
|
+
tags?: string[];
|
|
457
|
+
/**
|
|
458
|
+
* File visibility level
|
|
459
|
+
* - public: Anyone with the URL can access
|
|
460
|
+
* - private: Only uploadedBy can access
|
|
461
|
+
* - restricted: Only specific users (allowedUsers) can access
|
|
462
|
+
*/
|
|
463
|
+
visibility: FileVisibility;
|
|
464
|
+
/**
|
|
465
|
+
* List of user IDs authorized to access this file (if visibility = "restricted")
|
|
466
|
+
*/
|
|
467
|
+
allowedUsers?: Uuid[];
|
|
468
|
+
/**
|
|
469
|
+
* Soft delete timestamp (null = not deleted)
|
|
470
|
+
*/
|
|
471
|
+
deletedAt?: Date;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Data required to create a new file record
|
|
475
|
+
*/
|
|
476
|
+
interface CreateFile {
|
|
477
|
+
tenantId: Uuid;
|
|
478
|
+
name: string;
|
|
479
|
+
originalName: string;
|
|
480
|
+
mimeType: MimeType | string;
|
|
481
|
+
size: number;
|
|
482
|
+
storageProvider: StorageProvider;
|
|
483
|
+
storagePath: string;
|
|
484
|
+
storageBucket?: string;
|
|
485
|
+
url: string;
|
|
486
|
+
uploadedBy: Uuid;
|
|
487
|
+
folderPath?: string;
|
|
488
|
+
tags?: string[];
|
|
489
|
+
visibility?: FileVisibility;
|
|
490
|
+
allowedUsers?: Uuid[];
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Data for updating an existing file record
|
|
494
|
+
*/
|
|
495
|
+
interface UpdateFile {
|
|
496
|
+
name?: string;
|
|
497
|
+
folderPath?: string;
|
|
498
|
+
tags?: string[];
|
|
499
|
+
visibility?: FileVisibility;
|
|
500
|
+
allowedUsers?: Uuid[];
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Autocomplete suggestion from geocoding service
|
|
505
|
+
*/
|
|
506
|
+
interface GeocodingSuggestion {
|
|
507
|
+
/** Unique identifier from the provider */
|
|
508
|
+
id: string;
|
|
509
|
+
/** Human-readable label for display */
|
|
510
|
+
label: string;
|
|
511
|
+
/** Structured location data */
|
|
512
|
+
location: Location;
|
|
513
|
+
/** Optional match score/confidence (0-1) */
|
|
514
|
+
score?: number;
|
|
515
|
+
/** Optional additional metadata from the provider */
|
|
516
|
+
metadata?: Record<string, unknown>;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Parameters for autocomplete search
|
|
520
|
+
*/
|
|
521
|
+
interface GeocodingAutocompleteParams {
|
|
522
|
+
/** Search query */
|
|
523
|
+
query: string;
|
|
524
|
+
/** Restrict results to specific countries */
|
|
525
|
+
countries?: CountryIso3[];
|
|
526
|
+
/** Preferred language for results (ISO 639-1) */
|
|
527
|
+
language?: string;
|
|
528
|
+
/** Maximum number of results */
|
|
529
|
+
limit?: number;
|
|
530
|
+
/** Bias results toward a specific location */
|
|
531
|
+
biasLocation?: {
|
|
532
|
+
latitude: number;
|
|
533
|
+
longitude: number;
|
|
534
|
+
};
|
|
535
|
+
/** Session token for billing optimization (some providers) */
|
|
536
|
+
sessionToken?: string;
|
|
537
|
+
/**
|
|
538
|
+
* Level of address detail expected
|
|
539
|
+
* Adapters can use this to filter/optimize results
|
|
540
|
+
* - "full": Full address with street, city, postal code, etc.
|
|
541
|
+
* - "address": Street address without postal code
|
|
542
|
+
* - "city": City level only
|
|
543
|
+
* - "state": State/region level only
|
|
544
|
+
* - "country": Country level only
|
|
545
|
+
* - "coordinates": Only coordinates (lat/lng)
|
|
546
|
+
*/
|
|
547
|
+
granularity?: LocationGranularity;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Parameters for reverse geocoding
|
|
551
|
+
*/
|
|
552
|
+
interface ReverseGeocodingParams {
|
|
553
|
+
/** Latitude */
|
|
554
|
+
latitude: number;
|
|
555
|
+
/** Longitude */
|
|
556
|
+
longitude: number;
|
|
557
|
+
/** Preferred language for results */
|
|
558
|
+
language?: string;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Parameters for geocoding a structured address
|
|
562
|
+
*/
|
|
563
|
+
interface GeocodingParams {
|
|
564
|
+
/** Structured address components */
|
|
565
|
+
address: Partial<Location>;
|
|
566
|
+
/** Preferred language for results */
|
|
567
|
+
language?: string;
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Abstract geocoding adapter interface
|
|
571
|
+
* Implement this interface for different geocoding providers
|
|
572
|
+
*
|
|
573
|
+
* @example Google Maps implementation
|
|
574
|
+
* ```typescript
|
|
575
|
+
* class GoogleMapsGeocodingAdapter implements GeocodingAdapter {
|
|
576
|
+
* async autocomplete(params) {
|
|
577
|
+
* const response = await fetch(
|
|
578
|
+
* `https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${params.query}&key=${this.apiKey}`
|
|
579
|
+
* );
|
|
580
|
+
* // Transform response to GeocodingSuggestion[]
|
|
581
|
+
* }
|
|
582
|
+
* }
|
|
583
|
+
* ```
|
|
584
|
+
*
|
|
585
|
+
* @example Mapbox implementation
|
|
586
|
+
* ```typescript
|
|
587
|
+
* class MapboxGeocodingAdapter implements GeocodingAdapter {
|
|
588
|
+
* async autocomplete(params) {
|
|
589
|
+
* const response = await fetch(
|
|
590
|
+
* `https://api.mapbox.com/geocoding/v5/mapbox.places/${params.query}.json?access_token=${this.token}`
|
|
591
|
+
* );
|
|
592
|
+
* // Transform response to GeocodingSuggestion[]
|
|
593
|
+
* }
|
|
594
|
+
* }
|
|
595
|
+
* ```
|
|
596
|
+
*/
|
|
597
|
+
interface GeocodingAdapter {
|
|
598
|
+
/**
|
|
599
|
+
* Autocomplete address search
|
|
600
|
+
* Returns suggestions as the user types
|
|
601
|
+
*/
|
|
602
|
+
autocomplete(params: GeocodingAutocompleteParams): Promise<GeocodingSuggestion[]>;
|
|
603
|
+
/**
|
|
604
|
+
* Reverse geocode coordinates to an address
|
|
605
|
+
* Optional - some providers may not support this
|
|
606
|
+
*/
|
|
607
|
+
reverse?(params: ReverseGeocodingParams): Promise<GeocodingSuggestion | null>;
|
|
608
|
+
/**
|
|
609
|
+
* Geocode a structured address to coordinates
|
|
610
|
+
* Optional - some providers may not support this
|
|
611
|
+
*/
|
|
612
|
+
geocode?(params: GeocodingParams): Promise<GeocodingSuggestion | null>;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* No-op geocoding adapter
|
|
616
|
+
* Returns empty results when no geocoding provider is configured
|
|
617
|
+
*/
|
|
618
|
+
declare class NoopGeocodingAdapter implements GeocodingAdapter {
|
|
619
|
+
autocomplete(): Promise<GeocodingSuggestion[]>;
|
|
620
|
+
reverse(): Promise<null>;
|
|
621
|
+
geocode(): Promise<null>;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* User role in the application
|
|
626
|
+
* Can be extended with custom roles as needed
|
|
627
|
+
*/
|
|
628
|
+
type UserRole = "admin" | "member" | "guest" | string;
|
|
629
|
+
/**
|
|
630
|
+
* User status for account management
|
|
631
|
+
*/
|
|
632
|
+
type UserStatus = "active" | "pending" | "inactive" | "suspended";
|
|
633
|
+
/**
|
|
634
|
+
* User Profile - Represents application user data (authorization)
|
|
635
|
+
*
|
|
636
|
+
* ARCHITECTURE:
|
|
637
|
+
* - authId links to external auth provider (Supabase, Clerk, Auth0, etc.)
|
|
638
|
+
* - email is denormalized from auth provider for performance
|
|
639
|
+
* - Auth provider handles authentication (passwords, sessions, OAuth)
|
|
640
|
+
* - This type handles authorization (roles, permissions, tenant membership)
|
|
641
|
+
*
|
|
642
|
+
* @example
|
|
643
|
+
* ```typescript
|
|
644
|
+
* const profile: UserProfile = {
|
|
645
|
+
* id: "profile-123",
|
|
646
|
+
* tenantId: "tenant-456",
|
|
647
|
+
* authId: "supabase-auth-uuid-789",
|
|
648
|
+
* email: "john@example.com",
|
|
649
|
+
* firstName: "John",
|
|
650
|
+
* lastName: "Doe",
|
|
651
|
+
* role: "admin",
|
|
652
|
+
* status: "active",
|
|
653
|
+
* createdAt: new Date(),
|
|
654
|
+
* updatedAt: new Date(),
|
|
655
|
+
* };
|
|
656
|
+
* ```
|
|
657
|
+
*/
|
|
658
|
+
interface UserProfile extends Timestamps {
|
|
659
|
+
id: Uuid;
|
|
660
|
+
tenantId: Uuid;
|
|
661
|
+
/**
|
|
662
|
+
* Link to external auth provider (Supabase auth.users.id, Clerk user ID, etc.)
|
|
663
|
+
* This is the bridge between authentication (provider) and authorization (your app)
|
|
664
|
+
*/
|
|
665
|
+
authId: string;
|
|
666
|
+
/**
|
|
667
|
+
* Email address (denormalized from auth provider)
|
|
668
|
+
* Allows efficient querying and filtering without hitting auth provider API
|
|
669
|
+
*/
|
|
670
|
+
email: string;
|
|
671
|
+
/**
|
|
672
|
+
* User's first name
|
|
673
|
+
*/
|
|
674
|
+
firstName?: string;
|
|
675
|
+
/**
|
|
676
|
+
* User's last name
|
|
677
|
+
*/
|
|
678
|
+
lastName?: string;
|
|
679
|
+
/**
|
|
680
|
+
* Avatar/profile picture URL
|
|
681
|
+
*/
|
|
682
|
+
avatarUrl?: string;
|
|
683
|
+
/**
|
|
684
|
+
* User role for authorization
|
|
685
|
+
* Common values: "admin", "member", "guest"
|
|
686
|
+
* Can be extended with custom roles
|
|
687
|
+
*/
|
|
688
|
+
role: UserRole;
|
|
689
|
+
/**
|
|
690
|
+
* Account status
|
|
691
|
+
* - active: Normal user, full access
|
|
692
|
+
* - pending: Awaiting activation/approval
|
|
693
|
+
* - inactive: Deactivated account
|
|
694
|
+
* - suspended: Temporarily blocked
|
|
695
|
+
*/
|
|
696
|
+
status: UserStatus;
|
|
697
|
+
/**
|
|
698
|
+
* Last login timestamp (updated on each successful auth)
|
|
699
|
+
*/
|
|
700
|
+
lastLoginAt?: Date;
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* Data required to create a new user profile
|
|
704
|
+
*/
|
|
705
|
+
interface CreateUserProfile {
|
|
706
|
+
tenantId: Uuid;
|
|
707
|
+
authId: string;
|
|
708
|
+
email: string;
|
|
709
|
+
firstName?: string;
|
|
710
|
+
lastName?: string;
|
|
711
|
+
avatarUrl?: string;
|
|
712
|
+
role?: UserRole;
|
|
713
|
+
status?: UserStatus;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Data for updating an existing user profile
|
|
717
|
+
*/
|
|
718
|
+
interface UpdateUserProfile {
|
|
719
|
+
firstName?: string;
|
|
720
|
+
lastName?: string;
|
|
721
|
+
avatarUrl?: string;
|
|
722
|
+
role?: UserRole;
|
|
723
|
+
status?: UserStatus;
|
|
724
|
+
lastLoginAt?: Date;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Registry for native objects defined in code
|
|
729
|
+
* Native objects are system objects that cannot be deleted/modified by clients
|
|
730
|
+
* They are defined by developers and synced to the database at startup
|
|
731
|
+
*/
|
|
732
|
+
declare class NativeObjectRegistryClass {
|
|
733
|
+
private objects;
|
|
734
|
+
/**
|
|
735
|
+
* Register one or more native objects
|
|
736
|
+
* Auto-builds if ObjectBuilder is passed instead of ObjectDefinition
|
|
737
|
+
* @param objects - Single object/builder or array of objects/builders to register
|
|
738
|
+
* @returns this (for chaining)
|
|
739
|
+
* @throws Error if object is invalid or already registered
|
|
740
|
+
*
|
|
741
|
+
* @example
|
|
742
|
+
* ```typescript
|
|
743
|
+
* // No .build() needed - registry auto-builds!
|
|
744
|
+
* const PRODUCT = object({ id: "obj-product", name: "products", label: "Product" })
|
|
745
|
+
* .system()
|
|
746
|
+
* .attribute(text({ id: "attr-name", name: "name", label: "Name" }));
|
|
747
|
+
*
|
|
748
|
+
* registry.register(PRODUCT); // ← Auto-builds here
|
|
749
|
+
*
|
|
750
|
+
* // Can still explicitly .build() if you want
|
|
751
|
+
* registry.register(PRODUCT.build());
|
|
752
|
+
*
|
|
753
|
+
* // Register multiple
|
|
754
|
+
* registry.register([PRODUCT, ORDER, CUSTOMER]);
|
|
755
|
+
* ```
|
|
756
|
+
*/
|
|
757
|
+
register(objects: ObjectDefinition | ObjectDefinition[] | {
|
|
758
|
+
build: () => ObjectDefinition;
|
|
759
|
+
} | Array<{
|
|
760
|
+
build: () => ObjectDefinition;
|
|
761
|
+
}>): this;
|
|
762
|
+
/**
|
|
763
|
+
* Validate and register a single object
|
|
764
|
+
* @internal
|
|
765
|
+
*/
|
|
766
|
+
private validateAndRegister;
|
|
767
|
+
/**
|
|
768
|
+
* Get a native object by its name
|
|
769
|
+
* @param name - The object name
|
|
770
|
+
* @returns The object definition or undefined if not found
|
|
771
|
+
*
|
|
772
|
+
* @example
|
|
773
|
+
* ```typescript
|
|
774
|
+
* const product = registry.getByName("products");
|
|
775
|
+
* if (product) {
|
|
776
|
+
* console.log(product.label); // "Product"
|
|
777
|
+
* }
|
|
778
|
+
* ```
|
|
779
|
+
*/
|
|
780
|
+
getByName(name: string): ObjectDefinition | undefined;
|
|
781
|
+
/**
|
|
782
|
+
* Get a native object or throw if not found
|
|
783
|
+
* @param name - The object name
|
|
784
|
+
* @returns The object definition
|
|
785
|
+
* @throws Error if not found
|
|
786
|
+
*/
|
|
787
|
+
getByNameOrThrow(name: string): ObjectDefinition;
|
|
788
|
+
/**
|
|
789
|
+
* Get all registered native objects
|
|
790
|
+
* @returns Array of all registered object definitions
|
|
791
|
+
*/
|
|
792
|
+
getAll(): ObjectDefinition[];
|
|
793
|
+
/**
|
|
794
|
+
* Get all registered native object names
|
|
795
|
+
* @returns Array of object names
|
|
796
|
+
*/
|
|
797
|
+
listNames(): string[];
|
|
798
|
+
/**
|
|
799
|
+
* Check if a native object is registered
|
|
800
|
+
* @param name - The object name
|
|
801
|
+
* @returns true if registered, false otherwise
|
|
802
|
+
*/
|
|
803
|
+
has(name: string): boolean;
|
|
804
|
+
/**
|
|
805
|
+
* Get the number of registered objects
|
|
806
|
+
*/
|
|
807
|
+
get size(): number;
|
|
808
|
+
/**
|
|
809
|
+
* Clear all registered objects (useful for testing)
|
|
810
|
+
* @internal
|
|
811
|
+
*/
|
|
812
|
+
clear(): void;
|
|
813
|
+
/**
|
|
814
|
+
* Get registry summary for debugging
|
|
815
|
+
*/
|
|
816
|
+
summary(): string;
|
|
817
|
+
/**
|
|
818
|
+
* Log registry summary to console
|
|
819
|
+
*/
|
|
820
|
+
debug(): void;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Singleton instance of the registry
|
|
824
|
+
* Use this to register and retrieve native objects
|
|
825
|
+
*
|
|
826
|
+
* @example
|
|
827
|
+
* ```typescript
|
|
828
|
+
* import { registry } from "@stndrds/schema";
|
|
829
|
+
*
|
|
830
|
+
* // Register objects
|
|
831
|
+
* registry.register([PRODUCT, ORDER, CUSTOMER]);
|
|
832
|
+
*
|
|
833
|
+
* // Get object by name
|
|
834
|
+
* const product = registry.getByName("products");
|
|
835
|
+
*
|
|
836
|
+
* // List all
|
|
837
|
+
* console.log(registry.listNames()); // ["products", "orders", ...]
|
|
838
|
+
*
|
|
839
|
+
* // Debug
|
|
840
|
+
* registry.debug();
|
|
841
|
+
* ```
|
|
842
|
+
*/
|
|
843
|
+
declare const registry: NativeObjectRegistryClass;
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* Create a Zod schema for a text attribute
|
|
847
|
+
*/
|
|
848
|
+
declare function createTextValidator(attr: TextAttribute): z.ZodString;
|
|
849
|
+
/**
|
|
850
|
+
* Create a Zod schema for a number attribute
|
|
851
|
+
*/
|
|
852
|
+
declare function createNumberValidator(attr: NumberAttribute): z.ZodNumber;
|
|
853
|
+
/**
|
|
854
|
+
* Create a Zod schema for a checkbox attribute
|
|
855
|
+
*/
|
|
856
|
+
declare function createCheckboxValidator(_attr: CheckboxAttribute): z.ZodBoolean;
|
|
857
|
+
/**
|
|
858
|
+
* Create a Zod schema for a date attribute
|
|
859
|
+
*/
|
|
860
|
+
declare function createDateValidator(attr: DateAttribute): z.ZodString;
|
|
861
|
+
/**
|
|
862
|
+
* Create a Zod schema for a phone attribute
|
|
863
|
+
*/
|
|
864
|
+
declare function createPhoneValidator(_attr: PhoneAttribute): z.ZodType<{
|
|
865
|
+
countryCode: string;
|
|
866
|
+
phoneNumber: string;
|
|
867
|
+
}>;
|
|
868
|
+
/**
|
|
869
|
+
* Create a Zod schema for a currency attribute
|
|
870
|
+
*/
|
|
871
|
+
declare function createCurrencyValidator(_attr: CurrencyAttribute): z.ZodType<{
|
|
872
|
+
code: string;
|
|
873
|
+
value: number;
|
|
874
|
+
}>;
|
|
875
|
+
/**
|
|
876
|
+
* Create a Zod schema for a status attribute
|
|
877
|
+
*/
|
|
878
|
+
declare function createStatusValidator(attr: StatusAttribute): z.ZodEnum<[string, ...string[]]>;
|
|
879
|
+
/**
|
|
880
|
+
* Create a Zod schema for a select attribute
|
|
881
|
+
*/
|
|
882
|
+
declare function createSelectValidator(attr: SelectAttribute): z.ZodEnum<[string, ...string[]]>;
|
|
883
|
+
/**
|
|
884
|
+
* Create a Zod schema for a multiselect attribute
|
|
885
|
+
*/
|
|
886
|
+
declare function createMultiselectValidator(attr: MultiselectAttribute): z.ZodArray<z.ZodEnum<[string, ...string[]]>>;
|
|
887
|
+
/**
|
|
888
|
+
* Create a Zod schema for a location attribute
|
|
889
|
+
*/
|
|
890
|
+
type LocationShape = {
|
|
891
|
+
address?: string;
|
|
892
|
+
address2?: string;
|
|
893
|
+
city?: string;
|
|
894
|
+
state?: string;
|
|
895
|
+
postalCode?: string;
|
|
896
|
+
country?: string;
|
|
897
|
+
latitude?: number;
|
|
898
|
+
longitude?: number;
|
|
899
|
+
};
|
|
900
|
+
declare function createLocationValidator(_attr: LocationAttribute): z.ZodType<LocationShape>;
|
|
901
|
+
/**
|
|
902
|
+
* Create a Zod schema for a timestamp attribute
|
|
903
|
+
*/
|
|
904
|
+
declare function createTimestampValidator(_attr: TimestampAttribute): z.ZodNumber;
|
|
905
|
+
/**
|
|
906
|
+
* Create a Zod schema for a file attribute
|
|
907
|
+
*/
|
|
908
|
+
declare function createFileValidator(_attr: FileAttribute): z.ZodString;
|
|
909
|
+
/**
|
|
910
|
+
* Create a Zod schema for a user attribute
|
|
911
|
+
*/
|
|
912
|
+
declare function createUserValidator(_attr: UserAttribute): z.ZodString;
|
|
913
|
+
/**
|
|
914
|
+
* Create a Zod schema for a single relation attribute (cardinality: "one")
|
|
915
|
+
*/
|
|
916
|
+
declare function createSingleRelationValidator(attr: SingleRelationAttribute): z.ZodUnion<[z.ZodString, z.ZodNull]>;
|
|
917
|
+
/**
|
|
918
|
+
* Create a Zod schema for a multi relation attribute (cardinality: "many")
|
|
919
|
+
*/
|
|
920
|
+
declare function createMultiRelationValidator(attr: MultiRelationAttribute): z.ZodArray<z.ZodString>;
|
|
921
|
+
/**
|
|
922
|
+
* Create a Zod schema for a relation attribute
|
|
923
|
+
* Dispatches to single or multi validator based on cardinality
|
|
924
|
+
*/
|
|
925
|
+
declare function createRelationValidator(attr: RelationAttribute): z.ZodUnion<[z.ZodString, z.ZodNull]> | z.ZodArray<z.ZodString>;
|
|
926
|
+
/**
|
|
927
|
+
* Create a Zod schema for a rating attribute
|
|
928
|
+
*/
|
|
929
|
+
declare function createRatingValidator(attr: RatingAttribute): z.ZodNumber;
|
|
930
|
+
/**
|
|
931
|
+
* Create a Zod schema for any attribute type
|
|
932
|
+
*/
|
|
933
|
+
declare function createAttributeValidator(attr: Attribute): z.ZodTypeAny;
|
|
934
|
+
/**
|
|
935
|
+
* Create a Zod schema for an entire object
|
|
936
|
+
*/
|
|
937
|
+
declare function createObjectValidator(objectDef: ObjectDefinition): z.ZodType<Record<string, unknown>>;
|
|
938
|
+
/**
|
|
939
|
+
* Validation result
|
|
940
|
+
*/
|
|
941
|
+
interface ValidationResult {
|
|
942
|
+
success: boolean;
|
|
943
|
+
data?: Record<string, unknown>;
|
|
944
|
+
errors?: Array<{
|
|
945
|
+
path: string[];
|
|
946
|
+
message: string;
|
|
947
|
+
}>;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Validate data against an attribute schema
|
|
951
|
+
*/
|
|
952
|
+
declare function validateAttribute(attr: Attribute, value: unknown): ValidationResult;
|
|
953
|
+
/**
|
|
954
|
+
* Validate data against an object schema
|
|
955
|
+
*/
|
|
956
|
+
declare function validateObject(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
|
|
957
|
+
/**
|
|
958
|
+
* Validate and throw if invalid
|
|
959
|
+
*/
|
|
960
|
+
declare function validateObjectOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
|
|
961
|
+
/**
|
|
962
|
+
* Create a Zod schema for draft validation.
|
|
963
|
+
* All attributes become optional, but provided values are still validated.
|
|
964
|
+
*/
|
|
965
|
+
declare function createDraftValidator(objectDef: ObjectDefinition): z.ZodType<Record<string, unknown>>;
|
|
966
|
+
/**
|
|
967
|
+
* Validate data in draft mode.
|
|
968
|
+
* - All attributes are treated as optional (no required validation)
|
|
969
|
+
* - Provided values are still validated for format/type correctness
|
|
970
|
+
*
|
|
971
|
+
* Use this when creating records that may be incomplete (drafts).
|
|
972
|
+
*
|
|
973
|
+
* @example
|
|
974
|
+
* ```typescript
|
|
975
|
+
* const result = validateDraft(PRODUCT, { name: "Draft" });
|
|
976
|
+
* // → success even if "price" is required but missing
|
|
977
|
+
*
|
|
978
|
+
* const result2 = validateDraft(PRODUCT, { price: -10 });
|
|
979
|
+
* // → fails because price must be >= 0 (format validation still applies)
|
|
980
|
+
* ```
|
|
981
|
+
*/
|
|
982
|
+
declare function validateDraft(objectDef: ObjectDefinition, data: Record<string, unknown>): ValidationResult;
|
|
983
|
+
/**
|
|
984
|
+
* Validate draft data and throw if format validation fails.
|
|
985
|
+
*/
|
|
986
|
+
declare function validateDraftOrThrow(objectDef: ObjectDefinition, data: Record<string, unknown>): Record<string, unknown>;
|
|
987
|
+
/**
|
|
988
|
+
* Get the list of required attributes that are missing values.
|
|
989
|
+
*
|
|
990
|
+
* @example
|
|
991
|
+
* ```typescript
|
|
992
|
+
* const missing = getMissingRequiredAttributes(PRODUCT, { name: "Test" });
|
|
993
|
+
* // → [priceAttribute, statusAttribute] if price and status are required but missing
|
|
994
|
+
* ```
|
|
995
|
+
*/
|
|
996
|
+
declare function getMissingRequiredAttributes(objectDef: ObjectDefinition, data: Record<string, unknown>): Attribute[];
|
|
997
|
+
/**
|
|
998
|
+
* Check if a record is complete (all required attributes have valid values).
|
|
999
|
+
*
|
|
1000
|
+
* @returns `true` if all required values are present and valid, `false` otherwise
|
|
1001
|
+
*/
|
|
1002
|
+
declare function isRecordComplete(objectDef: ObjectDefinition, data: Record<string, unknown>): boolean;
|
|
1003
|
+
/**
|
|
1004
|
+
* Compute the completion status of a record based on its data.
|
|
1005
|
+
*
|
|
1006
|
+
* - `"complete"`: All required values are present and valid
|
|
1007
|
+
* - `"draft"`: One or more required values are missing or invalid
|
|
1008
|
+
*
|
|
1009
|
+
* This function is used to dynamically determine the status when
|
|
1010
|
+
* creating or updating records.
|
|
1011
|
+
*
|
|
1012
|
+
* @example
|
|
1013
|
+
* ```typescript
|
|
1014
|
+
* const status = computeRecordStatus(PRODUCT, {
|
|
1015
|
+
* name: "Nike Air Max",
|
|
1016
|
+
* price: 129.99,
|
|
1017
|
+
* status: "active"
|
|
1018
|
+
* });
|
|
1019
|
+
* // → "complete"
|
|
1020
|
+
*
|
|
1021
|
+
* const status2 = computeRecordStatus(PRODUCT, { name: "Draft Product" });
|
|
1022
|
+
* // → "draft" (missing required fields)
|
|
1023
|
+
* ```
|
|
1024
|
+
*/
|
|
1025
|
+
declare function computeRecordStatus(objectDef: ObjectDefinition, data: Record<string, unknown>): CompletionStatus;
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* Object as stored in database (metadata)
|
|
1029
|
+
*/
|
|
1030
|
+
interface DBObject extends Timestamps {
|
|
1031
|
+
id: Uuid;
|
|
1032
|
+
tenantId: TenantId;
|
|
1033
|
+
name: string;
|
|
1034
|
+
label: string;
|
|
1035
|
+
description?: string;
|
|
1036
|
+
icon?: IconName;
|
|
1037
|
+
system: boolean;
|
|
1038
|
+
metadata?: Record<string, unknown>;
|
|
1039
|
+
}
|
|
1040
|
+
interface CreateDBObject {
|
|
1041
|
+
tenantId: TenantId;
|
|
1042
|
+
name: string;
|
|
1043
|
+
label: string;
|
|
1044
|
+
description?: string;
|
|
1045
|
+
icon?: IconName;
|
|
1046
|
+
system?: boolean;
|
|
1047
|
+
metadata?: Record<string, unknown>;
|
|
1048
|
+
}
|
|
1049
|
+
interface UpdateDBObject {
|
|
1050
|
+
label?: string;
|
|
1051
|
+
description?: string;
|
|
1052
|
+
icon?: IconName;
|
|
1053
|
+
metadata?: Record<string, unknown>;
|
|
1054
|
+
}
|
|
1055
|
+
interface UpsertDBObject extends CreateDBObject {
|
|
1056
|
+
system: boolean;
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Attribute as stored in database (metadata)
|
|
1060
|
+
*/
|
|
1061
|
+
interface DBAttribute extends Timestamps {
|
|
1062
|
+
id: Uuid;
|
|
1063
|
+
objectId: Uuid;
|
|
1064
|
+
name: string;
|
|
1065
|
+
label: string;
|
|
1066
|
+
type: AttributeType;
|
|
1067
|
+
description?: string;
|
|
1068
|
+
icon?: IconName;
|
|
1069
|
+
system: boolean;
|
|
1070
|
+
required: boolean;
|
|
1071
|
+
unique: boolean;
|
|
1072
|
+
order: number;
|
|
1073
|
+
hidden?: boolean;
|
|
1074
|
+
archived?: boolean;
|
|
1075
|
+
deprecated?: boolean;
|
|
1076
|
+
defaultValue?: unknown;
|
|
1077
|
+
config: Record<string, unknown>;
|
|
1078
|
+
}
|
|
1079
|
+
interface CreateDBAttribute {
|
|
1080
|
+
objectId: Uuid;
|
|
1081
|
+
name: string;
|
|
1082
|
+
label: string;
|
|
1083
|
+
type: AttributeType;
|
|
1084
|
+
description?: string;
|
|
1085
|
+
icon?: IconName;
|
|
1086
|
+
system?: boolean;
|
|
1087
|
+
required?: boolean;
|
|
1088
|
+
unique?: boolean;
|
|
1089
|
+
order?: number;
|
|
1090
|
+
hidden?: boolean;
|
|
1091
|
+
archived?: boolean;
|
|
1092
|
+
deprecated?: boolean;
|
|
1093
|
+
defaultValue?: unknown;
|
|
1094
|
+
config?: Record<string, unknown>;
|
|
1095
|
+
}
|
|
1096
|
+
interface UpdateDBAttribute {
|
|
1097
|
+
label?: string;
|
|
1098
|
+
description?: string;
|
|
1099
|
+
icon?: IconName;
|
|
1100
|
+
required?: boolean;
|
|
1101
|
+
order?: number;
|
|
1102
|
+
hidden?: boolean;
|
|
1103
|
+
archived?: boolean;
|
|
1104
|
+
deprecated?: boolean;
|
|
1105
|
+
defaultValue?: unknown;
|
|
1106
|
+
config?: Record<string, unknown>;
|
|
1107
|
+
}
|
|
1108
|
+
interface UpsertDBAttribute extends CreateDBAttribute {
|
|
1109
|
+
objectId: Uuid;
|
|
1110
|
+
name: string;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* Object record creation data
|
|
1115
|
+
*/
|
|
1116
|
+
interface CreateObjectRecord {
|
|
1117
|
+
tenantId: TenantId;
|
|
1118
|
+
objectId: Uuid;
|
|
1119
|
+
data: Record<string, unknown>;
|
|
1120
|
+
/**
|
|
1121
|
+
* Completion status of the record.
|
|
1122
|
+
* - `draft`: Record is incomplete (missing required values)
|
|
1123
|
+
* - `complete`: All required values are present and valid
|
|
1124
|
+
*/
|
|
1125
|
+
completionStatus: "draft" | "complete";
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* Generic list options for pagination and sorting
|
|
1129
|
+
*/
|
|
1130
|
+
interface ListOptions {
|
|
1131
|
+
limit?: number;
|
|
1132
|
+
offset?: number;
|
|
1133
|
+
orderBy?: string;
|
|
1134
|
+
orderDirection?: "asc" | "desc";
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Search options for full-text search
|
|
1138
|
+
*/
|
|
1139
|
+
interface SearchOptions extends ListOptions {
|
|
1140
|
+
filters?: Record<string, unknown>;
|
|
1141
|
+
highlight?: boolean;
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* File-specific list options
|
|
1145
|
+
*/
|
|
1146
|
+
interface FileListOptions extends ListOptions {
|
|
1147
|
+
folderPath?: string;
|
|
1148
|
+
mimeType?: string;
|
|
1149
|
+
uploadedBy?: Uuid;
|
|
1150
|
+
includeDeleted?: boolean;
|
|
1151
|
+
}
|
|
1152
|
+
/**
|
|
1153
|
+
* Result of an operation
|
|
1154
|
+
*/
|
|
1155
|
+
interface OperationResult<T = unknown> {
|
|
1156
|
+
success: boolean;
|
|
1157
|
+
data?: T;
|
|
1158
|
+
error?: {
|
|
1159
|
+
code: string;
|
|
1160
|
+
message: string;
|
|
1161
|
+
details?: Record<string, unknown>;
|
|
1162
|
+
};
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Repository for objects table (metadata)
|
|
1167
|
+
*/
|
|
1168
|
+
interface ObjectsRepository {
|
|
1169
|
+
/**
|
|
1170
|
+
* Find object by ID
|
|
1171
|
+
*/
|
|
1172
|
+
findById(id: Uuid): Promise<DBObject | null>;
|
|
1173
|
+
/**
|
|
1174
|
+
* Find object by name and tenant
|
|
1175
|
+
*/
|
|
1176
|
+
findByName(tenantId: TenantId, name: string): Promise<DBObject | null>;
|
|
1177
|
+
/**
|
|
1178
|
+
* Find system/native object by name (system=true, for sync)
|
|
1179
|
+
*/
|
|
1180
|
+
findSystemByName(name: string): Promise<DBObject | null>;
|
|
1181
|
+
/**
|
|
1182
|
+
* Create object
|
|
1183
|
+
*/
|
|
1184
|
+
create(data: CreateDBObject): Promise<DBObject>;
|
|
1185
|
+
/**
|
|
1186
|
+
* Update object
|
|
1187
|
+
*/
|
|
1188
|
+
update(id: Uuid, data: Partial<UpdateDBObject>): Promise<DBObject>;
|
|
1189
|
+
/**
|
|
1190
|
+
* Delete object
|
|
1191
|
+
*/
|
|
1192
|
+
delete(id: Uuid): Promise<void>;
|
|
1193
|
+
/**
|
|
1194
|
+
* List all objects for a tenant
|
|
1195
|
+
*/
|
|
1196
|
+
list(tenantId: TenantId): Promise<DBObject[]>;
|
|
1197
|
+
/**
|
|
1198
|
+
* Upsert object (create or update based on nativeObjectId)
|
|
1199
|
+
*/
|
|
1200
|
+
upsert(data: UpsertDBObject): Promise<DBObject>;
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Repository for attributes table (metadata)
|
|
1204
|
+
*/
|
|
1205
|
+
interface AttributesRepository {
|
|
1206
|
+
/**
|
|
1207
|
+
* Find attribute by ID
|
|
1208
|
+
*/
|
|
1209
|
+
findById(id: Uuid): Promise<DBAttribute | null>;
|
|
1210
|
+
/**
|
|
1211
|
+
* Find attributes by object ID
|
|
1212
|
+
*/
|
|
1213
|
+
findByObjectId(objectId: Uuid): Promise<DBAttribute[]>;
|
|
1214
|
+
/**
|
|
1215
|
+
* Create attribute
|
|
1216
|
+
*/
|
|
1217
|
+
create(data: CreateDBAttribute): Promise<DBAttribute>;
|
|
1218
|
+
/**
|
|
1219
|
+
* Update attribute
|
|
1220
|
+
*/
|
|
1221
|
+
update(id: Uuid, data: Partial<UpdateDBAttribute>): Promise<DBAttribute>;
|
|
1222
|
+
/**
|
|
1223
|
+
* Delete attribute
|
|
1224
|
+
*/
|
|
1225
|
+
delete(id: Uuid): Promise<void>;
|
|
1226
|
+
/**
|
|
1227
|
+
* Delete multiple attributes by names (for sync cleanup)
|
|
1228
|
+
*/
|
|
1229
|
+
deleteByNames(objectId: Uuid, excludeNames: string[]): Promise<number>;
|
|
1230
|
+
/**
|
|
1231
|
+
* Upsert attribute (create or update based on objectId + name)
|
|
1232
|
+
*/
|
|
1233
|
+
upsert(data: UpsertDBAttribute): Promise<DBAttribute>;
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Repository for user_profiles table
|
|
1237
|
+
*/
|
|
1238
|
+
interface UserProfilesRepository {
|
|
1239
|
+
/**
|
|
1240
|
+
* Find user profile by ID
|
|
1241
|
+
*/
|
|
1242
|
+
findById(id: Uuid): Promise<UserProfile | null>;
|
|
1243
|
+
/**
|
|
1244
|
+
* Find user profile by auth ID (external auth provider)
|
|
1245
|
+
*/
|
|
1246
|
+
findByAuthId(authId: string): Promise<UserProfile | null>;
|
|
1247
|
+
/**
|
|
1248
|
+
* Find user profile by email
|
|
1249
|
+
*/
|
|
1250
|
+
findByEmail(tenantId: TenantId, email: string): Promise<UserProfile | null>;
|
|
1251
|
+
/**
|
|
1252
|
+
* Create user profile
|
|
1253
|
+
*/
|
|
1254
|
+
create(data: CreateUserProfile): Promise<UserProfile>;
|
|
1255
|
+
/**
|
|
1256
|
+
* Update user profile
|
|
1257
|
+
*/
|
|
1258
|
+
update(id: Uuid, data: UpdateUserProfile): Promise<UserProfile>;
|
|
1259
|
+
/**
|
|
1260
|
+
* Delete user profile
|
|
1261
|
+
*/
|
|
1262
|
+
delete(id: Uuid): Promise<void>;
|
|
1263
|
+
/**
|
|
1264
|
+
* List all user profiles for a tenant
|
|
1265
|
+
*/
|
|
1266
|
+
list(tenantId: TenantId, options?: ListOptions): Promise<UserProfile[]>;
|
|
1267
|
+
/**
|
|
1268
|
+
* Update last login timestamp
|
|
1269
|
+
*/
|
|
1270
|
+
updateLastLogin(id: Uuid): Promise<void>;
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Repository for files table
|
|
1274
|
+
*/
|
|
1275
|
+
interface FilesRepository {
|
|
1276
|
+
/**
|
|
1277
|
+
* Find file by ID
|
|
1278
|
+
*/
|
|
1279
|
+
findById(id: Uuid): Promise<File | null>;
|
|
1280
|
+
/**
|
|
1281
|
+
* Create file
|
|
1282
|
+
*/
|
|
1283
|
+
create(data: CreateFile): Promise<File>;
|
|
1284
|
+
/**
|
|
1285
|
+
* Update file
|
|
1286
|
+
*/
|
|
1287
|
+
update(id: Uuid, data: UpdateFile): Promise<File>;
|
|
1288
|
+
/**
|
|
1289
|
+
* Delete file (soft delete)
|
|
1290
|
+
*/
|
|
1291
|
+
delete(id: Uuid): Promise<void>;
|
|
1292
|
+
/**
|
|
1293
|
+
* Hard delete file (permanent)
|
|
1294
|
+
*/
|
|
1295
|
+
hardDelete(id: Uuid): Promise<void>;
|
|
1296
|
+
/**
|
|
1297
|
+
* List files for a tenant
|
|
1298
|
+
*/
|
|
1299
|
+
list(tenantId: TenantId, options?: FileListOptions): Promise<File[]>;
|
|
1300
|
+
/**
|
|
1301
|
+
* Find files by folder path
|
|
1302
|
+
*/
|
|
1303
|
+
findByFolder(tenantId: TenantId, folderPath: string): Promise<File[]>;
|
|
1304
|
+
/**
|
|
1305
|
+
* Find files by uploader
|
|
1306
|
+
*/
|
|
1307
|
+
findByUploader(uploadedBy: Uuid): Promise<File[]>;
|
|
1308
|
+
}
|
|
1309
|
+
/**
|
|
1310
|
+
* Repository for object_records table (unified JSONB)
|
|
1311
|
+
*/
|
|
1312
|
+
interface ObjectRecordsRepository {
|
|
1313
|
+
/**
|
|
1314
|
+
* Find record by ID
|
|
1315
|
+
*/
|
|
1316
|
+
findById(id: Uuid): Promise<ObjectRecord | null>;
|
|
1317
|
+
/**
|
|
1318
|
+
* Create record
|
|
1319
|
+
*/
|
|
1320
|
+
create(data: CreateObjectRecord): Promise<ObjectRecord>;
|
|
1321
|
+
/**
|
|
1322
|
+
* Update record
|
|
1323
|
+
*/
|
|
1324
|
+
update(id: Uuid, data: Partial<Record<string, unknown>>): Promise<ObjectRecord>;
|
|
1325
|
+
/**
|
|
1326
|
+
* Delete record
|
|
1327
|
+
*/
|
|
1328
|
+
delete(id: Uuid): Promise<void>;
|
|
1329
|
+
/**
|
|
1330
|
+
* List records for an object
|
|
1331
|
+
*/
|
|
1332
|
+
list(tenantId: TenantId, objectId: Uuid, options?: ListOptions): Promise<{
|
|
1333
|
+
records: ObjectRecord[];
|
|
1334
|
+
total: number;
|
|
1335
|
+
}>;
|
|
1336
|
+
/**
|
|
1337
|
+
* Search records using PostgreSQL full-text search
|
|
1338
|
+
*/
|
|
1339
|
+
search(tenantId: TenantId, objectId: Uuid, query: string, options?: SearchOptions): Promise<{
|
|
1340
|
+
records: ObjectRecord[];
|
|
1341
|
+
total: number;
|
|
1342
|
+
}>;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
/**
|
|
1346
|
+
* Generic database adapter interface
|
|
1347
|
+
* Any ORM (Drizzle, Prisma, Kysely, TypeORM) can implement this interface
|
|
1348
|
+
* to work with @stndrds/schema runtime services
|
|
1349
|
+
*
|
|
1350
|
+
* @example
|
|
1351
|
+
* ```typescript
|
|
1352
|
+
* // Drizzle implementation
|
|
1353
|
+
* import { createDrizzleAdapter } from "./adapters/drizzle";
|
|
1354
|
+
* import { db } from "./db";
|
|
1355
|
+
*
|
|
1356
|
+
* const adapter = createDrizzleAdapter(db);
|
|
1357
|
+
*
|
|
1358
|
+
* // Prisma implementation
|
|
1359
|
+
* import { createPrismaAdapter } from "./adapters/prisma";
|
|
1360
|
+
* import { prisma } from "./db";
|
|
1361
|
+
*
|
|
1362
|
+
* const adapter = createPrismaAdapter(prisma);
|
|
1363
|
+
* ```
|
|
1364
|
+
*/
|
|
1365
|
+
interface DatabaseAdapter {
|
|
1366
|
+
objects: ObjectsRepository;
|
|
1367
|
+
attributes: AttributesRepository;
|
|
1368
|
+
userProfiles: UserProfilesRepository;
|
|
1369
|
+
files: FilesRepository;
|
|
1370
|
+
objectRecords: ObjectRecordsRepository;
|
|
1371
|
+
transaction<T>(callback: (adapter: DatabaseAdapter) => Promise<T>): Promise<T>;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
interface InternalObjectRecord extends ObjectRecord {
|
|
1375
|
+
tenantId: TenantId;
|
|
1376
|
+
}
|
|
1377
|
+
interface MockStores {
|
|
1378
|
+
objects: Map<Uuid, DBObject>;
|
|
1379
|
+
attributes: Map<Uuid, DBAttribute>;
|
|
1380
|
+
userProfiles: Map<Uuid, UserProfile>;
|
|
1381
|
+
files: Map<Uuid, File>;
|
|
1382
|
+
objectRecords: Map<Uuid, InternalObjectRecord>;
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Create an in-memory mock adapter for testing and development
|
|
1386
|
+
*
|
|
1387
|
+
* This adapter stores all data in memory and is perfect for:
|
|
1388
|
+
* - Unit tests
|
|
1389
|
+
* - Integration tests
|
|
1390
|
+
* - Local development without a database
|
|
1391
|
+
* - Understanding the adapter interface
|
|
1392
|
+
*
|
|
1393
|
+
* @returns A DatabaseAdapter implementation using in-memory storage
|
|
1394
|
+
*
|
|
1395
|
+
* @example
|
|
1396
|
+
* ```typescript
|
|
1397
|
+
* import { createMockAdapter, RecordService } from "@stndrds/schema";
|
|
1398
|
+
*
|
|
1399
|
+
* // Create adapter
|
|
1400
|
+
* const adapter = createMockAdapter();
|
|
1401
|
+
*
|
|
1402
|
+
* // Use with services
|
|
1403
|
+
* const recordService = new RecordService(adapter, "tenant-123");
|
|
1404
|
+
*
|
|
1405
|
+
* // Create a record
|
|
1406
|
+
* const product = await recordService.createRecord("obj-product", {
|
|
1407
|
+
* name: "Nike Air Max",
|
|
1408
|
+
* price: 129.99
|
|
1409
|
+
* });
|
|
1410
|
+
*
|
|
1411
|
+
* // List records
|
|
1412
|
+
* const { records, total } = await recordService.listRecords("obj-product");
|
|
1413
|
+
* ```
|
|
1414
|
+
*/
|
|
1415
|
+
declare function createMockAdapter(): DatabaseAdapter & {
|
|
1416
|
+
_stores: MockStores;
|
|
1417
|
+
reset(): void;
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* Service for managing files
|
|
1422
|
+
* Handles file metadata CRUD, permissions, and soft delete
|
|
1423
|
+
*/
|
|
1424
|
+
declare class FileService {
|
|
1425
|
+
private adapter;
|
|
1426
|
+
private tenantId;
|
|
1427
|
+
constructor(adapter: DatabaseAdapter, tenantId: string);
|
|
1428
|
+
/**
|
|
1429
|
+
* Create a new file record (after upload to storage)
|
|
1430
|
+
*
|
|
1431
|
+
* @param data - File metadata
|
|
1432
|
+
* @returns Created file record
|
|
1433
|
+
*
|
|
1434
|
+
* @example
|
|
1435
|
+
* ```typescript
|
|
1436
|
+
* const service = new FileService(adapter, "tenant-123");
|
|
1437
|
+
*
|
|
1438
|
+
* // After uploading to S3
|
|
1439
|
+
* const file = await service.createFile({
|
|
1440
|
+
* tenantId: "tenant-123",
|
|
1441
|
+
* name: "contract-2025.pdf",
|
|
1442
|
+
* originalName: "Contract Acme Corp 2025.pdf",
|
|
1443
|
+
* mimeType: "application/pdf",
|
|
1444
|
+
* size: 2458624,
|
|
1445
|
+
* storageProvider: "s3",
|
|
1446
|
+
* storagePath: "tenants/123/files/2025/contract.pdf",
|
|
1447
|
+
* storageBucket: "my-app-files",
|
|
1448
|
+
* url: "https://cdn.example.com/files/file-123",
|
|
1449
|
+
* uploadedBy: "profile-456",
|
|
1450
|
+
* visibility: "private"
|
|
1451
|
+
* });
|
|
1452
|
+
* ```
|
|
1453
|
+
*/
|
|
1454
|
+
createFile(data: CreateFile): Promise<File>;
|
|
1455
|
+
/**
|
|
1456
|
+
* Get file by ID
|
|
1457
|
+
*/
|
|
1458
|
+
getFile(fileId: string): Promise<File | null>;
|
|
1459
|
+
/**
|
|
1460
|
+
* Get file by ID or throw
|
|
1461
|
+
*/
|
|
1462
|
+
getFileOrThrow(fileId: string): Promise<File>;
|
|
1463
|
+
/**
|
|
1464
|
+
* Update file metadata
|
|
1465
|
+
*
|
|
1466
|
+
* @param fileId - File UUID
|
|
1467
|
+
* @param data - Data to update
|
|
1468
|
+
* @returns Updated file
|
|
1469
|
+
*/
|
|
1470
|
+
updateFile(fileId: string, data: UpdateFile): Promise<File>;
|
|
1471
|
+
/**
|
|
1472
|
+
* Delete file (soft delete)
|
|
1473
|
+
*
|
|
1474
|
+
* @param fileId - File UUID
|
|
1475
|
+
* @param options - Delete options
|
|
1476
|
+
*/
|
|
1477
|
+
deleteFile(fileId: string, options?: {
|
|
1478
|
+
hard?: boolean;
|
|
1479
|
+
checkOwnership?: boolean;
|
|
1480
|
+
userId?: string;
|
|
1481
|
+
}): Promise<void>;
|
|
1482
|
+
/**
|
|
1483
|
+
* List files for the tenant
|
|
1484
|
+
*/
|
|
1485
|
+
listFiles(options?: FileListOptions): Promise<File[]>;
|
|
1486
|
+
/**
|
|
1487
|
+
* List files by folder
|
|
1488
|
+
*/
|
|
1489
|
+
listFilesByFolder(folderPath: string): Promise<File[]>;
|
|
1490
|
+
/**
|
|
1491
|
+
* List files uploaded by a specific user
|
|
1492
|
+
*/
|
|
1493
|
+
listFilesByUploader(uploadedBy: string): Promise<File[]>;
|
|
1494
|
+
/**
|
|
1495
|
+
* Change file visibility
|
|
1496
|
+
*
|
|
1497
|
+
* @param fileId - File UUID
|
|
1498
|
+
* @param visibility - New visibility level
|
|
1499
|
+
* @param allowedUsers - Users allowed to access (if restricted)
|
|
1500
|
+
*/
|
|
1501
|
+
changeVisibility(fileId: string, visibility: "public" | "private" | "restricted", allowedUsers?: string[]): Promise<File>;
|
|
1502
|
+
/**
|
|
1503
|
+
* Grant access to a file for specific users
|
|
1504
|
+
*
|
|
1505
|
+
* @param fileId - File UUID
|
|
1506
|
+
* @param userIds - User IDs to grant access
|
|
1507
|
+
*/
|
|
1508
|
+
grantAccess(fileId: string, userIds: string[]): Promise<File>;
|
|
1509
|
+
/**
|
|
1510
|
+
* Revoke access to a file for specific users
|
|
1511
|
+
*
|
|
1512
|
+
* @param fileId - File UUID
|
|
1513
|
+
* @param userIds - User IDs to revoke access
|
|
1514
|
+
*/
|
|
1515
|
+
revokeAccess(fileId: string, userIds: string[]): Promise<File>;
|
|
1516
|
+
/**
|
|
1517
|
+
* Check if user has access to a file
|
|
1518
|
+
*
|
|
1519
|
+
* @param fileId - File UUID
|
|
1520
|
+
* @param userId - User ID to check
|
|
1521
|
+
* @returns true if user can access the file
|
|
1522
|
+
*/
|
|
1523
|
+
canAccess(fileId: string, userId: string): Promise<boolean>;
|
|
1524
|
+
/**
|
|
1525
|
+
* Move file to different folder
|
|
1526
|
+
*/
|
|
1527
|
+
moveToFolder(fileId: string, newFolderPath: string): Promise<File>;
|
|
1528
|
+
/**
|
|
1529
|
+
* Add tags to file
|
|
1530
|
+
*/
|
|
1531
|
+
addTags(fileId: string, tags: string[]): Promise<File>;
|
|
1532
|
+
/**
|
|
1533
|
+
* Remove tags from file
|
|
1534
|
+
*/
|
|
1535
|
+
removeTags(fileId: string, tags: string[]): Promise<File>;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/**
|
|
1539
|
+
* Geocoding service for address autocomplete and geocoding operations
|
|
1540
|
+
*
|
|
1541
|
+
* @example
|
|
1542
|
+
* ```typescript
|
|
1543
|
+
* import { GeocodingService } from "@stndrds/schema";
|
|
1544
|
+
* import { GoogleMapsAdapter } from "./adapters/google-maps";
|
|
1545
|
+
*
|
|
1546
|
+
* const geocoding = new GeocodingService(new GoogleMapsAdapter({ apiKey: "..." }));
|
|
1547
|
+
*
|
|
1548
|
+
* const suggestions = await geocoding.autocomplete({
|
|
1549
|
+
* query: "40 Quai des Belges",
|
|
1550
|
+
* countries: ["FRA"],
|
|
1551
|
+
* limit: 5,
|
|
1552
|
+
* });
|
|
1553
|
+
* ```
|
|
1554
|
+
*/
|
|
1555
|
+
declare class GeocodingService {
|
|
1556
|
+
private readonly adapter;
|
|
1557
|
+
constructor(adapter: GeocodingAdapter);
|
|
1558
|
+
/**
|
|
1559
|
+
* Search for address suggestions as the user types
|
|
1560
|
+
*/
|
|
1561
|
+
autocomplete(params: GeocodingAutocompleteParams): Promise<GeocodingSuggestion[]>;
|
|
1562
|
+
/**
|
|
1563
|
+
* Reverse geocode coordinates to an address
|
|
1564
|
+
*/
|
|
1565
|
+
reverse(params: ReverseGeocodingParams): Promise<GeocodingSuggestion | null>;
|
|
1566
|
+
/**
|
|
1567
|
+
* Geocode a structured address to coordinates
|
|
1568
|
+
*/
|
|
1569
|
+
geocode(params: GeocodingParams): Promise<GeocodingSuggestion | null>;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
/**
|
|
1573
|
+
* Input for creating a custom object
|
|
1574
|
+
*/
|
|
1575
|
+
interface CreateCustomObjectInput {
|
|
1576
|
+
name: string;
|
|
1577
|
+
label: string;
|
|
1578
|
+
description?: string;
|
|
1579
|
+
icon?: IconName;
|
|
1580
|
+
attributes?: (Attribute | {
|
|
1581
|
+
build: () => Attribute;
|
|
1582
|
+
})[];
|
|
1583
|
+
metadata?: Record<string, unknown>;
|
|
1584
|
+
}
|
|
1585
|
+
/**
|
|
1586
|
+
* Input for adding an attribute to an object
|
|
1587
|
+
*/
|
|
1588
|
+
interface AddAttributeInput {
|
|
1589
|
+
name: string;
|
|
1590
|
+
label: string;
|
|
1591
|
+
type: AttributeType;
|
|
1592
|
+
required?: boolean;
|
|
1593
|
+
unique?: boolean;
|
|
1594
|
+
description?: string;
|
|
1595
|
+
placeholder?: string;
|
|
1596
|
+
icon?: IconName;
|
|
1597
|
+
defaultValue?: unknown;
|
|
1598
|
+
metadata?: Record<string, unknown>;
|
|
1599
|
+
[key: string]: unknown;
|
|
1600
|
+
}
|
|
1601
|
+
/**
|
|
1602
|
+
* Service for managing object schemas
|
|
1603
|
+
* Handles fusion of native objects (from registry) and custom objects (from database)
|
|
1604
|
+
*/
|
|
1605
|
+
declare class ObjectSchemaService {
|
|
1606
|
+
private adapter;
|
|
1607
|
+
private nativeRegistry;
|
|
1608
|
+
constructor(adapter: DatabaseAdapter, nativeRegistry: typeof registry);
|
|
1609
|
+
/**
|
|
1610
|
+
* Create a new custom object
|
|
1611
|
+
* Validates name format and ensures system=false
|
|
1612
|
+
*
|
|
1613
|
+
* @param definition - Object definition (attributes can be raw definitions or builders)
|
|
1614
|
+
* @param tenantId - Tenant ID owning the object
|
|
1615
|
+
* @returns Created ObjectDefinition
|
|
1616
|
+
*/
|
|
1617
|
+
createCustomObject(definition: CreateCustomObjectInput, tenantId: string): Promise<ObjectDefinition>;
|
|
1618
|
+
/**
|
|
1619
|
+
* Add a custom attribute to an existing object
|
|
1620
|
+
* Can be used on both custom and native objects
|
|
1621
|
+
* Attributes added via API are always custom (system=false)
|
|
1622
|
+
*
|
|
1623
|
+
* @param objectId - Object UUID from database
|
|
1624
|
+
* @param attribute - Attribute definition
|
|
1625
|
+
* @returns Created Attribute
|
|
1626
|
+
*/
|
|
1627
|
+
addAttributeToObject(objectId: string, attribute: AddAttributeInput): Promise<Attribute>;
|
|
1628
|
+
/**
|
|
1629
|
+
* Update an attribute
|
|
1630
|
+
* Can only update custom attributes (system=false)
|
|
1631
|
+
*
|
|
1632
|
+
* @param attributeId - Attribute UUID
|
|
1633
|
+
* @param updates - Partial attribute updates
|
|
1634
|
+
* @returns Updated Attribute
|
|
1635
|
+
*/
|
|
1636
|
+
updateAttribute(attributeId: string, updates: Partial<AddAttributeInput>): Promise<Attribute>;
|
|
1637
|
+
/**
|
|
1638
|
+
* Delete an attribute
|
|
1639
|
+
* Can only delete custom attributes (system=false)
|
|
1640
|
+
*
|
|
1641
|
+
* @param attributeId - Attribute UUID
|
|
1642
|
+
*/
|
|
1643
|
+
deleteAttribute(attributeId: string): Promise<void>;
|
|
1644
|
+
/**
|
|
1645
|
+
* List attributes for an object
|
|
1646
|
+
*
|
|
1647
|
+
* @param objectId - Object UUID
|
|
1648
|
+
* @param options - Filter options
|
|
1649
|
+
* @returns List of attributes
|
|
1650
|
+
*/
|
|
1651
|
+
listAttributes(objectId: string, options?: {
|
|
1652
|
+
systemOnly?: boolean;
|
|
1653
|
+
customOnly?: boolean;
|
|
1654
|
+
}): Promise<Attribute[]>;
|
|
1655
|
+
/**
|
|
1656
|
+
* Validate attribute name format (variable identifier)
|
|
1657
|
+
* @internal
|
|
1658
|
+
*/
|
|
1659
|
+
private validateAttributeName;
|
|
1660
|
+
/**
|
|
1661
|
+
* Get complete object schema (system + custom attributes)
|
|
1662
|
+
* If object is native, merges registry definition with DB custom attributes
|
|
1663
|
+
* If object is custom, returns DB definition only
|
|
1664
|
+
*
|
|
1665
|
+
* @param objectId - Object UUID from database
|
|
1666
|
+
* @returns Complete ObjectDefinition with all attributes
|
|
1667
|
+
*
|
|
1668
|
+
* @example
|
|
1669
|
+
* ```typescript
|
|
1670
|
+
* const service = new ObjectSchemaService(adapter, registry);
|
|
1671
|
+
* const productSchema = await service.getObjectSchema("obj-123");
|
|
1672
|
+
*
|
|
1673
|
+
* console.log(productSchema.attributes); // System + custom attributes
|
|
1674
|
+
* ```
|
|
1675
|
+
*/
|
|
1676
|
+
getObjectSchema(objectId: string): Promise<ObjectDefinition>;
|
|
1677
|
+
/**
|
|
1678
|
+
* Get object schema by name (for system/native objects)
|
|
1679
|
+
*/
|
|
1680
|
+
getObjectSchemaByName(name: string): Promise<ObjectDefinition>;
|
|
1681
|
+
/**
|
|
1682
|
+
* List all object schemas for a tenant
|
|
1683
|
+
*/
|
|
1684
|
+
listObjectSchemas(tenantId: string): Promise<ObjectDefinition[]>;
|
|
1685
|
+
/**
|
|
1686
|
+
* Merge native object from registry with custom attributes from DB
|
|
1687
|
+
* @internal
|
|
1688
|
+
*/
|
|
1689
|
+
private mergeNativeObject;
|
|
1690
|
+
/**
|
|
1691
|
+
* Convert DB object + attributes to ObjectDefinition
|
|
1692
|
+
* @internal
|
|
1693
|
+
*/
|
|
1694
|
+
private convertDBObjectToDefinition;
|
|
1695
|
+
/**
|
|
1696
|
+
* Convert DB attribute to Attribute type
|
|
1697
|
+
* @internal
|
|
1698
|
+
*/
|
|
1699
|
+
private convertDBAttributeToAttribute;
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
/**
|
|
1703
|
+
* Service for managing object records (CRUD operations)
|
|
1704
|
+
* Handles validation, dispatch to correct table, and data consistency
|
|
1705
|
+
*/
|
|
1706
|
+
declare class RecordService {
|
|
1707
|
+
private adapter;
|
|
1708
|
+
private tenantId;
|
|
1709
|
+
private schemaService;
|
|
1710
|
+
private relationService;
|
|
1711
|
+
constructor(adapter: DatabaseAdapter, tenantId: string);
|
|
1712
|
+
/**
|
|
1713
|
+
* Create a new record with validation
|
|
1714
|
+
*
|
|
1715
|
+
* @param objectId - Object UUID
|
|
1716
|
+
* @param data - Record data (attribute values)
|
|
1717
|
+
* @param options - Creation options
|
|
1718
|
+
* @returns Created record with computed completionStatus
|
|
1719
|
+
*
|
|
1720
|
+
* @example
|
|
1721
|
+
* ```typescript
|
|
1722
|
+
* const service = new RecordService(adapter, "tenant-123");
|
|
1723
|
+
*
|
|
1724
|
+
* // Create a complete record (strict validation)
|
|
1725
|
+
* const product = await service.createRecord("obj-product", {
|
|
1726
|
+
* name: "Nike Air Max",
|
|
1727
|
+
* price: 129.99,
|
|
1728
|
+
* status: "active"
|
|
1729
|
+
* });
|
|
1730
|
+
* // → product.completionStatus = "complete"
|
|
1731
|
+
*
|
|
1732
|
+
* // Create a draft record (allows missing required fields)
|
|
1733
|
+
* const draft = await service.createRecord("obj-product", {
|
|
1734
|
+
* name: "Draft Product"
|
|
1735
|
+
* }, { allowDraft: true });
|
|
1736
|
+
* // → draft.completionStatus = "draft"
|
|
1737
|
+
* ```
|
|
1738
|
+
*/
|
|
1739
|
+
createRecord(objectId: string, data: Record<string, unknown>, options?: {
|
|
1740
|
+
/**
|
|
1741
|
+
* Allow creating records with missing required fields.
|
|
1742
|
+
* Format validation still applies to provided values.
|
|
1743
|
+
* @default false
|
|
1744
|
+
*/
|
|
1745
|
+
allowDraft?: boolean;
|
|
1746
|
+
/**
|
|
1747
|
+
* Skip all validation (format + relations).
|
|
1748
|
+
* @default true
|
|
1749
|
+
*/
|
|
1750
|
+
validate?: boolean;
|
|
1751
|
+
/**
|
|
1752
|
+
* Skip relation validation only.
|
|
1753
|
+
* Useful for bulk imports where relations are validated separately.
|
|
1754
|
+
* @default false
|
|
1755
|
+
*/
|
|
1756
|
+
skipRelationValidation?: boolean;
|
|
1757
|
+
skipSystemCheck?: boolean;
|
|
1758
|
+
}): Promise<ObjectRecord>;
|
|
1759
|
+
/**
|
|
1760
|
+
* Get a record by ID
|
|
1761
|
+
*
|
|
1762
|
+
* @param recordId - Record UUID
|
|
1763
|
+
* @param options - Query options
|
|
1764
|
+
* @returns Record or null if not found
|
|
1765
|
+
*/
|
|
1766
|
+
getRecord(recordId: string, options?: {
|
|
1767
|
+
includeSchema?: boolean;
|
|
1768
|
+
}): Promise<ObjectRecord | null>;
|
|
1769
|
+
/**
|
|
1770
|
+
* Get a record by ID or throw if not found
|
|
1771
|
+
*/
|
|
1772
|
+
getRecordOrThrow(recordId: string): Promise<ObjectRecord>;
|
|
1773
|
+
/**
|
|
1774
|
+
* Update a record with validation
|
|
1775
|
+
*
|
|
1776
|
+
* The completion status is automatically recalculated after each update.
|
|
1777
|
+
* A draft record becomes complete when all required fields are filled.
|
|
1778
|
+
*
|
|
1779
|
+
* @param recordId - Record UUID
|
|
1780
|
+
* @param data - Partial data to update
|
|
1781
|
+
* @param options - Update options
|
|
1782
|
+
* @returns Updated record with recalculated completionStatus
|
|
1783
|
+
*
|
|
1784
|
+
* @example
|
|
1785
|
+
* ```typescript
|
|
1786
|
+
* // Update a draft record to make it complete
|
|
1787
|
+
* const updated = await service.updateRecord(draftId, {
|
|
1788
|
+
* price: 99.99,
|
|
1789
|
+
* status: "active"
|
|
1790
|
+
* });
|
|
1791
|
+
* // → updated.completionStatus = "complete" if all required fields now present
|
|
1792
|
+
* ```
|
|
1793
|
+
*/
|
|
1794
|
+
updateRecord(recordId: string, data: Partial<Record<string, unknown>>, options?: {
|
|
1795
|
+
/**
|
|
1796
|
+
* Skip validation entirely (format + relations).
|
|
1797
|
+
* @default true
|
|
1798
|
+
*/
|
|
1799
|
+
validate?: boolean;
|
|
1800
|
+
/**
|
|
1801
|
+
* Allow partial updates without strict validation.
|
|
1802
|
+
* Format validation still applies to provided values.
|
|
1803
|
+
* @default false
|
|
1804
|
+
*/
|
|
1805
|
+
partial?: boolean;
|
|
1806
|
+
/**
|
|
1807
|
+
* Skip relation validation only.
|
|
1808
|
+
* @default false
|
|
1809
|
+
*/
|
|
1810
|
+
skipRelationValidation?: boolean;
|
|
1811
|
+
}): Promise<ObjectRecord>;
|
|
1812
|
+
/**
|
|
1813
|
+
* Delete a record
|
|
1814
|
+
*
|
|
1815
|
+
* @param recordId - Record UUID
|
|
1816
|
+
* @param options - Delete options
|
|
1817
|
+
*/
|
|
1818
|
+
deleteRecord(recordId: string, options?: {
|
|
1819
|
+
checkSystem?: boolean;
|
|
1820
|
+
}): Promise<void>;
|
|
1821
|
+
/**
|
|
1822
|
+
* List records for an object with pagination
|
|
1823
|
+
*
|
|
1824
|
+
* @param objectId - Object UUID
|
|
1825
|
+
* @param options - List options
|
|
1826
|
+
* @returns Records and total count
|
|
1827
|
+
*/
|
|
1828
|
+
listRecords(objectId: string, options?: {
|
|
1829
|
+
limit?: number;
|
|
1830
|
+
offset?: number;
|
|
1831
|
+
orderBy?: string;
|
|
1832
|
+
orderDirection?: "asc" | "desc";
|
|
1833
|
+
}): Promise<{
|
|
1834
|
+
records: ObjectRecord[];
|
|
1835
|
+
total: number;
|
|
1836
|
+
}>;
|
|
1837
|
+
/**
|
|
1838
|
+
* Search records using full-text search
|
|
1839
|
+
*
|
|
1840
|
+
* @param objectId - Object UUID
|
|
1841
|
+
* @param query - Search query
|
|
1842
|
+
* @param options - Search options
|
|
1843
|
+
* @returns Matching records and total count
|
|
1844
|
+
*/
|
|
1845
|
+
searchRecords(objectId: string, query: string, options?: {
|
|
1846
|
+
limit?: number;
|
|
1847
|
+
offset?: number;
|
|
1848
|
+
filters?: Record<string, unknown>;
|
|
1849
|
+
}): Promise<{
|
|
1850
|
+
records: ObjectRecord[];
|
|
1851
|
+
total: number;
|
|
1852
|
+
}>;
|
|
1853
|
+
/**
|
|
1854
|
+
* Validate data against object schema without saving
|
|
1855
|
+
*
|
|
1856
|
+
* @param objectId - Object UUID
|
|
1857
|
+
* @param data - Data to validate
|
|
1858
|
+
* @returns Validation result
|
|
1859
|
+
*/
|
|
1860
|
+
validateData(objectId: string, data: Record<string, unknown>): Promise<ValidationResult>;
|
|
1861
|
+
/**
|
|
1862
|
+
* Compute the completion status for given data without saving.
|
|
1863
|
+
* Useful for UI to show draft/complete status before submitting.
|
|
1864
|
+
*
|
|
1865
|
+
* @param objectId - Object UUID
|
|
1866
|
+
* @param data - Data to check
|
|
1867
|
+
* @returns Computed completion status
|
|
1868
|
+
*/
|
|
1869
|
+
computeStatus(objectId: string, data: Record<string, unknown>): Promise<CompletionStatus>;
|
|
1870
|
+
/**
|
|
1871
|
+
* Refresh the completion status of an existing record.
|
|
1872
|
+
* Useful when schema changes and you need to recompute statuses.
|
|
1873
|
+
*
|
|
1874
|
+
* @param recordId - Record UUID
|
|
1875
|
+
* @returns Updated completion status
|
|
1876
|
+
*/
|
|
1877
|
+
refreshRecordStatus(recordId: string): Promise<CompletionStatus>;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
/**
|
|
1881
|
+
* Result of relation validation
|
|
1882
|
+
*/
|
|
1883
|
+
interface RelationValidationResult {
|
|
1884
|
+
valid: boolean;
|
|
1885
|
+
errors: RelationValidationError[];
|
|
1886
|
+
}
|
|
1887
|
+
/**
|
|
1888
|
+
* Individual relation validation error
|
|
1889
|
+
*/
|
|
1890
|
+
interface RelationValidationError {
|
|
1891
|
+
/** Attribute name */
|
|
1892
|
+
attribute: string;
|
|
1893
|
+
/** Error message */
|
|
1894
|
+
message: string;
|
|
1895
|
+
/** Invalid record IDs */
|
|
1896
|
+
invalidIds?: string[];
|
|
1897
|
+
}
|
|
1898
|
+
/**
|
|
1899
|
+
* Resolved relation option
|
|
1900
|
+
*/
|
|
1901
|
+
interface RelationOption {
|
|
1902
|
+
/** Record ID */
|
|
1903
|
+
id: string;
|
|
1904
|
+
/** Object ID */
|
|
1905
|
+
objectId: string;
|
|
1906
|
+
/** Object name (technical name) */
|
|
1907
|
+
objectName: string;
|
|
1908
|
+
/** Object label (display name) */
|
|
1909
|
+
objectLabel: string;
|
|
1910
|
+
/** Object icon */
|
|
1911
|
+
objectIcon?: string;
|
|
1912
|
+
/** Display label (resolved from titleAttribute) */
|
|
1913
|
+
label: string;
|
|
1914
|
+
/** Additional record data */
|
|
1915
|
+
data?: Record<string, unknown>;
|
|
1916
|
+
}
|
|
1917
|
+
/**
|
|
1918
|
+
* Response for relation options
|
|
1919
|
+
*/
|
|
1920
|
+
interface RelationOptionsResponse {
|
|
1921
|
+
options: RelationOption[];
|
|
1922
|
+
hasMore: boolean;
|
|
1923
|
+
total: number;
|
|
1924
|
+
}
|
|
1925
|
+
/**
|
|
1926
|
+
* Parameters for fetching relation options
|
|
1927
|
+
*/
|
|
1928
|
+
interface GetRelationOptionsParams {
|
|
1929
|
+
/** Search query */
|
|
1930
|
+
query?: string;
|
|
1931
|
+
/** Page number (1-based) */
|
|
1932
|
+
page?: number;
|
|
1933
|
+
/** Page size */
|
|
1934
|
+
pageSize?: number;
|
|
1935
|
+
/** Filter by specific target object */
|
|
1936
|
+
targetObject?: string;
|
|
1937
|
+
}
|
|
1938
|
+
/**
|
|
1939
|
+
* Service for validating relation attributes
|
|
1940
|
+
* Ensures referenced records exist and belong to valid target objects
|
|
1941
|
+
*/
|
|
1942
|
+
declare class RelationService {
|
|
1943
|
+
private adapter;
|
|
1944
|
+
private schemaService;
|
|
1945
|
+
constructor(adapter: DatabaseAdapter, nativeRegistry: typeof registry);
|
|
1946
|
+
/**
|
|
1947
|
+
* Validate all relation attributes in the data
|
|
1948
|
+
*
|
|
1949
|
+
* @param schema - Object schema containing attribute definitions
|
|
1950
|
+
* @param data - Record data to validate
|
|
1951
|
+
* @returns Validation result with errors if any
|
|
1952
|
+
*
|
|
1953
|
+
* @example
|
|
1954
|
+
* ```typescript
|
|
1955
|
+
* const result = await relationService.validateRelations(schema, {
|
|
1956
|
+
* company: "rec-123",
|
|
1957
|
+
* contacts: ["rec-456", "rec-789"]
|
|
1958
|
+
* });
|
|
1959
|
+
*
|
|
1960
|
+
* if (!result.valid) {
|
|
1961
|
+
* console.log(result.errors);
|
|
1962
|
+
* // [{ attribute: "company", message: "Record not found", invalidIds: ["rec-123"] }]
|
|
1963
|
+
* }
|
|
1964
|
+
* ```
|
|
1965
|
+
*/
|
|
1966
|
+
validateRelations(schema: ObjectDefinition, data: Record<string, unknown>): Promise<RelationValidationResult>;
|
|
1967
|
+
/**
|
|
1968
|
+
* Validate a single relation attribute value
|
|
1969
|
+
*/
|
|
1970
|
+
private validateRelationAttribute;
|
|
1971
|
+
/**
|
|
1972
|
+
* Extract IDs from relation value based on cardinality
|
|
1973
|
+
*/
|
|
1974
|
+
private extractIds;
|
|
1975
|
+
/**
|
|
1976
|
+
* Get valid object IDs from relation targets
|
|
1977
|
+
*/
|
|
1978
|
+
private getValidObjectIds;
|
|
1979
|
+
/**
|
|
1980
|
+
* Validate relations and throw if invalid
|
|
1981
|
+
*/
|
|
1982
|
+
validateRelationsOrThrow(schema: ObjectDefinition, data: Record<string, unknown>): Promise<void>;
|
|
1983
|
+
/**
|
|
1984
|
+
* Get available options for a relation attribute
|
|
1985
|
+
* Searches across all target objects defined in the relation
|
|
1986
|
+
*
|
|
1987
|
+
* @param attribute - Relation attribute definition
|
|
1988
|
+
* @param tenantId - Tenant ID for multi-tenant isolation
|
|
1989
|
+
* @param params - Query parameters
|
|
1990
|
+
*
|
|
1991
|
+
* @example
|
|
1992
|
+
* ```typescript
|
|
1993
|
+
* const options = await relationService.getOptions(attribute, "tenant-1", {
|
|
1994
|
+
* query: "nike",
|
|
1995
|
+
* page: 1,
|
|
1996
|
+
* pageSize: 20
|
|
1997
|
+
* });
|
|
1998
|
+
* ```
|
|
1999
|
+
*/
|
|
2000
|
+
getOptions(attribute: RelationAttribute, tenantId: string, params?: GetRelationOptionsParams): Promise<RelationOptionsResponse>;
|
|
2001
|
+
/**
|
|
2002
|
+
* Resolve record IDs to their display labels
|
|
2003
|
+
* Useful for displaying current values in the UI
|
|
2004
|
+
*
|
|
2005
|
+
* @param ids - Record IDs to resolve
|
|
2006
|
+
* @param tenantId - Tenant ID for multi-tenant isolation
|
|
2007
|
+
*
|
|
2008
|
+
* @example
|
|
2009
|
+
* ```typescript
|
|
2010
|
+
* const resolved = await relationService.resolveIds(["rec-1", "rec-2"], "tenant-1");
|
|
2011
|
+
* // [{ id: "rec-1", label: "Nike Air Max", objectName: "products", ... }]
|
|
2012
|
+
* ```
|
|
2013
|
+
*/
|
|
2014
|
+
resolveIds(ids: string[], tenantId: string): Promise<RelationOption[]>;
|
|
2015
|
+
/**
|
|
2016
|
+
* Find a relation attribute by ID
|
|
2017
|
+
*/
|
|
2018
|
+
findAttributeById(attributeId: string): Promise<RelationAttribute | null>;
|
|
2019
|
+
/**
|
|
2020
|
+
* Resolve display label from record values
|
|
2021
|
+
* Uses displayTemplate if provided, otherwise falls back to titleAttribute
|
|
2022
|
+
*/
|
|
2023
|
+
private resolveLabel;
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
/**
|
|
2027
|
+
* Service for managing user profiles
|
|
2028
|
+
* Handles user profile CRUD, auth provider sync, and role management
|
|
2029
|
+
*/
|
|
2030
|
+
declare class UserProfileService {
|
|
2031
|
+
private adapter;
|
|
2032
|
+
private tenantId;
|
|
2033
|
+
constructor(adapter: DatabaseAdapter, tenantId: string);
|
|
2034
|
+
/**
|
|
2035
|
+
* Create a new user profile (typically after first auth)
|
|
2036
|
+
*
|
|
2037
|
+
* @param data - User profile creation data
|
|
2038
|
+
* @returns Created user profile
|
|
2039
|
+
*
|
|
2040
|
+
* @example
|
|
2041
|
+
* ```typescript
|
|
2042
|
+
* const service = new UserProfileService(adapter, "tenant-123");
|
|
2043
|
+
*
|
|
2044
|
+
* // After Supabase auth
|
|
2045
|
+
* const profile = await service.createProfile({
|
|
2046
|
+
* tenantId: "tenant-123",
|
|
2047
|
+
* authId: authUser.id,
|
|
2048
|
+
* email: authUser.email,
|
|
2049
|
+
* firstName: authUser.user_metadata.first_name,
|
|
2050
|
+
* lastName: authUser.user_metadata.last_name,
|
|
2051
|
+
* role: "member",
|
|
2052
|
+
* status: "active"
|
|
2053
|
+
* });
|
|
2054
|
+
* ```
|
|
2055
|
+
*/
|
|
2056
|
+
createProfile(data: CreateUserProfile): Promise<UserProfile>;
|
|
2057
|
+
/**
|
|
2058
|
+
* Get user profile by ID
|
|
2059
|
+
*/
|
|
2060
|
+
getProfile(profileId: string): Promise<UserProfile | null>;
|
|
2061
|
+
/**
|
|
2062
|
+
* Get user profile by ID or throw
|
|
2063
|
+
*/
|
|
2064
|
+
getProfileOrThrow(profileId: string): Promise<UserProfile>;
|
|
2065
|
+
/**
|
|
2066
|
+
* Get user profile by auth provider ID
|
|
2067
|
+
*
|
|
2068
|
+
* @param authId - Auth provider user ID (Supabase, Clerk, etc.)
|
|
2069
|
+
* @returns User profile or null
|
|
2070
|
+
*/
|
|
2071
|
+
getProfileByAuthId(authId: string): Promise<UserProfile | null>;
|
|
2072
|
+
/**
|
|
2073
|
+
* Get or create user profile (idempotent operation)
|
|
2074
|
+
* Useful for auth callbacks - ensures profile exists
|
|
2075
|
+
*
|
|
2076
|
+
* @param authId - Auth provider user ID
|
|
2077
|
+
* @param data - Profile data to create if doesn't exist
|
|
2078
|
+
* @returns Existing or newly created profile
|
|
2079
|
+
*
|
|
2080
|
+
* @example
|
|
2081
|
+
* ```typescript
|
|
2082
|
+
* // In Supabase auth callback
|
|
2083
|
+
* const profile = await service.getOrCreateProfile(
|
|
2084
|
+
* authUser.id,
|
|
2085
|
+
* {
|
|
2086
|
+
* tenantId: "tenant-123",
|
|
2087
|
+
* authId: authUser.id,
|
|
2088
|
+
* email: authUser.email,
|
|
2089
|
+
* role: "member",
|
|
2090
|
+
* status: "active"
|
|
2091
|
+
* }
|
|
2092
|
+
* );
|
|
2093
|
+
* ```
|
|
2094
|
+
*/
|
|
2095
|
+
getOrCreateProfile(authId: string, data: CreateUserProfile): Promise<UserProfile>;
|
|
2096
|
+
/**
|
|
2097
|
+
* Update user profile
|
|
2098
|
+
*/
|
|
2099
|
+
updateProfile(profileId: string, data: UpdateUserProfile): Promise<UserProfile>;
|
|
2100
|
+
/**
|
|
2101
|
+
* Delete user profile
|
|
2102
|
+
*
|
|
2103
|
+
* @param profileId - Profile UUID
|
|
2104
|
+
* @param options - Delete options
|
|
2105
|
+
*/
|
|
2106
|
+
deleteProfile(profileId: string, options?: {
|
|
2107
|
+
checkAdmin?: boolean;
|
|
2108
|
+
}): Promise<void>;
|
|
2109
|
+
/**
|
|
2110
|
+
* List all user profiles for the tenant
|
|
2111
|
+
*/
|
|
2112
|
+
listProfiles(options?: ListOptions): Promise<UserProfile[]>;
|
|
2113
|
+
/**
|
|
2114
|
+
* Update last login timestamp
|
|
2115
|
+
*
|
|
2116
|
+
* @param profileId - Profile UUID
|
|
2117
|
+
*
|
|
2118
|
+
* @example
|
|
2119
|
+
* ```typescript
|
|
2120
|
+
* // After successful auth
|
|
2121
|
+
* await service.updateLastLogin(profile.id);
|
|
2122
|
+
* ```
|
|
2123
|
+
*/
|
|
2124
|
+
updateLastLogin(profileId: string): Promise<void>;
|
|
2125
|
+
/**
|
|
2126
|
+
* Change user role
|
|
2127
|
+
*
|
|
2128
|
+
* @param profileId - Profile UUID
|
|
2129
|
+
* @param newRole - New role
|
|
2130
|
+
*/
|
|
2131
|
+
changeRole(profileId: string, newRole: string): Promise<UserProfile>;
|
|
2132
|
+
/**
|
|
2133
|
+
* Change user status
|
|
2134
|
+
*
|
|
2135
|
+
* @param profileId - Profile UUID
|
|
2136
|
+
* @param newStatus - New status
|
|
2137
|
+
*/
|
|
2138
|
+
changeStatus(profileId: string, newStatus: "active" | "pending" | "inactive" | "suspended"): Promise<UserProfile>;
|
|
2139
|
+
/**
|
|
2140
|
+
* Get user by email
|
|
2141
|
+
*/
|
|
2142
|
+
getProfileByEmail(email: string): Promise<UserProfile | null>;
|
|
2143
|
+
/**
|
|
2144
|
+
* Check if user has role
|
|
2145
|
+
*/
|
|
2146
|
+
hasRole(profileId: string, role: string): Promise<boolean>;
|
|
2147
|
+
/**
|
|
2148
|
+
* Check if user is admin
|
|
2149
|
+
*/
|
|
2150
|
+
isAdmin(profileId: string): Promise<boolean>;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
/**
|
|
2154
|
+
* Result of sync operation
|
|
2155
|
+
*/
|
|
2156
|
+
interface SyncResult {
|
|
2157
|
+
success: boolean;
|
|
2158
|
+
objectsSynced: number;
|
|
2159
|
+
attributesSynced: number;
|
|
2160
|
+
objectsCreated: number;
|
|
2161
|
+
objectsUpdated: number;
|
|
2162
|
+
attributesCreated: number;
|
|
2163
|
+
attributesUpdated: number;
|
|
2164
|
+
attributesDeleted: number;
|
|
2165
|
+
errors: Array<{
|
|
2166
|
+
objectName: string;
|
|
2167
|
+
error: string;
|
|
2168
|
+
}>;
|
|
2169
|
+
}
|
|
2170
|
+
/**
|
|
2171
|
+
* Sync options
|
|
2172
|
+
*/
|
|
2173
|
+
interface SyncOptions {
|
|
2174
|
+
dryRun?: boolean;
|
|
2175
|
+
verbose?: boolean;
|
|
2176
|
+
tenantId?: string;
|
|
2177
|
+
}
|
|
2178
|
+
/**
|
|
2179
|
+
* Sync native objects from registry to database
|
|
2180
|
+
*
|
|
2181
|
+
* This function:
|
|
2182
|
+
* 1. Reads all registered native objects from the registry
|
|
2183
|
+
* 2. Upserts them into the database (objects + attributes tables)
|
|
2184
|
+
* 3. Marks them as system=true for protection
|
|
2185
|
+
* 4. Removes attributes that were deleted from code
|
|
2186
|
+
*
|
|
2187
|
+
* @param adapter - Database adapter implementing DatabaseAdapter interface
|
|
2188
|
+
* @param nativeRegistry - Registry containing native objects
|
|
2189
|
+
* @param options - Sync options (dryRun, verbose, tenantId)
|
|
2190
|
+
* @returns Sync result with statistics
|
|
2191
|
+
*
|
|
2192
|
+
* @example
|
|
2193
|
+
* ```typescript
|
|
2194
|
+
* import { syncNativeObjects } from "@stndrds/schema/runtime";
|
|
2195
|
+
* import { registry } from "./objects/native";
|
|
2196
|
+
* import { drizzleAdapter } from "./db/adapter";
|
|
2197
|
+
*
|
|
2198
|
+
* const result = await syncNativeObjects(drizzleAdapter, registry, {
|
|
2199
|
+
* verbose: true,
|
|
2200
|
+
* tenantId: "default"
|
|
2201
|
+
* });
|
|
2202
|
+
*
|
|
2203
|
+
* if (result.success) {
|
|
2204
|
+
* console.log(`✓ Synced ${result.objectsSynced} objects`);
|
|
2205
|
+
* } else {
|
|
2206
|
+
* console.error("Sync errors:", result.errors);
|
|
2207
|
+
* }
|
|
2208
|
+
* ```
|
|
2209
|
+
*/
|
|
2210
|
+
declare function syncNativeObjects(adapter: DatabaseAdapter, nativeRegistry: typeof registry, options?: SyncOptions): Promise<SyncResult>;
|
|
2211
|
+
/**
|
|
2212
|
+
* Verify that all native objects are synced to database
|
|
2213
|
+
*
|
|
2214
|
+
* @param adapter - Database adapter
|
|
2215
|
+
* @param nativeRegistry - Registry containing native objects
|
|
2216
|
+
* @returns true if all objects are synced, false otherwise
|
|
2217
|
+
*
|
|
2218
|
+
* @example
|
|
2219
|
+
* ```typescript
|
|
2220
|
+
* const isSynced = await verifyNativeObjectsSync(adapter, registry);
|
|
2221
|
+
* if (!isSynced) {
|
|
2222
|
+
* console.warn("Native objects not synced, running sync...");
|
|
2223
|
+
* await syncNativeObjects(adapter, registry);
|
|
2224
|
+
* }
|
|
2225
|
+
* ```
|
|
2226
|
+
*/
|
|
2227
|
+
declare function verifyNativeObjectsSync(adapter: DatabaseAdapter, nativeRegistry: typeof registry): Promise<boolean>;
|
|
2228
|
+
/**
|
|
2229
|
+
* Get sync statistics without modifying database
|
|
2230
|
+
*
|
|
2231
|
+
* @param adapter - Database adapter
|
|
2232
|
+
* @param nativeRegistry - Registry containing native objects
|
|
2233
|
+
* @returns Sync result (dry run)
|
|
2234
|
+
*/
|
|
2235
|
+
declare function getSyncPreview(adapter: DatabaseAdapter, nativeRegistry: typeof registry): Promise<SyncResult>;
|
|
2236
|
+
|
|
2237
|
+
export { type UserRole as $, type Attribute as A, type BaseAttribute as B, type Currency as C, type DateAttribute as D, type File as E, type FileAttribute as F, type CreateFile as G, type UpdateFile as H, type GeocodingSuggestion as I, type GeocodingAutocompleteParams as J, type ReverseGeocodingParams as K, type Location as L, type MultiselectAttribute as M, type NumberAttribute as N, type Option as O, type Phone as P, type GeocodingParams as Q, type RelationOnDelete as R, type StatusAttribute as S, type TextAttribute as T, type UserAttribute as U, type GeocodingAdapter as V, NoopGeocodingAdapter as W, type Timestamps as X, type ObjectAttribute as Y, type CompletionStatus as Z, type ObjectRecord as _, type SelectAttribute as a, type DBObject as a$, type UserStatus as a0, type UserProfile as a1, type CreateUserProfile as a2, type UpdateUserProfile as a3, type Uuid as a4, type TenantId as a5, generateId as a6, generatePrefixedId as a7, registry as a8, createTextValidator as a9, isRecordComplete as aA, computeRecordStatus as aB, type DatabaseAdapter as aC, createMockAdapter as aD, type ObjectsRepository as aE, type AttributesRepository as aF, type UserProfilesRepository as aG, type FilesRepository as aH, type ObjectRecordsRepository as aI, FileService as aJ, GeocodingService as aK, type CreateCustomObjectInput as aL, type AddAttributeInput as aM, ObjectSchemaService as aN, RecordService as aO, type RelationValidationResult as aP, type RelationValidationError as aQ, type RelationOption as aR, type RelationOptionsResponse as aS, type GetRelationOptionsParams as aT, RelationService as aU, UserProfileService as aV, type SyncResult as aW, type SyncOptions as aX, syncNativeObjects as aY, verifyNativeObjectsSync as aZ, getSyncPreview as a_, createNumberValidator as aa, createCheckboxValidator as ab, createDateValidator as ac, createPhoneValidator as ad, createCurrencyValidator as ae, createStatusValidator as af, createSelectValidator as ag, createMultiselectValidator as ah, createLocationValidator as ai, createTimestampValidator as aj, createFileValidator as ak, createUserValidator as al, createSingleRelationValidator as am, createMultiRelationValidator as an, createRelationValidator as ao, createRatingValidator as ap, createAttributeValidator as aq, createObjectValidator as ar, type ValidationResult as as, validateAttribute as at, validateObject as au, validateObjectOrThrow as av, createDraftValidator as aw, validateDraft as ax, validateDraftOrThrow as ay, getMissingRequiredAttributes as az, type TextAreaAttribute as b, type CreateDBObject as b0, type UpdateDBObject as b1, type UpsertDBObject as b2, type DBAttribute as b3, type CreateDBAttribute as b4, type UpdateDBAttribute as b5, type UpsertDBAttribute as b6, type CreateObjectRecord as b7, type ListOptions as b8, type SearchOptions as b9, type FileListOptions as ba, type OperationResult as bb, type CheckboxAttribute as c, type PhoneAttribute as d, type CurrencyAttribute as e, type LocationAttribute as f, type TimestampAttribute as g, type SingleRelationAttribute as h, type MultiRelationAttribute as i, type RelationTarget as j, type RatingAttribute as k, type ObjectDefinition as l, type AttributeType as m, type StatusGroup as n, type AttributeGroup as o, type NumberUnit as p, type DateFormat as q, type DateValue as r, type LocationGranularity as s, type DocumentType as t, type DocumentFace as u, type DocumentTypeConfig as v, type FileVerificationConfig as w, type RelationAttribute as x, type StorageProvider as y, type FileVisibility as z };
|