chore(ts-migration): migrate base44 client to TypeScript
Phase 4b-ii, and the last file in the transport layer. Type-only: the plain
emitted JavaScript is byte-identical at 9,302 bytes.
This file owns the session, so the annotations stay at the edges and nothing
about the auth model moves. `SESSION_KEY`, the localStorage mirror, the three
module-level mutables, the shared hydration promise, the `{ ...user }` spreads,
`window.location.href` on logout and `window.location.reload()` in
`resetDemoData` are all exactly as they were.
Nine sites, eight of them parameter types. The ninth is `hydration`, which needs
`Promise<any> | null` because the runtime already assigns both: the shared first
`GET /me`, then `null` once it has been consumed or superseded by a login.
Inference would have fixed it at `Promise<any>` and rejected the assignments
that make the sharing work.
`entities` is deliberately NOT annotated, and neither is `createEntity`'s
return. A probe run during the inspection showed what annotating it costs:
`Record<EntityName, EntityClient<any>>` makes `list()` return `Promise<any[]>`
where inference gives `Promise<any>`, and `agentStore.js` does
`qc.getQueryData(KEY) || (await ...list(...))`. React Query types
`getQueryData` as `unknown`; `unknown || any` collapses to `any` while
`unknown || any[]` stays `unknown`, and `.find` on the next line stops
compiling. Two new errors in a file this phase does not migrate. The generated
record types and `EntityClientFor<K>` are ready for the phase that migrates the
forty-five call sites in `krowHooks.js`.
The auth returns are likewise left inferred rather than typed `User`. That was
checked, not assumed: `admin/Profile.jsx` reads `user.avatar_url`, which is
neither a column on `users` nor part of the `/me` projection in `me.go` - it is
always undefined at run time. Typing the return would have turned a latent dead
branch into two compile errors in a file this phase does not touch. Worth
knowing about separately; not this commit's business.
One stale comment is kept verbatim - `@param {any} request` above
`owliver.suggestions`, which names a parameter that does not exist. Removing it
was the only remaining difference in the emitted output, and byte-identity is
worth more here than tidying a comment. Flagged for a later docs pass.
Verified: tsc 42 -> 40 with a set-difference showing two removed and none added;
npm test 1684/1691, the same seven failures as the parent commit (six documented
as deliberate in scripts/__baseline__/README.md, one the stale backend fixture);
lint 0 errors; build succeeds with the API origin inlined. This is also the
first run of the suite with a source-text-inspected file migrated - the harness
fix in 02a2ab0 is what makes it possible.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBG1wnuRfJKCstGB8Fekr8
This commit is contained in:
@@ -143,7 +143,11 @@ let authenticated = false;
|
|||||||
* A 401 here is the ordinary state of a signed-out visitor, not a failure: the
|
* A 401 here is the ordinary state of a signed-out visitor, not a failure: the
|
||||||
* app opens on the login page and this request is how it finds that out.
|
* app opens on the login page and this request is how it finds that out.
|
||||||
*/
|
*/
|
||||||
let hydration = request('GET', '/me')
|
/* `Promise<any> | null`, because the runtime already assigns both: the shared
|
||||||
|
first request, then `null` once it has been consumed or superseded by a
|
||||||
|
login. Inference alone would fix the type at `Promise<any>` and reject the
|
||||||
|
two `hydration = null` assignments that make the sharing work. */
|
||||||
|
let hydration: Promise<any> | null = request('GET', '/me')
|
||||||
.then((user) => {
|
.then((user) => {
|
||||||
currentUser = user;
|
currentUser = user;
|
||||||
authenticated = true;
|
authenticated = true;
|
||||||
@@ -204,7 +208,11 @@ const auth = {
|
|||||||
* by design: telling the two apart would say whether an address is
|
* by design: telling the two apart would say whether an address is
|
||||||
* registered. The caller shows that message as-is.
|
* registered. The caller shows that message as-is.
|
||||||
*/
|
*/
|
||||||
async login({ email, password, rememberMe = false }) {
|
async login({ email, password, rememberMe = false }: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
rememberMe?: boolean;
|
||||||
|
}) {
|
||||||
const user = await request('POST', '/auth/login', {
|
const user = await request('POST', '/auth/login', {
|
||||||
body: { email, password, remember_me: Boolean(rememberMe) },
|
body: { email, password, remember_me: Boolean(rememberMe) },
|
||||||
});
|
});
|
||||||
@@ -215,7 +223,7 @@ const auth = {
|
|||||||
return { ...user };
|
return { ...user };
|
||||||
},
|
},
|
||||||
|
|
||||||
async updateMe(patch) {
|
async updateMe(patch: any) {
|
||||||
const user = await request('PATCH', '/me', { body: patch });
|
const user = await request('PATCH', '/me', { body: patch });
|
||||||
currentUser = user;
|
currentUser = user;
|
||||||
cacheUser();
|
cacheUser();
|
||||||
@@ -247,7 +255,7 @@ const auth = {
|
|||||||
* question the shape exists to answer is now answered by whether this
|
* question the shape exists to answer is now answered by whether this
|
||||||
* function resolved at all.
|
* function resolved at all.
|
||||||
*/
|
*/
|
||||||
async updatePreferences(patch) {
|
async updatePreferences(patch: any) {
|
||||||
const preferences = await request('PATCH', '/me/preferences', { body: patch });
|
const preferences = await request('PATCH', '/me/preferences', { body: patch });
|
||||||
currentUser = { ...currentUser, preferences };
|
currentUser = { ...currentUser, preferences };
|
||||||
cacheUser();
|
cacheUser();
|
||||||
@@ -274,7 +282,7 @@ const auth = {
|
|||||||
* reach the API must still leave the browser signed out locally, and the
|
* reach the API must still leave the browser signed out locally, and the
|
||||||
* cookie it keeps will be refused by every request it is sent on.
|
* cookie it keeps will be refused by every request it is sent on.
|
||||||
*/
|
*/
|
||||||
async logout(redirectTo = '/admin/login') {
|
async logout(redirectTo: string = '/admin/login') {
|
||||||
try {
|
try {
|
||||||
await request('POST', '/auth/logout');
|
await request('POST', '/auth/logout');
|
||||||
} catch {
|
} catch {
|
||||||
@@ -320,7 +328,7 @@ const workflows = {
|
|||||||
* across from the application by the server, because it is already the truth
|
* across from the application by the server, because it is already the truth
|
||||||
* about this person and retyping it here is how the two records drift apart.
|
* about this person and retyping it here is how the two records drift apart.
|
||||||
*/
|
*/
|
||||||
async hire(applicationId, body = {}) {
|
async hire(applicationId: string, body: any = {}) {
|
||||||
return request('POST', `/job-applications/${encodeURIComponent(applicationId)}/hire`, {
|
return request('POST', `/job-applications/${encodeURIComponent(applicationId)}/hire`, {
|
||||||
body,
|
body,
|
||||||
});
|
});
|
||||||
@@ -336,7 +344,7 @@ const workflows = {
|
|||||||
* inside the same transaction; a worker taken straight from the talent pool
|
* inside the same transaction; a worker taken straight from the talent pool
|
||||||
* with neither is placed without one rather than given an invented one.
|
* with neither is placed without one rather than given an invented one.
|
||||||
*/
|
*/
|
||||||
async assign(jobPostingId, workers = []) {
|
async assign(jobPostingId: string, workers: any[] = []) {
|
||||||
return request('POST', `/job-postings/${encodeURIComponent(jobPostingId)}/assignments`, {
|
return request('POST', `/job-postings/${encodeURIComponent(jobPostingId)}/assignments`, {
|
||||||
body: { workers },
|
body: { workers },
|
||||||
});
|
});
|
||||||
@@ -368,7 +376,7 @@ const workflows = {
|
|||||||
*/
|
*/
|
||||||
const owliver = {
|
const owliver = {
|
||||||
/** @param {any} request */
|
/** @param {any} request */
|
||||||
async suggestions({ page, query = '' } = {}) {
|
async suggestions({ page, query = '' }: { page?: string; query?: string } = {}) {
|
||||||
if (!page) return [];
|
if (!page) return [];
|
||||||
const typed = String(query || '').trim();
|
const typed = String(query || '').trim();
|
||||||
const data = await request('GET', '/owliver/suggestions', {
|
const data = await request('GET', '/owliver/suggestions', {
|
||||||
@@ -388,7 +396,7 @@ const integrations = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const analytics = {
|
const analytics = {
|
||||||
track({ eventName, properties } = {}) {
|
track({ eventName, properties }: { eventName?: string; properties?: any } = {}) {
|
||||||
if (import.meta.env.DEV) {
|
if (import.meta.env.DEV) {
|
||||||
console.debug('[krow-demo] analytics', eventName, properties || {});
|
console.debug('[krow-demo] analytics', eventName, properties || {});
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user