@vurb/core 3.3.4 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +726 -677
  2. package/dist/cli/constants.js +59 -59
  3. package/dist/cli/scaffold.js +2 -0
  4. package/dist/cli/scaffold.js.map +1 -1
  5. package/dist/cli/templates/config.js +27 -27
  6. package/dist/cli/templates/config.js.map +1 -1
  7. package/dist/cli/templates/core.js +95 -95
  8. package/dist/cli/templates/index.d.ts +1 -0
  9. package/dist/cli/templates/index.d.ts.map +1 -1
  10. package/dist/cli/templates/index.js +2 -0
  11. package/dist/cli/templates/index.js.map +1 -1
  12. package/dist/cli/templates/middleware.js +25 -25
  13. package/dist/cli/templates/model.d.ts +7 -0
  14. package/dist/cli/templates/model.d.ts.map +1 -0
  15. package/dist/cli/templates/model.js +31 -0
  16. package/dist/cli/templates/model.js.map +1 -0
  17. package/dist/cli/templates/presenter.d.ts.map +1 -1
  18. package/dist/cli/templates/presenter.js +4 -9
  19. package/dist/cli/templates/presenter.js.map +1 -1
  20. package/dist/cli/templates/readme.d.ts.map +1 -1
  21. package/dist/cli/templates/readme.js +144 -142
  22. package/dist/cli/templates/readme.js.map +1 -1
  23. package/dist/cli/templates/testing.js +84 -84
  24. package/dist/cli/templates/tools.js +46 -46
  25. package/dist/cli/templates/vectors/database.js +69 -69
  26. package/dist/cli/templates/vectors/oauth.js +63 -63
  27. package/dist/cli/templates/vectors/openapi.js +97 -97
  28. package/dist/core/builder/BuildPipeline.d.ts +56 -0
  29. package/dist/core/builder/BuildPipeline.d.ts.map +1 -0
  30. package/dist/core/builder/BuildPipeline.js +139 -0
  31. package/dist/core/builder/BuildPipeline.js.map +1 -0
  32. package/dist/core/builder/FluentToolBuilder.d.ts +253 -19
  33. package/dist/core/builder/FluentToolBuilder.d.ts.map +1 -1
  34. package/dist/core/builder/FluentToolBuilder.js +354 -114
  35. package/dist/core/builder/FluentToolBuilder.js.map +1 -1
  36. package/dist/core/builder/ProxyHandler.d.ts +26 -0
  37. package/dist/core/builder/ProxyHandler.d.ts.map +1 -0
  38. package/dist/core/builder/ProxyHandler.js +65 -0
  39. package/dist/core/builder/ProxyHandler.js.map +1 -0
  40. package/dist/core/builder/SemanticDefaults.d.ts +25 -0
  41. package/dist/core/builder/SemanticDefaults.d.ts.map +1 -0
  42. package/dist/core/builder/SemanticDefaults.js +16 -0
  43. package/dist/core/builder/SemanticDefaults.js.map +1 -0
  44. package/dist/core/builder/index.d.ts +2 -1
  45. package/dist/core/builder/index.d.ts.map +1 -1
  46. package/dist/core/builder/index.js +1 -0
  47. package/dist/core/builder/index.js.map +1 -1
  48. package/dist/core/middleware/AuditTrail.d.ts.map +1 -1
  49. package/dist/core/middleware/AuditTrail.js +6 -2
  50. package/dist/core/middleware/AuditTrail.js.map +1 -1
  51. package/dist/core/middleware/RateLimiter.d.ts.map +1 -1
  52. package/dist/core/middleware/RateLimiter.js +3 -1
  53. package/dist/core/middleware/RateLimiter.js.map +1 -1
  54. package/dist/fsm/StateMachineGate.d.ts +3 -0
  55. package/dist/fsm/StateMachineGate.d.ts.map +1 -1
  56. package/dist/fsm/StateMachineGate.js +12 -0
  57. package/dist/fsm/StateMachineGate.js.map +1 -1
  58. package/dist/index.d.ts +4 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +3 -0
  61. package/dist/index.js.map +1 -1
  62. package/dist/introspection/SemanticProbe.js +49 -49
  63. package/dist/model/defineModel.d.ts +167 -0
  64. package/dist/model/defineModel.d.ts.map +1 -0
  65. package/dist/model/defineModel.js +345 -0
  66. package/dist/model/defineModel.js.map +1 -0
  67. package/dist/model/index.d.ts +8 -0
  68. package/dist/model/index.d.ts.map +1 -0
  69. package/dist/model/index.js +7 -0
  70. package/dist/model/index.js.map +1 -0
  71. package/dist/observability/TelemetryBus.d.ts.map +1 -1
  72. package/dist/observability/TelemetryBus.js +14 -13
  73. package/dist/observability/TelemetryBus.js.map +1 -1
  74. package/dist/presenter/Presenter.d.ts +21 -0
  75. package/dist/presenter/Presenter.d.ts.map +1 -1
  76. package/dist/presenter/Presenter.js +17 -8
  77. package/dist/presenter/Presenter.js.map +1 -1
  78. package/dist/presenter/PresenterPipeline.d.ts +2 -0
  79. package/dist/presenter/PresenterPipeline.d.ts.map +1 -1
  80. package/dist/presenter/PresenterPipeline.js +4 -0
  81. package/dist/presenter/PresenterPipeline.js.map +1 -1
  82. package/dist/presenter/definePresenter.d.ts.map +1 -1
  83. package/dist/presenter/definePresenter.js +13 -3
  84. package/dist/presenter/definePresenter.js.map +1 -1
  85. package/dist/prompt/FluentPromptBuilder.d.ts.map +1 -1
  86. package/dist/resource/ResourceRegistry.d.ts +3 -0
  87. package/dist/resource/ResourceRegistry.d.ts.map +1 -1
  88. package/dist/resource/ResourceRegistry.js +8 -2
  89. package/dist/resource/ResourceRegistry.js.map +1 -1
  90. package/dist/sandbox/SandboxGuard.js +7 -4
  91. package/dist/sandbox/SandboxGuard.js.map +1 -1
  92. package/dist/server/ServerAttachment.d.ts.map +1 -1
  93. package/dist/server/ServerAttachment.js +48 -9
  94. package/dist/server/ServerAttachment.js.map +1 -1
  95. package/package.json +1 -1
