@hirely/sdk 1.0.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@hirely/sdk` are documented here.
4
+
5
+ ## [0.1.0] - 2024-09-13
6
+
7
+ ### Added
8
+
9
+ - Initial public release of `@hirely/sdk`
10
+ - `Hirely` client class with `apiKey` validation
11
+ - `hirely.get()` — fetch complete portfolio in one request
12
+ - `hirely.me()` — fetch account info + full profile
13
+ - Resource helpers: `projects`, `work`, `education`, `skills`, `certificates`, `services`, `testimonials`, `faqs`, `contacts`, `cv`
14
+ - Per-resource lookup methods: `.getById()` and `.getBySlug()` (projects only)
15
+ - Typed error hierarchy: `HirelyError`, `HirelyAuthenticationError`, `HirelyNotFoundError`, `HirelyValidationError`, `HirelyRateLimitError`, `HirelyTimeoutError`, `HirelyServerError`
16
+ - SDK-side in-memory caching with configurable TTL
17
+ - Custom cache store interface (`HirelyCache`) for Redis or any external store
18
+ - Per-request cache bypass via `{ cache: false }`
19
+ - Exponential backoff retry logic for transient errors
20
+ - `AbortController`-based request timeout
21
+ - Zero runtime dependencies — uses native `fetch` API
22
+ - Full TypeScript support with declaration maps
23
+ - ESM-only output targeting ES2022
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hirely
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,532 @@
1
+ <div align="center">
2
+ <h1>@hirely/sdk</h1>
3
+ <p>Official JavaScript & TypeScript SDK for <a href="https://hirely.cc">Hirely</a></p>
4
+ <p>
5
+ <a href="https://www.npmjs.com/package/@hirely/sdk"><img src="https://img.shields.io/npm/v/@hirely/sdk.svg" alt="npm version" /></a>
6
+ <a href="https://www.npmjs.com/package/@hirely/sdk"><img src="https://img.shields.io/npm/dm/@hirely/sdk.svg" alt="downloads" /></a>
7
+ <img src="https://img.shields.io/badge/TypeScript-ready-blue" alt="TypeScript" />
8
+ <img src="https://img.shields.io/badge/license-MIT-green" alt="MIT license" />
9
+ </p>
10
+ </div>
11
+
12
+ ---
13
+
14
+ ## What is Hirely?
15
+
16
+ [Hirely](https://hirely.cc) is an **AI-powered career accelerator and professional portfolio platform** built for developers and freelancers. It combines intelligent content management, semantic job discovery, and a conversational AI career coach — all in one platform.
17
+
18
+ ### The platform at a glance
19
+
20
+ **AI-First career management**
21
+ Hirely's AI doesn't just store your data — it actively coaches you. It analyzes your skill matrix, identifies knowledge gaps, generates tailored CVs for specific job descriptions, scores your resume against ATS systems, and synthesizes your experience into compelling recruiter-ready biographies. An integrated conversational AI agent lets you build and update your entire profile through natural chat.
22
+
23
+ **Semantic professional discovery**
24
+ Hirely moves beyond keyword matching. Using Google Gemini vector embeddings, the platform understands the true intent behind searches — matching freelancers to clients based on deep contextual similarity, not just exact keyword overlap.
25
+
26
+ **Third-party integrations**
27
+ Connect GitHub to auto-import projects from public repositories (AI-generated descriptions, skill extraction, verified developer badge). Connect Spotify to display a live "Now Playing" widget on your public portfolio. LinkedIn, Discord, Figma, and Notion integrations are on the roadmap.
28
+
29
+ **Enterprise-grade infrastructure**
30
+ Built for scale: Redis SWR caching, background job queues, real-time AI quota management, cryptographic webhook verification, and GDPR/CCPA/EU AI Act compliance — including permanent Right to be Forgotten workflows and data portability exports.
31
+
32
+ ### How the SDK fits in
33
+
34
+ Hirely manages all your professional content — projects, work history, education, skills, certificates, testimonials, services, and more — through a rich dashboard. The `@hirely/sdk` is the bridge that lets you pull that content into **any website or app you build**, with full TypeScript types, caching, and error handling included.
35
+
36
+ ```
37
+ Hirely dashboard (content management + AI tools)
38
+ ↓ your public portfolio data
39
+ @hirely/sdk (this package)
40
+ ↓ typed, cached, ready to render
41
+ Your website / app (Next.js, Astro, Remix, plain HTML — your choice)
42
+ ```
43
+
44
+ **You own the presentation layer completely.** Use your own framework, your own design, your own domain. The SDK handles authentication, data fetching, retries, caching, and TypeScript types — so you can focus on building a great frontend.
45
+
46
+ ---
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ # Bun (recommended)
52
+ bun add @hirely/sdk
53
+
54
+ # npm
55
+ npm install @hirely/sdk
56
+
57
+ # pnpm
58
+ pnpm add @hirely/sdk
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Quick start
64
+
65
+ ```ts
66
+ import Hirely from "@hirely/sdk";
67
+
68
+ const hirely = new Hirely({
69
+ apiKey: process.env.HIRELY_API_KEY!,
70
+ });
71
+
72
+ const portfolio = await hirely.get();
73
+
74
+ console.log(portfolio.profile?.firstName);
75
+ console.log(portfolio.projects.length);
76
+ ```
77
+
78
+ ---
79
+
80
+ ## API key setup
81
+
82
+ Generate a public API key from your [Hirely dashboard](https://hirely.cc/dashboard/settings/api-keys).
83
+
84
+ ```env
85
+ HIRELY_API_KEY=hk_pub_xxxxxxxxxxxxxxxxxxxxxxxxx
86
+ ```
87
+
88
+ > **Note:** Your API key starts with `hk_pub_`. It is scoped to your account and provides **read-only** access to your public portfolio data. It cannot access or modify any other user's data.
89
+
90
+ ---
91
+
92
+ ## Usage
93
+
94
+ ### Full portfolio
95
+
96
+ The most efficient way to power a portfolio website — fetch everything in a single request:
97
+
98
+ ```ts
99
+ const portfolio = await hirely.get();
100
+
101
+ portfolio.profile // → HirelyProfile
102
+ portfolio.projects // → HirelyProject[]
103
+ portfolio.work // → HirelyWork[]
104
+ portfolio.education // → HirelyEducation[]
105
+ portfolio.skills // → HirelySkill[]
106
+ portfolio.certificates // → HirelyCertificate[]
107
+ portfolio.services // → HirelyService[]
108
+ portfolio.testimonials // → HirelyTestimonial[]
109
+ portfolio.faqs // → HirelyFaq[]
110
+ portfolio.contact // → HirelyContact | null
111
+ portfolio.cv // → HirelyCV | null
112
+ ```
113
+
114
+ ### Account info
115
+
116
+ ```ts
117
+ const me = await hirely.me();
118
+
119
+ me.userName // → "mahmoud"
120
+ me.email // → "hello@example.com"
121
+ me.plan // → "pro"
122
+ ```
123
+
124
+ ### Projects
125
+
126
+ ```ts
127
+ // All public projects
128
+ const projects = await hirely.projects();
129
+
130
+ // By MongoDB ID
131
+ const project = await hirely.projects.getById("665f1a2b3c4d5e6f7a8b9c0d");
132
+
133
+ // By slug (ideal for dynamic routes)
134
+ const project = await hirely.projects.getBySlug("my-awesome-app");
135
+
136
+ project.title // → "My Awesome App"
137
+ project.slug // → "my-awesome-app"
138
+ project.description // → "..."
139
+ project.technologies // → ["React", "TypeScript", "Node.js"]
140
+ project.demoUrl // → "https://example.com"
141
+ project.repositoryUrl // → "https://github.com/..."
142
+ project.featured // → true
143
+ ```
144
+
145
+ ### Work experience
146
+
147
+ ```ts
148
+ const jobs = await hirely.work();
149
+ const job = await hirely.work.getById("665...");
150
+
151
+ job.companyName // → "Acme Corp"
152
+ job.position // → "Senior Engineer"
153
+ job.isCurrent // → true
154
+ job.achievements // → ["Led migration to microservices", ...]
155
+ ```
156
+
157
+ ### Education
158
+
159
+ ```ts
160
+ const education = await hirely.education();
161
+ const entry = await hirely.education.getById("665...");
162
+
163
+ entry.institution // → "Cairo University"
164
+ entry.degree // → "Bachelor's"
165
+ entry.fieldOfStudy // → "Computer Science"
166
+ ```
167
+
168
+ ### Skills
169
+
170
+ ```ts
171
+ const skills = await hirely.skills();
172
+
173
+ // Group by category
174
+ const byCategory = skills.reduce((acc, skill) => {
175
+ const cat = skill.category ?? "Other";
176
+ acc[cat] = [...(acc[cat] ?? []), skill.name ?? ""];
177
+ return acc;
178
+ }, {} as Record<string, string[]>);
179
+ ```
180
+
181
+ ### Certificates
182
+
183
+ ```ts
184
+ const certs = await hirely.certificates();
185
+ const cert = await hirely.certificates.getById("665...");
186
+
187
+ cert.name // → "AWS Solutions Architect"
188
+ cert.issuer // → "Amazon Web Services"
189
+ cert.credentialUrl // → "https://credly.com/..."
190
+ ```
191
+
192
+ ### Services
193
+
194
+ ```ts
195
+ const services = await hirely.services();
196
+ const service = await hirely.services.getById("665...");
197
+
198
+ service.title // → "Full-Stack Development"
199
+ service.pricing?.type // → "fixed"
200
+ service.packages // → [{ name: "Basic", price: 500, ... }]
201
+ ```
202
+
203
+ ### Testimonials
204
+
205
+ ```ts
206
+ const testimonials = await hirely.testimonials();
207
+ const testimonial = await hirely.testimonials.getById("665...");
208
+
209
+ testimonial.client?.firstName // → "John"
210
+ testimonial.rating // → 5
211
+ testimonial.review // → "Exceptional work..."
212
+ ```
213
+
214
+ ### FAQ
215
+
216
+ ```ts
217
+ const faqs = await hirely.faqs();
218
+ const faq = await hirely.faqs.getById("665...");
219
+
220
+ faq.question // → "What is your availability?"
221
+ faq.answer // → "I'm available for..."
222
+ ```
223
+
224
+ ### Contacts & social links
225
+
226
+ ```ts
227
+ const contact = await hirely.contacts();
228
+
229
+ contact?.socialLinks?.forEach(link => {
230
+ console.log(link.platform, link.url);
231
+ // → "github", "https://github.com/..."
232
+ // → "linkedIn", "https://linkedin.com/..."
233
+ });
234
+ ```
235
+
236
+ ### CV
237
+
238
+ ```ts
239
+ const cv = await hirely.cv();
240
+
241
+ cv?.pdfUrl // → "https://cdn.hirely.cc/cvs/my-cv.pdf"
242
+ cv?.docxUrl // → "https://cdn.hirely.cc/cvs/my-cv.docx"
243
+ ```
244
+
245
+ ### Site info & settings
246
+
247
+ ```ts
248
+ const info = await hirely.info();
249
+
250
+ info?.isActive // → true
251
+ info?.showSkills // → true
252
+ info?.siteSettings?.bgColor // → "#0f0f0f"
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Caching
258
+
259
+ Enable optional in-memory response caching to reduce API calls:
260
+
261
+ ```ts
262
+ const hirely = new Hirely({
263
+ apiKey: process.env.HIRELY_API_KEY!,
264
+ cache: {
265
+ enabled: true,
266
+ ttl: 300, // seconds — cache responses for 5 minutes
267
+ },
268
+ });
269
+
270
+ // Normal call — uses cache
271
+ const projects = await hirely.projects();
272
+
273
+ // Bypass cache for a fresh request
274
+ const freshProjects = await hirely.projects({ cache: false });
275
+ ```
276
+
277
+ ### Custom cache store
278
+
279
+ Bring your own cache backend (Redis, Upstash, etc.):
280
+
281
+ ```ts
282
+ import type { HirelyCache } from "@hirely/sdk";
283
+
284
+ const redisStore: HirelyCache = {
285
+ get: async (key) => {
286
+ const raw = await redis.get(key);
287
+ return raw ? JSON.parse(raw) : undefined;
288
+ },
289
+ set: async (key, value, ttl) => {
290
+ await redis.set(key, JSON.stringify(value), "EX", ttl);
291
+ },
292
+ };
293
+
294
+ const hirely = new Hirely({
295
+ apiKey: process.env.HIRELY_API_KEY!,
296
+ cache: { enabled: true, ttl: 300, store: redisStore },
297
+ });
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Retries & timeouts
303
+
304
+ ```ts
305
+ const hirely = new Hirely({
306
+ apiKey: process.env.HIRELY_API_KEY!,
307
+ timeout: 10_000, // 10s timeout per request
308
+ retries: 2, // retry up to 2 times on transient errors (5xx, 429)
309
+ });
310
+ ```
311
+
312
+ The SDK automatically retries on `500`, `502`, `503`, `504`, `408`, `425`, and `429` with exponential backoff. It does **not** retry on `400`, `401`, `403`, `404`, or `422`.
313
+
314
+ ---
315
+
316
+ ## Error handling
317
+
318
+ ```ts
319
+ import Hirely, {
320
+ HirelyError,
321
+ HirelyAuthenticationError,
322
+ HirelyNotFoundError,
323
+ HirelyRateLimitError,
324
+ HirelyTimeoutError,
325
+ HirelyServerError,
326
+ } from "@hirely/sdk";
327
+
328
+ try {
329
+ const project = await hirely.projects.getBySlug("my-project");
330
+ } catch (error) {
331
+ if (error instanceof HirelyAuthenticationError) {
332
+ // 401/403 — invalid or missing API key
333
+ } else if (error instanceof HirelyNotFoundError) {
334
+ // 404 — resource does not exist
335
+ } else if (error instanceof HirelyRateLimitError) {
336
+ console.log(`Retry in ${error.retryAfter}s`);
337
+ } else if (error instanceof HirelyTimeoutError) {
338
+ // Request exceeded the configured timeout
339
+ } else if (error instanceof HirelyServerError) {
340
+ // 5xx server error
341
+ } else if (error instanceof HirelyError) {
342
+ // Any other SDK error
343
+ console.error(error.status, error.code, error.message);
344
+ }
345
+ }
346
+ ```
347
+
348
+ ---
349
+
350
+ ## Framework examples
351
+
352
+ ### Next.js (App Router)
353
+
354
+ ```tsx
355
+ // app/page.tsx
356
+ import Hirely from "@hirely/sdk";
357
+
358
+ const hirely = new Hirely({
359
+ apiKey: process.env.HIRELY_API_KEY!, // server-only env var
360
+ cache: { enabled: true, ttl: 300 },
361
+ });
362
+
363
+ export default async function Page() {
364
+ const portfolio = await hirely.get();
365
+
366
+ return (
367
+ <main>
368
+ <h1>
369
+ {portfolio.profile?.firstName} {portfolio.profile?.lastName}
370
+ </h1>
371
+ <p>{portfolio.profile?.about}</p>
372
+
373
+ <section>
374
+ <h2>Projects</h2>
375
+ {portfolio.projects.map((project) => (
376
+ <article key={project._id}>
377
+ <h3>{project.title}</h3>
378
+ <p>{project.shortDescription}</p>
379
+ <ul>
380
+ {project.technologies?.map((tech) => (
381
+ <li key={tech}>{tech}</li>
382
+ ))}
383
+ </ul>
384
+ {project.demoUrl && (
385
+ <a href={project.demoUrl}>Live Demo →</a>
386
+ )}
387
+ </article>
388
+ ))}
389
+ </section>
390
+ </main>
391
+ );
392
+ }
393
+ ```
394
+
395
+ ### Next.js dynamic project page
396
+
397
+ ```tsx
398
+ // app/projects/[slug]/page.tsx
399
+ import Hirely, { HirelyNotFoundError } from "@hirely/sdk";
400
+ import { notFound } from "next/navigation";
401
+
402
+ const hirely = new Hirely({ apiKey: process.env.HIRELY_API_KEY! });
403
+
404
+ export default async function ProjectPage({
405
+ params,
406
+ }: {
407
+ params: { slug: string };
408
+ }) {
409
+ try {
410
+ const project = await hirely.projects.getBySlug(params.slug);
411
+
412
+ return (
413
+ <article>
414
+ <h1>{project.title}</h1>
415
+ <p>{project.description}</p>
416
+ </article>
417
+ );
418
+ } catch (error) {
419
+ if (error instanceof HirelyNotFoundError) notFound();
420
+ throw error;
421
+ }
422
+ }
423
+ ```
424
+
425
+ ### Astro
426
+
427
+ ```astro
428
+ ---
429
+ // src/pages/index.astro
430
+ import Hirely from "@hirely/sdk";
431
+
432
+ const hirely = new Hirely({ apiKey: import.meta.env.HIRELY_API_KEY });
433
+ const portfolio = await hirely.get();
434
+ ---
435
+
436
+ <main>
437
+ <h1>{portfolio.profile?.firstName} {portfolio.profile?.lastName}</h1>
438
+ {portfolio.projects.map((p) => (
439
+ <article>
440
+ <h2>{p.title}</h2>
441
+ <p>{p.shortDescription}</p>
442
+ </article>
443
+ ))}
444
+ </main>
445
+ ```
446
+
447
+ ### Remix
448
+
449
+ ```tsx
450
+ // app/routes/_index.tsx
451
+ import { json } from "@remix-run/node";
452
+ import { useLoaderData } from "@remix-run/react";
453
+ import Hirely from "@hirely/sdk";
454
+
455
+ const hirely = new Hirely({ apiKey: process.env.HIRELY_API_KEY! });
456
+
457
+ export async function loader() {
458
+ const portfolio = await hirely.get();
459
+ return json({ portfolio });
460
+ }
461
+
462
+ export default function Index() {
463
+ const { portfolio } = useLoaderData<typeof loader>();
464
+ return <h1>{portfolio.profile?.firstName}</h1>;
465
+ }
466
+ ```
467
+
468
+ ---
469
+
470
+ ## Security
471
+
472
+ ### API key model
473
+
474
+ - Keys are generated in your Hirely dashboard
475
+ - Each key is scoped to **one Hirely account** — one key cannot access another user's data
476
+ - SDK access is **read-only** — the SDK cannot create, update, or delete any data
477
+ - Keys use the format `hk_pub_xxx` and are safe to use in server-side environments
478
+
479
+ ### Public vs. server environments
480
+
481
+ | Environment | Safe to use API key? |
482
+ |---|---|
483
+ | Next.js Server Components | ✅ Yes — runs on server |
484
+ | Astro SSR / SSG | ✅ Yes — runs on server |
485
+ | Node.js / Bun scripts | ✅ Yes |
486
+ | Remix loaders | ✅ Yes — runs on server |
487
+ | Browser (client-side) | ⚠️ Only if your use case explicitly requires it |
488
+
489
+ Because `hk_pub_` keys are read-only and scoped to your portfolio, exposing them in client-side code does not grant write access. However, it does expose your key to anyone who inspects your bundle. Use your judgement based on your application.
490
+
491
+ ---
492
+
493
+ ## Configuration reference
494
+
495
+ ```ts
496
+ interface HirelyConfig {
497
+ apiKey: string; // Required. Must start with hk_pub_
498
+ timeout?: number; // Request timeout in ms. Default: 30_000
499
+ retries?: number; // Retry attempts for transient errors. Default: 2
500
+ cache?: {
501
+ enabled: boolean; // Enable SDK-side caching
502
+ ttl?: number; // Cache TTL in seconds. Default: 300
503
+ store?: HirelyCache; // Custom cache store (Redis, etc.)
504
+ };
505
+ fetch?: typeof fetch; // Custom fetch implementation
506
+ }
507
+ ```
508
+
509
+ ---
510
+
511
+ ## Works with
512
+
513
+ | Runtime | Supported |
514
+ |---|---|
515
+ | Node.js 18+ | ✅ |
516
+ | Bun | ✅ |
517
+ | Deno | ✅ |
518
+ | Browser (modern) | ✅ |
519
+ | Next.js | ✅ |
520
+ | Astro | ✅ |
521
+ | Remix | ✅ |
522
+ | React (SSR/SSG) | ✅ |
523
+ | Vue / Nuxt | ✅ |
524
+ | Svelte / SvelteKit | ✅ |
525
+
526
+ No dependencies required. Uses the native `fetch` API available in all modern environments.
527
+
528
+ ---
529
+
530
+ ## License
531
+
532
+ MIT © [Hirely](https://hirely.cc)
@@ -0,0 +1 @@
1
+ export {};