common-typescript-utils 1.0.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ ## [1.0.1](https://github.com/mini-app-polis/common-typescript-utils/compare/v1.0.0...v1.0.1) (2026-04-05)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * correct doppler project, upgrade secrets-fetch-action to v2 ([02de9d4](https://github.com/mini-app-polis/common-typescript-utils/commit/02de9d40ff1ae3251b076cb2fef3d80d139a8e45))
7
+
8
+ # 1.0.0 (2026-04-05)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * build requirements ([f7d748c](https://github.com/mini-app-polis/common-typescript-utils/commit/f7d748c0d815df474f04420f862a8162feb7c907))
14
+ * ci ([f1a05f3](https://github.com/mini-app-polis/common-typescript-utils/commit/f1a05f379c2dbcc2ec621b63ca03fe0a1a6e6bb7))
15
+
16
+
17
+ ### Features
18
+
19
+ * Initial commit ([d460636](https://github.com/mini-app-polis/common-typescript-utils/commit/d46063636d7e127d8be1a129cc746b788ec23dcf))
20
+
21
+ # Changelog
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # common-typescript-utils
2
+
3
+ Shared TypeScript utilities for the MiniAppPolis ecosystem. The TypeScript counterpart to [`common-python-utils`](https://github.com/mini-app-polis/common-python-utils).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install common-typescript-utils
9
+ ```
10
+
11
+ ## Modules
12
+
13
+ ### `createLogger(service)`
14
+
15
+ Structured logger with dev/prod modes. In production emits JSON to stdout/stderr; in development emits emoji-prefixed human-readable lines.
16
+
17
+ ```typescript
18
+ import { createLogger } from "common-typescript-utils";
19
+
20
+ const logger = createLogger("my-service");
21
+
22
+ logger.info({ event: "server_started", category: "infra", context: { port: 3000 } });
23
+ logger.error({ event: "db_failure", category: "data", error: new Error("timeout") });
24
+ logger.start("initializing"); // 🚀 in dev, INFO JSON in prod
25
+ logger.success("ready"); // ✅ in dev, INFO JSON in prod
26
+ logger.failure("crashed"); // ❌ in dev, ERROR JSON in prod
27
+ ```
28
+
29
+ Log categories: `"infra" | "pipeline" | "data" | "api"`
30
+
31
+ ### `verifyClerkToken(token, jwksUrl)`
32
+
33
+ Raw JWKS + RS256 JWT verification using the Web Crypto API. Runtime-agnostic — works in Node 18+, Cloudflare Workers, and Deno without any polyfills.
34
+
35
+ ```typescript
36
+ import { verifyClerkToken } from "common-typescript-utils";
37
+
38
+ const payload = await verifyClerkToken(token, "https://your-clerk-instance.clerk.accounts.dev/.well-known/jwks.json");
39
+ // payload.sub — owner_id
40
+ // payload.email — resolved from email or email_addresses
41
+ ```
42
+
43
+ JWKS responses and imported keys are cached in-memory with a 1-hour TTL.
44
+
45
+ ### `success` / `successList` / `error` / `CommonErrors`
46
+
47
+ Standard API response envelopes.
48
+
49
+ ```typescript
50
+ import { success, successList, CommonErrors } from "common-typescript-utils";
51
+
52
+ return c.json(success({ id: 1, name: "foo" }));
53
+ // { data: { id: 1, name: "foo" }, meta: { version: "v1" } }
54
+
55
+ return c.json(successList(items), 200);
56
+ // { data: [...], meta: { version: "v1", count: 3 } }
57
+
58
+ return c.json(CommonErrors.notFound("User"), 404);
59
+ // { error: { code: "NOT_FOUND", message: "User not found" } }
60
+ ```
61
+
62
+ Available helpers: `unauthorized()`, `forbidden()`, `notFound(resource?)`, `badRequest(message)`, `internalError(message?)`, `validationError(zodIssues)`.
63
+
64
+ ### Schemas
65
+
66
+ Generic Zod schemas for common API patterns.
67
+
68
+ ```typescript
69
+ import { PaginationSchema, IdParamSchema, UserRoleSchema } from "common-typescript-utils";
70
+
71
+ const { page, limit } = PaginationSchema.parse(req.query);
72
+ const { id } = IdParamSchema.parse(req.params);
73
+ const role = UserRoleSchema.parse(req.body.role); // "user" | "admin"
74
+ ```
75
+
76
+ > **Note:** Domain-specific schemas (WCS divisions, session/checkin status, etc.) live in the repos that own those domains.
77
+
78
+ ## Development
79
+
80
+ ```bash
81
+ npm install
82
+ npm run typecheck
83
+ npm test
84
+ npm run build
85
+ ```
86
+
87
+ ## Release
88
+
89
+ Releases are automated via semantic-release on push to `main`. Requires `NPM_TOKEN` and `GITHUB_TOKEN` secrets.
90
+
91
+ ```
92
+ feat: → minor bump
93
+ fix: → patch bump
94
+ feat!: → major bump
95
+ ```
package/dist/auth.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export type ClerkPayload = {
2
+ sub: string;
3
+ email?: string;
4
+ } & Record<string, unknown>;
5
+ export declare function verifyClerkToken(token: string, jwksUrl: string): Promise<ClerkPayload>;
6
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAyD5B,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAkC5F"}
package/dist/auth.js ADDED
@@ -0,0 +1,77 @@
1
+ const CACHE_TTL_MS = 60 * 60 * 1000;
2
+ let cache = null;
3
+ const keyCache = new Map();
4
+ function base64UrlDecode(str) {
5
+ const padded = str
6
+ .replace(/-/g, "+")
7
+ .replace(/_/g, "/")
8
+ .padEnd(str.length + ((4 - (str.length % 4)) % 4), "=");
9
+ return Uint8Array.from(atob(padded), (c) => c.charCodeAt(0));
10
+ }
11
+ function decodePayload(token) {
12
+ const parts = token.split(".");
13
+ if (parts.length !== 3)
14
+ throw new Error("Malformed token");
15
+ const json = new TextDecoder().decode(base64UrlDecode(parts[1]));
16
+ return JSON.parse(json);
17
+ }
18
+ async function fetchJwks(jwksUrl) {
19
+ const now = Date.now();
20
+ if (cache && now < cache.expiry)
21
+ return cache.jwks;
22
+ const res = await fetch(jwksUrl);
23
+ if (!res.ok)
24
+ throw new Error(`JWKS fetch failed: ${res.status}`);
25
+ const jwks = (await res.json());
26
+ if (!jwks.keys?.length)
27
+ throw new Error("No keys in JWKS");
28
+ cache = { jwks, expiry: now + CACHE_TTL_MS };
29
+ return jwks;
30
+ }
31
+ async function importKeyForKid(jwksUrl, kid) {
32
+ const now = Date.now();
33
+ const cached = keyCache.get(kid);
34
+ if (cached && now < cached.expiry)
35
+ return cached.key;
36
+ const jwks = await fetchJwks(jwksUrl);
37
+ const jwk = jwks.keys.find((k) => k.kid === kid);
38
+ if (!jwk)
39
+ throw new Error(`No JWK for kid ${kid}`);
40
+ const key = await crypto.subtle.importKey("jwk", jwk, { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" }, false, ["verify"]);
41
+ keyCache.set(kid, { key, expiry: now + CACHE_TTL_MS });
42
+ return key;
43
+ }
44
+ export async function verifyClerkToken(token, jwksUrl) {
45
+ const parts = token.split(".");
46
+ if (parts.length !== 3)
47
+ throw new Error("Malformed token");
48
+ const headerJson = new TextDecoder().decode(base64UrlDecode(parts[0]));
49
+ const header = JSON.parse(headerJson);
50
+ if (!header.kid)
51
+ throw new Error("Token missing kid");
52
+ const key = await importKeyForKid(jwksUrl, header.kid);
53
+ const signingInput = new TextEncoder().encode(`${parts[0]}.${parts[1]}`);
54
+ const signature = base64UrlDecode(parts[2]);
55
+ const sigBuf = new Uint8Array(signature.byteLength);
56
+ sigBuf.set(signature);
57
+ const valid = await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key, sigBuf, signingInput);
58
+ if (!valid)
59
+ throw new Error("Invalid signature");
60
+ const payload = decodePayload(token);
61
+ const exp = payload.exp;
62
+ if (typeof exp === "number" && Date.now() / 1000 >= exp) {
63
+ throw new Error("Token expired");
64
+ }
65
+ const sub = payload.sub;
66
+ if (typeof sub !== "string" || !sub)
67
+ throw new Error("Invalid subject");
68
+ const email = typeof payload.email === "string"
69
+ ? payload.email
70
+ : typeof payload.email_addresses?.[0]
71
+ ?.email_address === "string"
72
+ ? payload.email_addresses[0]
73
+ .email_address
74
+ : undefined;
75
+ return { ...payload, sub, email };
76
+ }
77
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export * from "./logger.js";
2
+ export * from "./response.js";
3
+ export * from "./auth.js";
4
+ export * from "./schemas.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./logger.js";
2
+ export * from "./response.js";
3
+ export * from "./auth.js";
4
+ export * from "./schemas.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,20 @@
1
+ export type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR";
2
+ export type LogCategory = "infra" | "pipeline" | "data" | "api";
3
+ export interface LogParams {
4
+ event: string;
5
+ category: LogCategory;
6
+ context?: Record<string, unknown>;
7
+ }
8
+ export interface Logger {
9
+ debug: (params: LogParams) => void;
10
+ info: (params: LogParams) => void;
11
+ warn: (params: LogParams) => void;
12
+ error: (params: LogParams & {
13
+ error?: unknown;
14
+ }) => void;
15
+ start: (event: string, context?: Record<string, unknown>) => void;
16
+ success: (event: string, context?: Record<string, unknown>) => void;
17
+ failure: (event: string, context?: Record<string, unknown>) => void;
18
+ }
19
+ export declare function createLogger(service: string): Logger;
20
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAC3D,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,KAAK,CAAC;AAEhE,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,WAAW,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;IACnC,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;IAClC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,GAAG;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;IACzD,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAClE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACpE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACrE;AA0CD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA6FpD"}
package/dist/logger.js ADDED
@@ -0,0 +1,117 @@
1
+ function isProd() {
2
+ return process.env.NODE_ENV === "production";
3
+ }
4
+ function isoTimestamp() {
5
+ return new Date().toISOString();
6
+ }
7
+ function mergeErrorContext(context, error) {
8
+ const out = context ? { ...context } : {};
9
+ if (error instanceof Error) {
10
+ out.error_message = error.message;
11
+ out.error_stack = error.stack;
12
+ }
13
+ else if (error !== undefined) {
14
+ out.error = error;
15
+ }
16
+ return Object.keys(out).length > 0 ? out : undefined;
17
+ }
18
+ function emojiForLevel(level) {
19
+ switch (level) {
20
+ case "DEBUG":
21
+ return "🔍";
22
+ case "INFO":
23
+ return "📋";
24
+ case "WARN":
25
+ return "⚠️";
26
+ case "ERROR":
27
+ return "❌";
28
+ default: {
29
+ const _exhaustive = level;
30
+ return _exhaustive;
31
+ }
32
+ }
33
+ }
34
+ function writeLine(level, line) {
35
+ if (level === "ERROR")
36
+ console.error(line);
37
+ else
38
+ console.log(line);
39
+ }
40
+ export function createLogger(service) {
41
+ function emitProd(level, category, event, context) {
42
+ const payload = {
43
+ timestamp: isoTimestamp(),
44
+ service,
45
+ level,
46
+ category,
47
+ event,
48
+ };
49
+ if (context && Object.keys(context).length > 0) {
50
+ payload.context = context;
51
+ }
52
+ const line = JSON.stringify(payload);
53
+ writeLine(level, line);
54
+ }
55
+ function emitDev(level, category, event, context) {
56
+ const ctx = context && Object.keys(context).length > 0
57
+ ? ` ${JSON.stringify(context)}`
58
+ : "";
59
+ const line = `${emojiForLevel(level)} [${level}] [${category}] ${event}${ctx}`;
60
+ writeLine(level, line);
61
+ }
62
+ function emit(level, category, event, context) {
63
+ if (isProd())
64
+ emitProd(level, category, event, context);
65
+ else
66
+ emitDev(level, category, event, context);
67
+ }
68
+ return {
69
+ debug(params) {
70
+ emit("DEBUG", params.category, params.event, params.context);
71
+ },
72
+ info(params) {
73
+ emit("INFO", params.category, params.event, params.context);
74
+ },
75
+ warn(params) {
76
+ emit("WARN", params.category, params.event, params.context);
77
+ },
78
+ error(params) {
79
+ const ctx = mergeErrorContext(params.context, params.error);
80
+ emit("ERROR", params.category, params.event, ctx);
81
+ },
82
+ start(event, context) {
83
+ if (isProd()) {
84
+ emitProd("INFO", "infra", event, context);
85
+ }
86
+ else {
87
+ const ctx = context && Object.keys(context).length > 0
88
+ ? ` ${JSON.stringify(context)}`
89
+ : "";
90
+ console.log(`🚀 ${event}${ctx}`);
91
+ }
92
+ },
93
+ success(event, context) {
94
+ if (isProd()) {
95
+ emitProd("INFO", "infra", event, context);
96
+ }
97
+ else {
98
+ const ctx = context && Object.keys(context).length > 0
99
+ ? ` ${JSON.stringify(context)}`
100
+ : "";
101
+ console.log(`✅ ${event}${ctx}`);
102
+ }
103
+ },
104
+ failure(event, context) {
105
+ if (isProd()) {
106
+ emitProd("ERROR", "infra", event, context);
107
+ }
108
+ else {
109
+ const ctx = context && Object.keys(context).length > 0
110
+ ? ` ${JSON.stringify(context)}`
111
+ : "";
112
+ console.error(`❌ ${event}${ctx}`);
113
+ }
114
+ },
115
+ };
116
+ }
117
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { ZodIssue } from "zod";
2
+ declare const VERSION: "v1";
3
+ export type SuccessEnvelope<T> = {
4
+ data: T;
5
+ meta: {
6
+ version: typeof VERSION;
7
+ count?: number;
8
+ } & Record<string, unknown>;
9
+ };
10
+ export type ErrorEnvelope = {
11
+ error: {
12
+ code: string;
13
+ message: string;
14
+ };
15
+ };
16
+ export declare function success<T>(data: T, meta?: Record<string, unknown>): SuccessEnvelope<T>;
17
+ export declare function successList<T>(data: T[], meta?: Record<string, unknown>): SuccessEnvelope<T[]>;
18
+ export declare function error(code: string, message: string): ErrorEnvelope;
19
+ export declare const CommonErrors: {
20
+ unauthorized(): ErrorEnvelope;
21
+ forbidden(): ErrorEnvelope;
22
+ notFound(resource?: string): ErrorEnvelope;
23
+ badRequest(message: string): ErrorEnvelope;
24
+ internalError(message?: string): ErrorEnvelope;
25
+ validationError(issues: ZodIssue[]): ErrorEnvelope;
26
+ };
27
+ export {};
28
+ //# sourceMappingURL=response.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../src/response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAEpC,QAAA,MAAM,OAAO,EAAG,IAAa,CAAC;AAE9B,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;IAC/B,IAAI,EAAE,CAAC,CAAC;IACR,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7E,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C,CAAC;AAEF,wBAAgB,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAKtF;AAED,wBAAgB,WAAW,CAAC,CAAC,EAC3B,IAAI,EAAE,CAAC,EAAE,EACT,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,eAAe,CAAC,CAAC,EAAE,CAAC,CAKtB;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAElE;AAED,eAAO,MAAM,YAAY;oBACP,aAAa;iBAGhB,aAAa;wBAGN,MAAM,GAAG,aAAa;wBAGtB,MAAM,GAAG,aAAa;qCAGQ,aAAa;4BAGvC,QAAQ,EAAE,GAAG,aAAa;CAInD,CAAC"}
@@ -0,0 +1,38 @@
1
+ const VERSION = "v1";
2
+ export function success(data, meta) {
3
+ return {
4
+ data,
5
+ meta: { version: VERSION, ...meta },
6
+ };
7
+ }
8
+ export function successList(data, meta) {
9
+ return {
10
+ data,
11
+ meta: { version: VERSION, count: data.length, ...meta },
12
+ };
13
+ }
14
+ export function error(code, message) {
15
+ return { error: { code, message } };
16
+ }
17
+ export const CommonErrors = {
18
+ unauthorized() {
19
+ return error("UNAUTHORIZED", "Authentication required");
20
+ },
21
+ forbidden() {
22
+ return error("FORBIDDEN", "Admin access required");
23
+ },
24
+ notFound(resource) {
25
+ return error("NOT_FOUND", resource ? `${resource} not found` : "Not found");
26
+ },
27
+ badRequest(message) {
28
+ return error("BAD_REQUEST", message);
29
+ },
30
+ internalError(message = "Internal server error") {
31
+ return error("INTERNAL", message);
32
+ },
33
+ validationError(issues) {
34
+ const message = issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
35
+ return error("VALIDATION_ERROR", message || "Validation failed");
36
+ },
37
+ };
38
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../src/response.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,GAAG,IAAa,CAAC;AAW9B,MAAM,UAAU,OAAO,CAAI,IAAO,EAAE,IAA8B;IAChE,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE;KACpC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,IAAS,EACT,IAA8B;IAE9B,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,EAAE;KACxD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAY,EAAE,OAAe;IACjD,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,YAAY;QACV,OAAO,KAAK,CAAC,cAAc,EAAE,yBAAyB,CAAC,CAAC;IAC1D,CAAC;IACD,SAAS;QACP,OAAO,KAAK,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC;IACrD,CAAC;IACD,QAAQ,CAAC,QAAiB;QACxB,OAAO,KAAK,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC9E,CAAC;IACD,UAAU,CAAC,OAAe;QACxB,OAAO,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IACD,aAAa,CAAC,OAAO,GAAG,uBAAuB;QAC7C,OAAO,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IACD,eAAe,CAAC,MAAkB;QAChC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClF,OAAO,KAAK,CAAC,kBAAkB,EAAE,OAAO,IAAI,mBAAmB,CAAC,CAAC;IACnE,CAAC;CACF,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ export declare const UserRoleSchema: z.ZodEnum<["user", "admin"]>;
3
+ export type UserRole = z.infer<typeof UserRoleSchema>;
4
+ export declare const PaginationSchema: z.ZodObject<{
5
+ page: z.ZodDefault<z.ZodNumber>;
6
+ limit: z.ZodDefault<z.ZodNumber>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ page: number;
9
+ limit: number;
10
+ }, {
11
+ page?: number | undefined;
12
+ limit?: number | undefined;
13
+ }>;
14
+ export type Pagination = z.infer<typeof PaginationSchema>;
15
+ export declare const IdParamSchema: z.ZodObject<{
16
+ id: z.ZodString;
17
+ }, "strip", z.ZodTypeAny, {
18
+ id: string;
19
+ }, {
20
+ id: string;
21
+ }>;
22
+ export type IdParam = z.infer<typeof IdParamSchema>;
23
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc,8BAA4B,CAAC;AACxD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,gBAAgB;;;;;;;;;EAG3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,aAAa;;;;;;EAExB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { z } from "zod";
2
+ export const UserRoleSchema = z.enum(["user", "admin"]);
3
+ export const PaginationSchema = z.object({
4
+ page: z.coerce.number().int().min(1).default(1),
5
+ limit: z.coerce.number().int().min(1).max(100).default(20),
6
+ });
7
+ export const IdParamSchema = z.object({
8
+ id: z.string().min(1),
9
+ });
10
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAGxD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAC3D,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACtB,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "common-typescript-utils",
3
+ "version": "1.0.1",
4
+ "packageManager": "pnpm@9.0.0",
5
+ "description": "Shared TypeScript utilities for the MiniAppPolis ecosystem.",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "CHANGELOG.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.build.json",
21
+ "typecheck": "tsc --noEmit -p tsconfig.json",
22
+ "lint": "eslint src",
23
+ "test": "vitest run",
24
+ "test:coverage": "vitest run --coverage"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/mini-app-polis/common-typescript-utils.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/mini-app-polis/common-typescript-utils/issues"
32
+ },
33
+ "homepage": "https://github.com/mini-app-polis/common-typescript-utils#readme",
34
+ "keywords": [
35
+ "typescript",
36
+ "utils",
37
+ "miniapppolis"
38
+ ],
39
+ "author": "Kaiano Levine",
40
+ "license": "ISC",
41
+ "dependencies": {
42
+ "zod": "^3.24.1"
43
+ },
44
+ "devDependencies": {
45
+ "@eslint/js": "^9.16.0",
46
+ "@semantic-release/changelog": "^6.0.3",
47
+ "@semantic-release/commit-analyzer": "^13.0.1",
48
+ "@semantic-release/git": "^10.0.1",
49
+ "@semantic-release/github": "^12.0.6",
50
+ "@semantic-release/npm": "^13.1.5",
51
+ "@semantic-release/release-notes-generator": "^14.1.0",
52
+ "@types/node": "^22.10.2",
53
+ "@vitest/coverage-v8": "^2.1.8",
54
+ "eslint": "^9.16.0",
55
+ "semantic-release": "^24.2.9",
56
+ "typescript": "^5.7.2",
57
+ "typescript-eslint": "^8.18.0",
58
+ "vitest": "^2.1.8"
59
+ }
60
+ }