lazypock 0.8.1 → 0.8.2
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/{chunk-BJQUGPKE.js → chunk-V2XSEOWF.js} +16 -4
- package/dist/{chunk-BJQUGPKE.js.map → chunk-V2XSEOWF.js.map} +1 -1
- package/dist/cli.cjs +15 -3
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.global.js +15 -3
- package/dist/cli.global.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +27 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.global.js +27 -8
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +13 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen.ts +24 -3
- package/src/http.ts +21 -7
package/src/codegen.ts
CHANGED
|
@@ -183,8 +183,19 @@ export class TypedClient extends LazypockClient {
|
|
|
183
183
|
//
|
|
184
184
|
// create()/update() take the collection's *CreateData — the read model
|
|
185
185
|
// omits password/hidden fields, but the write model carries them.
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
// T extends string (rather than keyof LazypockCollections) with a conditional
|
|
187
|
+
// return type, so the IDE suggests collection names AND unknown/dynamic names
|
|
188
|
+
// still resolve to the untyped service — a studio that manages
|
|
189
|
+
// user-created collections must be able to call collection(someString).
|
|
190
|
+
//
|
|
191
|
+
// create()/update() take the collection's *CreateData — the read model
|
|
192
|
+
// omits password/hidden fields, but the write model carries them.
|
|
193
|
+
override collection<T extends string>(name: T): T extends keyof LazypockCollections
|
|
194
|
+
? CollectionService<LazypockCollections[T], LazypockCreateData[T]>
|
|
195
|
+
: CollectionService<unknown> {
|
|
196
|
+
return super.collection(name) as T extends keyof LazypockCollections
|
|
197
|
+
? CollectionService<LazypockCollections[T], LazypockCreateData[T]>
|
|
198
|
+
: CollectionService<unknown>;
|
|
188
199
|
}
|
|
189
200
|
}
|
|
190
201
|
`);
|
|
@@ -221,12 +232,22 @@ function memberLine(f: SchemaField): string {
|
|
|
221
232
|
* Unlike the read model, create/update data includes password fields (sent as
|
|
222
233
|
* plain strings — the server hashes them) and hidden fields: the server
|
|
223
234
|
* accepts them on write and never returns them in responses.
|
|
235
|
+
*
|
|
236
|
+
* A field is only marked required when it actually needs a client value:
|
|
237
|
+
* fields with a server-side default (`options.defaultValue`) and the auth
|
|
238
|
+
* system fields `verified` / `emailVisibility` (the server defaults them to
|
|
239
|
+
* false/true even though the snapshot doesn't carry `defaultValue`) stay
|
|
240
|
+
* optional, so `create({ email, password_hash })` typechecks without forcing
|
|
241
|
+
* callers to send values the server would fill in anyway.
|
|
224
242
|
*/
|
|
225
243
|
function createDataMemberLine(f: SchemaField): string {
|
|
226
244
|
// Autodate columns are server-managed; never writable.
|
|
227
245
|
if (f.type === "autodate") return "";
|
|
228
246
|
const key = fieldKey(f.name);
|
|
229
|
-
const
|
|
247
|
+
const serverDefaulted =
|
|
248
|
+
f.options?.defaultValue !== undefined ||
|
|
249
|
+
(f.system && (f.name === "verified" || f.name === "emailVisibility"));
|
|
250
|
+
const req = f.required && !serverDefaulted ? "" : "?";
|
|
230
251
|
const type = f.type === "password" ? "string" : fieldTypeScriptType(f);
|
|
231
252
|
if (type === "never") return "";
|
|
232
253
|
return ` ${JSON.stringify(key)}${req}: ${type};`;
|
package/src/http.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Only relies on globalThis.fetch — works in browser, React Native, and Node 18+
|
|
3
3
|
|
|
4
4
|
import { ApiError, type Method, type RequestOptions } from "./types";
|
|
5
|
-
import type { AuthStore } from "./auth";
|
|
5
|
+
import type { AuthModel, AuthStore } from "./auth";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Low-level HTTP client wrapping `fetch` with automatic auth token injection.
|
|
@@ -74,10 +74,10 @@ export class HttpClient {
|
|
|
74
74
|
}
|
|
75
75
|
const data = (await res.json()) as Record<string, unknown>;
|
|
76
76
|
if (data && typeof data.token === "string") {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
);
|
|
77
|
+
const record = data["record"];
|
|
78
|
+
const model: AuthModel | null =
|
|
79
|
+
record && typeof record === "object" ? (record as AuthModel) : null;
|
|
80
|
+
this.authStore.set(data.token, model);
|
|
81
81
|
return data as { token: string; record: Record<string, unknown> };
|
|
82
82
|
}
|
|
83
83
|
return null;
|
|
@@ -300,8 +300,22 @@ export class HttpClient {
|
|
|
300
300
|
if (bodyText) {
|
|
301
301
|
data = JSON.parse(bodyText) as Record<string, unknown>;
|
|
302
302
|
}
|
|
303
|
-
} catch {
|
|
304
|
-
//
|
|
303
|
+
} catch (err) {
|
|
304
|
+
// An abort that lands while the body is streaming (auto-cancelled
|
|
305
|
+
// duplicate, manual cancel, or external signal) means the whole
|
|
306
|
+
// request was cancelled — surface it as an abort error instead of
|
|
307
|
+
// silently returning an empty object, which callers would treat as
|
|
308
|
+
// a successful-but-empty response (e.g. a list request would clear
|
|
309
|
+
// the current rows).
|
|
310
|
+
if (isAbortError(err)) {
|
|
311
|
+
throw new ApiError(
|
|
312
|
+
"The request was aborted (most likely auto-cancelled by a newer request with the same requestKey)",
|
|
313
|
+
{},
|
|
314
|
+
0,
|
|
315
|
+
true,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
// Not JSON / read failure — keep data as empty object
|
|
305
319
|
}
|
|
306
320
|
|
|
307
321
|
if (!res!.ok) {
|