@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.
Files changed (128) hide show
  1. package/dist/chunk-3ABIOLKO.mjs +4624 -0
  2. package/dist/chunk-3IRX2BDY.mjs +3970 -0
  3. package/dist/chunk-4OTLPWSP.mjs +4448 -0
  4. package/dist/chunk-54ODQBUN.mjs +3867 -0
  5. package/dist/chunk-6HIA3FR2.mjs +4230 -0
  6. package/dist/chunk-6P3XHNLD.mjs +4171 -0
  7. package/dist/chunk-7LJECNAS.mjs +4167 -0
  8. package/dist/chunk-A2WNLUKV.mjs +4475 -0
  9. package/dist/chunk-AA3234RM.mjs +4475 -0
  10. package/dist/chunk-ADNXDLLD.mjs +3136 -0
  11. package/dist/chunk-B4DCDQUI.mjs +4695 -0
  12. package/dist/chunk-B4PSXY6I.mjs +4527 -0
  13. package/dist/chunk-BJHJBZCM.mjs +4228 -0
  14. package/dist/chunk-C3ZWTO6G.mjs +4474 -0
  15. package/dist/chunk-CLOGNKDD.mjs +4040 -0
  16. package/dist/chunk-EW4V63PA.mjs +3053 -0
  17. package/dist/chunk-FR2LCO6R.mjs +2485 -0
  18. package/dist/chunk-GJSF2RKL.mjs +2786 -0
  19. package/dist/chunk-GO5NPP2X.mjs +4726 -0
  20. package/dist/chunk-H3ZYJUDS.mjs +3050 -0
  21. package/dist/chunk-IDDLSFSK.mjs +4230 -0
  22. package/dist/chunk-JRADUJQ7.mjs +4726 -0
  23. package/dist/chunk-NEDR6N7R.mjs +3118 -0
  24. package/dist/chunk-NESPRMDF.mjs +2482 -0
  25. package/dist/chunk-NWFGRJBW.mjs +4612 -0
  26. package/dist/chunk-NXJ57GSN.mjs +2918 -0
  27. package/dist/chunk-O4C5FCTS.mjs +3961 -0
  28. package/dist/chunk-O4PRB27Q.mjs +2513 -0
  29. package/dist/chunk-OJDFNUCR.mjs +4463 -0
  30. package/dist/chunk-OSEKVBHC.mjs +4627 -0
  31. package/dist/chunk-QX4U6U6K.mjs +2484 -0
  32. package/dist/chunk-RMDQ6LKV.mjs +3046 -0
  33. package/dist/chunk-SBXKDATH.mjs +2673 -0
  34. package/dist/chunk-SKMP3AP3.mjs +2918 -0
  35. package/dist/chunk-STMS7WZD.mjs +2623 -0
  36. package/dist/chunk-T3T6PTFG.mjs +3057 -0
  37. package/dist/chunk-TPW72RAH.mjs +4624 -0
  38. package/dist/chunk-TUQEGNGV.mjs +2534 -0
  39. package/dist/chunk-TVKFS3YN.mjs +2449 -0
  40. package/dist/chunk-TZTH3BHG.mjs +3110 -0
  41. package/dist/chunk-W6MU3XPG.mjs +4612 -0
  42. package/dist/chunk-WL7Z3YFR.mjs +4603 -0
  43. package/dist/chunk-XNVVYHH3.mjs +4602 -0
  44. package/dist/chunk-XTA3WY64.mjs +2918 -0
  45. package/dist/chunk-YV7DEZFZ.mjs +2528 -0
  46. package/dist/chunk-ZLJPJND6.mjs +4474 -0
  47. package/dist/chunk-ZNZXTCEX.mjs +4234 -0
  48. package/dist/index.d.mts +1222 -0
  49. package/dist/index.d.ts +1222 -0
  50. package/dist/index.js +5320 -0
  51. package/dist/index.mjs +635 -0
  52. package/dist/runtime-2iKarXtl.d.mts +1924 -0
  53. package/dist/runtime-2iKarXtl.d.ts +1924 -0
  54. package/dist/runtime-4l2ddHZ7.d.mts +2242 -0
  55. package/dist/runtime-4l2ddHZ7.d.ts +2243 -0
  56. package/dist/runtime-8hKS6zAv.d.mts +2226 -0
  57. package/dist/runtime-8hKS6zAv.d.ts +2226 -0
  58. package/dist/runtime-B6yjtoR3.d.mts +4142 -0
  59. package/dist/runtime-B6yjtoR3.d.ts +4142 -0
  60. package/dist/runtime-BGCShrZB.d.mts +2001 -0
  61. package/dist/runtime-BGCShrZB.d.ts +2001 -0
  62. package/dist/runtime-BRW4NGAk.d.mts +1668 -0
  63. package/dist/runtime-BRW4NGAk.d.ts +1668 -0
  64. package/dist/runtime-BnfBr314.d.mts +1683 -0
  65. package/dist/runtime-BnfBr314.d.ts +1683 -0
  66. package/dist/runtime-BrqhiJUF.d.mts +4151 -0
  67. package/dist/runtime-BrqhiJUF.d.ts +4151 -0
  68. package/dist/runtime-Bvj8c-BE.d.mts +4277 -0
  69. package/dist/runtime-Bvj8c-BE.d.ts +4277 -0
  70. package/dist/runtime-C03qT4qU.d.mts +4267 -0
  71. package/dist/runtime-C03qT4qU.d.ts +4267 -0
  72. package/dist/runtime-CaCZ7mSf.d.mts +2974 -0
  73. package/dist/runtime-CaCZ7mSf.d.ts +2974 -0
  74. package/dist/runtime-CaIzNX0Z.d.mts +4091 -0
  75. package/dist/runtime-CaIzNX0Z.d.ts +4091 -0
  76. package/dist/runtime-ChPTgmLP.d.mts +4320 -0
  77. package/dist/runtime-ChPTgmLP.d.ts +4320 -0
  78. package/dist/runtime-CnImZ1Vv.d.mts +4267 -0
  79. package/dist/runtime-CnImZ1Vv.d.ts +4267 -0
  80. package/dist/runtime-Cp-B26Nj.d.mts +2890 -0
  81. package/dist/runtime-Cp-B26Nj.d.ts +2890 -0
  82. package/dist/runtime-Cq8jfk3c.d.mts +4277 -0
  83. package/dist/runtime-Cq8jfk3c.d.ts +4277 -0
  84. package/dist/runtime-CqDFXhhP.d.mts +1685 -0
  85. package/dist/runtime-CqDFXhhP.d.ts +1685 -0
  86. package/dist/runtime-CqtpZLdL.d.mts +4280 -0
  87. package/dist/runtime-CqtpZLdL.d.ts +4280 -0
  88. package/dist/runtime-D-4DblaZ.d.mts +4147 -0
  89. package/dist/runtime-D-4DblaZ.d.ts +4147 -0
  90. package/dist/runtime-D59sSqNl.d.mts +4146 -0
  91. package/dist/runtime-D59sSqNl.d.ts +4146 -0
  92. package/dist/runtime-DEfPk3wT.d.mts +1840 -0
  93. package/dist/runtime-DEfPk3wT.d.ts +1840 -0
  94. package/dist/runtime-DGV-7vES.d.mts +1685 -0
  95. package/dist/runtime-DGV-7vES.d.ts +1685 -0
  96. package/dist/runtime-DNacghqc.d.mts +3971 -0
  97. package/dist/runtime-DNacghqc.d.ts +3971 -0
  98. package/dist/runtime-DPLsUHYK.d.mts +3977 -0
  99. package/dist/runtime-DPLsUHYK.d.ts +3977 -0
  100. package/dist/runtime-DTxCw60F.d.mts +2973 -0
  101. package/dist/runtime-DTxCw60F.d.ts +2973 -0
  102. package/dist/runtime-DUXJ-zNS.d.mts +2788 -0
  103. package/dist/runtime-DUXJ-zNS.d.ts +2788 -0
  104. package/dist/runtime-DbljInhV.d.mts +2237 -0
  105. package/dist/runtime-DbljInhV.d.ts +2237 -0
  106. package/dist/runtime-DcH3y6Yu.d.mts +4272 -0
  107. package/dist/runtime-DcH3y6Yu.d.ts +4272 -0
  108. package/dist/runtime-DdBFz85g.d.mts +4229 -0
  109. package/dist/runtime-DdBFz85g.d.ts +4229 -0
  110. package/dist/runtime-DjMWhjkm.d.mts +4321 -0
  111. package/dist/runtime-DjMWhjkm.d.ts +4321 -0
  112. package/dist/runtime-Djz3fOBE.d.mts +2078 -0
  113. package/dist/runtime-Djz3fOBE.d.ts +2078 -0
  114. package/dist/runtime-Dli8g3Aq.d.mts +2082 -0
  115. package/dist/runtime-Dli8g3Aq.d.ts +2082 -0
  116. package/dist/runtime-a8J378im.d.mts +4123 -0
  117. package/dist/runtime-a8J378im.d.ts +4123 -0
  118. package/dist/runtime-dp3rb3Lf.d.mts +2968 -0
  119. package/dist/runtime-dp3rb3Lf.d.ts +2968 -0
  120. package/dist/runtime-iWXlSN_H.d.mts +1683 -0
  121. package/dist/runtime-iWXlSN_H.d.ts +1683 -0
  122. package/dist/runtime-yMql0npY.d.mts +4321 -0
  123. package/dist/runtime-yMql0npY.d.ts +4321 -0
  124. package/dist/runtime.d.mts +3 -0
  125. package/dist/runtime.d.ts +3 -0
  126. package/dist/runtime.js +3626 -0
  127. package/dist/runtime.mjs +48 -0
  128. package/package.json +58 -0
