lazypock 0.1.2 → 0.1.5

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/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n// ── Codegen CLI ─────────────────────────────────────────\n// `lazypock` — fetches the live collection schema from a Lazypock\n// API and writes a fully-typed `lazypock.types.ts` module.\n//\n// Auth methods (pick one):\n// 1. Superuser email + password:\n// npx lazypock --url http://localhost:4000/api --email admin@... --password ...\n// 2. API key (recommended, generated from the Settings dashboard):\n// npx lazypock --url http://localhost:4000/api --api-key <key>\n//\n// Or via env vars (no flags):\n// LAZYPOCK_URL=... LAZYPOCK_API_KEY=... npx lazypock\n// LAZYPOCK_URL=... LAZYPOCK_EMAIL=... LAZYPOCK_PASSWORD=... npx lazypock\n//\n// NOTE: `lazypock-gen` remains as a deprecated alias for backwards\n// compatibility. Both invoke the same executable.\n\nimport { writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { generateTypes } from \"./codegen\";\nimport type { CollectionsResponse } from \"./schema\";\n\ninterface CliOptions {\n\turl: string;\n\temail: string;\n\tpassword: string;\n\tapiKey: string;\n\tout: string;\n\tpackageName: string;\n\tskipSystem: boolean;\n}\n\nfunction fail(msg: string): never {\n\tconsole.error(`\\n❌ ${msg}\\n`);\n\tprocess.exit(1);\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n\tconst args = [...argv];\n\tconst get = (flag: string, envKey: string, def = \"\"): string => {\n\t\tconst i = args.indexOf(flag);\n\t\tif (i !== -1 && i + 1 < args.length) return args[i + 1];\n\t\treturn process.env[envKey] ?? def;\n\t};\n\tconst has = (flag: string): boolean => args.includes(flag);\n\n\tconst url = get(\"--url\", \"LAZYPOCK_URL\");\n\tconst email = get(\"--email\", \"LAZYPOCK_EMAIL\");\n\tconst password = get(\"--password\", \"LAZYPOCK_PASSWORD\");\n\tconst apiKey = get(\"--api-key\", \"LAZYPOCK_API_KEY\");\n\n\tif (!url) fail(\"Missing API URL. Pass --url or set LAZYPOCK_URL.\");\n\tif (!apiKey) {\n\t\tif (!email)\n\t\t\tfail(\n\t\t\t\t\"Missing credentials. Pass --api-key, or --email + --password, or set LAZYPOCK_API_KEY / LAZYPOCK_EMAIL.\",\n\t\t\t);\n\t\tif (!password)\n\t\t\tfail(\"Missing password. Pass --password, or set LAZYPOCK_PASSWORD.\");\n\t}\n\n\tconst out = get(\"--out\", \"LAZYPOCK_OUT\", \"lazypock.types.ts\");\n\tconst packageName = get(\"--package\", \"LAZYPOCK_PACKAGE\", \"lazypock\");\n\n\treturn {\n\t\turl,\n\t\temail,\n\t\tpassword,\n\t\tapiKey,\n\t\tout,\n\t\tpackageName,\n\t\tskipSystem: has(\"--skip-system\"),\n\t};\n}\n\nasync function fetchCollections(\n\topts: CliOptions,\n): Promise<CollectionsResponse> {\n\tconst base = opts.url.replace(/\\/+$/, \"\");\n\n\tlet authKey: string;\n\tif (opts.apiKey) {\n\t\t// Step 1: use a stored API key directly (no login round-trip).\n\t\t// The key is sent as `Authorization: Bearer <key>` and recognised\n\t\t// by the backend's Auth.Plug as an API key.\n\t\tauthKey = opts.apiKey;\n\t} else {\n\t\t// Step 1: login as superuser to get a token\n\t\tconst loginRes = await fetch(base + \"/superusers/login\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({ email: opts.email, password: opts.password }),\n\t\t});\n\t\tif (!loginRes.ok) {\n\t\t\tconst text = await loginRes.text();\n\t\t\tfail(\n\t\t\t\t`Superuser login failed (${loginRes.status}). ${text.slice(0, 200)}`,\n\t\t\t);\n\t\t}\n\t\tconst loginData = (await loginRes.json()) as { token?: string };\n\t\tif (!loginData.token) fail(\"Login response did not include a token.\");\n\t\tauthKey = loginData.token;\n\t}\n\n\t// Step 2: fetch collections\n\tconst collRes = await fetch(base + \"/collections\", {\n\t\theaders: { Authorization: \"Bearer \" + authKey },\n\t});\n\tif (!collRes.ok) {\n\t\tconst text = await collRes.text();\n\t\tfail(\n\t\t\t`Failed to fetch collections (${collRes.status}). ${text.slice(0, 200)}`,\n\t\t);\n\t}\n\treturn (await collRes.json()) as CollectionsResponse;\n}\n\nasync function main(): Promise<void> {\n\tconst opts = parseArgs(process.argv.slice(2));\n\tconst authLabel = opts.apiKey\n\t\t? `API key ${opts.apiKey.slice(0, 4)}…${opts.apiKey.slice(-4)}`\n\t\t: opts.email;\n\tconsole.log(`\\n🔌 Connecting to ${opts.url} as ${authLabel} …`);\n\n\tconst { items } = await fetchCollections(opts);\n\tconsole.log(`📦 Found ${items.length} collection(s).`);\n\n\tconst source = generateTypes(items, {\n\t\tpackageName: opts.packageName,\n\t\tskipSystem: opts.skipSystem,\n\t});\n\n\tconst outPath = resolve(process.cwd(), opts.out);\n\tawait writeFile(outPath, source, \"utf8\");\n\tconsole.log(`✅ Wrote ${outPath} (${source.length} bytes).`);\n\tconsole.log(\n\t\t`\\nImport it in your app:\\n import { createClient } from './${opts.out.replace(/\\.ts$/, \"\")}';\\n`,\n\t);\n}\n\nmain().catch((err) => {\n\tconsole.error(err);\n\tprocess.exit(1);\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n// ── Codegen CLI ─────────────────────────────────────────\n// `lazypock` — fetches the live collection schema from a Lazypock\n// API and writes a fully-typed `lazypock.types.ts` module.\n//\n// Auth methods (pick one):\n// 1. Superuser email + password:\n// npx lazypock --url http://localhost:4000/api --email admin@... --password ...\n// 2. API key (recommended, generated from the Settings dashboard):\n// npx lazypock --url http://localhost:4000/api --apikey <key>\n//\n// Or via env vars (no flags):\n// LAZYPOCK_URL=... LAZYPOCK_API_KEY=... npx lazypock\n// LAZYPOCK_URL=... LAZYPOCK_EMAIL=... LAZYPOCK_PASSWORD=... npx lazypock\n//\n// NOTE: `lazypock-gen` remains as a deprecated alias for backwards\n// compatibility. Both invoke the same executable.\n\nimport { writeFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { generateTypes } from \"./codegen\";\nimport type { CollectionsResponse } from \"./schema\";\n\ninterface CliOptions {\n\turl: string;\n\temail: string;\n\tpassword: string;\n\tapiKey: string;\n\tout: string;\n\tpackageName: string;\n\tskipSystem: boolean;\n}\n\nfunction fail(msg: string): never {\n\tconsole.error(`\\n❌ ${msg}\\n`);\n\tprocess.exit(1);\n}\n\nfunction parseArgs(argv: string[]): CliOptions {\n\tconst args = [...argv];\n\tconst get = (flag: string, envKey: string, def = \"\"): string => {\n\t\tconst i = args.indexOf(flag);\n\t\tif (i !== -1 && i + 1 < args.length) return args[i + 1];\n\t\treturn process.env[envKey] ?? def;\n\t};\n\tconst has = (flag: string): boolean => args.includes(flag);\n\n\tconst url = get(\"--url\", \"LAZYPOCK_URL\");\n\tconst email = get(\"--email\", \"LAZYPOCK_EMAIL\");\n\tconst password = get(\"--password\", \"LAZYPOCK_PASSWORD\");\n\tconst apiKey =\n\t\tget(\"--apikey\", \"LAZYPOCK_API_KEY\") || get(\"--api-key\", \"LAZYPOCK_API_KEY\");\n\n\tif (!url) fail(\"Missing API URL. Pass --url or set LAZYPOCK_URL.\");\n\tif (!apiKey) {\n\t\tif (!email)\n\t\t\tfail(\n\t\t\t\t\"Missing credentials. Pass --apikey, or --email + --password, or set LAZYPOCK_API_KEY / LAZYPOCK_EMAIL.\",\n\t\t\t);\n\t\tif (!password)\n\t\t\tfail(\"Missing password. Pass --password, or set LAZYPOCK_PASSWORD.\");\n\t}\n\n\tconst out =\n\t\tget(\"--output\", \"LAZYPOCK_OUT\") ||\n\t\tget(\"--out\", \"LAZYPOCK_OUT\", \"lazypock.types.ts\");\n\tconst packageName = get(\"--package\", \"LAZYPOCK_PACKAGE\", \"lazypock\");\n\n\treturn {\n\t\turl,\n\t\temail,\n\t\tpassword,\n\t\tapiKey,\n\t\tout,\n\t\tpackageName,\n\t\tskipSystem: has(\"--skip-system\"),\n\t};\n}\n\nasync function fetchCollections(\n\topts: CliOptions,\n): Promise<CollectionsResponse> {\n\tconst base = opts.url.replace(/\\/+$/, \"\");\n\n\tlet authKey: string;\n\tif (opts.apiKey) {\n\t\t// Step 1: use a stored API key directly (no login round-trip).\n\t\t// The key is sent as `Authorization: Bearer <key>` and recognised\n\t\t// by the backend's Auth.Plug as an API key.\n\t\tauthKey = opts.apiKey;\n\t} else {\n\t\t// Step 1: login as superuser to get a token\n\t\tconst loginRes = await fetch(base + \"/superusers/login\", {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({ email: opts.email, password: opts.password }),\n\t\t});\n\t\tif (!loginRes.ok) {\n\t\t\tconst text = await loginRes.text();\n\t\t\tfail(\n\t\t\t\t`Superuser login failed (${loginRes.status}). ${text.slice(0, 200)}`,\n\t\t\t);\n\t\t}\n\t\tconst loginData = (await loginRes.json()) as { token?: string };\n\t\tif (!loginData.token) fail(\"Login response did not include a token.\");\n\t\tauthKey = loginData.token;\n\t}\n\n\t// Step 2: fetch collections\n\tconst collRes = await fetch(base + \"/collections\", {\n\t\theaders: { Authorization: \"Bearer \" + authKey },\n\t});\n\tif (!collRes.ok) {\n\t\tconst text = await collRes.text();\n\t\tfail(\n\t\t\t`Failed to fetch collections (${collRes.status}). ${text.slice(0, 200)}`,\n\t\t);\n\t}\n\treturn (await collRes.json()) as CollectionsResponse;\n}\n\nasync function main(): Promise<void> {\n\tconst opts = parseArgs(process.argv.slice(2));\n\tconst authLabel = opts.apiKey\n\t\t? `API key ${opts.apiKey.slice(0, 4)}…${opts.apiKey.slice(-4)}`\n\t\t: opts.email;\n\tconsole.log(`\\n🔌 Connecting to ${opts.url} as ${authLabel} …`);\n\n\tconst { items } = await fetchCollections(opts);\n\tconsole.log(`📦 Found ${items.length} collection(s).`);\n\n\tconst source = generateTypes(items, {\n\t\tpackageName: opts.packageName,\n\t\tskipSystem: opts.skipSystem,\n\t});\n\n\tconst outPath = resolve(process.cwd(), opts.out);\n\tawait writeFile(outPath, source, \"utf8\");\n\tconsole.log(`✅ Wrote ${outPath} (${source.length} bytes).`);\n\tconsole.log(\n\t\t`\\nImport it in your app:\\n import { createClient } from './${opts.out.replace(/\\.ts$/, \"\")}';\\n`,\n\t);\n}\n\nmain().catch((err) => {\n\tconsole.error(err);\n\tprocess.exit(1);\n});\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -23,6 +23,7 @@ __export(index_exports, {
23
23
  ApiError: () => ApiError,
