founder-schema 0.1.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.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * founder-schema — API response envelope
3
+ *
4
+ * Every Founder Circle endpoint answers in this shape. The clients read the
5
+ * failure reason at `error.message`, so a handler must never return a bare
6
+ * string body.
7
+ *
8
+ * @module founder-schema/responses/common
9
+ */
10
+ import { z } from 'zod';
11
+ export const apiErrorSchema = z.object({
12
+ code: z.string(),
13
+ message: z.string(),
14
+ /** Field-level problems, keyed by the path the client rendered. */
15
+ details: z.record(z.string(), z.array(z.string())).optional(),
16
+ });
17
+ /** Success envelope. `T` is the payload schema. */
18
+ export const successResponseSchema = (data) => z.object({
19
+ success: z.literal(true),
20
+ data,
21
+ message: z.string().optional(),
22
+ });
23
+ export const errorResponseSchema = z.object({
24
+ success: z.literal(false),
25
+ error: apiErrorSchema,
26
+ });
27
+ /**
28
+ * Cursor-paginated list envelope.
29
+ *
30
+ * `nextCursor` is REQUIRED and is `null` at the end of the list. Omitting the
31
+ * key is not the same thing and does not validate: a handler must decide
32
+ * whether there is another page and say so, because "the key is missing" and
33
+ * "there are no more results" are indistinguishable to a client that has to
34
+ * choose between showing a Load more button and not showing one.
35
+ *
36
+ * An earlier version of this comment said absence and null were equivalent.
37
+ * They never were; the schema has always required the key. Corrected
38
+ * 2026-09-21, and pinned by a test.
39
+ */
40
+ export const paginatedSchema = (item) => z.object({
41
+ items: z.array(item),
42
+ nextCursor: z.string().nullable(),
43
+ });
44
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/responses/common.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,mEAAmE;IACnE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC9D,CAAC,CAAC;AAGH,mDAAmD;AACnD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAsB,IAAO,EAAE,EAAE,CACpE,CAAC,CAAC,MAAM,CAAC;IACP,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IACxB,IAAI;IACJ,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IACzB,KAAK,EAAE,cAAc;CACtB,CAAC,CAAC;AAGH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAsB,IAAO,EAAE,EAAE,CAC9D,CAAC,CAAC,MAAM,CAAC;IACP,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IACpB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC","sourcesContent":["/**\n * founder-schema — API response envelope\n *\n * Every Founder Circle endpoint answers in this shape. The clients read the\n * failure reason at `error.message`, so a handler must never return a bare\n * string body.\n *\n * @module founder-schema/responses/common\n */\n\nimport { z } from 'zod';\n\nexport const apiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n /** Field-level problems, keyed by the path the client rendered. */\n details: z.record(z.string(), z.array(z.string())).optional(),\n});\nexport type ApiError = z.infer<typeof apiErrorSchema>;\n\n/** Success envelope. `T` is the payload schema. */\nexport const successResponseSchema = <T extends z.ZodType>(data: T) =>\n z.object({\n success: z.literal(true),\n data,\n message: z.string().optional(),\n });\n\nexport const errorResponseSchema = z.object({\n success: z.literal(false),\n error: apiErrorSchema,\n});\nexport type ErrorResponse = z.infer<typeof errorResponseSchema>;\n\n/**\n * Cursor-paginated list envelope.\n *\n * `nextCursor` is REQUIRED and is `null` at the end of the list. Omitting the\n * key is not the same thing and does not validate: a handler must decide\n * whether there is another page and say so, because \"the key is missing\" and\n * \"there are no more results\" are indistinguishable to a client that has to\n * choose between showing a Load more button and not showing one.\n *\n * An earlier version of this comment said absence and null were equivalent.\n * They never were; the schema has always required the key. Corrected\n * 2026-09-21, and pinned by a test.\n */\nexport const paginatedSchema = <T extends z.ZodType>(item: T) =>\n z.object({\n items: z.array(item),\n nextCursor: z.string().nullable(),\n });\n"]}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * founder-schema — response barrel
3
+ *
4
+ * @module founder-schema/responses
5
+ */
6
+ export { type ApiError, apiErrorSchema, type ErrorResponse, errorResponseSchema, paginatedSchema, successResponseSchema, } from './common.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/responses/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,QAAQ,EACb,cAAc,EACd,KAAK,aAAa,EAClB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * founder-schema — response barrel
3
+ *
4
+ * @module founder-schema/responses
5
+ */
6
+ export { apiErrorSchema, errorResponseSchema, paginatedSchema, successResponseSchema, } from './common.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/responses/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAEL,cAAc,EAEd,mBAAmB,EACnB,eAAe,EACf,qBAAqB,GACtB,MAAM,aAAa,CAAC","sourcesContent":["/**\n * founder-schema — response barrel\n *\n * @module founder-schema/responses\n */\n\nexport {\n type ApiError,\n apiErrorSchema,\n type ErrorResponse,\n errorResponseSchema,\n paginatedSchema,\n successResponseSchema,\n} from './common.js';\n"]}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "founder-schema",
3
+ "version": "0.1.0",
4
+ "description": "Shared Zod schemas for Founder Circle — single source of truth for API contracts, validation, and TypeScript types (backend + web client + app client).",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "sideEffects": false,
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json",
23
+ "type-check": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "lint": "biome lint .",
27
+ "format": "biome format --write .",
28
+ "check": "npm run type-check && biome check --write .",
29
+ "check:staged": "biome check --staged --write --no-errors-on-unmatched",
30
+ "prepublishOnly": "npm run build && npm run check"
31
+ },
32
+ "keywords": [
33
+ "zod",
34
+ "schema",
35
+ "founders",
36
+ "networking",
37
+ "typescript"
38
+ ],
39
+ "author": "Hari",
40
+ "license": "MIT",
41
+ "peerDependencies": {
42
+ "zod": "^4.4.0"
43
+ },
44
+ "devDependencies": {
45
+ "@biomejs/biome": "^2.4.2",
46
+ "@types/node": "^24.10.1",
47
+ "typescript": "^5.9.3",
48
+ "vitest": "^4.1.11",
49
+ "zod": "^4.4.3"
50
+ }
51
+ }