Compare commits
11 Commits
ea672a9d91
...
v0.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 2412238236 | |||
| 6c88dd79d8 | |||
| 1638435e26 | |||
| 618d9591b4 | |||
| b2e9e82f5e | |||
| 81005c54cd | |||
| e02737359c | |||
| 827b53e630 | |||
| d4dfed9603 | |||
| 21c9fccf5e | |||
| e5e728705c |
33
README.md
33
README.md
@@ -1,9 +1,32 @@
|
||||
# zod-pocketbase
|
||||
# zod-pocketbase-continued
|
||||
|
||||
Zod tooling for your Pocketbase instance.
|
||||
Zod tooling for your PocketBase instance.
|
||||
|
||||
To see how to get started, check out the [docs](https://zod-pocketbase.vercel.app)
|
||||
This repository is a continuation of [Gregory Bouteiller's zod-pocketbase](https://github.com/gbouteiller/zod-pocketbase), as the original repository was outdated for 10 months.
|
||||
|
||||
## Licensing
|
||||
## Documentation
|
||||
|
||||
[MIT Licensed](./LICENSE). Made with ❤️ by [Gregory Bouteiller](https://github.com/gbouteiller).
|
||||
[Old documentation is compatible with the current version](https://zod-pocketbase.vercel.app)
|
||||
|
||||
## Compatibility
|
||||
|
||||
- **PocketBase**: v0.30.0
|
||||
- **PocketBase JS SDK**: v0.26.2
|
||||
|
||||
## Changes from Original
|
||||
|
||||
### Project Structure
|
||||
- Removed `doc/`, `playground/` and monorepo configuration
|
||||
- Replaced `pnpm` and `node` in favor of `bun`
|
||||
- Switched `.github/` to `.gitea/` and `gh` to `tea`
|
||||
|
||||
### Dependencies & Code
|
||||
- Migrated from `tsup` to `tsdown`
|
||||
- Updated all npm dependencies (except `zod`, which was only updated to the latest 3 version)
|
||||
- Removed unused dependencies
|
||||
- Fixed `getPocketbase` function in `sdk.ts` to match the latest PocketBase version
|
||||
- Implemented most TODOs left in `content.ts`
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](./LICENSE)
|
||||
|
||||
@@ -33,6 +33,41 @@ export const RecordModel = z.object({
|
||||
});
|
||||
export type RecordModel = z.infer<typeof RecordModel>;
|
||||
|
||||
/******* JSON FIELD *******/
|
||||
export const pbJsonField = (maxSizeInBytes: number = 1048576) => {
|
||||
const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
||||
const jsonSchema: z.ZodType<any> = z.lazy(() =>
|
||||
z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)])
|
||||
);
|
||||
|
||||
const stringTransform = z.string()
|
||||
.max(maxSizeInBytes, `JSON field cannot exceed ${maxSizeInBytes} bytes`)
|
||||
.transform((val: string) => {
|
||||
if (val === "true") return true;
|
||||
if (val === "false") return false;
|
||||
if (val === "null") return null;
|
||||
|
||||
if ((val.startsWith('[') && val.endsWith(']'))||(val.startsWith('{') && val.endsWith('}')))
|
||||
try {
|
||||
return JSON.parse(val);
|
||||
} catch {
|
||||
return val;
|
||||
}
|
||||
|
||||
const num = Number(val);
|
||||
if (!isNaN(num) && isFinite(num) && val.trim() !== '')
|
||||
return num;
|
||||
|
||||
if (val.startsWith('"') && val.endsWith('"'))
|
||||
return val.slice(1, -1);
|
||||
|
||||
return val;
|
||||
});
|
||||
|
||||
return z.union([jsonSchema, stringTransform]);
|
||||
};
|
||||
|
||||
|
||||
/******* RECORDS *******/
|
||||
@@_RECORDS_@@
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
description = "Zod-PocketBase development environment with Bun";
|
||||
description = "Zod-PocketBase-Continue development environment with Bun";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
@@ -30,7 +30,7 @@
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
echo "🚀 Zod-PocketBase development environment (Bun-powered)"
|
||||
echo "🚀 Zod-PocketBase-Continue development environment (Bun-powered)"
|
||||
echo "Bun version: $(bun --version)"
|
||||
echo "Tea version: $(tea --version)"
|
||||
echo ""
|
||||
@@ -52,7 +52,7 @@
|
||||
};
|
||||
|
||||
packages.default = pkgs.stdenv.mkDerivation {
|
||||
name = "zod-pocketbase";
|
||||
name = "zod-pocketbase-continue";
|
||||
src = ./.;
|
||||
|
||||
buildInputs = [ bun ];
|
||||
|
||||
24
package.json
24
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "zod-pocketbase",
|
||||
"name": "zod-pocketbase-continue",
|
||||
"version": "0.5.0",
|
||||
"description": "",
|
||||
"description": "Zod tooling for your PocketBase instance.",
|
||||
"author": {
|
||||
"email": "garandplg@garandplg.com",
|
||||
"name": "Garand_PLG",
|
||||
@@ -16,7 +16,7 @@
|
||||
"type generation",
|
||||
"zod"
|
||||
],
|
||||
"homepage": "https://gitea.garandplg.com/GarandPLG/zod-pocketbase",
|
||||
"homepage": "https://gitea.garandplg.com/GarandPLG/zod-pocketbase-continue",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
@@ -28,7 +28,7 @@
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"bin": {
|
||||
"zod-pocketbase": "dist/server/cli.js"
|
||||
"zod-pocketbase-continue": "dist/server/cli.js"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
@@ -45,8 +45,8 @@
|
||||
"assets"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "tsup --watch",
|
||||
"build": "tsup",
|
||||
"dev": "tsdown --watch",
|
||||
"build": "tsdown",
|
||||
"changeset": "changeset",
|
||||
"release": "bun scripts/release.mjs"
|
||||
},
|
||||
@@ -54,20 +54,16 @@
|
||||
"@clack/prompts": "^0.11.0",
|
||||
"c12": "^3.3.0",
|
||||
"citty": "^0.1.6",
|
||||
"es-toolkit": "^1.39.10"
|
||||
"es-toolkit": "^1.40.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.29.7",
|
||||
"@types/node": "^24.6.2",
|
||||
"@typescript-eslint/parser": "^8.45.0",
|
||||
"@types/node": "^24.7.1",
|
||||
"@typescript-eslint/parser": "^8.46.0",
|
||||
"eslint": "^9.37.0",
|
||||
"eslint-plugin-astro": "^1.3.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.10.2",
|
||||
"pocketbase": "^0.26.2",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
"prettier-plugin-tailwindcss": "^0.6.14",
|
||||
"tsup": "^8.5.0",
|
||||
"tsdown": "^0.15.6",
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/** @type {import("prettier").Config} */
|
||||
export default {
|
||||
printWidth: 140,
|
||||
plugins: ["prettier-plugin-astro", "prettier-plugin-tailwindcss"],
|
||||
overrides: [{ files: "*.astro", options: { parser: "astro" } }],
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ export const defaultConfig = {
|
||||
nameEnumValues: (name: string) => `${name}Values`,
|
||||
nameRecordSchema: (name: string) => `${pascalCase(name)}Record`,
|
||||
nameRecordType: (name: string) => `${pascalCase(name)}Record`,
|
||||
output: "./zod-pocketbase.ts",
|
||||
output: "./zod-pocketbase-continue.ts",
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
253
src/content.ts
253
src/content.ts
@@ -1,6 +1,6 @@
|
||||
import { sortBy } from "es-toolkit";
|
||||
import type { CollectionModel, CollectionField } from "pocketbase";
|
||||
import type { GenerateOpts } from "./server/utils.ts";
|
||||
import type { GenerateOpts } from "@/server/utils.ts";
|
||||
|
||||
export function stringifyContent(collections: CollectionModel[], opts: GenerateOpts) {
|
||||
function getCollectionSelectFields() {
|
||||
@@ -9,7 +9,7 @@ export function stringifyContent(collections: CollectionModel[], opts: GenerateO
|
||||
.filter((field: CollectionField) => field.type === "select")
|
||||
.map((field: CollectionField) => ({
|
||||
name: opts.nameEnumField(collection.name, field.name),
|
||||
values: ((field as any).options?.values ?? []) as string[],
|
||||
values: ((field as any).values ?? []) as string[],
|
||||
})),
|
||||
);
|
||||
}
|
||||
@@ -26,17 +26,7 @@ export function stringifyContent(collections: CollectionModel[], opts: GenerateO
|
||||
const schemaName = opts.nameRecordSchema(name);
|
||||
const typeName = opts.nameRecordType(name);
|
||||
|
||||
// Filter out system fields that are already inherited from RecordModel or should be omitted
|
||||
const systemFields = new Set([
|
||||
"id",
|
||||
"created",
|
||||
"updated",
|
||||
"collectionId",
|
||||
"collectionName",
|
||||
"expand", // inherited from BaseModel/RecordModel
|
||||
"password",
|
||||
"tokenKey", // should not be in response schema
|
||||
]);
|
||||
const systemFields = new Set(["id", "created", "updated", "collectionId", "collectionName", "expand", "password", "tokenKey"]);
|
||||
|
||||
const customFields = fields.filter((field) => !systemFields.has(field.name));
|
||||
const fieldStrings = sortBy(customFields, ["name"]).map((field) => stringifyField(field, name));
|
||||
@@ -44,125 +34,6 @@ export function stringifyContent(collections: CollectionModel[], opts: GenerateO
|
||||
return `export const ${schemaName} = z.object({\n\t...RecordModel.omit({ expand: true }).shape,\n\tcollectionName: z.literal("${name}"),\n\t${fieldStrings.join(",\n\t")},\n});\nexport type ${typeName} = z.infer<typeof ${schemaName}>;`;
|
||||
}
|
||||
|
||||
function stringifyField(field: CollectionField, collectionName: string) {
|
||||
let schema: string;
|
||||
// TODO:
|
||||
console.log(`${collectionName}: ${field.type}`);
|
||||
switch (field.type) {
|
||||
case "bool":
|
||||
schema = stringifyBoolField(field);
|
||||
break;
|
||||
case "date":
|
||||
schema = stringifyDateField(field);
|
||||
break;
|
||||
case "editor":
|
||||
schema = stringifyEditorField(field);
|
||||
break;
|
||||
case "email":
|
||||
schema = stringifyEmailField(field);
|
||||
break;
|
||||
case "file":
|
||||
schema = stringifyFileField(field);
|
||||
break;
|
||||
case "json":
|
||||
schema = stringifyJsonField(field);
|
||||
break;
|
||||
case "number":
|
||||
schema = stringifyNumberField(field);
|
||||
break;
|
||||
case "relation":
|
||||
schema = stringifyRelationField(field);
|
||||
break;
|
||||
case "select":
|
||||
schema = stringifySelectField(field, collectionName);
|
||||
break;
|
||||
case "text":
|
||||
schema = stringifyTextField(field);
|
||||
break;
|
||||
case "url":
|
||||
schema = stringifyUrlField(field);
|
||||
break;
|
||||
case "geoPoint":
|
||||
schema = stringifyGeoPointField(field);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown field type "${field.type}" for field "${field.name}". Using z.any() as fallback.`);
|
||||
schema = "z.any()";
|
||||
break;
|
||||
}
|
||||
return `${field.name}: ${schema}${(field as any).required ? "" : ".optional()"}`;
|
||||
}
|
||||
|
||||
function stringifyBoolField(_: CollectionField) {
|
||||
return "z.boolean()";
|
||||
}
|
||||
|
||||
function stringifyDateField(_field: CollectionField) {
|
||||
// TODO: implement min and max
|
||||
return "z.string().pipe(z.coerce.date())";
|
||||
}
|
||||
|
||||
function stringifyEditorField(_field: CollectionField) {
|
||||
// TODO: implement convertUrls
|
||||
return "z.string()";
|
||||
}
|
||||
|
||||
function stringifyEmailField(_field: CollectionField) {
|
||||
// TODO: implement exceptDomains and onlyDomains
|
||||
return "z.string().email()";
|
||||
}
|
||||
|
||||
function stringifyFileField(field: CollectionField) {
|
||||
const maxSelect = (field as any).options?.maxSelect;
|
||||
// TODO: implement maxSize, mimeTypes, protected, thumbs
|
||||
return `z.string()${maxSelect === 1 ? "" : `.array()${maxSelect ? `.max(${maxSelect})` : ""}`}`;
|
||||
}
|
||||
|
||||
function stringifyJsonField(_field: CollectionField) {
|
||||
// TODO: implement maxSize and json schema
|
||||
return "z.any()";
|
||||
}
|
||||
|
||||
function stringifyNumberField(field: CollectionField) {
|
||||
const options = (field as any).options || {};
|
||||
const { max, min, noDecimal } = options;
|
||||
return `z.number()${noDecimal ? ".int()" : ""}${min ? `.min(${min})` : ""}${max ? `.max(${max})` : ""}`;
|
||||
}
|
||||
|
||||
function stringifyRelationField(field: CollectionField) {
|
||||
const options = (field as any).options || {};
|
||||
const required = (field as any).required;
|
||||
const { maxSelect, minSelect } = options;
|
||||
// TODO: implement cascadeDelete, displayFields
|
||||
const min = minSelect ? `.min(${minSelect})` : "";
|
||||
const max = maxSelect ? `.max(${maxSelect})` : "";
|
||||
const multiple = maxSelect === 1 ? "" : `.array()${min}${max}`;
|
||||
const isOptional = required || maxSelect !== 1 ? `` : `.transform((id) => id === "" ? undefined : id)`;
|
||||
return `z.string()${isOptional}${multiple}`;
|
||||
}
|
||||
|
||||
function stringifySelectField(field: CollectionField, collectionName: string) {
|
||||
const maxSelect = (field as any).options?.maxSelect;
|
||||
// TODO: implement values
|
||||
return `${opts.nameEnumSchema(opts.nameEnumField(collectionName, field.name))}${maxSelect === 1 ? "" : `.array().max(${maxSelect})`}`;
|
||||
}
|
||||
|
||||
function stringifyTextField(field: CollectionField) {
|
||||
const options = (field as any).options || {};
|
||||
const { max, min } = options;
|
||||
// TODO: implement pattern
|
||||
return `z.string()${min ? `.min(${min})` : ""}${max ? `.max(${max})` : ""}`;
|
||||
}
|
||||
|
||||
function stringifyUrlField(_field: CollectionField) {
|
||||
// TODO: implement exceptDomains and onlyDomains
|
||||
return "z.string().url()";
|
||||
}
|
||||
|
||||
function stringifyGeoPointField(_field: CollectionField) {
|
||||
return "z.object({ lat: z.number().min(-90).max(90), lng: z.number().min(-180).max(180) })";
|
||||
}
|
||||
|
||||
function stringifySchemasEntry({ name }: CollectionModel) {
|
||||
return `["${name}", ${opts.nameRecordSchema(name)}]`;
|
||||
}
|
||||
@@ -171,6 +42,124 @@ export function stringifyContent(collections: CollectionModel[], opts: GenerateO
|
||||
return `\t\tcollection(idOrName: "${name}"): RecordService<z.input<typeof ${opts.nameRecordSchema(name)}>>;`;
|
||||
}
|
||||
|
||||
function stringifyField(field: CollectionField, collectionName: string) {
|
||||
let schema: string;
|
||||
switch (field.type) {
|
||||
case "bool":
|
||||
schema = "z.boolean()";
|
||||
break;
|
||||
|
||||
case "date":
|
||||
const minConstraintDate = field.min ? `.min(new Date("${field.min}"))` : "";
|
||||
const maxConstraintDate = field.max ? `.max(new Date("${field.max}"))` : "";
|
||||
|
||||
schema = `z.string().pipe(z.coerce.date()${minConstraintDate}${maxConstraintDate})`;
|
||||
break;
|
||||
|
||||
case "editor":
|
||||
// TODO: implement convertUrls
|
||||
schema = "z.string()";
|
||||
break;
|
||||
|
||||
case "email":
|
||||
const onlyDomainsConstraint = createDomainConstraint(field.onlyDomains, true, "email");
|
||||
const exceptDomainsConstraint = createDomainConstraint(field.exceptDomains, false, "email");
|
||||
|
||||
schema = `z.string().email()${onlyDomainsConstraint}${exceptDomainsConstraint}`;
|
||||
break;
|
||||
|
||||
case "file":
|
||||
const maxSelectFile: number = field.maxSelect;
|
||||
const maxSizeFile: number = field.maxSize;
|
||||
const mimeTypesArray: string[] = field.mimeTypes || [];
|
||||
// const protectedFile: boolean = field.protected;
|
||||
// const thumbsFileArray: string[] = field.thumbs || [];
|
||||
|
||||
const fileFieldMaxSelect = maxSelectFile ? `.max(${maxSelectFile})` : "";
|
||||
const fileFieldTypeArray = maxSelectFile === 1 ? "" : `.array()${fileFieldMaxSelect}`;
|
||||
|
||||
let fileValidation = "z.instanceof(File)";
|
||||
|
||||
if (maxSizeFile) fileValidation += `.refine((file) => file.size <= ${maxSizeFile}, { message: "File size too large" })`;
|
||||
|
||||
if (mimeTypesArray.length > 0)
|
||||
fileValidation += `.refine((file) => ${JSON.stringify(mimeTypesArray)}.includes(file.type), { message: "Invalid file type" })`;
|
||||
|
||||
const baseFileSchema = `z.union([z.string(), ${fileValidation}])`;
|
||||
schema = `${baseFileSchema}${fileFieldTypeArray}`;
|
||||
break;
|
||||
|
||||
case "json":
|
||||
schema = field.maxSize > 0 ? `pbJsonField(${field.maxSize})` : "pbJsonField()";
|
||||
break;
|
||||
|
||||
case "number":
|
||||
const maxNumber = field.maxNumber ? `.max(${field.maxNumber})` : "";
|
||||
const minNumber = field.minNumber ? `.min(${field.minNumber})` : "";
|
||||
const noDecimal = field.noDecimal ? ".int()" : "";
|
||||
|
||||
schema = `z.number()${noDecimal}${minNumber}${maxNumber}`;
|
||||
break;
|
||||
|
||||
case "relation":
|
||||
// TODO: implement cascadeDelete, displayFields, multiple records query
|
||||
const multiple = field.maxSelect === 1 ? "" : `.array().min(${field.minSelect}).max(${field.maxSelect})`;
|
||||
const isOptional = field.required || field.maxSelect !== 1 ? `` : `.transform((id: string) => id === "" ? undefined : id)`;
|
||||
|
||||
schema = `z.string()${isOptional}${multiple}`;
|
||||
break;
|
||||
|
||||
case "select":
|
||||
const maxSelect = field.maxSelect === 1 ? "" : `.array().max(${field.maxSelect})`;
|
||||
|
||||
schema = `${opts.nameEnumSchema(opts.nameEnumField(collectionName, field.name))}${maxSelect}`;
|
||||
break;
|
||||
|
||||
case "text":
|
||||
const patternText =
|
||||
field.pattern && field.pattern.trim() !== "" ? `.regex(new RegExp("${field.pattern.replace(/"/g, '\\"')}"))` : "";
|
||||
const maxText = field.max ? `.max(${field.max})` : "";
|
||||
const minText = field.min ? `.min(${field.min})` : "";
|
||||
|
||||
schema = `z.string()${minText}${maxText}${patternText}`;
|
||||
break;
|
||||
|
||||
case "url":
|
||||
const onlyDomainsUrlConstraint = createDomainConstraint(field.onlyDomains, true, "url");
|
||||
const exceptDomainsUrlConstraint = createDomainConstraint(field.exceptDomains, false, "url");
|
||||
|
||||
schema = `z.string().url()${onlyDomainsUrlConstraint}${exceptDomainsUrlConstraint}`;
|
||||
break;
|
||||
|
||||
case "geoPoint":
|
||||
schema = "z.object({ lat: z.number().min(-90).max(90), lon: z.number().min(-180).max(180) })";
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn(`Unknown field type "${field.type}" for field "${field.name}". Using z.any() as fallback.`);
|
||||
schema = "z.any()";
|
||||
break;
|
||||
}
|
||||
return `${field.name}: ${schema}${(field as any).required ? "" : ".optional()"}`;
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
|
||||
const createDomainConstraint = (domains: string[], isWhitelist: boolean, type: "email" | "url") => {
|
||||
if (!domains?.length) return "";
|
||||
|
||||
const domainsList = domains.map((domain) => `"${domain}"`).join(", ");
|
||||
const messageType = isWhitelist ? "isn't one of the allowed ones" : "is one of the disallowed ones";
|
||||
const negation = isWhitelist ? "" : "!";
|
||||
|
||||
const domainExtraction = type === "email" ? 'const domain = value.split("@")[1];' : "const domain = new URL(value).hostname;";
|
||||
|
||||
const errorHandling = type === "url" ? "try { " : "";
|
||||
const errorCatch = type === "url" ? " } catch { return false; }" : "";
|
||||
|
||||
return `.refine((value: string) => { ${errorHandling}${domainExtraction} const domainsArray = [${domainsList}]; return domain && ${negation}domainsArray.includes(domain);${errorCatch} }, { message: "Invalid ${type}, domain ${messageType}" })`;
|
||||
};
|
||||
|
||||
return {
|
||||
collectionNames: `[\n\t${collections.map(({ name }) => `"${name}"`).join(",\n\t")},\n]`,
|
||||
enums: getCollectionSelectFields().map(stringifyEnum).join("\n\n"),
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { default as Pocketbase, SendOptions } from "pocketbase";
|
||||
import { fullListOptionsFrom, optionsFrom } from "./options.js";
|
||||
import type { AnyZodRecord, RecordFullListOpts, RecordIdRef, RecordRef, RecordSlugRef } from "./types.ts";
|
||||
import { AnyRecordsList, type RecordsList } from "./schemas.ts";
|
||||
import { fullListOptionsFrom, optionsFrom } from "@/options.ts";
|
||||
import type { AnyZodRecord, RecordFullListOpts, RecordIdRef, RecordRef, RecordSlugRef } from "@/types.ts";
|
||||
import { AnyRecordsList } from "@/schemas.ts";
|
||||
import type { RecordsList } from "@/schemas.ts";
|
||||
|
||||
export function helpersFrom({ fetch, pocketbase }: HelpersFromOpts) {
|
||||
async function getRecord<C extends string, S extends AnyZodRecord>(ref: RecordSlugRef<C>, opts: GetRecordOpts<S>): Promise<S["_output"]>;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { z, type AnyZodObject, type ZodTypeAny } from "zod";
|
||||
import type { AnyZodRecord, RecordFullListOpts, RecordListOpts } from "./types.ts";
|
||||
import { z } from "zod";
|
||||
import type { AnyZodObject, ZodTypeAny } from "zod";
|
||||
import type { AnyZodRecord, RecordFullListOpts, RecordListOpts } from "@/types.ts";
|
||||
|
||||
/**
|
||||
* Extends the given schema with the given expansion.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { type AnyZodObject, type objectUtil, z, type ZodEffects, type ZodObject, ZodOptional, type ZodRawShape } from "zod";
|
||||
import type { AnyZodRecord, HasRequiredKeys, ZodRecordKeys } from "./types.ts";
|
||||
import { z, ZodOptional, ZodEffects } from "zod";
|
||||
import type { AnyZodObject, objectUtil, ZodObject, ZodRawShape } from "zod";
|
||||
import type { AnyZodRecord, HasRequiredKeys, ZodRecordKeys } from "@/types.ts";
|
||||
|
||||
/**
|
||||
* Records list schema.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Pocketbase from "pocketbase";
|
||||
import type { Credentials } from "./config.ts";
|
||||
import type { Credentials } from "@/config.ts";
|
||||
|
||||
let adminPocketbase: Pocketbase;
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
import { Config, type ResolvedConfig } from "../config.ts";
|
||||
import { Config } from "@/config.ts";
|
||||
import type { ResolvedConfig } from "@/config.ts";
|
||||
import pkg from "../../package.json" with { type: "json" };
|
||||
import { loadConfig } from "c12";
|
||||
import { defineCommand, runMain } from "citty";
|
||||
import { cancel, group, intro, log, outro, confirm, text, spinner, multiselect, isCancel } from "@clack/prompts";
|
||||
import { fetchCollections } from "../utils.ts";
|
||||
import { generate } from "./utils.ts";
|
||||
import { fetchCollections } from "@/utils.ts";
|
||||
import { generate } from "@/server/utils.ts";
|
||||
import { existsSync } from "node:fs";
|
||||
|
||||
async function getConfig() {
|
||||
const { config } = await loadConfig({ name: "zod-pocketbase", rcFile: false, dotenv: true });
|
||||
const { config } = await loadConfig({ name: "zod-pocketbase-continue", rcFile: false, dotenv: true });
|
||||
const { ZOD_POCKETBASE_ADMIN_EMAIL: adminEmail, ZOD_POCKETBASE_ADMIN_PASSWORD: adminPassword, ZOD_POCKETBASE_URL: url } = process.env;
|
||||
const result = Config.safeParse({ ...config, adminEmail, adminPassword, url });
|
||||
if (!result.success) {
|
||||
@@ -72,7 +73,7 @@ async function setGeneratedFilePath(config: ResolvedConfig) {
|
||||
}
|
||||
|
||||
const main = defineCommand({
|
||||
meta: { name: "zod-pocketbase", version: pkg.version, description: "Generate Zod schemas for your pocketbase instance." },
|
||||
meta: { name: "zod-pocketbase-continue", version: pkg.version, description: "Generate Zod schemas for your pocketbase instance." },
|
||||
run: async () => {
|
||||
intro(`ZOD POCKETBASE`);
|
||||
const config = await getConfig();
|
||||
|
||||
@@ -2,8 +2,8 @@ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import type { CollectionModel } from "pocketbase";
|
||||
import { stringifyContent } from "../content.js";
|
||||
import type { ResolvedConfig } from "../config.ts";
|
||||
import { stringifyContent } from "@/content.js";
|
||||
import type { ResolvedConfig } from "@/config.ts";
|
||||
|
||||
export async function generate(collections: CollectionModel[], opts: GenerateOpts) {
|
||||
const stub = readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../../assets/stubs/index.ts"), "utf-8");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { sortBy } from "es-toolkit";
|
||||
import type { CollectionModel } from "pocketbase";
|
||||
import { getPocketbase } from "./sdk.js";
|
||||
import type { Credentials } from "./config.ts";
|
||||
import { getPocketbase } from "@/sdk.js";
|
||||
import type { Credentials } from "@/config.ts";
|
||||
|
||||
export async function fetchCollections(credentials: Credentials): Promise<CollectionModel[]> {
|
||||
const pocketbase = await getPocketbase(credentials);
|
||||
|
||||
@@ -46,7 +46,11 @@
|
||||
// Report an error for unreachable code instead of just a warning.
|
||||
"allowUnreachableCode": false,
|
||||
// Report an error for unused labels instead of just a warning.
|
||||
"allowUnusedLabels": false
|
||||
"allowUnusedLabels": false,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["dist", "assets/stubs"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { defineConfig } from "tsup";
|
||||
import { defineConfig } from "tsdown";
|
||||
import packageJson from "./package.json" with { type: "json" };
|
||||
|
||||
export default defineConfig((options) => {
|
||||
@@ -7,7 +7,7 @@ export default defineConfig((options) => {
|
||||
entry: ["src/**/*.(ts|js)"],
|
||||
format: ["esm"],
|
||||
target: "node24",
|
||||
bundle: true,
|
||||
unbundle: true,
|
||||
dts: true,
|
||||
sourcemap: true,
|
||||
clean: true,
|
||||
Reference in New Issue
Block a user