24
24
  AuthStore: () => AuthStore,
25
25
  CollectionService: () => CollectionService,
26
+ CollectionsService: () => CollectionsService,
26
27
  FilesService: () => FilesService,
27
28
  LazypockClient: () => LazypockClient,
28
29
  RealtimeService: () => RealtimeService,
@@ -353,17 +354,62 @@ var CollectionService = class {
353
354
  return encodeURIComponent(id);
354
355
  }
355
356
  /**
356
- * List records with optional filter/sort/pagination.
357
- * @param params Query parameters including `filter`, `sort`, `page`, `perPage`, `expand`.
358
- * @param options Optional request options.
357
+ * Fetch a paginated list of records (PocketBase `getList`).
358
+ *
359
+ * @param page Page number (default 1).
360
+ * @param perPage Records per page (default 30).
361
+ * @param options Query params (`filter`, `sort`, `expand`, `fields`) + request options.
359
362
  */
360
- list(params, options) {
361
- const qs = params ? "?" + new URLSearchParams(params).toString() : "";
363
+ getList(page = 1, perPage = 30, options) {
364
+ const { ...rest } = options ?? {};
365
+ const qs = new URLSearchParams(
366
+ Object.fromEntries(
367
+ Object.entries({ page: String(page), perPage: String(perPage), ...rest }).map(
368
+ ([k, v]) => [k, String(v)]
369
+ )
370
+ )
371
+ ).toString();
362
372
  return this.http.get(
363
- "/" + this.encodeId(this.collectionName) + qs,
373
+ "/" + this.encodeId(this.collectionName) + "?" + qs,
364
374
  options
365
375
  );
366
376
  }
377
+ /**
378
+ * Fetch all records at once (auto-paginates). Mirrors PocketBase's
379
+ * `pb.collection(name).getFullList()`.
380
+ *
381
+ * @param options Query params (`sort`, `filter`, `batch`, etc.) + request options.
382
+ */
383
+ async getFullList(options) {
384
+ const { batch = 1e3, ...rest } = options ?? {};
385
+ const items = [];
386
+ let page = 1;
387
+ for (; ; ) {
388
+ const res = await this.getList(
389
+ page,
390
+ batch,
391
+ rest
392
+ );
393
+ if (!res || !res.items || res.items.length === 0) break;
394
+ items.push(...res.items);
395
+ if (page >= (res.totalPages ?? page)) break;
396
+ page += 1;
397
+ }
398
+ return items;
399
+ }
400
+ /**
401
+ * Fetch the first record matching a filter (PocketBase `getFirstListItem`).
402
+ *
403
+ * @param filter Filter expression (e.g. `title = 'x'`).
404
+ * @param options Optional request options.
405
+ */
406
+ async getFirstListItem(filter, options) {
407
+ const res = await this.getList(1, 1, {
408
+ ...options,
409
+ filter
410
+ });
411
+ return res?.items?.[0] ?? null;
412
+ }
367
413
  /**
368
414
  * Get a single record by ID.
369
415
  * @param id Record ID.
@@ -808,6 +854,135 @@ var FilesService = class {
808
854
  }
809
855
  };
810
856
 
857
+ // src/collections.ts
858
+ var REGISTRY_TOPIC = "collections";
859
+ var CollectionsService = class {
860
+ /** @internal */
861
+ constructor(http, realtime) {
862
+ this.http = http;
863
+ this.realtime = realtime;
864
+ }
865
+ /**
866
+ * Fetch a paginated list of collections (admin).
867
+ *
868
+ * @param params Optional query params (`page`, `perPage`, `filter`, `sort`).
869
+ * @param options Optional request options.
870
+ */
871
+ async getList(params, options) {
872
+ const qs = params ? "?" + new URLSearchParams(
873
+ Object.fromEntries(
874
+ Object.entries(params).map(([k, v]) => [k, String(v)])
875
+ )
876
+ ).toString() : "";
877
+ return this.http?.get("/collections" + qs, options) ?? null;
878
+ }
879
+ /**
880
+ * Fetch all collections at once (auto-paginates). Mirrors PocketBase's
881
+ * `pb.collections.getFullList()` — defaults to listing everything.
882
+ *
883
+ * @param options Query params (`sort`, `batch`, etc.) or request options.
884
+ */
885
+ async getFullList(options) {
886
+ if (!this.http) return [];
887
+ const { batch = 1e3, ...rest } = options ?? {};
888
+ const items = [];
889
+ let page = 1;
890
+ for (; ; ) {
891
+ const res = await this.getList({
892
+ ...rest,
893
+ page,
894
+ perPage: batch
895
+ });
896
+ if (!res || !res.items || res.items.length === 0) break;
897
+ items.push(...res.items);
898
+ if (page >= (res.totalPages ?? page)) break;
899
+ page += 1;
900
+ }
901
+ return items;
902
+ }
903
+ /**
904
+ * Get a single collection by ID or name (admin).
905
+ *
906
+ * @param id Collection ID or name.
907
+ * @param options Optional request options.
908
+ */
909
+ async getOne(id, options) {
910
+ return this.http?.get("/collections/" + encodeURIComponent(id), options) ?? null;
911
+ }
912
+ /**
913
+ * Create a new collection (admin).
914
+ *
915
+ * @param data Collection definition (name, type, fields, options, rules, etc.).
916
+ * @param options Optional request options.
917
+ */
918
+ async create(data, options) {
919
+ return this.http?.post("/collections", data, options) ?? null;
920
+ }
921
+ /**
922
+ * Update an existing collection (admin).
923
+ *
924
+ * @param id Collection ID or name.
925
+ * @param data Updated collection fields.
926
+ * @param options Optional request options.
927
+ */
928
+ async update(id, data, options) {
929
+ return this.http?.patch(
930
+ "/collections/" + encodeURIComponent(id),
931
+ data,
932
+ options
933
+ ) ?? null;
934
+ }
935
+ /**
936
+ * Delete a collection (admin).
937
+ *
938
+ * @param id Collection ID or name.
939
+ * @param options Optional request options.
940
+ */
941
+ async delete(id, options) {
942
+ const res = this.http?.delete(
943
+ "/collections/" + encodeURIComponent(id),
944
+ options
945
+ );
946
+ return res == null ? false : true;
947
+ }
948
+ /**
949
+ * Subscribe to collection registry changes.
950
+ *
951
+ * @param callback Received on every collection create/update/delete.
952
+ * @returns A function that unsubscribes this callback.
953
+ */
954
+ subscribe(callback) {
955
+ if (!this.realtime) {
956
+ console.warn("[lazypock] No realtime service configured.");
957
+ return () => {
958
+ };
959
+ }
960
+ const handler = (raw) => {
961
+ callback({
962
+ action: normalizeAction2(raw.event),
963
+ collection: raw.payload ?? {},
964
+ topic: raw.topic
965
+ });
966
+ };
967
+ this.realtime.ensureConnected();
968
+ this.realtime.subscribe(REGISTRY_TOPIC, handler);
969
+ return () => this.realtime?.unsubscribe(REGISTRY_TOPIC, handler);
970
+ }
971
+ /**
972
+ * Unsubscribe all callbacks from the registry channel.
973
+ */
974
+ unsubscribe() {
975
+ this.realtime?.unsubscribe(REGISTRY_TOPIC);
976
+ }
977
+ };
978
+ function normalizeAction2(event) {
979
+ const e = event.toLowerCase();
980
+ if (e === "create") return "create";
981
+ if (e === "update") return "update";
982
+ if (e === "delete") return "delete";
983
+ return "update";
984
+ }
985
+
811
986
  // src/typegen.ts