@@ -0,0 +1,2449 @@
1
+ // src/utils.ts
2
+ function generateId() {
3
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
4
+ return crypto.randomUUID();
5
+ }
6
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
7
+ const r = Math.random() * 16 | 0;
8
+ const v = c === "x" ? r : r & 3 | 8;
9
+ return v.toString(16);
10
+ });
11
+ }
12
+ function generatePrefixedId(prefix) {
13
+ return `${prefix}_${generateId()}`;
14
+ }
15
+
16
+ // src/runtime/mock-adapter.ts
17
+ function createMockObjectsRepository(stores) {
18
+ return {
19
+ findById(id) {
20
+ return Promise.resolve(stores.objects.get(id) ?? null);
21
+ },
22
+ findByName(tenantId, name) {
23
+ for (const obj of stores.objects.values()) {
24
+ if (obj.tenantId === tenantId && obj.name === name) {
25
+ return Promise.resolve(obj);
26
+ }
27
+ }
28
+ return Promise.resolve(null);
29
+ },
30
+ findSystemByName(name) {
31
+ for (const obj of stores.objects.values()) {
32
+ if (obj.system && obj.name === name) {
33
+ return Promise.resolve(obj);
34
+ }
35
+ }
36
+ return Promise.resolve(null);
37
+ },
38
+ create(data) {
39
+ const obj = {
40
+ id: generateId(),
41
+ tenantId: data.tenantId,
42
+ name: data.name,
43
+ label: data.label,
44
+ description: data.description,
45
+ system: data.system ?? false,
46
+ metadata: data.metadata,
47
+ createdAt: /* @__PURE__ */ new Date(),
48
+ updatedAt: /* @__PURE__ */ new Date()
49
+ };
50
+ stores.objects.set(obj.id, obj);
51
+ return Promise.resolve(obj);
52
+ },
53
+ update(id, data) {
54
+ const existing = stores.objects.get(id);
55
+ if (!existing) {
56
+ return Promise.reject(new Error(`Object ${id} not found`));
57
+ }
58
+ const updated = {
59
+ ...existing,
60
+ ...data,
61
+ updatedAt: /* @__PURE__ */ new Date()
62
+ };
63
+ stores.objects.set(id, updated);
64
+ return Promise.resolve(updated);
65
+ },
66
+ delete(id) {
67
+ stores.objects.delete(id);
68
+ return Promise.resolve();
69
+ },
70
+ list(tenantId) {
71
+ const results = Array.from(stores.objects.values()).filter(
72
+ (obj) => obj.tenantId === tenantId
73
+ );
74
+ return Promise.resolve(results);
75
+ },
76
+ upsert(data) {
77
+ for (const obj of stores.objects.values()) {
78
+ if (obj.system && obj.name === data.name) {
79
+ const updated = {
80
+ ...obj,
81
+ label: data.label,
82
+ description: data.description,
83
+ metadata: data.metadata,
84
+ updatedAt: /* @__PURE__ */ new Date()
85
+ };
86
+ stores.objects.set(obj.id, updated);
87
+ return Promise.resolve(updated);
88
+ }
89
+ }
90
+ const newObj = {
91
+ id: generateId(),
92
+ tenantId: data.tenantId,
93
+ name: data.name,
94
+ label: data.label,
95
+ description: data.description,
96
+ system: data.system,
97
+ metadata: data.metadata,
98
+ createdAt: /* @__PURE__ */ new Date(),
99
+ updatedAt: /* @__PURE__ */ new Date()
100
+ };
101
+ stores.objects.set(newObj.id, newObj);
102
+ return Promise.resolve(newObj);
103
+ }
104
+ };
105
+ }
106
+ function createMockAttributesRepository(stores) {
107
+ return {
108
+ findById(id) {
109
+ return Promise.resolve(stores.attributes.get(id) ?? null);
110
+ },
111
+ findByObjectId(objectId) {
112
+ const results = Array.from(stores.attributes.values()).filter(
113
+ (attr) => attr.objectId === objectId
114
+ );
115
+ return Promise.resolve(results);
116
+ },
117
+ create(data) {
118
+ const attr = {
119
+ id: generateId(),
120
+ objectId: data.objectId,
121
+ name: data.name,
122
+ label: data.label,
123
+ type: data.type,
124
+ system: data.system ?? false,
125
+ required: data.required ?? false,
126
+ unique: data.unique ?? false,
127
+ orderIndex: data.orderIndex ?? 0,
128
+ config: data.config ?? {},
129
+ createdAt: /* @__PURE__ */ new Date(),
130
+ updatedAt: /* @__PURE__ */ new Date()
131
+ };
132
+ stores.attributes.set(attr.id, attr);
133
+ return Promise.resolve(attr);
134
+ },
135
+ update(id, data) {
136
+ const existing = stores.attributes.get(id);
137
+ if (!existing) {
138
+ return Promise.reject(new Error(`Attribute ${id} not found`));
139
+ }
140
+ const updated = {
141
+ ...existing,
142
+ ...data,
143
+ updatedAt: /* @__PURE__ */ new Date()
144
+ };
145
+ stores.attributes.set(id, updated);
146
+ return Promise.resolve(updated);
147
+ },
148
+ delete(id) {
149
+ stores.attributes.delete(id);
150
+ return Promise.resolve();
151
+ },
152
+ deleteByNames(objectId, excludeNames) {
153
+ let count = 0;
154
+ for (const [id, attr] of stores.attributes.entries()) {
155
+ if (attr.objectId === objectId && !excludeNames.includes(attr.name)) {
156
+ stores.attributes.delete(id);
157
+ count++;
158
+ }
159
+ }
160
+ return Promise.resolve(count);
161
+ },
162
+ upsert(data) {
163
+ for (const attr of stores.attributes.values()) {
164
+ if (attr.objectId === data.objectId && attr.name === data.name) {
165
+ const updated = {
166
+ ...attr,
167
+ label: data.label ?? attr.label,
168
+ type: data.type ?? attr.type,
169
+ system: data.system ?? attr.system,
170
+ required: data.required ?? attr.required,
171
+ unique: data.unique ?? attr.unique,
172
+ orderIndex: data.orderIndex ?? attr.orderIndex,
173
+ config: data.config ?? attr.config,
174
+ updatedAt: /* @__PURE__ */ new Date()
175
+ };
176
+ stores.attributes.set(attr.id, updated);
177
+ return Promise.resolve(updated);
178
+ }
179
+ }
180
+ return this.create(data);
181
+ }
182
+ };
183
+ }
184
+ function createMockUserProfilesRepository(stores) {
185
+ return {
186
+ findById(id) {
187
+ return Promise.resolve(stores.userProfiles.get(id) ?? null);
188
+ },
189
+ findByAuthId(authId) {
190
+ for (const profile of stores.userProfiles.values()) {
191
+ if (profile.authId === authId) {
192
+ return Promise.resolve(profile);
193
+ }
194
+ }
195
+ return Promise.resolve(null);
196
+ },
197
+ findByEmail(tenantId, email) {
198
+ for (const profile of stores.userProfiles.values()) {
199
+ if (profile.tenantId === tenantId && profile.email === email) {
200
+ return Promise.resolve(profile);
201
+ }
202
+ }
203
+ return Promise.resolve(null);
204
+ },
205
+ create(data) {
206
+ const profile = {
207
+ id: generateId(),
208
+ tenantId: data.tenantId,
209
+ authId: data.authId,
210
+ email: data.email,
211
+ firstName: data.firstName,
212
+ lastName: data.lastName,
213
+ avatarUrl: data.avatarUrl,
214
+ role: data.role ?? "member",
215
+ status: data.status ?? "active",
216
+ createdAt: /* @__PURE__ */ new Date(),
217
+ updatedAt: /* @__PURE__ */ new Date()
218
+ };
219
+ stores.userProfiles.set(profile.id, profile);
220
+ return Promise.resolve(profile);
221
+ },
222
+ update(id, data) {
223
+ const existing = stores.userProfiles.get(id);
224
+ if (!existing) {
225
+ return Promise.reject(new Error(`UserProfile ${id} not found`));
226
+ }
227
+ const updated = {
228
+ ...existing,
229
+ ...data,
230
+ updatedAt: /* @__PURE__ */ new Date()
231
+ };
232
+ stores.userProfiles.set(id, updated);
233
+ return Promise.resolve(updated);
234
+ },
235
+ delete(id) {
236
+ stores.userProfiles.delete(id);
237
+ return Promise.resolve();
238
+ },
239
+ list(tenantId, options) {
240
+ let results = Array.from(stores.userProfiles.values()).filter((p) => p.tenantId === tenantId);
241
+ if (options?.limit) {
242
+ results = results.slice(options.offset ?? 0, (options.offset ?? 0) + options.limit);
243
+ }
244
+ return Promise.resolve(results);
245
+ },
246
+ updateLastLogin(id) {
247
+ const profile = stores.userProfiles.get(id);
248
+ if (profile) {
249
+ profile.lastLoginAt = /* @__PURE__ */ new Date();
250
+ stores.userProfiles.set(id, profile);
251
+ }
252
+ return Promise.resolve();
253
+ }
254
+ };
255
+ }
256
+ function createMockFilesRepository(stores) {
257
+ return {
258
+ findById(id) {
259
+ const file2 = stores.files.get(id);
260
+ if (file2?.deletedAt) return Promise.resolve(null);
261
+ return Promise.resolve(file2 ?? null);
262
+ },
263
+ create(data) {
264
+ const file2 = {
265
+ id: generateId(),
266
+ tenantId: data.tenantId,
267
+ name: data.name,
268
+ originalName: data.originalName,
269
+ mimeType: data.mimeType,
270
+ size: data.size,
271
+ storageProvider: data.storageProvider,
272
+ storagePath: data.storagePath,
273
+ storageBucket: data.storageBucket,
274
+ url: data.url,
275
+ uploadedBy: data.uploadedBy,
276
+ folderPath: data.folderPath,
277
+ tags: data.tags,
278
+ visibility: data.visibility ?? "private",
279
+ allowedUsers: data.allowedUsers,
280
+ createdAt: /* @__PURE__ */ new Date(),
281
+ updatedAt: /* @__PURE__ */ new Date()
282
+ };
283
+ stores.files.set(file2.id, file2);
284
+ return Promise.resolve(file2);
285
+ },
286
+ update(id, data) {
287
+ const existing = stores.files.get(id);
288
+ if (!existing) {
289
+ return Promise.reject(new Error(`File ${id} not found`));
290
+ }
291
+ const updated = {
292
+ ...existing,
293
+ ...data,
294
+ updatedAt: /* @__PURE__ */ new Date()
295
+ };
296
+ stores.files.set(id, updated);
297
+ return Promise.resolve(updated);
298
+ },
299
+ delete(id) {
300
+ const file2 = stores.files.get(id);
301
+ if (file2) {
302
+ file2.deletedAt = /* @__PURE__ */ new Date();
303
+ stores.files.set(id, file2);
304
+ }
305
+ return Promise.resolve();
306
+ },
307
+ hardDelete(id) {
308
+ stores.files.delete(id);
309
+ return Promise.resolve();
310
+ },
311
+ list(tenantId, options) {
312
+ let results = Array.from(stores.files.values()).filter(
313
+ (f) => f.tenantId === tenantId && !f.deletedAt
314
+ );
315
+ if (options?.mimeType) {
316
+ results = results.filter((f) => f.mimeType === options.mimeType);
317
+ }
318
+ if (options?.limit) {
319
+ results = results.slice(options.offset ?? 0, (options.offset ?? 0) + options.limit);
320
+ }
321
+ return Promise.resolve(results);
322
+ },
323
+ findByFolder(tenantId, folderPath) {
324
+ const results = Array.from(stores.files.values()).filter(
325
+ (f) => f.tenantId === tenantId && f.folderPath === folderPath && !f.deletedAt
326
+ );
327
+ return Promise.resolve(results);
328
+ },
329
+ findByUploader(uploadedBy) {
330
+ const results = Array.from(stores.files.values()).filter(
331
+ (f) => f.uploadedBy === uploadedBy && !f.deletedAt
332
+ );
333
+ return Promise.resolve(results);
334
+ }
335
+ };
336
+ }
337
+ function createMockObjectRecordsRepository(stores) {
338
+ return {
339
+ findById(id) {
340
+ const internal = stores.objectRecords.get(id);
341
+ if (!internal) return Promise.resolve(null);
342
+ const { tenantId: _, ...record } = internal;
343
+ return Promise.resolve(record);
344
+ },
345
+ create(data) {
346
+ const internal = {
347
+ id: generateId(),
348
+ tenantId: data.tenantId,
349
+ objectId: data.objectId,
350
+ values: data.data,
351
+ createdAt: /* @__PURE__ */ new Date(),
352
+ updatedAt: /* @__PURE__ */ new Date()
353
+ };
354
+ stores.objectRecords.set(internal.id, internal);
355
+ const { tenantId: _, ...record } = internal;
356
+ return Promise.resolve(record);
357
+ },
358
+ update(id, data) {
359
+ const existing = stores.objectRecords.get(id);
360
+ if (!existing) {
361
+ return Promise.reject(new Error(`ObjectRecord ${id} not found`));
362
+ }
363
+ const updated = {
364
+ ...existing,
365
+ values: { ...existing.values, ...data },
366
+ updatedAt: /* @__PURE__ */ new Date()
367
+ };
368
+ stores.objectRecords.set(id, updated);
369
+ const { tenantId: _, ...record } = updated;
370
+ return Promise.resolve(record);
371
+ },
372
+ delete(id) {
373
+ stores.objectRecords.delete(id);
374
+ return Promise.resolve();
375
+ },
376
+ list(tenantId, objectId, options) {
377
+ let results = Array.from(stores.objectRecords.values()).filter(
378
+ (r) => r.tenantId === tenantId && r.objectId === objectId
379
+ );
380
+ const total = results.length;
381
+ if (options?.limit) {
382
+ results = results.slice(options.offset ?? 0, (options.offset ?? 0) + options.limit);
383
+ }
384
+ const records = results.map(({ tenantId: _, ...r }) => r);
385
+ return Promise.resolve({ records, total });
386
+ },
387
+ search(tenantId, objectId, query, options) {
388
+ const lowerQuery = query.toLowerCase();
389
+ let results = Array.from(stores.objectRecords.values()).filter((r) => {
390
+ if (r.tenantId !== tenantId || r.objectId !== objectId) return false;
391
+ return Object.values(r.values).some(
392
+ (val) => String(val).toLowerCase().includes(lowerQuery)
393
+ );
394
+ });
395
+ const total = results.length;
396
+ if (options?.limit) {
397
+ results = results.slice(options.offset ?? 0, (options.offset ?? 0) + options.limit);
398
+ }
399
+ const records = results.map(({ tenantId: _, ...r }) => r);
400
+ return Promise.resolve({ records, total });
401
+ }
402
+ };
403
+ }
404
+ function createMockAdapter() {
405
+ const stores = {
406
+ objects: /* @__PURE__ */ new Map(),
407
+ attributes: /* @__PURE__ */ new Map(),
408
+ userProfiles: /* @__PURE__ */ new Map(),
409
+ files: /* @__PURE__ */ new Map(),
410
+ objectRecords: /* @__PURE__ */ new Map()
411
+ };
412
+ const adapter = {
413
+ objects: createMockObjectsRepository(stores),
414
+ attributes: createMockAttributesRepository(stores),
415
+ userProfiles: createMockUserProfilesRepository(stores),
416
+ files: createMockFilesRepository(stores),
417
+ objectRecords: createMockObjectRecordsRepository(stores),
418
+ async transaction(callback) {
419
+ return await callback(adapter);
420
+ },
421
+ // Expose stores for testing inspection
422
+ _stores: stores,
423
+ // Reset all stores (useful between tests)
424
+ reset() {
425
+ stores.objects.clear();
426
+ stores.attributes.clear();
427
+ stores.userProfiles.clear();
428
+ stores.files.clear();
429
+ stores.objectRecords.clear();
430
+ }
431
+ };
432
+ return adapter;
433
+ }
434
+
435
+ // src/runtime/services/file.service.ts
436
+ var FileService = class {
437
+ constructor(adapter, tenantId) {
438
+ this.adapter = adapter;
439
+ this.tenantId = tenantId;
440
+ }
441
+ /**
442
+ * Create a new file record (after upload to storage)
443
+ *
444
+ * @param data - File metadata
445
+ * @returns Created file record
446
+ *
447
+ * @example
448
+ * ```typescript
449
+ * const service = new FileService(adapter, "tenant-123");
450
+ *
451
+ * // After uploading to S3
452
+ * const file = await service.createFile({
453
+ * tenantId: "tenant-123",
454
+ * name: "contract-2025.pdf",
455
+ * originalName: "Contract Acme Corp 2025.pdf",
456
+ * mimeType: "application/pdf",
457
+ * size: 2458624,
458
+ * storageProvider: "s3",
459
+ * storagePath: "tenants/123/files/2025/contract.pdf",
460
+ * storageBucket: "my-app-files",
461
+ * url: "https://cdn.example.com/files/file-123",
462
+ * uploadedBy: "profile-456",
463
+ * visibility: "private"
464
+ * });
465
+ * ```
466
+ */
467
+ async createFile(data) {
468
+ if (data.tenantId !== this.tenantId) {
469
+ throw new Error(
470
+ `Tenant mismatch: service initialized with "${this.tenantId}" but data has "${data.tenantId}"`
471
+ );
472
+ }
473
+ return await this.adapter.files.create(data);
474
+ }
475
+ /**
476
+ * Get file by ID
477
+ */
478
+ async getFile(fileId) {
479
+ const file2 = await this.adapter.files.findById(fileId);
480
+ if (file2?.deletedAt) {
481
+ return null;
482
+ }
483
+ return file2;
484
+ }
485
+ /**
486
+ * Get file by ID or throw
487
+ */
488
+ async getFileOrThrow(fileId) {
489
+ const file2 = await this.getFile(fileId);
490
+ if (!file2) {
491
+ throw new Error(`File with id "${fileId}" not found`);
492
+ }
493
+ return file2;
494
+ }
495
+ /**
496
+ * Update file metadata
497
+ *
498
+ * @param fileId - File UUID
499
+ * @param data - Data to update
500
+ * @returns Updated file
501
+ */
502
+ async updateFile(fileId, data) {
503
+ await this.getFileOrThrow(fileId);
504
+ return await this.adapter.files.update(fileId, data);
505
+ }
506
+ /**
507
+ * Delete file (soft delete)
508
+ *
509
+ * @param fileId - File UUID
510
+ * @param options - Delete options
511
+ */
512
+ async deleteFile(fileId, options) {
513
+ if (options?.checkOwnership && options.userId) {
514
+ const file2 = await this.getFileOrThrow(fileId);
515
+ if (file2.uploadedBy !== options.userId) {
516
+ throw new Error("You can only delete files you uploaded");
517
+ }
518
+ }
519
+ if (options?.hard) {
520
+ await this.adapter.files.hardDelete(fileId);
521
+ } else {
522
+ await this.adapter.files.delete(fileId);
523
+ }
524
+ }
525
+ /**
526
+ * List files for the tenant
527
+ */
528
+ async listFiles(options) {
529
+ return await this.adapter.files.list(this.tenantId, options);
530
+ }
531
+ /**
532
+ * List files by folder
533
+ */
534
+ async listFilesByFolder(folderPath) {
535
+ return await this.adapter.files.findByFolder(this.tenantId, folderPath);
536
+ }
537
+ /**
538
+ * List files uploaded by a specific user
539
+ */
540
+ async listFilesByUploader(uploadedBy) {
541
+ return await this.adapter.files.findByUploader(uploadedBy);
542
+ }
543
+ /**
544
+ * Change file visibility
545
+ *
546
+ * @param fileId - File UUID
547
+ * @param visibility - New visibility level
548
+ * @param allowedUsers - Users allowed to access (if restricted)
549
+ */
550
+ async changeVisibility(fileId, visibility, allowedUsers) {
551
+ const updateData = { visibility };
552
+ if (visibility === "restricted" && allowedUsers) {
553
+ updateData.allowedUsers = allowedUsers;
554
+ }
555
+ return await this.updateFile(fileId, updateData);
556
+ }
557
+ /**
558
+ * Grant access to a file for specific users
559
+ *
560
+ * @param fileId - File UUID
561
+ * @param userIds - User IDs to grant access
562
+ */
563
+ async grantAccess(fileId, userIds) {
564
+ const file2 = await this.getFileOrThrow(fileId);
565
+ const currentAllowed = file2.allowedUsers || [];
566
+ const newAllowed = [.../* @__PURE__ */ new Set([...currentAllowed, ...userIds])];
567
+ return await this.updateFile(fileId, {
568
+ visibility: "restricted",
569
+ allowedUsers: newAllowed
570
+ });
571
+ }
572
+ /**
573
+ * Revoke access to a file for specific users
574
+ *
575
+ * @param fileId - File UUID
576
+ * @param userIds - User IDs to revoke access
577
+ */
578
+ async revokeAccess(fileId, userIds) {
579
+ const file2 = await this.getFileOrThrow(fileId);
580
+ const currentAllowed = file2.allowedUsers || [];
581
+ const newAllowed = currentAllowed.filter((id) => !userIds.includes(id));
582
+ return await this.updateFile(fileId, {
583
+ allowedUsers: newAllowed
584
+ });
585
+ }
586
+ /**
587
+ * Check if user has access to a file
588
+ *
589
+ * @param fileId - File UUID
590
+ * @param userId - User ID to check
591
+ * @returns true if user can access the file
592
+ */
593
+ async canAccess(fileId, userId) {
594
+ const file2 = await this.getFile(fileId);
595
+ if (!file2) {
596
+ return false;
597
+ }
598
+ if (file2.visibility === "public") {
599
+ return true;
600
+ }
601
+ if (file2.uploadedBy === userId) {
602
+ return true;
603
+ }
604
+ if (file2.visibility === "restricted") {
605
+ return file2.allowedUsers?.includes(userId) ?? false;
606
+ }
607
+ return false;
608
+ }
609
+ /**
610
+ * Move file to different folder
611
+ */
612
+ async moveToFolder(fileId, newFolderPath) {
613
+ return await this.updateFile(fileId, { folderPath: newFolderPath });
614
+ }
615
+ /**
616
+ * Add tags to file
617
+ */
618
+ async addTags(fileId, tags) {
619
+ const file2 = await this.getFileOrThrow(fileId);
620
+ const currentTags = file2.tags || [];
621
+ const newTags = [.../* @__PURE__ */ new Set([...currentTags, ...tags])];
622
+ return await this.updateFile(fileId, { tags: newTags });
623
+ }
624
+ /**
625
+ * Remove tags from file
626
+ */
627
+ async removeTags(fileId, tags) {
628
+ const file2 = await this.getFileOrThrow(fileId);
629
+ const currentTags = file2.tags || [];
630
+ const newTags = currentTags.filter((tag) => !tags.includes(tag));
631
+ return await this.updateFile(fileId, { tags: newTags });
632
+ }
633
+ };
634
+
635
+ // src/builders/attribute-builders.ts
636
+ import { z } from "zod";
637
+ var BaseAttributeBuilder = class {
638
+ constructor(type, config) {
639
+ this.validateVariableName(config.name);
640
+ this.attr = {
641
+ name: config.name,
642
+ label: config.label,
643
+ type,
644
+ required: false
645
+ };
646
+ }
647
+ /**
648
+ * Validate attribute name as valid variable identifier
649
+ * Accepts: camelCase, snake_case, PascalCase, UPPER_CASE
650
+ * @internal
651
+ */
652
+ validateVariableName(name) {
653
+ const variableNameSchema = z.string().min(1, "Attribute name cannot be empty").max(63, "Attribute name is too long (max 63 characters)").regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, {
654
+ message: "Invalid attribute name format.\nName must be a valid variable identifier:\n \u2705 Valid: 'firstName', 'first_name', 'FirstName', 'FIRST_NAME'\n \u274C Invalid: 'first-name', 'first name', '123name', 'first.name'"
655
+ });
656
+ try {
657
+ variableNameSchema.parse(name);
658
+ } catch (error) {
659
+ if (error instanceof z.ZodError) {
660
+ throw new Error(`[AttributeBuilder] ${error.errors[0].message}`);
661
+ }
662
+ throw error;
663
+ }
664
+ }
665
+ required() {
666
+ this.attr.required = true;
667
+ return this;
668
+ }
669
+ optional() {
670
+ this.attr.required = false;
671
+ return this;
672
+ }
673
+ system() {
674
+ this.attr.system = true;
675
+ return this;
676
+ }
677
+ disabled() {
678
+ this.attr.disabled = true;
679
+ return this;
680
+ }
681
+ hidden() {
682
+ this.attr.hidden = true;
683
+ return this;
684
+ }
685
+ placeholder(value) {
686
+ this.attr.placeholder = value;
687
+ return this;
688
+ }
689
+ description(value) {
690
+ this.attr.description = value;
691
+ return this;
692
+ }
693
+ icon(value) {
694
+ this.attr.icon = value;
695
+ return this;
696
+ }
697
+ order(value) {
698
+ this.attr.order = value;
699
+ return this;
700
+ }
701
+ defaultValue(value) {
702
+ this.attr.defaultValue = value;
703
+ return this;
704
+ }
705
+ metadata(value) {
706
+ this.attr.metadata = value;
707
+ return this;
708
+ }
709
+ build() {
710
+ return this.attr;
711
+ }
712
+ };
713
+ var TextAttributeBuilder = class extends BaseAttributeBuilder {
714
+ unique() {
715
+ this.attr.unique = true;
716
+ return this;
717
+ }
718
+ minLength(value) {
719
+ this.attr.minLength = value;
720
+ return this;
721
+ }
722
+ maxLength(value) {
723
+ this.attr.maxLength = value;
724
+ return this;
725
+ }
726
+ pattern(value) {
727
+ this.attr.pattern = value;
728
+ return this;
729
+ }
730
+ /**
731
+ * Set email validation pattern
732
+ * Shorthand for .pattern() with RFC 5322 compliant email regex
733
+ *
734
+ * @example
735
+ * ```typescript
736
+ * text({ name: "email", label: "Email" }).email().required()
737
+ * ```
738
+ */
739
+ email() {
740
+ this.attr.pattern = "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$";
741
+ return this;
742
+ }
743
+ /**
744
+ * Set URL validation pattern
745
+ * Shorthand for .pattern() with URL regex
746
+ *
747
+ * @example
748
+ * ```typescript
749
+ * text({ name: "website", label: "Website" }).url()
750
+ * ```
751
+ */
752
+ url() {
753
+ this.attr.pattern = "^https?:\\/\\/[\\w\\-]+(\\.[\\w\\-]+)+[/#?]?.*$";
754
+ return this;
755
+ }
756
+ /**
757
+ * Set slug validation pattern (lowercase, hyphens, no spaces)
758
+ *
759
+ * @example
760
+ * ```typescript
761
+ * text({ name: "slug", label: "Slug" }).slug()
762
+ * ```
763
+ */
764
+ slug() {
765
+ this.attr.pattern = "^[a-z0-9]+(?:-[a-z0-9]+)*$";
766
+ return this;
767
+ }
768
+ };
769
+ function text(config) {
770
+ return new TextAttributeBuilder("text", config);
771
+ }
772
+ var NumberAttributeBuilder = class extends BaseAttributeBuilder {
773
+ unique() {
774
+ this.attr.unique = true;
775
+ return this;
776
+ }
777
+ multiple() {
778
+ this.attr.multiple = true;
779
+ return this;
780
+ }
781
+ min(value) {
782
+ this.attr.min = value;
783
+ return this;
784
+ }
785
+ max(value) {
786
+ this.attr.max = value;
787
+ return this;
788
+ }
789
+ integer() {
790
+ this.attr.unit = "integer";
791
+ this.attr.decimals = 0;
792
+ return this;
793
+ }
794
+ decimal(decimals = 2) {
795
+ this.attr.unit = "decimal";
796
+ this.attr.decimals = decimals;
797
+ return this;
798
+ }
799
+ percentage() {
800
+ this.attr.unit = "percentage";
801
+ return this;
802
+ }
803
+ };
804
+ function number(config) {
805
+ return new NumberAttributeBuilder("number", config);
806
+ }
807
+ var CheckboxAttributeBuilder = class extends BaseAttributeBuilder {
808
+ unique() {
809
+ this.attr.unique = true;
810
+ return this;
811
+ }
812
+ };
813
+ function checkbox(config) {
814
+ return new CheckboxAttributeBuilder("checkbox", config);
815
+ }
816
+ var DateAttributeBuilder = class extends BaseAttributeBuilder {
817
+ unique() {
818
+ this.attr.unique = true;
819
+ return this;
820
+ }
821
+ multiple() {
822
+ this.attr.multiple = true;
823
+ return this;
824
+ }
825
+ format(value) {
826
+ this.attr.dateFormat = value;
827
+ return this;
828
+ }
829
+ minDate(value) {
830
+ this.attr.minDate = value;
831
+ return this;
832
+ }
833
+ maxDate(value) {
834
+ this.attr.maxDate = value;
835
+ return this;
836
+ }
837
+ };
838
+ function date(config) {
839
+ return new DateAttributeBuilder("date", config);
840
+ }
841
+ var PhoneAttributeBuilder = class extends BaseAttributeBuilder {
842
+ unique() {
843
+ this.attr.unique = true;
844
+ return this;
845
+ }
846
+ multiple() {
847
+ this.attr.multiple = true;
848
+ return this;
849
+ }
850
+ defaultCountry(value) {
851
+ this.attr.defaultCountryCode = value;
852
+ return this;
853
+ }
854
+ };
855
+ function phone(config) {
856
+ return new PhoneAttributeBuilder("phone", config);
857
+ }
858
+ var CurrencyAttributeBuilder = class extends BaseAttributeBuilder {
859
+ unique() {
860
+ this.attr.unique = true;
861
+ return this;
862
+ }
863
+ multiple() {
864
+ this.attr.multiple = true;
865
+ return this;
866
+ }
867
+ defaultCurrency(value) {
868
+ this.attr.defaultCurrency = value;
869
+ return this;
870
+ }
871
+ allowedCurrencies(value) {
872
+ this.attr.allowedCurrencies = value;
873
+ return this;
874
+ }
875
+ };
876
+ function currency(config) {
877
+ return new CurrencyAttributeBuilder("currency", config);
878
+ }
879
+ var StatusAttributeBuilder = class extends BaseAttributeBuilder {
880
+ unique() {
881
+ this.attr.unique = true;
882
+ return this;
883
+ }
884
+ options(value) {
885
+ this.attr.options = value;
886
+ return this;
887
+ }
888
+ option(config) {
889
+ if (!this.attr.options) {
890
+ this.attr.options = [];
891
+ }
892
+ this.attr.options.push(config);
893
+ return this;
894
+ }
895
+ };
896
+ function status(config) {
897
+ return new StatusAttributeBuilder("status", config);
898
+ }
899
+ var SelectAttributeBuilder = class extends BaseAttributeBuilder {
900
+ unique() {
901
+ this.attr.unique = true;
902
+ return this;
903
+ }
904
+ options(value) {
905
+ this.attr.options = value;
906
+ return this;
907
+ }
908
+ option(config) {
909
+ if (!this.attr.options) {
910
+ this.attr.options = [];
911
+ }
912
+ this.attr.options.push(config);
913
+ return this;
914
+ }
915
+ };
916
+ function select(config) {
917
+ return new SelectAttributeBuilder("select", config);
918
+ }
919
+ var MultiselectAttributeBuilder = class extends BaseAttributeBuilder {
920
+ unique() {
921
+ this.attr.unique = true;
922
+ return this;
923
+ }
924
+ options(value) {
925
+ this.attr.options = value;
926
+ return this;
927
+ }
928
+ option(config) {
929
+ if (!this.attr.options) {
930
+ this.attr.options = [];
931
+ }
932
+ this.attr.options.push(config);
933
+ return this;
934
+ }
935
+ };
936
+ function multiselect(config) {
937
+ return new MultiselectAttributeBuilder("multiselect", config);
938
+ }
939
+ var LocationAttributeBuilder = class extends BaseAttributeBuilder {
940
+ unique() {
941
+ this.attr.unique = true;
942
+ return this;
943
+ }
944
+ multiple() {
945
+ this.attr.multiple = true;
946
+ return this;
947
+ }
948
+ granularity(value) {
949
+ this.attr.granularity = value;
950
+ return this;
951
+ }
952
+ enableAutocomplete() {
953
+ this.attr.enableAutocomplete = true;
954
+ return this;
955
+ }
956
+ enableMap() {
957
+ this.attr.enableMap = true;
958
+ return this;
959
+ }
960
+ defaultCountry(value) {
961
+ this.attr.defaultCountry = value;
962
+ return this;
963
+ }
964
+ allowedCountries(value) {
965
+ this.attr.allowedCountries = value;
966
+ return this;
967
+ }
968
+ displayFormat(value) {
969
+ this.attr.displayFormat = value;
970
+ return this;
971
+ }
972
+ };
973
+ function location(config) {
974
+ return new LocationAttributeBuilder("location", config);
975
+ }
976
+ var TimestampAttributeBuilder = class extends BaseAttributeBuilder {
977
+ unique() {
978
+ this.attr.unique = true;
979
+ return this;
980
+ }
981
+ multiple() {
982
+ this.attr.multiple = true;
983
+ return this;
984
+ }
985
+ autoUpdate() {
986
+ this.attr.autoUpdate = true;
987
+ return this;
988
+ }
989
+ };
990
+ function timestamp(config) {
991
+ return new TimestampAttributeBuilder("timestamp", config);
992
+ }
993
+ var FileAttributeBuilder = class extends BaseAttributeBuilder {
994
+ unique() {
995
+ this.attr.unique = true;
996
+ return this;
997
+ }
998
+ multiple(maxFiles) {
999
+ this.attr.multiple = true;
1000
+ if (maxFiles !== void 0) {
1001
+ this.attr.maxFiles = maxFiles;
1002
+ }
1003
+ return this;
1004
+ }
1005
+ maxSize(bytes) {
1006
+ this.attr.maxSize = bytes;
1007
+ return this;
1008
+ }
1009
+ allowedTypes(types) {
1010
+ this.attr.allowedTypes = types;
1011
+ return this;
1012
+ }
1013
+ verification(config) {
1014
+ this.attr.verification = config;
1015
+ return this;
1016
+ }
1017
+ };
1018
+ function file(config) {
1019
+ return new FileAttributeBuilder("file", config);
1020
+ }
1021
+ var UserAttributeBuilder = class extends BaseAttributeBuilder {
1022
+ unique() {
1023
+ this.attr.unique = true;
1024
+ return this;
1025
+ }
1026
+ multiple() {
1027
+ this.attr.multiple = true;
1028
+ return this;
1029
+ }
1030
+ allowedRoles(roles) {
1031
+ this.attr.allowedRoles = roles;
1032
+ return this;
1033
+ }
1034
+ };
1035
+ function user(config) {
1036
+ return new UserAttributeBuilder("user", config);
1037
+ }
1038
+ var RelationAttributeBuilder = class extends BaseAttributeBuilder {
1039
+ unique() {
1040
+ this.attr.unique = true;
1041
+ return this;
1042
+ }
1043
+ multiple(limit) {
1044
+ this.attr.multiple = true;
1045
+ if (limit !== void 0) {
1046
+ this.attr.limit = limit;
1047
+ }
1048
+ return this;
1049
+ }
1050
+ relation(objectIds) {
1051
+ this.attr.relation = objectIds;
1052
+ return this;
1053
+ }
1054
+ cascadeDelete() {
1055
+ this.attr.cascadeDelete = true;
1056
+ return this;
1057
+ }
1058
+ };
1059
+ function relation(config) {
1060
+ return new RelationAttributeBuilder("relation", config);
1061
+ }
1062
+ var RatingAttributeBuilder = class extends BaseAttributeBuilder {
1063
+ unique() {
1064
+ this.attr.unique = true;
1065
+ return this;
1066
+ }
1067
+ max(value) {
1068
+ this.attr.max = value;
1069
+ return this;
1070
+ }
1071
+ iconType(value) {
1072
+ this.attr.iconType = value;
1073
+ return this;
1074
+ }
1075
+ };
1076
+ function rating(config) {
1077
+ return new RatingAttributeBuilder("rating", config);
1078
+ }
1079
+
1080
+ // src/builders/object-builder.ts
1081
+ import z2 from "zod";
1082
+ var ObjectBuilder = class {
1083
+ constructor(config) {
1084
+ this.validateName(config.name);
1085
+ this.obj = {
1086
+ name: config.name,
1087
+ label: config.label,
1088
+ attributes: [],
1089
+ system: false
1090
+ };
1091
+ }
1092
+ /**
1093
+ * Set object description
1094
+ */
1095
+ description(value) {
1096
+ this.obj.description = value;
1097
+ return this;
1098
+ }
1099
+ /**
1100
+ * Set object icon
1101
+ */
1102
+ icon(value) {
1103
+ this.obj.icon = value;
1104
+ return this;
1105
+ }
1106
+ /**
1107
+ * Mark as system/native object (defined in code, protected)
1108
+ * System objects cannot be deleted/modified by clients
1109
+ */
1110
+ system() {
1111
+ this.obj.system = true;
1112
+ return this;
1113
+ }
1114
+ /**
1115
+ * Add an attribute to the object
1116
+ * @param attr - Attribute definition or builder (auto-builds if builder)
1117
+ */
1118
+ attribute(attr) {
1119
+ if (!this.obj.attributes) {
1120
+ this.obj.attributes = [];
1121
+ }
1122
+ const finalAttr = "build" in attr ? attr.build() : attr;
1123
+ this.obj.attributes.push(finalAttr);
1124
+ return this;
1125
+ }
1126
+ /**
1127
+ * Add multiple attributes at once
1128
+ */
1129
+ attributes(attrs) {
1130
+ if (!this.obj.attributes) {
1131
+ this.obj.attributes = [];
1132
+ }
1133
+ const finalAttrs = attrs.map((attr) => "build" in attr ? attr.build() : attr);
1134
+ this.obj.attributes.push(...finalAttrs);
1135
+ return this;
1136
+ }
1137
+ /**
1138
+ * Set metadata
1139
+ */
1140
+ metadata(value) {
1141
+ this.obj.metadata = value;
1142
+ return this;
1143
+ }
1144
+ /**
1145
+ * Build the final ObjectDefinition
1146
+ * @throws Error if required fields are missing or invalid
1147
+ */
1148
+ build() {
1149
+ if (!this.obj.name) {
1150
+ throw new Error("[ObjectBuilder] Missing required field: name");
1151
+ }
1152
+ if (!this.obj.label) {
1153
+ throw new Error("[ObjectBuilder] Missing required field: label");
1154
+ }
1155
+ return this.obj;
1156
+ }
1157
+ /**
1158
+ * Validate object name format
1159
+ * Must be kebab-case (slug format), max 63 characters
1160
+ * @internal
1161
+ */
1162
+ validateName(name) {
1163
+ if (name === void 0) {
1164
+ return;
1165
+ }
1166
+ const objectNameSchema = z2.string().min(1, "Object name cannot be empty").max(63, "Object name is too long (max 63 characters)").regex(/^[a-z][a-z0-9-]*$/, {
1167
+ message: "Invalid object name format.\nName must be in kebab-case (slug format):\n \u2705 Valid: 'products', 'user-profiles', 'order-items'\n \u274C Invalid: 'Products', 'userProfiles', 'user_profiles'"
1168
+ });
1169
+ try {
1170
+ objectNameSchema.parse(name);
1171
+ } catch (error) {
1172
+ if (error instanceof z2.ZodError) {
1173
+ throw new Error(`[ObjectBuilder] ${error.errors[0].message}`);
1174
+ }
1175
+ throw error;
1176
+ }
1177
+ }
1178
+ };
1179
+ function object(config) {
1180
+ return new ObjectBuilder(config);
1181
+ }
1182
+
1183
+ // src/runtime/services/object-schema.service.ts
1184
+ var ObjectSchemaService = class {
1185
+ constructor(adapter, nativeRegistry) {
1186
+ this.adapter = adapter;
1187
+ this.nativeRegistry = nativeRegistry;
1188
+ }
1189
+ /**
1190
+ * Create a new custom object
1191
+ * Validates name format and ensures system=false
1192
+ *
1193
+ * @param definition - Object definition (attributes can be raw definitions or builders)
1194
+ * @param tenantId - Tenant ID owning the object
1195
+ * @returns Created ObjectDefinition
1196
+ */
1197
+ async createCustomObject(definition, tenantId) {
1198
+ const builder = object({
1199
+ name: definition.name,
1200
+ label: definition.label
1201
+ });
1202
+ if (definition.description) builder.description(definition.description);
1203
+ if (definition.icon) builder.icon(definition.icon);
1204
+ if (definition.metadata) builder.metadata(definition.metadata);
1205
+ if (definition.attributes && definition.attributes.length > 0) {
1206
+ builder.attributes(definition.attributes);
1207
+ }
1208
+ const objectDef = builder.build();
1209
+ const existing = await this.adapter.objects.findByName(tenantId, objectDef.name);
1210
+ if (existing) {
1211
+ throw new Error(`Object with name "${objectDef.name}" already exists`);
1212
+ }
1213
+ const metadata = {
1214
+ ...objectDef.metadata,
1215
+ icon: objectDef.icon
1216
+ };
1217
+ const dbObject = await this.adapter.objects.create({
1218
+ tenantId,
1219
+ name: objectDef.name,
1220
+ label: objectDef.label,
1221
+ description: objectDef.description,
1222
+ system: false,
1223
+ // Always false for custom objects
1224
+ metadata
1225
+ });
1226
+ const createdAttributes = [];
1227
+ if (objectDef.attributes.length > 0) {
1228
+ for (const attr of objectDef.attributes) {
1229
+ const dbAttr = await this.adapter.attributes.create({
1230
+ objectId: dbObject.id,
1231
+ name: attr.name,
1232
+ label: attr.label,
1233
+ type: attr.type,
1234
+ required: attr.required ?? false,
1235
+ unique: attr.unique ?? false,
1236
+ system: false,
1237
+ // Always false for custom attributes
1238
+ config: {
1239
+ ...attr,
1240
+ // Remove common fields stored in columns
1241
+ id: void 0,
1242
+ name: void 0,
1243
+ label: void 0,
1244
+ type: void 0,
1245
+ required: void 0,
1246
+ unique: void 0,
1247
+ system: void 0
1248
+ }
1249
+ });
1250
+ createdAttributes.push(this.convertDBAttributeToAttribute(dbAttr));
1251
+ }
1252
+ }
1253
+ return {
1254
+ ...objectDef,
1255
+ id: dbObject.id,
1256
+ attributes: createdAttributes,
1257
+ system: false
1258
+ };
1259
+ }
1260
+ /**
1261
+ * Add a custom attribute to an existing object
1262
+ * Can be used on both custom and native objects
1263
+ * Attributes added via API are always custom (system=false)
1264
+ *
1265
+ * @param objectId - Object UUID from database
1266
+ * @param attribute - Attribute definition
1267
+ * @returns Created Attribute
1268
+ */
1269
+ async addAttributeToObject(objectId, attribute) {
1270
+ this.validateAttributeName(attribute.name);
1271
+ const dbObject = await this.adapter.objects.findById(objectId);
1272
+ if (!dbObject) {
1273
+ throw new Error(`Object with id "${objectId}" not found`);
1274
+ }
1275
+ const existingAttributes = await this.adapter.attributes.findByObjectId(objectId);
1276
+ const duplicate = existingAttributes.find((attr) => attr.name === attribute.name);
1277
+ if (duplicate) {
1278
+ throw new Error(
1279
+ `Attribute with name "${attribute.name}" already exists on object "${dbObject.name}"`
1280
+ );
1281
+ }
1282
+ const dbAttr = await this.adapter.attributes.create({
1283
+ objectId,
1284
+ name: attribute.name,
1285
+ label: attribute.label,
1286
+ type: attribute.type,
1287
+ required: attribute.required ?? false,
1288
+ unique: attribute.unique ?? false,
1289
+ system: false,
1290
+ // Always false for attributes added via API
1291
+ config: {
1292
+ // Store all extra properties in config
1293
+ ...attribute,
1294
+ // Remove common fields stored in columns
1295
+ name: void 0,
1296
+ label: void 0,
1297
+ type: void 0,
1298
+ required: void 0,
1299
+ unique: void 0,
1300
+ system: void 0
1301
+ }
1302
+ });
1303
+ return this.convertDBAttributeToAttribute(dbAttr);
1304
+ }
1305
+ /**
1306
+ * Update an attribute
1307
+ * Can only update custom attributes (system=false)
1308
+ *
1309
+ * @param attributeId - Attribute UUID
1310
+ * @param updates - Partial attribute updates
1311
+ * @returns Updated Attribute
1312
+ */
1313
+ async updateAttribute(attributeId, updates) {
1314
+ const dbAttr = await this.adapter.attributes.findById(attributeId);
1315
+ if (!dbAttr) {
1316
+ throw new Error(`Attribute with id "${attributeId}" not found`);
1317
+ }
1318
+ if (dbAttr.system) {
1319
+ throw new Error(
1320
+ `Cannot modify system attribute "${dbAttr.name}". System attributes are protected.`
1321
+ );
1322
+ }
1323
+ if (updates.name && updates.name !== dbAttr.name) {
1324
+ throw new Error(
1325
+ "Attribute name cannot be changed after creation. Create a new attribute instead."
1326
+ );
1327
+ }
1328
+ if (updates.type && updates.type !== dbAttr.type) {
1329
+ throw new Error(
1330
+ "Attribute type cannot be changed after creation. Create a new attribute instead."
1331
+ );
1332
+ }
1333
+ const updatedDbAttr = await this.adapter.attributes.update(attributeId, {
1334
+ label: updates.label,
1335
+ required: updates.required,
1336
+ config: updates ? {
1337
+ ...dbAttr.config,
1338
+ ...updates,
1339
+ // Remove common fields
1340
+ name: void 0,
1341
+ label: void 0,
1342
+ type: void 0,
1343
+ required: void 0,
1344
+ unique: void 0,
1345
+ system: void 0
1346
+ } : dbAttr.config
1347
+ });
1348
+ return this.convertDBAttributeToAttribute(updatedDbAttr);
1349
+ }
1350
+ /**
1351
+ * Delete an attribute
1352
+ * Can only delete custom attributes (system=false)
1353
+ *
1354
+ * @param attributeId - Attribute UUID
1355
+ */
1356
+ async deleteAttribute(attributeId) {
1357
+ const dbAttr = await this.adapter.attributes.findById(attributeId);
1358
+ if (!dbAttr) {
1359
+ throw new Error(`Attribute with id "${attributeId}" not found`);
1360
+ }
1361
+ if (dbAttr.system) {
1362
+ throw new Error(
1363
+ `Cannot delete system attribute "${dbAttr.name}". System attributes are protected.`
1364
+ );
1365
+ }
1366
+ await this.adapter.attributes.delete(attributeId);
1367
+ }
1368
+ /**
1369
+ * List attributes for an object
1370
+ *
1371
+ * @param objectId - Object UUID
1372
+ * @param options - Filter options
1373
+ * @returns List of attributes
1374
+ */
1375
+ async listAttributes(objectId, options) {
1376
+ const dbAttributes = await this.adapter.attributes.findByObjectId(objectId);
1377
+ let filtered = dbAttributes;
1378
+ if (options?.systemOnly) {
1379
+ filtered = dbAttributes.filter((attr) => attr.system);
1380
+ } else if (options?.customOnly) {
1381
+ filtered = dbAttributes.filter((attr) => !attr.system);
1382
+ }
1383
+ return filtered.map((attr) => this.convertDBAttributeToAttribute(attr));
1384
+ }
1385
+ /**
1386
+ * Validate attribute name format (variable identifier)
1387
+ * @internal
1388
+ */
1389
+ validateAttributeName(name) {
1390
+ const variableNameRegex = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
1391
+ if (!name || name.length === 0) {
1392
+ throw new Error("Attribute name cannot be empty");
1393
+ }
1394
+ if (name.length > 63) {
1395
+ throw new Error("Attribute name is too long (max 63 characters)");
1396
+ }
1397
+ if (!variableNameRegex.test(name)) {
1398
+ throw new Error(
1399
+ "Invalid attribute name format.\nName must be a valid variable identifier:\n \u2705 Valid: 'firstName', 'first_name', 'FirstName', 'FIRST_NAME'\n \u274C Invalid: 'first-name', 'first name', '123name', 'first.name'"
1400
+ );
1401
+ }
1402
+ }
1403
+ /**
1404
+ * Get complete object schema (system + custom attributes)
1405
+ * If object is native, merges registry definition with DB custom attributes
1406
+ * If object is custom, returns DB definition only
1407
+ *
1408
+ * @param objectId - Object UUID from database
1409
+ * @returns Complete ObjectDefinition with all attributes
1410
+ *
1411
+ * @example
1412
+ * ```typescript
1413
+ * const service = new ObjectSchemaService(adapter, registry);
1414
+ * const productSchema = await service.getObjectSchema("obj-123");
1415
+ *
1416
+ * console.log(productSchema.attributes); // System + custom attributes
1417
+ * ```
1418
+ */
1419
+ async getObjectSchema(objectId) {
1420
+ const dbObject = await this.adapter.objects.findById(objectId);
1421
+ if (!dbObject) {
1422
+ throw new Error(`Object with id "${objectId}" not found`);
1423
+ }
1424
+ const dbAttributes = await this.adapter.attributes.findByObjectId(objectId);
1425
+ if (dbObject.system) {
1426
+ return this.mergeNativeObject(dbObject, dbAttributes);
1427
+ }
1428
+ return this.convertDBObjectToDefinition(dbObject, dbAttributes);
1429
+ }
1430
+ /**
1431
+ * Get object schema by name (for system/native objects)
1432
+ */
1433
+ async getObjectSchemaByName(name) {
1434
+ const dbObject = await this.adapter.objects.findSystemByName(name);
1435
+ if (!dbObject) {
1436
+ throw new Error(`Native object "${name}" not found in database`);
1437
+ }
1438
+ const dbAttributes = await this.adapter.attributes.findByObjectId(dbObject.id);
1439
+ return this.mergeNativeObject(dbObject, dbAttributes);
1440
+ }
1441
+ /**
1442
+ * List all object schemas for a tenant
1443
+ */
1444
+ async listObjectSchemas(tenantId) {
1445
+ const dbObjects = await this.adapter.objects.list(tenantId);
1446
+ const schemas = await Promise.all(
1447
+ dbObjects.map(async (dbObject) => {
1448
+ const dbAttributes = await this.adapter.attributes.findByObjectId(dbObject.id);
1449
+ if (dbObject.system) {
1450
+ return this.mergeNativeObject(dbObject, dbAttributes);
1451
+ }
1452
+ return this.convertDBObjectToDefinition(dbObject, dbAttributes);
1453
+ })
1454
+ );
1455
+ return schemas;
1456
+ }
1457
+ /**
1458
+ * Merge native object from registry with custom attributes from DB
1459
+ * @internal
1460
+ */
1461
+ mergeNativeObject(dbObject, dbAttributes) {
1462
+ const nativeObject = this.nativeRegistry.getByName(dbObject.name);
1463
+ if (!nativeObject) {
1464
+ throw new Error(
1465
+ `Native object "${dbObject.name}" not found in registry. Make sure to register it before querying.`
1466
+ );
1467
+ }
1468
+ const customAttributes = dbAttributes.filter((attr) => !attr.system);
1469
+ const customAttrs = customAttributes.map(
1470
+ (dbAttr) => this.convertDBAttributeToAttribute(dbAttr)
1471
+ );
1472
+ return {
1473
+ ...nativeObject,
1474
+ id: dbObject.id,
1475
+ attributes: [
1476
+ ...nativeObject.attributes,
1477
+ // System attributes from code
1478
+ ...customAttrs
1479
+ // Custom attributes from DB
1480
+ ]
1481
+ };
1482
+ }
1483
+ /**
1484
+ * Convert DB object + attributes to ObjectDefinition
1485
+ * @internal
1486
+ */
1487
+ convertDBObjectToDefinition(dbObject, dbAttributes) {
1488
+ const attributes = dbAttributes.map(
1489
+ (dbAttr) => this.convertDBAttributeToAttribute(dbAttr)
1490
+ );
1491
+ return {
1492
+ id: dbObject.id,
1493
+ name: dbObject.name,
1494
+ label: dbObject.label,
1495
+ description: dbObject.description,
1496
+ icon: dbObject.metadata?.icon,
1497
+ attributes,
1498
+ system: dbObject.system,
1499
+ metadata: dbObject.metadata
1500
+ };
1501
+ }
1502
+ /**
1503
+ * Convert DB attribute to Attribute type
1504
+ * @internal
1505
+ */
1506
+ convertDBAttributeToAttribute(dbAttr) {
1507
+ const baseAttr = {
1508
+ ...dbAttr.config,
1509
+ id: dbAttr.id,
1510
+ name: dbAttr.name,
1511
+ label: dbAttr.label,
1512
+ type: dbAttr.type,
1513
+ required: dbAttr.required,
1514
+ system: dbAttr.system,
1515
+ unique: dbAttr.unique
1516
+ };
1517
+ return baseAttr;
1518
+ }
1519
+ };
1520
+
1521
+ // src/native/registry.ts
1522
+ var NativeObjectRegistryClass = class {
1523
+ constructor() {
1524
+ this.objects = /* @__PURE__ */ new Map();
1525
+ }
1526
+ /**
1527
+ * Register one or more native objects
1528
+ * Auto-builds if ObjectBuilder is passed instead of ObjectDefinition
1529
+ * @param objects - Single object/builder or array of objects/builders to register
1530
+ * @returns this (for chaining)
1531
+ * @throws Error if object is invalid or already registered
1532
+ *
1533
+ * @example
1534
+ * ```typescript
1535
+ * // No .build() needed - registry auto-builds!
1536
+ * const PRODUCT = object({ id: "obj-product", name: "products", label: "Product" })
1537
+ * .system()
1538
+ * .attribute(text({ id: "attr-name", name: "name", label: "Name" }));
1539
+ *
1540
+ * registry.register(PRODUCT); // ← Auto-builds here
1541
+ *
1542
+ * // Can still explicitly .build() if you want
1543
+ * registry.register(PRODUCT.build());
1544
+ *
1545
+ * // Register multiple
1546
+ * registry.register([PRODUCT, ORDER, CUSTOMER]);
1547
+ * ```
1548
+ */
1549
+ register(objects) {
1550
+ const objectsArray = Array.isArray(objects) ? objects : [objects];
1551
+ for (const obj of objectsArray) {
1552
+ const object2 = "build" in obj && typeof obj.build === "function" ? obj.build() : obj;
1553
+ this.validateAndRegister(object2);
1554
+ }
1555
+ return this;
1556
+ }
1557
+ /**
1558
+ * Validate and register a single object
1559
+ * @internal
1560
+ */
1561
+ validateAndRegister(object2) {
1562
+ if (!object2.system) {
1563
+ throw new Error(
1564
+ `[NativeObjectRegistry] Cannot register object "${object2.name}" (id: ${object2.id}): missing system flag.
1565
+ Native objects must have system=true. Did you forget to call .system() in your builder?`
1566
+ );
1567
+ }
1568
+ if (this.objects.has(object2.name)) {
1569
+ const existing = this.objects.get(object2.name);
1570
+ throw new Error(
1571
+ `[NativeObjectRegistry] Duplicate object name "${object2.name}":
1572
+ - Existing: "${existing?.label}" (id: ${existing?.id})
1573
+ - New: "${object2.label}" (id: ${object2.id})
1574
+ Please use unique names for each native object.`
1575
+ );
1576
+ }
1577
+ this.objects.set(object2.name, object2);
1578
+ }
1579
+ /**
1580
+ * Get a native object by its name
1581
+ * @param name - The object name
1582
+ * @returns The object definition or undefined if not found
1583
+ *
1584
+ * @example
1585
+ * ```typescript
1586
+ * const product = registry.getByName("products");
1587
+ * if (product) {
1588
+ * console.log(product.label); // "Product"
1589
+ * }
1590
+ * ```
1591
+ */
1592
+ getByName(name) {
1593
+ return this.objects.get(name);
1594
+ }
1595
+ /**
1596
+ * Get a native object or throw if not found
1597
+ * @param name - The object name
1598
+ * @returns The object definition
1599
+ * @throws Error if not found
1600
+ */
1601
+ getByNameOrThrow(name) {
1602
+ const object2 = this.objects.get(name);
1603
+ if (!object2) {
1604
+ throw new Error(
1605
+ `[NativeObjectRegistry] Native object "${name}" not found.
1606
+ Available objects: ${this.listNames().join(", ")}`
1607
+ );
1608
+ }
1609
+ return object2;
1610
+ }
1611
+ /**
1612
+ * Get all registered native objects
1613
+ * @returns Array of all registered object definitions
1614
+ */
1615
+ getAll() {
1616
+ return Array.from(this.objects.values());
1617
+ }
1618
+ /**
1619
+ * Get all registered native object names
1620
+ * @returns Array of object names
1621
+ */
1622
+ listNames() {
1623
+ return Array.from(this.objects.keys());
1624
+ }
1625
+ /**
1626
+ * Check if a native object is registered
1627
+ * @param name - The object name
1628
+ * @returns true if registered, false otherwise
1629
+ */
1630
+ has(name) {
1631
+ return this.objects.has(name);
1632
+ }
1633
+ /**
1634
+ * Get the number of registered objects
1635
+ */
1636
+ get size() {
1637
+ return this.objects.size;
1638
+ }
1639
+ /**
1640
+ * Clear all registered objects (useful for testing)
1641
+ * @internal
1642
+ */
1643
+ clear() {
1644
+ this.objects.clear();
1645
+ }
1646
+ /**
1647
+ * Get registry summary for debugging
1648
+ */
1649
+ summary() {
1650
+ const objects = this.getAll();
1651
+ return [
1652
+ `[NativeObjectRegistry] ${this.size} native object(s) registered:`,
1653
+ ...objects.map(
1654
+ (obj) => ` - ${obj.name}: "${obj.label}" (${obj.attributes.length} attributes)`
1655
+ )
1656
+ ].join("\n");
1657
+ }
1658
+ /**
1659
+ * Log registry summary to console
1660
+ */
1661
+ debug() {
1662
+ console.info(this.summary());
1663
+ }
1664
+ };
1665
+ var registry = new NativeObjectRegistryClass();
1666
+
1667
+ // src/validation/validators.ts
1668
+ import { z as z3 } from "zod";
1669
+ function createTextValidator(attr) {
1670
+ let schema = z3.string();
1671
+ if (attr.minLength !== void 0) {
1672
+ schema = schema.min(
1673
+ attr.minLength,
1674
+ `${attr.label} must be at least ${attr.minLength} characters`
1675
+ );
1676
+ }
1677
+ if (attr.maxLength !== void 0) {
1678
+ schema = schema.max(
1679
+ attr.maxLength,
1680
+ `${attr.label} must be at most ${attr.maxLength} characters`
1681
+ );
1682
+ }
1683
+ if (attr.pattern) {
1684
+ schema = schema.regex(new RegExp(attr.pattern), `${attr.label} format is invalid`);
1685
+ }
1686
+ return schema;
1687
+ }
1688
+ function createNumberValidator(attr) {
1689
+ let schema = z3.number();
1690
+ if (attr.min !== void 0) {
1691
+ schema = schema.min(attr.min, `${attr.label} must be at least ${attr.min}`);
1692
+ }
1693
+ if (attr.max !== void 0) {
1694
+ schema = schema.max(attr.max, `${attr.label} must be at most ${attr.max}`);
1695
+ }
1696
+ if (attr.unit === "integer") {
1697
+ schema = schema.int(`${attr.label} must be an integer`);
1698
+ }
1699
+ if (attr.multiple) {
1700
+ return z3.array(schema);
1701
+ }
1702
+ return schema;
1703
+ }
1704
+ function createCheckboxValidator(_attr) {
1705
+ return z3.boolean();
1706
+ }
1707
+ function createDateValidator(attr) {
1708
+ const schema = z3.string().datetime({ message: `${attr.label} must be a valid ISO date` });
1709
+ if (attr.multiple) {
1710
+ return z3.array(schema);
1711
+ }
1712
+ return schema;
1713
+ }
1714
+ function createPhoneValidator(attr) {
1715
+ const schema = z3.object({
1716
+ countryCode: z3.string().length(3),
1717
+ phoneNumber: z3.string().min(1)
1718
+ });
1719
+ if (attr.multiple) {
1720
+ return z3.array(schema);
1721
+ }
1722
+ return schema;
1723
+ }
1724
+ function createCurrencyValidator(attr) {
1725
+ const schema = z3.object({
1726
+ code: z3.string().length(3),
1727
+ value: z3.number().min(0)
1728
+ });
1729
+ if (attr.multiple) {
1730
+ return z3.array(schema);
1731
+ }
1732
+ return schema;
1733
+ }
1734
+ function createStatusValidator(attr) {
1735
+ const validValues = attr.options.map((opt) => opt.value);
1736
+ return z3.enum(validValues, {
1737
+ errorMap: () => ({
1738
+ message: `${attr.label} must be one of: ${validValues.join(", ")}`
1739
+ })
1740
+ });
1741
+ }
1742
+ function createSelectValidator(attr) {
1743
+ const validValues = attr.options.map((opt) => opt.value);
1744
+ return z3.enum(validValues, {
1745
+ errorMap: () => ({
1746
+ message: `${attr.label} must be one of: ${validValues.join(", ")}`
1747
+ })
1748
+ });
1749
+ }
1750
+ function createMultiselectValidator(attr) {
1751
+ const validValues = attr.options.map((opt) => opt.value);
1752
+ return z3.array(
1753
+ z3.enum(validValues, {
1754
+ errorMap: () => ({
1755
+ message: `Each value must be one of: ${validValues.join(", ")}`
1756
+ })
1757
+ })
1758
+ );
1759
+ }
1760
+ function createLocationValidator(attr) {
1761
+ const schema = z3.object({
1762
+ address: z3.string().optional(),
1763
+ address2: z3.string().optional(),
1764
+ city: z3.string().optional(),
1765
+ state: z3.string().optional(),
1766
+ postalCode: z3.string().optional(),
1767
+ country: z3.string().length(3).optional(),
1768
+ latitude: z3.number().optional(),
1769
+ longitude: z3.number().optional()
1770
+ });
1771
+ if (attr.multiple) {
1772
+ return z3.array(schema);
1773
+ }
1774
+ return schema;
1775
+ }
1776
+ function createTimestampValidator(attr) {
1777
+ const schema = z3.number().int().positive();
1778
+ if (attr.multiple) {
1779
+ return z3.array(schema);
1780
+ }
1781
+ return schema;
1782
+ }
1783
+ function createFileValidator(attr) {
1784
+ const schema = z3.string().uuid();
1785
+ if (attr.multiple) {
1786
+ const arraySchema = z3.array(schema);
1787
+ if (attr.maxFiles) {
1788
+ return arraySchema.max(attr.maxFiles, `Maximum ${attr.maxFiles} files allowed`);
1789
+ }
1790
+ return arraySchema;
1791
+ }
1792
+ return schema;
1793
+ }
1794
+ function createUserValidator(attr) {
1795
+ const schema = z3.string().uuid();
1796
+ if (attr.multiple) {
1797
+ return z3.array(schema);
1798
+ }
1799
+ return schema;
1800
+ }
1801
+ function createRelationValidator(attr) {
1802
+ const schema = z3.string().uuid();
1803
+ if (attr.multiple) {
1804
+ const arraySchema = z3.array(schema);
1805
+ if (attr.limit) {
1806
+ return arraySchema.max(attr.limit, `Maximum ${attr.limit} relations allowed`);
1807
+ }
1808
+ return arraySchema;
1809
+ }
1810
+ return schema;
1811
+ }
1812
+ function createRatingValidator(attr) {
1813
+ let schema = z3.number().int().min(0);
1814
+ if (attr.max !== void 0) {
1815
+ schema = schema.max(attr.max, `${attr.label} must be at most ${attr.max}`);
1816
+ }
1817
+ return schema;
1818
+ }
1819
+ function createAttributeValidator(attr) {
1820
+ switch (attr.type) {
1821
+ case "text":
1822
+ return createTextValidator(attr);
1823
+ case "number":
1824
+ return createNumberValidator(attr);
1825
+ case "checkbox":
1826
+ return createCheckboxValidator(attr);
1827
+ case "date":
1828
+ return createDateValidator(attr);
1829
+ case "phone":
1830
+ return createPhoneValidator(attr);
1831
+ case "currency":
1832
+ return createCurrencyValidator(attr);
1833
+ case "status":
1834
+ return createStatusValidator(attr);
1835
+ case "location":
1836
+ return createLocationValidator(attr);
1837
+ case "timestamp":
1838
+ return createTimestampValidator(attr);
1839
+ case "select":
1840
+ return createSelectValidator(attr);
1841
+ case "multiselect":
1842
+ return createMultiselectValidator(attr);
1843
+ case "file":
1844
+ return createFileValidator(attr);
1845
+ case "user":
1846
+ return createUserValidator(attr);
1847
+ case "relation":
1848
+ return createRelationValidator(attr);
1849
+ case "rating":
1850
+ return createRatingValidator(attr);
1851
+ default:
1852
+ return z3.unknown();
1853
+ }
1854
+ }
1855
+ function createObjectValidator(objectDef) {
1856
+ const shape = {};
1857
+ for (const attr of objectDef.attributes) {
1858
+ let validator = createAttributeValidator(attr);
1859
+ if (!attr.required) {
1860
+ validator = validator.optional();
1861
+ }
1862
+ shape[attr.name] = validator;
1863
+ }
1864
+ return z3.object(shape);
1865
+ }
1866
+ function validateAttribute(attr, value) {
1867
+ const validator = createAttributeValidator(attr);
1868
+ if (!attr.required && (value === void 0 || value === null)) {
1869
+ return { success: true, data: { [attr.name]: value } };
1870
+ }
1871
+ const result = validator.safeParse(value);
1872
+ if (result.success) {
1873
+ return {
1874
+ success: true,
1875
+ data: { [attr.name]: result.data }
1876
+ };
1877
+ }
1878
+ return {
1879
+ success: false,
1880
+ errors: result.error.errors.map((err) => ({
1881
+ path: [attr.name, ...err.path.map(String)],
1882
+ message: err.message
1883
+ }))
1884
+ };
1885
+ }
1886
+ function validateObject(objectDef, data) {
1887
+ const validator = createObjectValidator(objectDef);
1888
+ const result = validator.safeParse(data);
1889
+ if (result.success) {
1890
+ return {
1891
+ success: true,
1892
+ data: result.data
1893
+ };
1894
+ }
1895
+ return {
1896
+ success: false,
1897
+ errors: result.error.errors.map((err) => ({
1898
+ path: err.path.map(String),
1899
+ message: err.message
1900
+ }))
1901
+ };
1902
+ }
1903
+ function validateObjectOrThrow(objectDef, data) {
1904
+ const result = validateObject(objectDef, data);
1905
+ if (!result.success) {
1906
+ const errorMessages = result.errors?.map((err) => `${err.path.join(".")}: ${err.message}`).join("\n") || "Unknown validation error";
1907
+ throw new Error(`Validation failed for ${objectDef.label}:
1908
+ ${errorMessages}`);
1909
+ }
1910
+ return result.data;
1911
+ }
1912
+
1913
+ // src/runtime/services/record.service.ts
1914
+ var RecordService = class {
1915
+ constructor(adapter, tenantId) {
1916
+ this.adapter = adapter;
1917
+ this.tenantId = tenantId;
1918
+ this.schemaService = new ObjectSchemaService(adapter, registry);
1919
+ }
1920
+ /**
1921
+ * Create a new record with validation
1922
+ *
1923
+ * @param objectId - Object UUID
1924
+ * @param data - Record data (attribute values)
1925
+ * @param options - Creation options
1926
+ * @returns Created record
1927
+ *
1928
+ * @example
1929
+ * ```typescript
1930
+ * const service = new RecordService(adapter, "tenant-123");
1931
+ *
1932
+ * const product = await service.createRecord("obj-product", {
1933
+ * name: "Nike Air Max",
1934
+ * price: 129.99,
1935
+ * sku: "NIKE-AM-001"
1936
+ * });
1937
+ * ```
1938
+ */
1939
+ async createRecord(objectId, data, options) {
1940
+ const schema = await this.schemaService.getObjectSchema(objectId);
1941
+ if (options?.validate !== false) {
1942
+ validateObjectOrThrow(schema, data);
1943
+ }
1944
+ const record = await this.adapter.objectRecords.create({
1945
+ tenantId: this.tenantId,
1946
+ objectId,
1947
+ data
1948
+ });
1949
+ return record;
1950
+ }
1951
+ /**
1952
+ * Get a record by ID
1953
+ *
1954
+ * @param recordId - Record UUID
1955
+ * @param options - Query options
1956
+ * @returns Record or null if not found
1957
+ */
1958
+ async getRecord(recordId, options) {
1959
+ const record = await this.adapter.objectRecords.findById(recordId);
1960
+ if (!record) {
1961
+ return null;
1962
+ }
1963
+ if (options?.includeSchema) {
1964
+ const schema = await this.schemaService.getObjectSchema(record.objectId);
1965
+ const recordWithSchema = record;
1966
+ recordWithSchema.schema = schema;
1967
+ return recordWithSchema;
1968
+ }
1969
+ return record;
1970
+ }
1971
+ /**
1972
+ * Get a record by ID or throw if not found
1973
+ */
1974
+ async getRecordOrThrow(recordId) {
1975
+ const record = await this.getRecord(recordId);
1976
+ if (!record) {
1977
+ throw new Error(`Record with id "${recordId}" not found`);
1978
+ }
1979
+ return record;
1980
+ }
1981
+ /**
1982
+ * Update a record with validation
1983
+ *
1984
+ * @param recordId - Record UUID
1985
+ * @param data - Partial data to update
1986
+ * @param options - Update options
1987
+ * @returns Updated record
1988
+ */
1989
+ async updateRecord(recordId, data, options) {
1990
+ const existing = await this.getRecordOrThrow(recordId);
1991
+ const schema = await this.schemaService.getObjectSchema(existing.objectId);
1992
+ const mergedData = { ...existing.values, ...data };
1993
+ if (options?.validate !== false && !options?.partial) {
1994
+ validateObjectOrThrow(schema, mergedData);
1995
+ }
1996
+ const updated = await this.adapter.objectRecords.update(recordId, data);
1997
+ return updated;
1998
+ }
1999
+ /**
2000
+ * Delete a record
2001
+ *
2002
+ * @param recordId - Record UUID
2003
+ * @param options - Delete options
2004
+ */
2005
+ async deleteRecord(recordId, options) {
2006
+ if (options?.checkSystem) {
2007
+ const record = await this.getRecordOrThrow(recordId);
2008
+ const schema = await this.schemaService.getObjectSchema(record.objectId);
2009
+ if (schema.system) {
2010
+ throw new Error(`Cannot delete record of system object "${schema.label}"`);
2011
+ }
2012
+ }
2013
+ await this.adapter.objectRecords.delete(recordId);
2014
+ }
2015
+ /**
2016
+ * List records for an object with pagination
2017
+ *
2018
+ * @param objectId - Object UUID
2019
+ * @param options - List options
2020
+ * @returns Records and total count
2021
+ */
2022
+ async listRecords(objectId, options) {
2023
+ return await this.adapter.objectRecords.list(this.tenantId, objectId, options);
2024
+ }
2025
+ /**
2026
+ * Search records using full-text search
2027
+ *
2028
+ * @param objectId - Object UUID
2029
+ * @param query - Search query
2030
+ * @param options - Search options
2031
+ * @returns Matching records and total count
2032
+ */
2033
+ async searchRecords(objectId, query, options) {
2034
+ return await this.adapter.objectRecords.search(this.tenantId, objectId, query, options);
2035
+ }
2036
+ /**
2037
+ * Validate data against object schema without saving
2038
+ *
2039
+ * @param objectId - Object UUID
2040
+ * @param data - Data to validate
2041
+ * @returns Validation result
2042
+ */
2043
+ async validateData(objectId, data) {
2044
+ const schema = await this.schemaService.getObjectSchema(objectId);
2045
+ return validateObject(schema, data);
2046
+ }
2047
+ };
2048
+
2049
+ // src/runtime/services/user-profile.service.ts
2050
+ var UserProfileService = class {
2051
+ constructor(adapter, tenantId) {
2052
+ this.adapter = adapter;
2053
+ this.tenantId = tenantId;
2054
+ }
2055
+ /**
2056
+ * Create a new user profile (typically after first auth)
2057
+ *
2058
+ * @param data - User profile creation data
2059
+ * @returns Created user profile
2060
+ *
2061
+ * @example
2062
+ * ```typescript
2063
+ * const service = new UserProfileService(adapter, "tenant-123");
2064
+ *
2065
+ * // After Supabase auth
2066
+ * const profile = await service.createProfile({
2067
+ * tenantId: "tenant-123",
2068
+ * authId: authUser.id,
2069
+ * email: authUser.email,
2070
+ * firstName: authUser.user_metadata.first_name,
2071
+ * lastName: authUser.user_metadata.last_name,
2072
+ * role: "member",
2073
+ * status: "active"
2074
+ * });
2075
+ * ```
2076
+ */
2077
+ async createProfile(data) {
2078
+ if (data.tenantId !== this.tenantId) {
2079
+ throw new Error(
2080
+ `Tenant mismatch: service initialized with "${this.tenantId}" but data has "${data.tenantId}"`
2081
+ );
2082
+ }
2083
+ const existing = await this.adapter.userProfiles.findByAuthId(data.authId);
2084
+ if (existing) {
2085
+ throw new Error(`User profile with authId "${data.authId}" already exists`);
2086
+ }
2087
+ const existingEmail = await this.adapter.userProfiles.findByEmail(this.tenantId, data.email);
2088
+ if (existingEmail) {
2089
+ throw new Error(`User profile with email "${data.email}" already exists in this tenant`);
2090
+ }
2091
+ return await this.adapter.userProfiles.create(data);
2092
+ }
2093
+ /**
2094
+ * Get user profile by ID
2095
+ */
2096
+ async getProfile(profileId) {
2097
+ return await this.adapter.userProfiles.findById(profileId);
2098
+ }
2099
+ /**
2100
+ * Get user profile by ID or throw
2101
+ */
2102
+ async getProfileOrThrow(profileId) {
2103
+ const profile = await this.getProfile(profileId);
2104
+ if (!profile) {
2105
+ throw new Error(`User profile with id "${profileId}" not found`);
2106
+ }
2107
+ return profile;
2108
+ }
2109
+ /**
2110
+ * Get user profile by auth provider ID
2111
+ *
2112
+ * @param authId - Auth provider user ID (Supabase, Clerk, etc.)
2113
+ * @returns User profile or null
2114
+ */
2115
+ async getProfileByAuthId(authId) {
2116
+ return await this.adapter.userProfiles.findByAuthId(authId);
2117
+ }
2118
+ /**
2119
+ * Get or create user profile (idempotent operation)
2120
+ * Useful for auth callbacks - ensures profile exists
2121
+ *
2122
+ * @param authId - Auth provider user ID
2123
+ * @param data - Profile data to create if doesn't exist
2124
+ * @returns Existing or newly created profile
2125
+ *
2126
+ * @example
2127
+ * ```typescript
2128
+ * // In Supabase auth callback
2129
+ * const profile = await service.getOrCreateProfile(
2130
+ * authUser.id,
2131
+ * {
2132
+ * tenantId: "tenant-123",
2133
+ * authId: authUser.id,
2134
+ * email: authUser.email,
2135
+ * role: "member",
2136
+ * status: "active"
2137
+ * }
2138
+ * );
2139
+ * ```
2140
+ */
2141
+ async getOrCreateProfile(authId, data) {
2142
+ const existing = await this.getProfileByAuthId(authId);
2143
+ if (existing) {
2144
+ return existing;
2145
+ }
2146
+ return await this.createProfile(data);
2147
+ }
2148
+ /**
2149
+ * Update user profile
2150
+ */
2151
+ async updateProfile(profileId, data) {
2152
+ await this.getProfileOrThrow(profileId);
2153
+ return await this.adapter.userProfiles.update(profileId, data);
2154
+ }
2155
+ /**
2156
+ * Delete user profile
2157
+ *
2158
+ * @param profileId - Profile UUID
2159
+ * @param options - Delete options
2160
+ */
2161
+ async deleteProfile(profileId, options) {
2162
+ if (options?.checkAdmin) {
2163
+ const profile = await this.getProfileOrThrow(profileId);
2164
+ if (profile.role === "admin") {
2165
+ const allProfiles = await this.listProfiles();
2166
+ const adminCount = allProfiles.filter((p) => p.role === "admin").length;
2167
+ if (adminCount <= 1) {
2168
+ throw new Error("Cannot delete the last admin user");
2169
+ }
2170
+ }
2171
+ }
2172
+ await this.adapter.userProfiles.delete(profileId);
2173
+ }
2174
+ /**
2175
+ * List all user profiles for the tenant
2176
+ */
2177
+ async listProfiles(options) {
2178
+ return await this.adapter.userProfiles.list(this.tenantId, options);
2179
+ }
2180
+ /**
2181
+ * Update last login timestamp
2182
+ *
2183
+ * @param profileId - Profile UUID
2184
+ *
2185
+ * @example
2186
+ * ```typescript
2187
+ * // After successful auth
2188
+ * await service.updateLastLogin(profile.id);
2189
+ * ```
2190
+ */
2191
+ async updateLastLogin(profileId) {
2192
+ await this.adapter.userProfiles.updateLastLogin(profileId);
2193
+ }
2194
+ /**
2195
+ * Change user role
2196
+ *
2197
+ * @param profileId - Profile UUID
2198
+ * @param newRole - New role
2199
+ */
2200
+ async changeRole(profileId, newRole) {
2201
+ return await this.updateProfile(profileId, { role: newRole });
2202
+ }
2203
+ /**
2204
+ * Change user status
2205
+ *
2206
+ * @param profileId - Profile UUID
2207
+ * @param newStatus - New status
2208
+ */
2209
+ async changeStatus(profileId, newStatus) {
2210
+ return await this.updateProfile(profileId, { status: newStatus });
2211
+ }
2212
+ /**
2213
+ * Get user by email
2214
+ */
2215
+ async getProfileByEmail(email) {
2216
+ return await this.adapter.userProfiles.findByEmail(this.tenantId, email);
2217
+ }
2218
+ /**
2219
+ * Check if user has role
2220
+ */
2221
+ async hasRole(profileId, role) {
2222
+ const profile = await this.getProfile(profileId);
2223
+ return profile?.role === role;
2224
+ }
2225
+ /**
2226
+ * Check if user is admin
2227
+ */
2228
+ async isAdmin(profileId) {
2229
+ return await this.hasRole(profileId, "admin");
2230
+ }
2231
+ };
2232
+
2233
+ // src/runtime/sync.ts
2234
+ var BASE_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
2235
+ "id",
2236
+ "name",
2237
+ "label",
2238
+ "type",
2239
+ "required",
2240
+ "system",
2241
+ "unique",
2242
+ "order"
2243
+ ]);
2244
+ function extractAttributeConfig(attr) {
2245
+ return Object.fromEntries(
2246
+ Object.entries(attr).filter(
2247
+ ([key, value]) => !BASE_ATTRIBUTE_KEYS.has(key) && value !== void 0
2248
+ )
2249
+ );
2250
+ }
2251
+ async function syncNativeObjects(adapter, nativeRegistry, options = {}) {
2252
+ const result = {
2253
+ success: true,
2254
+ objectsSynced: 0,
2255
+ attributesSynced: 0,
2256
+ objectsCreated: 0,
2257
+ objectsUpdated: 0,
2258
+ attributesCreated: 0,
2259
+ attributesUpdated: 0,
2260
+ attributesDeleted: 0,
2261
+ errors: []
2262
+ };
2263
+ const nativeObjects = nativeRegistry.getAll();
2264
+ if (options.verbose) {
2265
+ console.info(`[SyncService] Starting sync for ${nativeObjects.length} native objects...`);
2266
+ }
2267
+ try {
2268
+ await adapter.transaction(async (tx) => {
2269
+ for (const nativeObject of nativeObjects) {
2270
+ try {
2271
+ await syncSingleObject(tx, nativeObject, result, options);
2272
+ } catch (error) {
2273
+ result.success = false;
2274
+ result.errors.push({
2275
+ objectName: nativeObject.name,
2276
+ error: error instanceof Error ? error.message : String(error)
2277
+ });
2278
+ if (options.verbose) {
2279
+ console.error(`[SyncService] \u2717 Failed to sync ${nativeObject.name}:`, error);
2280
+ }
2281
+ }
2282
+ }
2283
+ });
2284
+ } catch (error) {
2285
+ result.success = false;
2286
+ result.errors.push({
2287
+ objectName: "transaction",
2288
+ error: error instanceof Error ? error.message : String(error)
2289
+ });
2290
+ }
2291
+ if (options.verbose) {
2292
+ console.info(
2293
+ `[SyncService] ${result.success ? "\u2713" : "\u2717"} Sync complete:
2294
+ Objects: ${result.objectsCreated} created, ${result.objectsUpdated} updated
2295
+ Attributes: ${result.attributesCreated} created, ${result.attributesUpdated} updated, ${result.attributesDeleted} deleted
2296
+ Errors: ${result.errors.length}`
2297
+ );
2298
+ }
2299
+ return result;
2300
+ }
2301
+ async function syncSingleObject(adapter, nativeObject, result, options) {
2302
+ if (!nativeObject.system) {
2303
+ throw new Error(`Object ${nativeObject.name} is not marked as system`);
2304
+ }
2305
+ const existingObject = await adapter.objects.findSystemByName(nativeObject.name);
2306
+ const isNew = !existingObject;
2307
+ updateObjectStats(result, isNew);
2308
+ if (options.dryRun) {
2309
+ await handleDryRun(adapter, nativeObject, existingObject, result, options, isNew);
2310
+ return;
2311
+ }
2312
+ const dbObject = await upsertObject(adapter, nativeObject, options);
2313
+ await syncAttributes(adapter, nativeObject, dbObject, existingObject, result);
2314
+ if (!isNew) {
2315
+ await cleanupAttributes(adapter, dbObject.id, nativeObject, result);
2316
+ }
2317
+ logSyncSuccess(nativeObject, options);
2318
+ }
2319
+ function updateObjectStats(result, isNew) {
2320
+ if (isNew) {
2321
+ result.objectsCreated++;
2322
+ } else {
2323
+ result.objectsUpdated++;
2324
+ }
2325
+ result.objectsSynced++;
2326
+ }
2327
+ async function handleDryRun(adapter, nativeObject, existingObject, result, options, isNew) {
2328
+ if (options.verbose) {
2329
+ console.info(`[SyncService] Would ${isNew ? "create" : "update"} object: ${nativeObject.name}`);
2330
+ }
2331
+ for (const attr of nativeObject.attributes) {
2332
+ const existingAttr = existingObject ? await adapter.attributes.findByObjectId(existingObject.id).then((attrs) => attrs.find((a) => a.name === attr.name)) : null;
2333
+ if (existingAttr) {
2334
+ result.attributesUpdated++;
2335
+ } else {
2336
+ result.attributesCreated++;
2337
+ }
2338
+ result.attributesSynced++;
2339
+ }
2340
+ }
2341
+ async function upsertObject(adapter, nativeObject, options) {
2342
+ return await adapter.objects.upsert({
2343
+ tenantId: options.tenantId || "default",
2344
+ system: true,
2345
+ name: nativeObject.name,
2346
+ label: nativeObject.label,
2347
+ description: nativeObject.description,
2348
+ metadata: nativeObject.metadata
2349
+ });
2350
+ }
2351
+ async function syncAttributes(adapter, nativeObject, dbObject, existingObject, result) {
2352
+ for (const [index, attr] of nativeObject.attributes.entries()) {
2353
+ const existingAttr = existingObject ? await adapter.attributes.findByObjectId(dbObject.id).then((attrs) => attrs.find((a) => a.name === attr.name)) : null;
2354
+ await adapter.attributes.upsert({
2355
+ objectId: dbObject.id,
2356
+ name: attr.name,
2357
+ label: attr.label,
2358
+ type: attr.type,
2359
+ system: attr.system ?? true,
2360
+ required: attr.required ?? false,
2361
+ unique: "unique" in attr ? attr.unique ?? false : false,
2362
+ orderIndex: attr.order ?? index,
2363
+ config: extractAttributeConfig(attr)
2364
+ });
2365
+ if (existingAttr) {
2366
+ result.attributesUpdated++;
2367
+ } else {
2368
+ result.attributesCreated++;
2369
+ }
2370
+ result.attributesSynced++;
2371
+ }
2372
+ }
2373
+ async function cleanupAttributes(adapter, objectId, nativeObject, result) {
2374
+ const attributeNames = nativeObject.attributes.map((attr) => attr.name);
2375
+ const deletedCount = await adapter.attributes.deleteByNames(objectId, attributeNames);
2376
+ result.attributesDeleted += deletedCount;
2377
+ }
2378
+ function logSyncSuccess(nativeObject, options) {
2379
+ if (options.verbose) {
2380
+ console.info(
2381
+ `[SyncService] \u2713 Synced ${nativeObject.name}: ${nativeObject.attributes.length} attributes`
2382
+ );
2383
+ }
2384
+ }
2385
+ async function verifyNativeObjectsSync(adapter, nativeRegistry) {
2386
+ const nativeObjects = nativeRegistry.getAll();
2387
+ for (const obj of nativeObjects) {
2388
+ if (!obj.system) continue;
2389
+ const existing = await adapter.objects.findSystemByName(obj.name);
2390
+ if (!existing) {
2391
+ return false;
2392
+ }
2393
+ }
2394
+ return true;
2395
+ }
2396
+ async function getSyncPreview(adapter, nativeRegistry) {
2397
+ return await syncNativeObjects(adapter, nativeRegistry, { dryRun: true });
2398
+ }
2399
+
2400
+ export {
2401
+ generateId,
2402
+ generatePrefixedId,
2403
+ text,
2404
+ number,
2405
+ checkbox,
2406
+ date,
2407
+ phone,
2408
+ currency,
2409
+ status,
2410
+ select,
2411
+ multiselect,
2412
+ location,
2413
+ timestamp,
2414
+ file,
2415
+ user,
2416
+ relation,
2417
+ rating,
2418
+ ObjectBuilder,
2419
+ object,
2420
+ registry,
2421
+ createTextValidator,
2422
+ createNumberValidator,
2423
+ createCheckboxValidator,
2424
+ createDateValidator,
2425
+ createPhoneValidator,
2426
+ createCurrencyValidator,
2427
+ createStatusValidator,
2428
+ createSelectValidator,
2429
+ createMultiselectValidator,
2430
+ createLocationValidator,
2431
+ createTimestampValidator,
2432
+ createFileValidator,
2433
+ createUserValidator,
2434
+ createRelationValidator,
2435
+ createRatingValidator,
2436
+ createAttributeValidator,
2437
+ createObjectValidator,
2438
+ validateAttribute,
2439
+ validateObject,
2440
+ validateObjectOrThrow,
2441
+ createMockAdapter,
2442
+ FileService,
2443
+ ObjectSchemaService,
2444
+ RecordService,
2445
+ UserProfileService,
2446
+ syncNativeObjects,
2447
+ verifyNativeObjectsSync,
2448
+ getSyncPreview
2449
+ };