lazypock 0.7.0 → 0.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lazypock",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
package/src/codegen.ts CHANGED
@@ -149,10 +149,13 @@ export function createClient(options: LazypockClientOptions): TypedClient {
149
149
  }
150
150
 
151
151
  export class TypedClient extends LazypockClient {
152
- override collection<T extends string>(name: T): T extends keyof LazypockCollections
153
- ? CollectionService<LazypockCollections[T]>
154
- : CollectionService<unknown> {
155
- return super.collection(name) as T extends keyof LazypockCollections ? CollectionService<LazypockCollections[T]> : CollectionService<unknown>;
152
+ // K extends keyof LazypockCollections (rather than a generic string with a
153
+ // conditional return) so the IDE suggests collection names and unknown names
154
+ // are rejected at compile time:
155
+ // client.collection("posts") // suggested + typed
156
+ // client.collection("nope") // TS error
157
+ override collection<K extends keyof LazypockCollections>(name: K): CollectionService<LazypockCollections[K]> {
158
+ return super.collection(name) as CollectionService<LazypockCollections[K]>;
156
159
  }
157
160
  }
158
161
  `);
package/src/collection.ts CHANGED
@@ -99,8 +99,9 @@ export class CollectionService<T = ApiRecord> {
99
99
  private schema?: CollectionSchema;
100
100
  /**
101
101
  * Active field projection from {@link select}. `"*"` (or unset) means
102
- * "all visible (non-hidden) fields" — resolved against the schema when
103
- * one is available, otherwise left to the server.
102
+ * "all visible (non-hidden) fields plus the implicit system keys" —
103
+ * resolved against the schema when one is available, otherwise left to
104
+ * the server.
104
105
  */
105
106
  private fieldsPreset?: string;
106
107
 
@@ -137,9 +138,10 @@ export class CollectionService<T = ApiRecord> {
137
138
  * const t = await client.collection("posts").select("id", "title").getList();
138
139
  * // GET /api/posts?fields=id,title
139
140
  *
140
- * // All visible fields (hidden fields are excluded server-side)
141
+ * // All visible fields (implicit system keys id/created/updated/… are
142
+ * // kept; hidden fields are excluded via the projection)
141
143
  * const all = await client.collection("posts").select("*").getList();
142
- * // GET /api/posts?fields=id,title,published,… (schema known)
144
+ * // GET /api/posts?fields=id,created,updated,collectionId,collectionName,title,published,… (schema known)
143
145
  * ```
144
146
  *
145
147
  * When no schema is known, the default (no `select()` call) sends no
@@ -173,7 +175,8 @@ export class CollectionService<T = ApiRecord> {
173
175
  * Fields to send with reads:
174
176
  * 1. explicit `options.fields` (caller wins)
175
177
  * 2. `select()` preset
176
- * 3. schema default — all visible (non-hidden, non-system) fields
178
+ * 3. schema default — all visible (non-hidden) fields plus the implicit
179
+ * system keys (`id`, `created`, `updated`, `collectionId`, `collectionName`)
177
180
  */
178
181
  private effectiveFields(optionsFields?: string): string | undefined {
179
182
  if (optionsFields !== undefined) return optionsFields;
@@ -187,8 +190,18 @@ export class CollectionService<T = ApiRecord> {
187
190
  }
188
191
 
189
192
  /**
190
- * All non-hidden, non-system, non-password field names from the schema.
191
- * `undefined` when no schema is available (server decides).
193
+ * All non-hidden, non-password, non-autodate field names from the schema,
194
+ * prefixed with the implicit system keys that are part of every record
195
+ * (`id`, `created`, `updated`, `collectionId`, `collectionName`).
196
+ *
197
+ * The system keys never appear in the schema (they are implied for every
198
+ * collection) but MUST be listed explicitly when projecting — the server
199
+ * applies strict projection, so unrequested fields are dropped. Without
200
+ * them, `getList`/`getOne` responses lose `id` (and `created`/`updated`),
201
+ * breaking selection, edits, and relation references.
202
+ *
203
+ * `undefined` when no schema fields are available (server decides — its
204
+ * default returns every non-password field, including the system keys).
192
205
  */
193
206
  visibleFields(): string | undefined {
194
207
  if (!this.schema?.fields) return undefined;
@@ -200,7 +213,18 @@ export class CollectionService<T = ApiRecord> {
200
213
  f.type !== "autodate",
201
214
  )
202
215
  .map((f) => f.name);
203
- return visible.length > 0 ? visible.join(",") : undefined;
216
+ if (visible.length === 0) return undefined;
217
+ // Dedupe in case a schema ever names a field after a system key.
218
+ return [
219
+ ...new Set([
220
+ "id",
221
+ "created",
222
+ "updated",
223
+ "collectionId",
224
+ "collectionName",
225
+ ...visible,
226
+ ]),
227
+ ].join(",");
204
228
  }
205
229
 
206
230
  /** Warn once when an expand field is not a relation (schema known). */
package/src/lazypock.ts CHANGED
@@ -120,6 +120,14 @@ export interface LazypockClientOptions {
120
120
  export class LazypockClient {
121
121
  readonly http: HttpClient;
122
122
  readonly authStore: AuthStore;
123
+ /**
124
+ * Resolves once persisted auth state has been loaded from storage.
125
+ * The client auto-initializes its auth store on construction, so a
126
+ * previously persisted token is ready immediately (no manual
127
+ * `authStore.init()` needed). Await this only if you must gate on
128
+ * the restored session.
129
+ */
130
+ readonly authReady: Promise<void>;
123
131
  readonly realtime: RealtimeService;
124
132
  readonly collections: CollectionsService;
125
133
  readonly files: FilesService;
@@ -134,6 +142,12 @@ export class LazypockClient {
134
142
  const baseUrl = options.baseUrl.replace(/\/+$/, "");
135
143
  this.authStore =
136
144
  options.authStore ?? new AuthStore(options.storage ?? memoryStorage);
145
+ // Auto-init the auth store so persisted tokens are restored without a
146
+ // manual `await client.authStore.init()`. A caller-provided store is
147
+ // left untouched — it owns its own initialization lifecycle.
148
+ this.authReady = options.authStore
149
+ ? Promise.resolve()
150
+ : this.authStore.init();
137
151
  this.http = new HttpClient(baseUrl, this.authStore);
138
152
  this.realtime = options.realtime ?? new RealtimeService();
139
153
  // Cache the socket URL so collection-level subscribe() can auto-connect.
package/src/schema.ts CHANGED
@@ -6,6 +6,8 @@ export interface SchemaField {
6
6
  id?: string;
7
7
  name: string;
8
8
  type: string;
9
+ /** For relation fields: the target collection id (server-resolved). */
10
+ collectionId?: string | null;
9
11
  required?: boolean;
10
12
  unique?: boolean;
11
13
  options?: {