@hadoku/jobplatform-worker 2.32.14 → 2.32.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +107 -53
- package/dist/routes/account.d.ts +75 -0
- package/dist/routes/account.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAMN,KAAK,iBAAiB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAMN,KAAK,iBAAiB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAUzC,UAAU,UAAU;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE;QAAE,WAAW,EAAE,iBAAiB,CAAA;KAAE,CAAC;CAC9C;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,SAAqB,uCAuDrE;AAYD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,IAErC,SAAS,OAAO,EAAE,MAAM,gBAAgB,kCAChD;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,IAC1C,MAAM,MAAM,UAGpB;AAED,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,cAAc,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -800,7 +800,7 @@ const AddProfileCompanyResponseSchema = S(
|
|
|
800
800
|
const DeleteCompanyResponseSchema = S(
|
|
801
801
|
z.object({ deleted: z.literal(true), id: z.string() })
|
|
802
802
|
).openapi("DeleteCompanyResponse");
|
|
803
|
-
const app$
|
|
803
|
+
const app$5 = new OpenAPIHono();
|
|
804
804
|
const healthRoute = createRoute({
|
|
805
805
|
method: "get",
|
|
806
806
|
path: "/health",
|
|
@@ -818,7 +818,7 @@ const healthRoute = createRoute({
|
|
|
818
818
|
}
|
|
819
819
|
}
|
|
820
820
|
});
|
|
821
|
-
app$
|
|
821
|
+
app$5.openapi(healthRoute, (c) => {
|
|
822
822
|
const status = "healthy";
|
|
823
823
|
return c.json(
|
|
824
824
|
{
|
|
@@ -829,7 +829,7 @@ app$4.openapi(healthRoute, (c) => {
|
|
|
829
829
|
200
|
|
830
830
|
);
|
|
831
831
|
});
|
|
832
|
-
const healthRoutes = app$
|
|
832
|
+
const healthRoutes = app$5;
|
|
833
833
|
const DEFAULT_BASE_URL$1 = "https://hadoku.me/contact/api/mailfeed";
|
|
834
834
|
function baseUrl$1(env) {
|
|
835
835
|
return (env.MAILFEED_BASE_URL ?? DEFAULT_BASE_URL$1).replace(/\/$/, "");
|
|
@@ -1814,7 +1814,7 @@ function scheduleRankBuild(c, db, profileId, profile) {
|
|
|
1814
1814
|
rebuildRank(db, profileId, profile).finally(() => building.delete(profileId))
|
|
1815
1815
|
);
|
|
1816
1816
|
}
|
|
1817
|
-
const app$
|
|
1817
|
+
const app$4 = new OpenAPIHono();
|
|
1818
1818
|
const CULL_DAYS = 60;
|
|
1819
1819
|
const CULL_BATCH = 500;
|
|
1820
1820
|
async function cullExpired(db) {
|
|
@@ -1864,14 +1864,14 @@ async function rankNewJobs(db) {
|
|
|
1864
1864
|
await markRankBuilt(db, state.profile_id, profile, head2);
|
|
1865
1865
|
}
|
|
1866
1866
|
}
|
|
1867
|
-
app$
|
|
1868
|
-
app$
|
|
1869
|
-
app$
|
|
1870
|
-
app$
|
|
1871
|
-
app$
|
|
1872
|
-
app$
|
|
1873
|
-
app$
|
|
1874
|
-
app$
|
|
1867
|
+
app$4.use("/ingest", requireMinTier("friend"));
|
|
1868
|
+
app$4.use("/ingest/backfill-slugs", requireMinTier("friend"));
|
|
1869
|
+
app$4.use("/ingest/backfill-roles", requireMinTier("friend"));
|
|
1870
|
+
app$4.use("/ingest/backfill-salary", requireMinTier("friend"));
|
|
1871
|
+
app$4.use("/ingest/cull", requireMinTier("friend"));
|
|
1872
|
+
app$4.use("/ingest/rebuild-rank", requireMinTier("friend"));
|
|
1873
|
+
app$4.use("/ingest/reconcile-mail", requireMinTier("friend"));
|
|
1874
|
+
app$4.use("/directives", requireMinTier("friend"));
|
|
1875
1875
|
function normalizeWorkplaceType(wt) {
|
|
1876
1876
|
if (wt === "on_site") return "onsite";
|
|
1877
1877
|
return wt;
|
|
@@ -1895,7 +1895,7 @@ const ingestRoute = createRoute({
|
|
|
1895
1895
|
}
|
|
1896
1896
|
});
|
|
1897
1897
|
const INGEST_BATCH_CHUNK = 100;
|
|
1898
|
-
app$
|
|
1898
|
+
app$4.openapi(ingestRoute, async (c) => {
|
|
1899
1899
|
const { jobs, batch_number, is_final, source, board_slug } = c.req.valid("json");
|
|
1900
1900
|
const db = c.env.JOB_PLATFORM_DB;
|
|
1901
1901
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -2028,7 +2028,7 @@ const backfillRoute = createRoute({
|
|
|
2028
2028
|
}
|
|
2029
2029
|
}
|
|
2030
2030
|
});
|
|
2031
|
-
app$
|
|
2031
|
+
app$4.openapi(backfillRoute, async (c) => {
|
|
2032
2032
|
const { limit } = c.req.valid("query");
|
|
2033
2033
|
const db = c.env.JOB_PLATFORM_DB;
|
|
2034
2034
|
const rows = await db.prepare("SELECT id, url FROM jobs WHERE ats IS NULL OR slug IS NULL LIMIT ?").bind(limit).all();
|
|
@@ -2080,7 +2080,7 @@ const rebuildRankRoute = createRoute({
|
|
|
2080
2080
|
}
|
|
2081
2081
|
}
|
|
2082
2082
|
});
|
|
2083
|
-
app$
|
|
2083
|
+
app$4.openapi(rebuildRankRoute, async (c) => {
|
|
2084
2084
|
const { profile_id } = c.req.valid("query");
|
|
2085
2085
|
const db = c.env.JOB_PLATFORM_DB;
|
|
2086
2086
|
const pending = profile_id ? [{ id: profile_id }] : (await db.prepare("SELECT id FROM profiles ORDER BY id").all()).results;
|
|
@@ -2144,7 +2144,7 @@ const backfillRolesRoute = createRoute({
|
|
|
2144
2144
|
}
|
|
2145
2145
|
}
|
|
2146
2146
|
});
|
|
2147
|
-
app$
|
|
2147
|
+
app$4.openapi(backfillRolesRoute, async (c) => {
|
|
2148
2148
|
const { limit, reclassify } = c.req.valid("query");
|
|
2149
2149
|
const db = c.env.JOB_PLATFORM_DB;
|
|
2150
2150
|
const all = reclassify === "true";
|
|
@@ -2196,7 +2196,7 @@ const directivesRoute = createRoute({
|
|
|
2196
2196
|
}
|
|
2197
2197
|
}
|
|
2198
2198
|
});
|
|
2199
|
-
app$
|
|
2199
|
+
app$4.openapi(directivesRoute, async (c) => {
|
|
2200
2200
|
const db = c.env.JOB_PLATFORM_DB;
|
|
2201
2201
|
const companyRows = await db.prepare("SELECT DISTINCT ats, slug FROM profile_companies ORDER BY ats, slug").all();
|
|
2202
2202
|
const profileRows = await db.prepare("SELECT keywords FROM profiles").all();
|
|
@@ -2256,7 +2256,7 @@ const backfillSalaryRoute = createRoute({
|
|
|
2256
2256
|
}
|
|
2257
2257
|
}
|
|
2258
2258
|
});
|
|
2259
|
-
app$
|
|
2259
|
+
app$4.openapi(backfillSalaryRoute, async (c) => {
|
|
2260
2260
|
const { limit, cursor } = c.req.valid("query");
|
|
2261
2261
|
const db = c.env.JOB_PLATFORM_DB;
|
|
2262
2262
|
const rows = await db.prepare(
|
|
@@ -2303,7 +2303,7 @@ const cullRoute = createRoute({
|
|
|
2303
2303
|
}
|
|
2304
2304
|
}
|
|
2305
2305
|
});
|
|
2306
|
-
app$
|
|
2306
|
+
app$4.openapi(cullRoute, async (c) => {
|
|
2307
2307
|
const culled = await cullExpired(c.env.JOB_PLATFORM_DB);
|
|
2308
2308
|
const stripped = await stripStaleDescriptions(c.env.JOB_PLATFORM_DB);
|
|
2309
2309
|
return c.json(
|
|
@@ -2372,7 +2372,7 @@ const reconcileMailRoute = createRoute({
|
|
|
2372
2372
|
}
|
|
2373
2373
|
}
|
|
2374
2374
|
});
|
|
2375
|
-
app$
|
|
2375
|
+
app$4.openapi(reconcileMailRoute, async (c) => {
|
|
2376
2376
|
const { reset, ownerName } = c.req.valid("query");
|
|
2377
2377
|
const who = await effectiveUserId(c, ownerName);
|
|
2378
2378
|
if (isEffectiveUserError(who)) return c.json(who.error.body, who.error.status);
|
|
@@ -2433,7 +2433,7 @@ const reconcileViewRoute = createRoute({
|
|
|
2433
2433
|
}
|
|
2434
2434
|
}
|
|
2435
2435
|
});
|
|
2436
|
-
app$
|
|
2436
|
+
app$4.openapi(reconcileViewRoute, async (c) => {
|
|
2437
2437
|
const { ownerName } = c.req.valid("query");
|
|
2438
2438
|
const who = await effectiveUserId(c, ownerName);
|
|
2439
2439
|
if (isEffectiveUserError(who)) return c.json(who.error.body, who.error.status);
|
|
@@ -2442,7 +2442,7 @@ app$3.openapi(reconcileViewRoute, async (c) => {
|
|
|
2442
2442
|
const view = await reconcileView(c.env, who.userId);
|
|
2443
2443
|
return c.json({ success: true, data: view }, 200);
|
|
2444
2444
|
});
|
|
2445
|
-
const ingestRoutes = app$
|
|
2445
|
+
const ingestRoutes = app$4;
|
|
2446
2446
|
const DEFAULT_PROFILE = {
|
|
2447
2447
|
name: "Default",
|
|
2448
2448
|
keywords: ["software engineer", "ai", "ml", "platform", "backend", "distributed systems"],
|
|
@@ -2549,11 +2549,11 @@ async function triggerSearch(env) {
|
|
|
2549
2549
|
);
|
|
2550
2550
|
}
|
|
2551
2551
|
}
|
|
2552
|
-
const app$
|
|
2553
|
-
app$
|
|
2554
|
-
app$
|
|
2555
|
-
app$
|
|
2556
|
-
app$
|
|
2552
|
+
const app$3 = new OpenAPIHono();
|
|
2553
|
+
app$3.use("/profiles", requireMinTier("friend"));
|
|
2554
|
+
app$3.use("/profiles/*", requireMinTier("friend"));
|
|
2555
|
+
app$3.use("/profiles", requireIdentity);
|
|
2556
|
+
app$3.use("/profiles/*", requireIdentity);
|
|
2557
2557
|
async function requireIdentity(c, next) {
|
|
2558
2558
|
if (!c.req.header("X-User-Id")?.trim()) {
|
|
2559
2559
|
return c.json(
|
|
@@ -2644,7 +2644,7 @@ async function ensureDefaultProfile(db, userId) {
|
|
|
2644
2644
|
async function ownedProfile(db, userId, id) {
|
|
2645
2645
|
return db.prepare("SELECT * FROM profiles WHERE id = ? AND user_id = ?").bind(id, userId).first();
|
|
2646
2646
|
}
|
|
2647
|
-
app$
|
|
2647
|
+
app$3.openapi(
|
|
2648
2648
|
createRoute({
|
|
2649
2649
|
method: "get",
|
|
2650
2650
|
path: "/profiles",
|
|
@@ -2668,7 +2668,7 @@ app$2.openapi(
|
|
|
2668
2668
|
});
|
|
2669
2669
|
}
|
|
2670
2670
|
);
|
|
2671
|
-
app$
|
|
2671
|
+
app$3.openapi(
|
|
2672
2672
|
createRoute({
|
|
2673
2673
|
method: "post",
|
|
2674
2674
|
path: "/profiles",
|
|
@@ -2706,7 +2706,7 @@ app$2.openapi(
|
|
|
2706
2706
|
return c.json({ success: true, data: { profile } }, 201);
|
|
2707
2707
|
}
|
|
2708
2708
|
);
|
|
2709
|
-
app$
|
|
2709
|
+
app$3.openapi(
|
|
2710
2710
|
createRoute({
|
|
2711
2711
|
method: "put",
|
|
2712
2712
|
path: "/profiles/{id}",
|
|
@@ -2765,7 +2765,7 @@ app$2.openapi(
|
|
|
2765
2765
|
return c.json({ success: true, data: { profile } }, 200);
|
|
2766
2766
|
}
|
|
2767
2767
|
);
|
|
2768
|
-
app$
|
|
2768
|
+
app$3.openapi(
|
|
2769
2769
|
createRoute({
|
|
2770
2770
|
method: "delete",
|
|
2771
2771
|
path: "/profiles/{id}",
|
|
@@ -2808,7 +2808,7 @@ app$2.openapi(
|
|
|
2808
2808
|
return c.json({ success: true, data: { deleted: true, id } }, 200);
|
|
2809
2809
|
}
|
|
2810
2810
|
);
|
|
2811
|
-
app$
|
|
2811
|
+
app$3.openapi(
|
|
2812
2812
|
createRoute({
|
|
2813
2813
|
method: "get",
|
|
2814
2814
|
path: "/profiles/{profileId}/companies",
|
|
@@ -2849,7 +2849,7 @@ app$2.openapi(
|
|
|
2849
2849
|
);
|
|
2850
2850
|
}
|
|
2851
2851
|
);
|
|
2852
|
-
app$
|
|
2852
|
+
app$3.openapi(
|
|
2853
2853
|
createRoute({
|
|
2854
2854
|
method: "post",
|
|
2855
2855
|
path: "/profiles/{profileId}/companies",
|
|
@@ -2912,7 +2912,7 @@ app$2.openapi(
|
|
|
2912
2912
|
);
|
|
2913
2913
|
}
|
|
2914
2914
|
);
|
|
2915
|
-
app$
|
|
2915
|
+
app$3.openapi(
|
|
2916
2916
|
createRoute({
|
|
2917
2917
|
method: "delete",
|
|
2918
2918
|
path: "/profiles/{profileId}/companies/{companyId}",
|
|
@@ -2993,7 +2993,7 @@ function deserializeProfile(r) {
|
|
|
2993
2993
|
created_at: r.created_at
|
|
2994
2994
|
};
|
|
2995
2995
|
}
|
|
2996
|
-
const profileRoutes = app$
|
|
2996
|
+
const profileRoutes = app$3;
|
|
2997
2997
|
const LIGHT_CANDIDATE_CAP = 5e4;
|
|
2998
2998
|
const FULL_SCORE_CAP = 800;
|
|
2999
2999
|
const ID_CHUNK = 100;
|
|
@@ -5424,23 +5424,23 @@ function registerFillRoutes(app2) {
|
|
|
5424
5424
|
);
|
|
5425
5425
|
});
|
|
5426
5426
|
}
|
|
5427
|
+
const app$2 = new OpenAPIHono();
|
|
5428
|
+
registerFeedRoute(app$2);
|
|
5429
|
+
registerPreflightRoute(app$2);
|
|
5430
|
+
registerPacketsRoute(app$2);
|
|
5431
|
+
registerDetailRoute(app$2);
|
|
5432
|
+
registerStateRoutes(app$2);
|
|
5433
|
+
registerFeedbackRoutes(app$2);
|
|
5434
|
+
registerTailoringRoutes(app$2);
|
|
5435
|
+
registerApplicationRoutes(app$2);
|
|
5436
|
+
registerVerificationRoutes(app$2);
|
|
5437
|
+
registerFillRoutes(app$2);
|
|
5438
|
+
registerAnswerRoutes(app$2);
|
|
5439
|
+
registerOwnerRoutes(app$2);
|
|
5440
|
+
const jobRoutes = app$2;
|
|
5427
5441
|
const app$1 = new OpenAPIHono();
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
registerPacketsRoute(app$1);
|
|
5431
|
-
registerDetailRoute(app$1);
|
|
5432
|
-
registerStateRoutes(app$1);
|
|
5433
|
-
registerFeedbackRoutes(app$1);
|
|
5434
|
-
registerTailoringRoutes(app$1);
|
|
5435
|
-
registerApplicationRoutes(app$1);
|
|
5436
|
-
registerVerificationRoutes(app$1);
|
|
5437
|
-
registerFillRoutes(app$1);
|
|
5438
|
-
registerAnswerRoutes(app$1);
|
|
5439
|
-
registerOwnerRoutes(app$1);
|
|
5440
|
-
const jobRoutes = app$1;
|
|
5441
|
-
const app = new OpenAPIHono();
|
|
5442
|
-
app.use("/companies/*", requireMinTier("friend"));
|
|
5443
|
-
app.openapi(
|
|
5442
|
+
app$1.use("/companies/*", requireMinTier("friend"));
|
|
5443
|
+
app$1.openapi(
|
|
5444
5444
|
createRoute({
|
|
5445
5445
|
method: "post",
|
|
5446
5446
|
path: "/companies/match",
|
|
@@ -5481,7 +5481,7 @@ app.openapi(
|
|
|
5481
5481
|
}
|
|
5482
5482
|
}
|
|
5483
5483
|
);
|
|
5484
|
-
app.openapi(
|
|
5484
|
+
app$1.openapi(
|
|
5485
5485
|
createRoute({
|
|
5486
5486
|
method: "post",
|
|
5487
5487
|
path: "/companies/probe",
|
|
@@ -5522,7 +5522,60 @@ app.openapi(
|
|
|
5522
5522
|
}
|
|
5523
5523
|
}
|
|
5524
5524
|
);
|
|
5525
|
-
const companyRoutes = app;
|
|
5525
|
+
const companyRoutes = app$1;
|
|
5526
|
+
const ERASED_TABLES = [
|
|
5527
|
+
// A profile's children first, found through the profile while it still exists.
|
|
5528
|
+
{
|
|
5529
|
+
table: "profile_companies",
|
|
5530
|
+
sql: "DELETE FROM profile_companies WHERE profile_id IN (SELECT id FROM profiles WHERE user_id = ?1)"
|
|
5531
|
+
},
|
|
5532
|
+
{
|
|
5533
|
+
table: "job_profile_rank",
|
|
5534
|
+
sql: "DELETE FROM job_profile_rank WHERE profile_id IN (SELECT id FROM profiles WHERE user_id = ?1)"
|
|
5535
|
+
},
|
|
5536
|
+
{
|
|
5537
|
+
table: "job_profile_rank_state",
|
|
5538
|
+
sql: "DELETE FROM job_profile_rank_state WHERE profile_id IN (SELECT id FROM profiles WHERE user_id = ?1)"
|
|
5539
|
+
},
|
|
5540
|
+
{ table: "profiles", sql: "DELETE FROM profiles WHERE user_id = ?1" },
|
|
5541
|
+
{ table: "profile_tombstones", sql: "DELETE FROM profile_tombstones WHERE user_id = ?1" },
|
|
5542
|
+
{ table: "job_states", sql: "DELETE FROM job_states WHERE user_id = ?1" },
|
|
5543
|
+
{ table: "job_feedback", sql: "DELETE FROM job_feedback WHERE user_id = ?1" },
|
|
5544
|
+
{ table: "applications", sql: "DELETE FROM applications WHERE user_id = ?1" },
|
|
5545
|
+
{ table: "application_answers", sql: "DELETE FROM application_answers WHERE user_id = ?1" },
|
|
5546
|
+
{ table: "applicant_profiles", sql: "DELETE FROM applicant_profiles WHERE user_id = ?1" },
|
|
5547
|
+
{ table: "mail_reconcile_state", sql: "DELETE FROM mail_reconcile_state WHERE user_id = ?1" },
|
|
5548
|
+
{ table: "mail_unmatched", sql: "DELETE FROM mail_unmatched WHERE user_id = ?1" },
|
|
5549
|
+
{ table: "owner_name_cache", sql: "DELETE FROM owner_name_cache WHERE user_id = ?1" }
|
|
5550
|
+
];
|
|
5551
|
+
async function eraseUser(db, userId) {
|
|
5552
|
+
const results = await db.batch(ERASED_TABLES.map(({ sql }) => db.prepare(sql).bind(userId)));
|
|
5553
|
+
const erased = {};
|
|
5554
|
+
ERASED_TABLES.forEach(({ table }, i) => {
|
|
5555
|
+
erased[table] = results[i].meta.changes;
|
|
5556
|
+
});
|
|
5557
|
+
return erased;
|
|
5558
|
+
}
|
|
5559
|
+
const app = new OpenAPIHono();
|
|
5560
|
+
app.post("/_account/erase", async (c) => {
|
|
5561
|
+
const auth = c.get("authContext");
|
|
5562
|
+
if (!tierAtLeast(auth, "member")) {
|
|
5563
|
+
return c.json(
|
|
5564
|
+
{ success: false, error: "Unauthorized", message: "Edge seal required" },
|
|
5565
|
+
401
|
|
5566
|
+
);
|
|
5567
|
+
}
|
|
5568
|
+
const userId = auth.userId?.trim();
|
|
5569
|
+
if (!userId) {
|
|
5570
|
+
return c.json(
|
|
5571
|
+
{ success: false, error: "Unauthorized", message: "No X-User-Id to erase" },
|
|
5572
|
+
401
|
|
5573
|
+
);
|
|
5574
|
+
}
|
|
5575
|
+
const erased = await eraseUser(c.env.JOB_PLATFORM_DB, userId);
|
|
5576
|
+
return c.json({ success: true, erased }, 200);
|
|
5577
|
+
});
|
|
5578
|
+
const accountRoutes = app;
|
|
5526
5579
|
function createJobPlatformHandler(basePath = "/jobplatform/api") {
|
|
5527
5580
|
const app2 = new OpenAPIHono({
|
|
5528
5581
|
defaultHook: wrappedValidationHook
|
|
@@ -5543,6 +5596,7 @@ function createJobPlatformHandler(basePath = "/jobplatform/api") {
|
|
|
5543
5596
|
app2.route("/", profileRoutes);
|
|
5544
5597
|
app2.route("/", jobRoutes);
|
|
5545
5598
|
app2.route("/", companyRoutes);
|
|
5599
|
+
app2.route("/", accountRoutes);
|
|
5546
5600
|
app2.doc(
|
|
5547
5601
|
"/openapi.json",
|
|
5548
5602
|
createOpenAPIDocConfig({
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /_account/erase — the account-erase hook (hadoku_site IDENTITY_MODEL
|
|
3
|
+
* R12, "Erase hooks").
|
|
4
|
+
*
|
|
5
|
+
* 200 → { success: true, erased: { <table>: <rows deleted> } }
|
|
6
|
+
* 401 → no edge seal, or a sealed request that names nobody
|
|
7
|
+
*
|
|
8
|
+
* When a person deletes their account, edge-router calls this under its seal
|
|
9
|
+
* (X-Edge-Auth, X-Hadoku-Tier: member, X-User-Id) and closes the account only
|
|
10
|
+
* once every hook has answered its counts. The person is the edge-stamped
|
|
11
|
+
* X-User-Id and nothing else: never a body field, never an ownerName (R5).
|
|
12
|
+
*
|
|
13
|
+
* Only the edge can reach it. edge-router 404s every inbound path with an
|
|
14
|
+
* `_account` segment before routing, so no page can erase a signed-in visitor
|
|
15
|
+
* with one POST through the proxy. A direct hit on the workers.dev origin
|
|
16
|
+
* carries no valid seal, so createEdgeAuth degrades it to public and it is
|
|
17
|
+
* refused here.
|
|
18
|
+
*
|
|
19
|
+
* Idempotent: every statement is a DELETE by user id, so a second call
|
|
20
|
+
* matches nothing and answers zeros. The edge calls it twice by design.
|
|
21
|
+
*
|
|
22
|
+
* What is erased, and why it is the person's own (ERASED_TABLES below is the
|
|
23
|
+
* list; erase.test.ts fails if a table with a user_id column is missing from
|
|
24
|
+
* it):
|
|
25
|
+
*
|
|
26
|
+
* profiles Their scoring profiles. Each is theirs alone; a
|
|
27
|
+
* profile is never shared.
|
|
28
|
+
* profile_companies The companies in their profiles' slices. Deleting
|
|
29
|
+
* them drops those boards from GET /directives unless
|
|
30
|
+
* another person's profile also subscribes, which is
|
|
31
|
+
* exactly what a subscription means.
|
|
32
|
+
* job_profile_rank Derived feed ranking for their profiles. Always safe
|
|
33
|
+
* job_profile_rank_state to delete (the feed ranks live without it); kept
|
|
34
|
+
* would be rows for profiles that no longer exist.
|
|
35
|
+
* profile_tombstones Their "I deleted the Default profile" markers.
|
|
36
|
+
* job_states Their triage of each posting (and the packet slug
|
|
37
|
+
* they sent with an application).
|
|
38
|
+
* job_feedback Their up/down votes, one per (user, job).
|
|
39
|
+
* applications Their apply queue. The runner writes these ON THEIR
|
|
40
|
+
* BEHALF (ownerName), which is why the data lives here
|
|
41
|
+
* and not in prefs-api, but every row is the person's.
|
|
42
|
+
* A row handed to someone else (POST
|
|
43
|
+
* /applications/:id/owner) is that person's now, and
|
|
44
|
+
* stays.
|
|
45
|
+
* application_answers Their standing answers to form questions, including
|
|
46
|
+
* demographic ones.
|
|
47
|
+
* applicant_profiles Their contact facts, education and work history.
|
|
48
|
+
* mail_reconcile_state Reconciliation of their mailbox: cursor and counts.
|
|
49
|
+
* mail_unmatched Subjects and senders of their ATS mail.
|
|
50
|
+
* owner_name_cache A STORED NAME: a cached display-name → userId
|
|
51
|
+
* resolution. It must go, or the name keeps resolving
|
|
52
|
+
* to an erased person for up to 15 minutes.
|
|
53
|
+
*
|
|
54
|
+
* Not erased: `jobs`, the shared corpus of postings, which names no person.
|
|
55
|
+
* No shared table in this app records who contributed to it, so the erase
|
|
56
|
+
* leaves no userId behind in shared state.
|
|
57
|
+
*
|
|
58
|
+
* Outside this app: the packets a variant_slug points at live in resume-api's
|
|
59
|
+
* KV, and are erased (or not) by resume-api.
|
|
60
|
+
*/
|
|
61
|
+
import { OpenAPIHono } from '@hono/zod-openapi';
|
|
62
|
+
import type { D1Database } from '@cloudflare/workers-types';
|
|
63
|
+
import type { RouteContext } from './jobs/shared.js';
|
|
64
|
+
/** Each table this hook erases, with the DELETE that removes one person's rows. */
|
|
65
|
+
export declare const ERASED_TABLES: readonly {
|
|
66
|
+
table: string;
|
|
67
|
+
sql: string;
|
|
68
|
+
}[];
|
|
69
|
+
/**
|
|
70
|
+
* Delete every row that is this person's own, in one transaction (D1 runs a
|
|
71
|
+
* batch atomically), and count what each table lost.
|
|
72
|
+
*/
|
|
73
|
+
export declare function eraseUser(db: D1Database, userId: string): Promise<Record<string, number>>;
|
|
74
|
+
export declare const accountRoutes: OpenAPIHono<RouteContext, {}, "/">;
|
|
75
|
+
//# sourceMappingURL=account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/routes/account.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,mFAAmF;AACnF,eAAO,MAAM,aAAa,EAAE,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAwBlE,CAAC;AAEF;;;GAGG;AACH,wBAAsB,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAO/F;AAyBD,eAAO,MAAM,aAAa,oCAAM,CAAC"}
|