@@ -0,0 +1,167 @@
1
+ /**
2
+ * defineModel — Eloquent-inspired Model Definition for Vurb.ts
3
+ *
4
+ * Synthesizes the best DX patterns from 10 globally acclaimed frameworks:
5
+ * • Laravel: $casts, $fillable, $hidden, $guarded, timestamps()
6
+ * • Django: choices (enum), verbose_name (label-first)
7
+ * • Rails: attr_accessible (whitelist) + attr_protected (blacklist)
8
+ * • Prisma: @default() values
9
+ * • Pydantic: Field(alias=, examples=, description=)
10
+ * • Drizzle: column-as-function type helpers
11
+ * • Convex: defineTable() factory
12
+ * • Spring: @JsonIgnore → hidden
13
+ * • NestJS: DTOs per operation → fillable profiles
14
+ * • Mongoose: schema options in closure
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { defineModel } from '@vurb/core';
19
+ *
20
+ * export const TaskModel = defineModel('Task', m => {
21
+ * m.casts({
22
+ * title: m.string('Task title'),
23
+ * description: m.text('Description in markdown'),
24
+ * status: m.enum('Status', ['open', 'done']).default('open'),
25
+ * due_date: m.date('Due date'),
26
+ * is_bug: m.boolean('Bug flag').default(false),
27
+ * });
28
+ *
29
+ * m.timestamps();
30
+ * m.hidden(['internal_id']);
31
+ * m.guarded(['uuid', 'created_at', 'updated_at']);
32
+ *
33
+ * m.fillable({
34
+ * create: ['title', 'description', 'due_date', 'is_bug'],
35
+ * update: ['title', 'description', 'due_date', 'is_bug'],
36
+ * filter: ['title', 'status', 'is_bug'],
37
+ * });
38
+ * });
39
+ * ```
40
+ *
41
+ * @module
42
+ */
43
+ import { z, type ZodType, type ZodObject, type ZodRawShape } from 'zod';
44
+ /** Internal field type discriminator */
45
+ type FieldType = 'string' | 'text' | 'number' | 'boolean' | 'date' | 'timestamp' | 'uuid' | 'id' | 'enum' | 'object' | 'list';
46
+ /** A field definition descriptor — chainable for .default(), .alias(), .examples() */
47
+ export declare class FieldDef {
48
+ /** @internal */ readonly _type: FieldType;
49
+ /** @internal */ readonly _label: string | undefined;
50
+ /** @internal */ readonly _enumValues: readonly [string, ...string[]] | undefined;
51
+ /** @internal */ readonly _shape: Record<string, FieldDef> | undefined;
52
+ /** @internal */ _defaultValue?: unknown;
53
+ /** @internal */ _alias?: string;
54
+ /** @internal */ _examples?: unknown[];
55
+ constructor(type: FieldType, label?: string, options?: {
56
+ enumValues?: readonly [string, ...string[]];
57
+ shape?: Record<string, FieldDef>;
58
+ });
59
+ /** Set a default value (Prisma-inspired `@default()`) */
60
+ default(value: unknown): this;
61
+ /** Set an alias name (Pydantic-inspired `Field(alias=)`) */
62
+ alias(name: string): this;
63
+ /** Set example values (Pydantic-inspired `Field(examples=[])`) */
64
+ examples(values: unknown[]): this;
65
+ }
66
+ /**
67
+ * Compile a FieldDef into a Zod schema for input context.
68
+ *
69
+ * Unlike `compileField()` (which defaults everything to optional for output schemas),
70
+ * this function produces schemas suitable for tool input parameters:
71
+ * - For **create**: string/text fields become required `z.string()`, number fields become optional
72
+ * - For **update/filter** (`forceOptional = true`): all fields become optional
73
+ *
74
+ * @param def - Field definition to compile
75
+ * @param forceOptional - If true, all fields become optional (update/filter semantics)
76
+ * @returns Zod schema for input validation
77
+ */
78
+ export declare function compileFieldForInput(def: FieldDef, forceOptional: boolean): ZodType;
79
+ /** The compiled Model object returned by `defineModel()` */
80
+ export interface Model {
81
+ /** Model name (e.g. 'Task') */
82
+ readonly name: string;
83
+ /** Compiled Zod schema — compatible with Presenter.schema() */
84
+ readonly schema: ZodObject<ZodRawShape>;
85
+ /** Field definitions map */
86
+ readonly fields: Record<string, FieldDef>;
87
+ /** Hidden fields — never shown in output (Spring @JsonIgnore) */
88
+ readonly hidden: string[];
89
+ /** Guarded fields — never fillable (Rails attr_protected) */
90
+ readonly guarded: string[];
91
+ /** Input profiles per operation (Laravel $fillable) */
92
+ readonly input: Record<string, string[]>;
93
+ /** Default values (Prisma @default) */
94
+ readonly defaults: Record<string, unknown>;
95
+ /**
96
+ * Apply field aliases — renames agent-facing keys to API-facing keys.
97
+ * Pydantic-inspired `model_dump(by_alias=True)`.
98
+ * Strips undefined values. Non-aliased keys pass through unchanged.
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * // Model: content → .alias('description')
103
+ * ProposalModel.toApi({ title: 'X', content: 'Y' })
104
+ * // → { title: 'X', description: 'Y' }
105
+ * ```
106
+ */
107
+ readonly toApi: (data: Record<string, unknown>) => Record<string, unknown>;
108
+ /** Type helper — `typeof model.infer` gives you the TS type */
109
+ readonly infer: z.infer<ZodObject<ZodRawShape>>;
110
+ }
111
+ /**
112
+ * Builder class that exposes type functions and configuration methods.
113
+ * Passed as `m` in the `defineModel()` closure.
114
+ */
115
+ export declare class ModelBuilder {
116
+ /** @internal */ _fields: Record<string, FieldDef>;
117
+ /** @internal */ _hidden: string[];
118
+ /** @internal */ _guarded: string[];
119
+ /** @internal */ _fillableProfiles: Record<string, string[]>;
120
+ /** String field — general purpose text */
121
+ string(label?: string): FieldDef;
122
+ /** Text field — semantic: markdown, multiline, long content */
123
+ text(label?: string): FieldDef;
124
+ /** Numeric field */
125
+ number(label?: string): FieldDef;
126
+ /** Boolean field */
127
+ boolean(label?: string): FieldDef;
128
+ /** Date field — automatically hints YYYY-MM-DD format */
129
+ date(label?: string): FieldDef;
130
+ /** Timestamp field — ISO datetime */
131
+ timestamp(label?: string): FieldDef;
132
+ /** UUID field — string with UUID semantics */
133
+ uuid(label?: string): FieldDef;
134
+ /** ID field — always required, numeric */
135
+ id(label?: string): FieldDef;
136
+ /** Enum field — Django-style choices, tells AI valid values */
137
+ enum(label: string, values: readonly [string, ...string[]]): FieldDef;
138
+ /** Nested object field */
139
+ object(label: string, shape: Record<string, FieldDef>): FieldDef;
140
+ /** Array of objects field */
141
+ list(label: string, shape: Record<string, FieldDef>): FieldDef;
142
+ /** Define field types and labels — like Laravel's `$casts` */
143
+ casts(fields: Record<string, FieldDef>): void;
144
+ /** Add created_at + updated_at timestamp fields — like Laravel's `timestamps()` */
145
+ timestamps(): void;
146
+ /** Fields hidden from output — like Spring's `@JsonIgnore` or Laravel's `$hidden` */
147
+ hidden(fields: string[]): void;
148
+ /** Fields that can NEVER be input — like Rails' `attr_protected` or Laravel's `$guarded` */
149
+ guarded(fields: string[]): void;
150
+ /** Define input profiles per operation — like Laravel's `$fillable` + NestJS DTOs */
151
+ fillable(profiles: Record<string, string[]>): void;
152
+ /** @internal Compile all fields into a Zod schema */
153
+ _compile(): {
154
+ schema: ZodObject<ZodRawShape>;
155
+ defaults: Record<string, unknown>;
156
+ };
157
+ }
158
+ /**
159
+ * Define a Model — one file, one entity, one source of truth.
160
+ *
161
+ * @param name - Model name (e.g. 'Task', 'Sprint', 'Project')
162
+ * @param configure - Closure function that receives a `ModelBuilder` (`m`)
163
+ * @returns Compiled `Model` with `.schema`, `.fields`, `.input`, `.hidden`, `.guarded`
164
+ */
165
+ export declare function defineModel(name: string, configure: (m: ModelBuilder) => void): Model;
166
+ export {};
167
+ //# sourceMappingURL=defineModel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defineModel.d.ts","sourceRoot":"","sources":["../../src/model/defineModel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,345 @@
1
+ /**
2
+ * defineModel — Eloquent-inspired Model Definition for Vurb.ts
3
+ *
4
+ * Synthesizes the best DX patterns from 10 globally acclaimed frameworks:
5
+ * • Laravel: $casts, $fillable, $hidden, $guarded, timestamps()
6
+ * • Django: choices (enum), verbose_name (label-first)
7
+ * • Rails: attr_accessible (whitelist) + attr_protected (blacklist)
8
+ * • Prisma: @default() values
9
+ * • Pydantic: Field(alias=, examples=, description=)
10
+ * • Drizzle: column-as-function type helpers
11
+ * • Convex: defineTable() factory
12
+ * • Spring: @JsonIgnore → hidden
13
+ * • NestJS: DTOs per operation → fillable profiles
14
+ * • Mongoose: schema options in closure
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { defineModel } from '@vurb/core';
19
+ *
20
+ * export const TaskModel = defineModel('Task', m => {
21
+ * m.casts({
22
+ * title: m.string('Task title'),
23
+ * description: m.text('Description in markdown'),
24
+ * status: m.enum('Status', ['open', 'done']).default('open'),
25
+ * due_date: m.date('Due date'),
26
+ * is_bug: m.boolean('Bug flag').default(false),
27
+ * });
28
+ *
29
+ * m.timestamps();
30
+ * m.hidden(['internal_id']);
31
+ * m.guarded(['uuid', 'created_at', 'updated_at']);
32
+ *
33
+ * m.fillable({
34
+ * create: ['title', 'description', 'due_date', 'is_bug'],
35
+ * update: ['title', 'description', 'due_date', 'is_bug'],
36
+ * filter: ['title', 'status', 'is_bug'],
37
+ * });
38
+ * });
39
+ * ```
40
+ *
41
+ * @module
42
+ */
43
+ import { z } from 'zod';
44
+ /** A field definition descriptor — chainable for .default(), .alias(), .examples() */
45
+ export class FieldDef {
46
+ /** @internal */ _type;
47
+ /** @internal */ _label;
48
+ /** @internal */ _enumValues;
49
+ /** @internal */ _shape;
50
+ /** @internal */ _defaultValue;
51
+ /** @internal */ _alias;
52
+ /** @internal */ _examples;
53
+ constructor(type, label, options) {
54
+ this._type = type;
55
+ this._label = label;
56
+ this._enumValues = options?.enumValues;
57
+ this._shape = options?.shape;
58
+ }
59
+ /** Set a default value (Prisma-inspired `@default()`) */
60
+ default(value) {
61
+ this._defaultValue = value;
62
+ return this;
63
+ }
64
+ /** Set an alias name (Pydantic-inspired `Field(alias=)`) */
65
+ alias(name) {
66
+ this._alias = name;
67
+ return this;
68
+ }
69
+ /** Set example values (Pydantic-inspired `Field(examples=[])`) */
70
+ examples(values) {
71
+ this._examples = values;
72
+ return this;
73
+ }
74
+ }
75
+ // ── Compile FieldDef → Zod ──────────────────────────────
76
+ function compileField(def) {
77
+ let schema;
78
+ switch (def._type) {
79
+ case 'string':
80
+ case 'text':
81
+ schema = z.string();
82
+ break;
83
+ case 'number':
84
+ schema = z.number();
85
+ break;
86
+ case 'boolean':
87
+ schema = z.boolean();
88
+ break;
89
+ case 'date':
90
+ schema = z.string();
91
+ break;
92
+ case 'timestamp':
93
+ schema = z.string();
94
+ break;
95
+ case 'uuid':
96
+ schema = z.string();
97
+ break;
98
+ case 'id':
99
+ // IDs are always required — return early with describe if present
100
+ schema = z.number();
101
+ if (def._label)
102
+ schema = schema.describe(def._label);
103
+ return schema;
104
+ case 'enum':
105
+ schema = z.enum(def._enumValues);
106
+ break;
107
+ case 'object': {
108
+ const shape = {};
109
+ if (def._shape) {
110
+ for (const [key, childDef] of Object.entries(def._shape)) {
111
+ shape[key] = compileField(childDef);
112
+ }
113
+ }
114
+ schema = z.object(shape);
115
+ break;
116
+ }
117
+ case 'list': {
118
+ const itemShape = {};
119
+ if (def._shape) {
120
+ for (const [key, childDef] of Object.entries(def._shape)) {
121
+ itemShape[key] = compileField(childDef);
122
+ }
123
+ }
124
+ schema = z.array(z.object(itemShape));
125
+ break;
126
+ }
127
+ }
128
+ // Add description (label) — Drizzle + Django verbose_name
129
+ if (def._label) {
130
+ // Add format hint for date fields — automatically hint YYYY-MM-DD
131
+ const label = def._type === 'date'
132
+ ? `${def._label} (YYYY-MM-DD)`
133
+ : def._label;
134
+ schema = schema.describe(label);
135
+ }
136
+ // Everything except `id` is optional + nullable by default
137
+ // (API responses may omit fields)
138
+ if (def._type === 'boolean' || def._type === 'list') {
139
+ schema = schema.optional();
140
+ }
141
+ else {
142
+ schema = schema.optional().nullable();
143
+ }
144
+ return schema;
145
+ }
146
+ /**
147
+ * Compile a FieldDef into a Zod schema for input context.
148
+ *
149
+ * Unlike `compileField()` (which defaults everything to optional for output schemas),
150
+ * this function produces schemas suitable for tool input parameters:
151
+ * - For **create**: string/text fields become required `z.string()`, number fields become optional
152
+ * - For **update/filter** (`forceOptional = true`): all fields become optional
153
+ *
154
+ * @param def - Field definition to compile
155
+ * @param forceOptional - If true, all fields become optional (update/filter semantics)
156
+ * @returns Zod schema for input validation
157
+ */
158
+ export function compileFieldForInput(def, forceOptional) {
159
+ let schema;
160
+ switch (def._type) {
161
+ case 'string':
162
+ case 'text':
163
+ case 'uuid':
164
+ case 'date':
165
+ case 'timestamp':
166
+ schema = z.string();
167
+ break;
168
+ case 'number':
169
+ schema = z.number();
170
+ break;
171
+ case 'boolean':
172
+ schema = z.boolean();
173
+ break;
174
+ case 'id':
175
+ schema = z.number();
176
+ break;
177
+ case 'enum':
178
+ schema = z.enum(def._enumValues);
179
+ break;
180
+ case 'object': {
181
+ const shape = {};
182
+ if (def._shape) {
183
+ for (const [key, childDef] of Object.entries(def._shape)) {
184
+ shape[key] = compileFieldForInput(childDef, false);
185
+ }
186
+ }
187
+ schema = z.object(shape);
188
+ break;
189
+ }
190
+ case 'list': {
191
+ const itemShape = {};
192
+ if (def._shape) {
193
+ for (const [key, childDef] of Object.entries(def._shape)) {
194
+ itemShape[key] = compileFieldForInput(childDef, false);
195
+ }
196
+ }
197
+ schema = z.array(z.object(itemShape));
198
+ break;
199
+ }
200
+ }
201
+ // Add description (label)
202
+ if (def._label) {
203
+ const label = def._type === 'date'
204
+ ? `${def._label} (YYYY-MM-DD)`
205
+ : def._label;
206
+ schema = schema.describe(label);
207
+ }
208
+ // Apply optionality: forceOptional makes everything optional
209
+ if (forceOptional) {
210
+ schema = schema.optional();
211
+ }
212
+ return schema;
213
+ }
214
+ // ── ModelBuilder (the `m` argument) ─────────────────────
215
+ /**
216
+ * Builder class that exposes type functions and configuration methods.
217
+ * Passed as `m` in the `defineModel()` closure.
218
+ */
219
+ export class ModelBuilder {
220
+ /** @internal */ _fields = {};
221
+ /** @internal */ _hidden = [];
222
+ /** @internal */ _guarded = [];
223
+ /** @internal */ _fillableProfiles = {};
224
+ // ── Type Functions (Drizzle-style) ──────────────────
225
+ /** String field — general purpose text */
226
+ string(label) {
227
+ return new FieldDef('string', label);
228
+ }
229
+ /** Text field — semantic: markdown, multiline, long content */
230
+ text(label) {
231
+ return new FieldDef('text', label);
232
+ }
233
+ /** Numeric field */
234
+ number(label) {
235
+ return new FieldDef('number', label);
236
+ }
237
+ /** Boolean field */
238
+ boolean(label) {
239
+ return new FieldDef('boolean', label);
240
+ }
241
+ /** Date field — automatically hints YYYY-MM-DD format */
242
+ date(label) {
243
+ return new FieldDef('date', label);
244
+ }
245
+ /** Timestamp field — ISO datetime */
246
+ timestamp(label) {
247
+ return new FieldDef('timestamp', label);
248
+ }
249
+ /** UUID field — string with UUID semantics */
250
+ uuid(label) {
251
+ return new FieldDef('uuid', label);
252
+ }
253
+ /** ID field — always required, numeric */
254
+ id(label) {
255
+ return new FieldDef('id', label);
256
+ }
257
+ /** Enum field — Django-style choices, tells AI valid values */
258
+ enum(label, values) {
259
+ return new FieldDef('enum', label, { enumValues: values });
260
+ }
261
+ /** Nested object field */
262
+ object(label, shape) {
263
+ return new FieldDef('object', label, { shape });
264
+ }
265
+ /** Array of objects field */
266
+ list(label, shape) {
267
+ return new FieldDef('list', label, { shape });
268
+ }
269
+ // ── Configuration Methods (Laravel-style) ───────────
270
+ /** Define field types and labels — like Laravel's `$casts` */
271
+ casts(fields) {
272
+ this._fields = { ...this._fields, ...fields };
273
+ }
274
+ /** Add created_at + updated_at timestamp fields — like Laravel's `timestamps()` */
275
+ timestamps() {
276
+ this._fields['created_at'] = new FieldDef('timestamp', 'Creation timestamp');
277
+ this._fields['updated_at'] = new FieldDef('timestamp', 'Last update timestamp');
278
+ }
279
+ /** Fields hidden from output — like Spring's `@JsonIgnore` or Laravel's `$hidden` */
280
+ hidden(fields) {
281
+ this._hidden = fields;
282
+ }
283
+ /** Fields that can NEVER be input — like Rails' `attr_protected` or Laravel's `$guarded` */
284
+ guarded(fields) {
285
+ this._guarded = fields;
286
+ }
287
+ /** Define input profiles per operation — like Laravel's `$fillable` + NestJS DTOs */
288
+ fillable(profiles) {
289
+ this._fillableProfiles = profiles;
290
+ }
291
+ // ── Compile ─────────────────────────────────────────
292
+ /** @internal Compile all fields into a Zod schema */
293
+ _compile() {
294
+ const shape = {};
295
+ const defaults = {};
296
+ for (const [name, def] of Object.entries(this._fields)) {
297
+ shape[name] = compileField(def);
298
+ if (def._defaultValue !== undefined) {
299
+ defaults[name] = def._defaultValue;
300
+ }
301
+ }
302
+ return { schema: z.object(shape), defaults };
303
+ }
304
+ }
305
+ // ── Factory ─────────────────────────────────────────────
306
+ /**
307
+ * Define a Model — one file, one entity, one source of truth.
308
+ *
309
+ * @param name - Model name (e.g. 'Task', 'Sprint', 'Project')
310
+ * @param configure - Closure function that receives a `ModelBuilder` (`m`)
311
+ * @returns Compiled `Model` with `.schema`, `.fields`, `.input`, `.hidden`, `.guarded`
312
+ */
313
+ export function defineModel(name, configure) {
314
+ const builder = new ModelBuilder();
315
+ configure(builder);
316
+ const { schema, defaults } = builder._compile();
317
+ // Pre-compute alias map at definition time (not per-call)
318
+ const aliasMap = new Map();
319
+ for (const [fieldName, fieldDef] of Object.entries(builder._fields)) {
320
+ if (fieldDef._alias) {
321
+ aliasMap.set(fieldName, fieldDef._alias);
322
+ }
323
+ }
324
+ const toApi = (data) => {
325
+ const result = {};
326
+ for (const [k, v] of Object.entries(data)) {
327
+ if (v !== undefined) {
328
+ result[aliasMap.get(k) ?? k] = v;
329
+ }
330
+ }
331
+ return result;
332
+ };
333
+ return Object.freeze({
334
+ name,
335
+ schema,
336
+ fields: Object.freeze(builder._fields),
337
+ hidden: Object.freeze(builder._hidden),
338
+ guarded: Object.freeze(builder._guarded),
339
+ input: Object.freeze(builder._fillableProfiles),
340
+ defaults: Object.freeze(defaults),
341
+ toApi,
342
+ infer: undefined,
343
+ });
344
+ }
345
+ //# sourceMappingURL=defineModel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defineModel.js","sourceRoot":"","sources":["../../src/model/defineModel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Model Layer — Barrel Export
3
+ *
4
+ * @module
5
+ */
6
+ export { defineModel, FieldDef, ModelBuilder, compileFieldForInput } from './defineModel.js';
7
+ export type { Model } from './defineModel.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7F,YAAY,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Model Layer — Barrel Export
3
+ *
4
+ * @module
5
+ */
6
+ export { defineModel, FieldDef, ModelBuilder, compileFieldForInput } from './defineModel.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"TelemetryBus.d.ts","sourceRoot":"","sources":["../../src/observability/TelemetryBus.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAkCzE;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAM7D;AA2DD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,IAAI,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAmDpF;AA2ED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;CACzD;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;IACnC,mCAAmC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAqKnG"}
1
+ {"version":3,"file":"TelemetryBus.d.ts","sourceRoot":"","sources":["../../src/observability/TelemetryBus.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAkCzE;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAM7D;AA2DD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,IAAI,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAmDpF;AA2ED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,cAAc,GAAG,SAAS,CAAC;CACzD;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;IACnC,mCAAmC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAsKnG"}
@@ -326,6 +326,18 @@ export async function createTelemetryBus(config) {
326
326
  });
