@nebutra/contracts 0.1.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +16 -6
- package/.turbo/turbo-test.log +15 -0
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +31 -0
- package/LICENSE +21 -676
- package/dist/admin.d.ts +416 -0
- package/dist/admin.js +51 -0
- package/dist/admin.js.map +1 -0
- package/dist/chunk-ERZTZ3PW.js +257 -0
- package/dist/chunk-ERZTZ3PW.js.map +1 -0
- package/dist/chunk-PU65L2HQ.js +218 -0
- package/dist/chunk-PU65L2HQ.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +107 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/sleptons.d.ts +510 -0
- package/dist/sleptons.js +61 -0
- package/dist/sleptons.js.map +1 -0
- package/package.json +18 -3
- package/src/__tests__/admin.test.ts +120 -0
- package/src/admin.ts +297 -0
- package/src/index.ts +2 -0
- package/src/sleptons.test.ts +62 -0
- package/src/sleptons.ts +242 -0
- package/tsup.config.ts +2 -0
- package/vitest.config.ts +10 -0
package/src/sleptons.ts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sleptons résumé content contract (v1).
|
|
5
|
+
*
|
|
6
|
+
* The résumé is the structured "track record" attached 1:1 to a Sleptons member
|
|
7
|
+
* profile. It is stored as a JSON document (`sleptons_resumes.content`) and
|
|
8
|
+
* validated against this schema on every write. Derived/query columns are
|
|
9
|
+
* computed by the consumer (apps/sleptons), never stored inside `content`.
|
|
10
|
+
*
|
|
11
|
+
* Design source: docs/superpowers/specs/2026-09-07-sleptons-resume-system-design.md §3.
|
|
12
|
+
* Lineage: adapted from the CVise `Profile` Zod model (legacy, archived 2026-09-07).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export const RESUME_CONTENT_VERSION = 1 as const;
|
|
16
|
+
|
|
17
|
+
export const ResumeLangSchema = z.enum(["ZH", "EN", "MIX"]);
|
|
18
|
+
export type ResumeLang = z.infer<typeof ResumeLangSchema>;
|
|
19
|
+
|
|
20
|
+
export const ResumePeriodSchema = z.string().max(40); // free text, e.g. "2024.06 – 2025.01"
|
|
21
|
+
|
|
22
|
+
const shortText = z.string().max(200);
|
|
23
|
+
const bullet = z.string().max(600);
|
|
24
|
+
const bullets = z.array(bullet).max(12);
|
|
25
|
+
const tags = z.array(z.string().max(40)).max(20);
|
|
26
|
+
|
|
27
|
+
export const ResumeLinksSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
github: z.string().max(200).optional(),
|
|
30
|
+
linkedin: z.string().max(200).optional(),
|
|
31
|
+
twitter: z.string().max(200).optional(),
|
|
32
|
+
personal: z.string().max(200).optional(),
|
|
33
|
+
})
|
|
34
|
+
.partial();
|
|
35
|
+
|
|
36
|
+
export const ResumeBasicSchema = z.object({
|
|
37
|
+
name: z.string().min(1).max(120),
|
|
38
|
+
name_en: z.string().max(120).optional(),
|
|
39
|
+
email: z.email().optional(),
|
|
40
|
+
phone: z.string().max(40).optional(),
|
|
41
|
+
location: z.string().max(120).optional(),
|
|
42
|
+
website: z.url().optional(),
|
|
43
|
+
links: ResumeLinksSchema.optional(),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export const ResumeObjectiveSchema = z.object({
|
|
47
|
+
summary: z.string().max(4000).optional(), // sanitized HTML or plain text
|
|
48
|
+
advantage_tags: z.array(z.string().max(40)).max(8).optional(),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export const VentureStageSchema = z.enum([
|
|
52
|
+
"idea",
|
|
53
|
+
"building",
|
|
54
|
+
"launched",
|
|
55
|
+
"scaling",
|
|
56
|
+
"exited",
|
|
57
|
+
"closed",
|
|
58
|
+
]);
|
|
59
|
+
export type VentureStage = z.infer<typeof VentureStageSchema>;
|
|
60
|
+
|
|
61
|
+
export const ResumeVentureSchema = z.object({
|
|
62
|
+
name: shortText,
|
|
63
|
+
role: shortText.optional(),
|
|
64
|
+
period: ResumePeriodSchema.optional(),
|
|
65
|
+
stage: VentureStageSchema.optional(),
|
|
66
|
+
outcome: z.string().max(600).optional(),
|
|
67
|
+
url: z.url().optional(),
|
|
68
|
+
details: bullets.optional(),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
export const ExperienceKindSchema = z.enum(["work", "campus", "founder"]);
|
|
72
|
+
export type ExperienceKind = z.infer<typeof ExperienceKindSchema>;
|
|
73
|
+
|
|
74
|
+
export const ResumeExperienceSchema = z.object({
|
|
75
|
+
kind: ExperienceKindSchema.default("work"),
|
|
76
|
+
period: ResumePeriodSchema,
|
|
77
|
+
org: shortText,
|
|
78
|
+
title: shortText,
|
|
79
|
+
details: bullets.optional(),
|
|
80
|
+
rich: z.string().max(6000).optional(),
|
|
81
|
+
tags: tags.optional(),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export const ResumeEducationSchema = z.object({
|
|
85
|
+
school: shortText,
|
|
86
|
+
school_en: shortText.optional(),
|
|
87
|
+
major: shortText.optional(),
|
|
88
|
+
degree: shortText.optional(),
|
|
89
|
+
period: ResumePeriodSchema.optional(),
|
|
90
|
+
gpa: z.string().max(40).optional(),
|
|
91
|
+
courses: z.array(z.string().max(80)).max(30).optional(),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
export const ResumeProjectSchema = z.object({
|
|
95
|
+
name: shortText,
|
|
96
|
+
role: shortText.optional(),
|
|
97
|
+
period: ResumePeriodSchema.optional(),
|
|
98
|
+
stack: tags.optional(),
|
|
99
|
+
details: bullets.optional(),
|
|
100
|
+
links: z.array(z.string().max(300)).max(6).optional(),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
export const ResumeAchievementSchema = z.object({
|
|
104
|
+
title: shortText,
|
|
105
|
+
level: z.string().max(40).optional(),
|
|
106
|
+
year: z.string().max(10).optional(),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
export const ResumeCertificateSchema = z.object({
|
|
110
|
+
name: shortText,
|
|
111
|
+
issuer: shortText.optional(),
|
|
112
|
+
year: z.string().max(10).optional(),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
export const RESUME_SKILL_CATEGORIES = [
|
|
116
|
+
"programming",
|
|
117
|
+
"ai_engineering",
|
|
118
|
+
"ai_theory",
|
|
119
|
+
"data",
|
|
120
|
+
"product",
|
|
121
|
+
"finance",
|
|
122
|
+
"tools",
|
|
123
|
+
"ai_tools",
|
|
124
|
+
"languages",
|
|
125
|
+
] as const;
|
|
126
|
+
export type ResumeSkillCategory = (typeof RESUME_SKILL_CATEGORIES)[number];
|
|
127
|
+
|
|
128
|
+
export const ResumeSkillsSchema = z
|
|
129
|
+
.object(
|
|
130
|
+
Object.fromEntries(RESUME_SKILL_CATEGORIES.map((k) => [k, tags.optional()])) as Record<
|
|
131
|
+
ResumeSkillCategory,
|
|
132
|
+
z.ZodOptional<typeof tags>
|
|
133
|
+
>,
|
|
134
|
+
)
|
|
135
|
+
.partial();
|
|
136
|
+
|
|
137
|
+
export const ResumePublicationSchema = z.object({
|
|
138
|
+
title: z.string().max(300),
|
|
139
|
+
venue: shortText.optional(),
|
|
140
|
+
year: z.string().max(10).optional(),
|
|
141
|
+
url: z.string().max(300).optional(),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
export const ResumePatentSchema = z.object({
|
|
145
|
+
title: z.string().max(300),
|
|
146
|
+
id: z.string().max(60).optional(),
|
|
147
|
+
year: z.string().max(10).optional(),
|
|
148
|
+
status: z.string().max(40).optional(),
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
export const ResumeOpenSourceSchema = z.object({
|
|
152
|
+
repo: z.string().max(200),
|
|
153
|
+
stars: z.number().int().nonnegative().optional(),
|
|
154
|
+
role: shortText.optional(),
|
|
155
|
+
highlights: bullets.optional(),
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
export const ResumeFundingSchema = z.object({
|
|
159
|
+
round: z.string().max(40),
|
|
160
|
+
amount: z.string().max(40).optional(),
|
|
161
|
+
date: z.string().max(20).optional(),
|
|
162
|
+
investors: z.array(shortText).max(20).optional(),
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
export const ResumePressSchema = z.object({
|
|
166
|
+
title: z.string().max(300),
|
|
167
|
+
outlet: shortText.optional(),
|
|
168
|
+
url: z.url().optional(),
|
|
169
|
+
date: z.string().max(20).optional(),
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
export const ResumeVolunteeringSchema = z.object({
|
|
173
|
+
org: shortText,
|
|
174
|
+
role: shortText.optional(),
|
|
175
|
+
period: ResumePeriodSchema.optional(),
|
|
176
|
+
details: bullets.optional(),
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
export const ResumeMarginsSchema = z.object({
|
|
180
|
+
top: z.string().max(10),
|
|
181
|
+
right: z.string().max(10),
|
|
182
|
+
bottom: z.string().max(10),
|
|
183
|
+
left: z.string().max(10),
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
export const DEFAULT_RESUME_MARGINS = {
|
|
187
|
+
top: "12mm",
|
|
188
|
+
right: "12mm",
|
|
189
|
+
bottom: "12mm",
|
|
190
|
+
left: "12mm",
|
|
191
|
+
} as const;
|
|
192
|
+
|
|
193
|
+
export const ResumePreferencesSchema = z.object({
|
|
194
|
+
length: z.enum(["1page", "2pages"]).default("1page"),
|
|
195
|
+
show_icons: z.boolean().default(true),
|
|
196
|
+
show_contact_public: z.boolean().default(false),
|
|
197
|
+
paper: z.enum(["A4", "Letter"]).default("A4"),
|
|
198
|
+
margins: ResumeMarginsSchema.default(DEFAULT_RESUME_MARGINS),
|
|
199
|
+
max_bullets_per_entry: z.number().int().min(1).max(8).default(3),
|
|
200
|
+
section_order: z.array(z.string().max(40)).max(30).optional(),
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
export const ResumeContentV1Schema = z.object({
|
|
204
|
+
version: z.literal(RESUME_CONTENT_VERSION).default(RESUME_CONTENT_VERSION),
|
|
205
|
+
basic: ResumeBasicSchema,
|
|
206
|
+
objective: ResumeObjectiveSchema.default({}),
|
|
207
|
+
ventures: z.array(ResumeVentureSchema).max(20).optional(),
|
|
208
|
+
experiences: z.array(ResumeExperienceSchema).max(30).optional(),
|
|
209
|
+
education: z.array(ResumeEducationSchema).max(10).optional(),
|
|
210
|
+
projects: z.array(ResumeProjectSchema).max(30).optional(),
|
|
211
|
+
achievements: z.array(ResumeAchievementSchema).max(30).optional(),
|
|
212
|
+
certificates: z.array(ResumeCertificateSchema).max(30).optional(),
|
|
213
|
+
skills: ResumeSkillsSchema.optional(),
|
|
214
|
+
publications: z.array(ResumePublicationSchema).max(50).optional(),
|
|
215
|
+
patents: z.array(ResumePatentSchema).max(30).optional(),
|
|
216
|
+
opensource: z.array(ResumeOpenSourceSchema).max(30).optional(),
|
|
217
|
+
funding: z.array(ResumeFundingSchema).max(20).optional(),
|
|
218
|
+
press: z.array(ResumePressSchema).max(30).optional(),
|
|
219
|
+
volunteering: z.array(ResumeVolunteeringSchema).max(20).optional(),
|
|
220
|
+
interests: z.array(z.string().max(60)).max(20).optional(),
|
|
221
|
+
preferences: ResumePreferencesSchema.prefault({}),
|
|
222
|
+
});
|
|
223
|
+
export type ResumeContentV1 = z.infer<typeof ResumeContentV1Schema>;
|
|
224
|
+
export type ResumeContentV1Input = z.input<typeof ResumeContentV1Schema>;
|
|
225
|
+
|
|
226
|
+
/** Write payload accepted by `PUT /api/resume`. */
|
|
227
|
+
export const ResumeWriteSchema = z.object({
|
|
228
|
+
content: ResumeContentV1Schema,
|
|
229
|
+
is_public: z.boolean().optional(),
|
|
230
|
+
language: ResumeLangSchema.optional(),
|
|
231
|
+
});
|
|
232
|
+
export type ResumeWrite = z.infer<typeof ResumeWriteSchema>;
|
|
233
|
+
|
|
234
|
+
/** Columns derived from `content` on every save; see apps/sleptons/src/lib/resume/derive.ts. */
|
|
235
|
+
export const ResumeDerivedSchema = z.object({
|
|
236
|
+
headline: z.string().max(120).nullable(),
|
|
237
|
+
skills_flat: z.array(z.string()),
|
|
238
|
+
highlights: z.array(z.string()).max(3),
|
|
239
|
+
years_active: z.number().int().nonnegative().nullable(),
|
|
240
|
+
completeness: z.number().int().min(0).max(100),
|
|
241
|
+
});
|
|
242
|
+
export type ResumeDerived = z.infer<typeof ResumeDerivedSchema>;
|
package/tsup.config.ts
CHANGED