812
987
  function fieldTypeScriptType(field, fallback = "unknown") {
813
988
  const opts = field.options ?? {};
@@ -968,11 +1143,13 @@ export function createClient(options: LazypockClientOptions): TypedClient {
968
1143
  }
969
1144
 
970
1145
  export class TypedClient extends LazypockClient {
971
- override collection<K extends keyof LazypockCollections>(name: K): CollectionService<LazypockCollections[K]>;
972
- override collection(name: string): CollectionService<unknown> {
973
- return super.collection(name) as unknown as CollectionService<unknown>;
1146
+ override collection<T extends string>(name: T): T extends keyof LazypockCollections
1147
+ ? CollectionService<LazypockCollections[T]>
1148
+ : CollectionService<unknown> {
1149
+ return super.collection(name) as T extends keyof LazypockCollections ? CollectionService<LazypockCollections[T]> : CollectionService<unknown>;
974
1150
  }
975
- }`);
1151
+ }
1152
+ `);
976
1153
  return sections.join("\n\n") + "\n";
977
1154
  }
978
1155
  function renderInterface(opts) {
@@ -1006,6 +1183,7 @@ var LazypockClient = class {
1006
1183
  this.realtime.setUrl(wsUrlFromBaseUrl(baseUrl));
1007
1184
  }
1008
1185
  this.files = new FilesService(this.http);
1186
+ this.collections = new CollectionsService(this.http, this.realtime);
1009
1187
  if (options.types?.schemas) {
1010
1188
  this.schemaByName = new Map(
1011
1189
  options.types.schemas.map((s) => [s.name, s])
@@ -1166,129 +1344,6 @@ var LazypockClient = class {
1166
1344
  health(options) {
1167
1345
  return this.http.get("/health", options);
1168
1346
  }
1169
- // ── Collection Management (admin) ──
1170
- /**
1171
- * List all collections (admin).
1172
- * @param q URL query string (e.g. `page=1&perPage=200`).
1173
- * @param options Optional request options.
1174
- */
1175
- listCollections(q, options) {
1176
- return this.http.get(
1177
- "/collections" + (q ? "?" + q : ""),
1178
- options
1179
- );
1180
- }
1181
- /**
1182
- * Get a single collection by ID or name.
1183
- * @param id Collection ID or name.
1184
- * @param options Optional request options.
1185
- */
1186
- getCollection(id, options) {
1187
- return this.http.get(
1188
- "/collections/" + encodeURIComponent(id),
1189
- options
1190
- );
1191
- }
1192
- /**
1193
- * Create a new collection (admin).
1194
- * @param data Collection definition (name, type, fields, options, rules, etc.).
1195
- * @param options Optional request options.
1196
- */
1197
- createCollection(data, options) {
1198
- return this.http.post("/collections", data, options);
1199
- }
1200
- /**
1201
- * Update an existing collection (admin).
1202
- * @param id Collection ID or name.
1203
- * @param data Updated collection fields.
1204
- * @param options Optional request options.
1205
- */
1206
- updateCollection(id, data, options) {
1207
- return this.http.patch(
1208
- "/collections/" + encodeURIComponent(id),
1209
- data,
1210
- options
1211
- );
1212
- }
1213
- /**
1214
- * Delete a collection (admin).
1215
- * @param id Collection ID or name.
1216
- * @param options Optional request options.
1217
- */
1218
- deleteCollection(id, options) {
1219
- return this.http.delete("/collections/" + encodeURIComponent(id), options);
1220
- }
1221
- // ── Records (dynamic collection) ──
1222
- /**
1223
- * List records from a dynamic collection with optional filter/sort/pagination.
1224
- *
1225
- * @param coll Collection name.
1226
- * @param params Query parameters including:
1227
- * - `filter` — PocketBase filter syntax (e.g. `title~'hello' && published=true`)
1228
- * - `sort` — Comma-separated, `-` prefix for DESC (e.g. `-created,title`)
1229
- * - `page` — Page number (default: 1)
1230
- * - `perPage` — Items per page (default: 30, max: 200)
1231
- * - `expand` — Comma-separated relation fields (e.g. `author,category`)
1232
- * @param options Optional request options.
1233
- */
1234
- listRecords(coll, params, options) {
1235
- const qs = params ? "?" + new URLSearchParams(params).toString() : "";
1236
- return this.http.get(
1237
- "/" + encodeURIComponent(coll) + qs,
1238
- options
1239
- );
1240
- }
1241
- /**
1242
- * Get a single record by ID.
1243
- * @param coll Collection name.
1244
- * @param id Record ID.
1245
- * @param options Optional request options.
1246
- */
1247
- getRecord(coll, id, options) {
1248
- return this.http.get(
1249
- "/" + encodeURIComponent(coll) + "/" + encodeURIComponent(id),
1250
- options
1251
- );
1252
- }
1253
- /**
1254
- * Create a record in a dynamic collection.
1255
- * @param coll Collection name.
1256
- * @param data Record fields.
1257
- * @param options Optional request options.
1258
- */
1259
- createRecord(coll, data, options) {
1260
- return this.http.post(
1261
- "/" + encodeURIComponent(coll),
1262
- data,
1263
- options
1264
- );
1265
- }
1266
- /**
1267
- * Update a record in a dynamic collection.
1268
- * @param coll Collection name.
1269
- * @param id Record ID.
1270
- * @param data Updated record fields.
1271
- * @param options Optional request options.
1272
- */
1273
- updateRecord(coll, id, data, options) {
1274
- return this.http.patch(
1275
- "/" + encodeURIComponent(coll) + "/" + encodeURIComponent(id),
1276
- data,
1277
- options
1278
- );
1279
- }
1280
- /**
1281
- * Delete a record from a dynamic collection.
1282
- * @param coll Collection name.
1283
- * @param id Record ID.
1284
- * @param options Optional request options.
1285
- */
1286
- deleteRecord(coll, id, options) {
1287
- return this.http.delete(
1288
- "/" + encodeURIComponent(coll) + "/" + encodeURIComponent(id),
1289
- options
1290
- );
1291
- }
1292
1347
  };
1293
1348
 
1294
1349
  // src/client.ts
@@ -1305,6 +1360,7 @@ function createClient(options) {
1305
1360
  ApiError,
1306
1361
  AuthStore,
1307
1362
  CollectionService,
1363
+ CollectionsService,
1308
1364
  FilesService,
1309
1365
  LazypockClient,
1310
1366
  RealtimeService,