327
327
  });
328
328
  // ── Start Listening ───────────────────────────────────
329
+ // Bug #7 fix: chmod inside the listen callback to eliminate the race
330
+ // window where the socket is world-readable before permissions are set.
331
+ const chmodSocket = () => {
332
+ if (platform() !== 'win32') {
333
+ try {
334
+ chmodSync(socketPath, 0o600);
335
+ }
336
+ catch {
337
+ process.stderr.write('[vurb] Warning: Could not restrict socket permissions.\n');
338
+ }
339
+ }
340
+ };
329
341
  await new Promise((resolve, reject) => {
330
342
  server.once('error', (err) => {
331
343
  if (err.code === 'EADDRINUSE') {
@@ -337,27 +349,16 @@ export async function createTelemetryBus(config) {
337
349
  }
338
350
  catch { /* ignore on Windows */ }
339
351
  server.once('error', (retryErr) => reject(retryErr));
340
- server.listen(socketPath, () => resolve());
352
+ server.listen(socketPath, () => { chmodSocket(); resolve(); });
341
353
  }
342
354
  else {
343
355
  reject(err);
344
356
  }
345
357
  });
346
- server.listen(socketPath, () => resolve());
358
+ server.listen(socketPath, () => { chmodSocket(); resolve(); });
347
359
  });
348
360
  // ── Registry: announce this server for auto-discovery ──
349
361
  writeRegistryFile(process.pid, config?.path ? undefined : 'vurb');
350
- // ── Gotcha #1: IPC Security (chmod 0o600) ─────────────
351
- // Restrict socket to owner-only on POSIX to prevent PII sniffing
352
- if (platform() !== 'win32') {
353
- try {
354
- chmodSync(socketPath, 0o600);
355
- }
356
- catch {
357
- // Non-fatal — log warning via stderr (never stdout!)
358
- process.stderr.write('[vurb] Warning: Could not restrict socket permissions.\n');
359
- }
360
- }
361
362
  // ── Heartbeat Timer ───────────────────────────────────
362
363
  const heartbeatTimer = setInterval(() => {
363
364
  if (clients.size === 0)