nuxt-api-contract 0.1.0 → 0.2.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.
Files changed (34) hide show
  1. package/README.md +32 -7
  2. package/dist/chunks/server.mjs +162 -0
  3. package/dist/cli.mjs +33 -1
  4. package/dist/client.d.mts +5 -69
  5. package/dist/client.d.ts +5 -69
  6. package/dist/client.mjs +3 -1
  7. package/dist/composables.mjs +2 -1
  8. package/dist/mock.d.mts +54 -0
  9. package/dist/mock.d.ts +54 -0
  10. package/dist/mock.mjs +8 -0
  11. package/dist/module.d.mts +8 -2
  12. package/dist/module.d.ts +8 -2
  13. package/dist/module.mjs +4 -2
  14. package/dist/runtime/shared/mock.mjs +188 -0
  15. package/dist/server.d.mts +7 -4
  16. package/dist/server.d.ts +7 -4
  17. package/dist/server.mjs +6 -3
  18. package/dist/shared/nuxt-api-contract.BOxyDvRy.d.mts +40 -0
  19. package/dist/shared/{nuxt-api-contract.S1zqCiJX.d.ts → nuxt-api-contract.B_UvrNC8.d.ts} +1 -1
  20. package/dist/shared/nuxt-api-contract.Bd2Y7Lx0.mjs +191 -0
  21. package/dist/shared/nuxt-api-contract.BgPd-YXc.d.mts +53 -0
  22. package/dist/shared/nuxt-api-contract.BuWjAHJe.d.ts +40 -0
  23. package/dist/shared/nuxt-api-contract.C7KxMQHa.d.ts +53 -0
  24. package/dist/shared/{nuxt-api-contract.CPm9WbWA.d.mts → nuxt-api-contract.CFG8gzJH.d.mts} +2 -2
  25. package/dist/shared/{nuxt-api-contract.CPm9WbWA.d.ts → nuxt-api-contract.CFG8gzJH.d.ts} +2 -2
  26. package/dist/shared/nuxt-api-contract.DZfOzVaB.d.mts +16 -0
  27. package/dist/shared/nuxt-api-contract.DZfOzVaB.d.ts +16 -0
  28. package/dist/shared/nuxt-api-contract.Dr4tPqGB.mjs +38 -0
  29. package/dist/shared/{nuxt-api-contract.QDGSGaVY.mjs → nuxt-api-contract.V15soI_f.mjs} +1 -38
  30. package/dist/shared/{nuxt-api-contract.B9JBCRk8.d.mts → nuxt-api-contract.VCevNWQV.d.mts} +1 -1
  31. package/dist/shared.d.mts +4 -2
  32. package/dist/shared.d.ts +4 -2
  33. package/dist/shared.mjs +3 -1
  34. package/package.json +5 -1
@@ -0,0 +1,188 @@
1
+ import { mockContract } from "./contract.mjs";
2
+ function zodDef(schema) {
3
+ return schema._def;
4
+ }
5
+ export function createRng(seed) {
6
+ let state = seed >>> 0;
7
+ return function() {
8
+ state = state + 1831565813 | 0;
9
+ let t = state;
10
+ t = Math.imul(t ^ t >>> 15, t | 1);
11
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
12
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
13
+ };
14
+ }
15
+ function strHash(value) {
16
+ let hash = 2166136261;
17
+ for (let i = 0; i < value.length; i++) {
18
+ hash ^= value.charCodeAt(i);
19
+ hash = Math.imul(hash, 16777619);
20
+ }
21
+ return hash >>> 0;
22
+ }
23
+ function pick(items, rng) {
24
+ return items[Math.floor(rng() * items.length) % items.length];
25
+ }
26
+ function intBetween(rng, min, max) {
27
+ return Math.floor(min + rng() * (max - min + 1));
28
+ }
29
+ const FIRST_NAMES = ["John", "Jane", "Alex", "Maria", "Ivan", "Elena"];
30
+ const LAST_NAMES = ["Doe", "Smith", "Brown", "Ivanov", "Miller"];
31
+ const WORDS = ["mock", "demo", "sample", "alpha", "beta", "gamma"];
32
+ const MOCK_EPOCH = Date.UTC(2024, 0, 1);
33
+ const YEAR_MS = 365 * 24 * 3600 * 1e3;
34
+ function mockUuid(rng) {
35
+ const hex = () => Math.floor(rng() * 65535).toString(16).padStart(4, "0");
36
+ return `${hex()}${hex()}-4${hex().slice(1)}-8${hex().slice(1)}-4${hex().slice(1)}-${hex()}${hex()}${hex()}`;
37
+ }
38
+ function mockString(key, def, ctx) {
39
+ const lower = key.toLowerCase();
40
+ const checks = def.checks ?? [];
41
+ const check = (kind) => checks.find((c) => c.kind === kind)?.value;
42
+ const format = checks.find((c) => c.kind === "format")?.value;
43
+ const hasCheck = (kind) => checks.some((c) => c.kind === kind);
44
+ let value;
45
+ if (format === "email" || hasCheck("email") || lower.includes("email")) {
46
+ const name = pick(FIRST_NAMES, ctx.rng).toLowerCase();
47
+ value = `${name}.${pick(LAST_NAMES, ctx.rng).toLowerCase()}@example.com`;
48
+ } else if (hasCheck("uuid")) {
49
+ value = mockUuid(ctx.rng);
50
+ } else if (hasCheck("datetime") || lower === "createdat" || lower === "updatedat" || lower.endsWith("date") || lower.endsWith("_at")) {
51
+ value = new Date(MOCK_EPOCH - Math.floor(ctx.rng() * YEAR_MS)).toISOString();
52
+ } else if (hasCheck("url") || lower.endsWith("url") || lower.endsWith("link")) {
53
+ value = `https://example.com/${pick(WORDS, ctx.rng)}/${intBetween(ctx.rng, 1, 999)}`;
54
+ } else if (lower.includes("phone") || lower.includes("tel")) {
55
+ value = `+1 555 010 ${intBetween(ctx.rng, 1e3, 9999)}`;
56
+ } else if (lower === "id" || lower.endsWith("_id") || lower.endsWith("id")) {
57
+ value = `id-${intBetween(ctx.rng, 1, 99999)}`;
58
+ } else if (lower.includes("slug")) {
59
+ value = `${pick(WORDS, ctx.rng)}-${intBetween(ctx.rng, 1, 999)}`;
60
+ } else if (lower === "name" || lower.endsWith("name")) {
61
+ value = `${pick(FIRST_NAMES, ctx.rng)} ${pick(LAST_NAMES, ctx.rng)}`;
62
+ } else if (lower === "title") {
63
+ value = `${pick(WORDS, ctx.rng)} title`;
64
+ } else if (lower.includes("password") || lower.includes("token") || lower.includes("secret")) {
65
+ value = "********";
66
+ } else if (lower.includes("description") || lower === "bio" || lower === "text") {
67
+ value = `Mock ${pick(WORDS, ctx.rng)} description for automated testing.`;
68
+ } else {
69
+ value = `${pick(WORDS, ctx.rng)}-${intBetween(ctx.rng, 1, 9999)}`;
70
+ }
71
+ const minLength = check("min");
72
+ if (minLength !== void 0) {
73
+ while (value.length < minLength) value += "-filler";
74
+ }
75
+ const maxLength = check("max");
76
+ if (maxLength !== void 0 && value.length > maxLength) {
77
+ value = value.slice(0, maxLength);
78
+ }
79
+ return value;
80
+ }
81
+ function mockNumber(def, ctx) {
82
+ const checks = def.checks ?? [];
83
+ const isInt = checks.some((c) => c.kind === "int");
84
+ const min = checks.find((c) => c.kind === "min")?.value ?? 1;
85
+ const max = checks.find((c) => c.kind === "max")?.value ?? 100;
86
+ const multipleOf = checks.find((c) => c.kind === "multipleOf")?.value;
87
+ if (multipleOf !== void 0 && multipleOf > 0) {
88
+ const minMul = Math.max(1, Math.ceil(min / multipleOf));
89
+ const maxMul = Math.max(minMul, Math.floor(max / multipleOf));
90
+ return intBetween(ctx.rng, minMul, maxMul) * multipleOf;
91
+ }
92
+ return isInt ? intBetween(ctx.rng, min, max) : Math.round((min + ctx.rng() * (max - min)) * 100) / 100;
93
+ }
94
+ function singular(key) {
95
+ return key.endsWith("s") && key.length > 1 ? key.slice(0, -1) : key;
96
+ }
97
+ export function generateMockValue(schema, key, ctx) {
98
+ if (ctx.depth > 6) return "mock";
99
+ const def = zodDef(schema);
100
+ const kind = def.typeName ?? "unknown";
101
+ ctx.depth++;
102
+ try {
103
+ switch (kind) {
104
+ case "ZodString":
105
+ return mockString(key, def, ctx);
106
+ case "ZodNumber":
107
+ return mockNumber(def, ctx);
108
+ case "ZodBoolean":
109
+ return ctx.rng() < 0.75;
110
+ case "ZodDate":
111
+ return new Date(MOCK_EPOCH - Math.floor(ctx.rng() * YEAR_MS));
112
+ case "ZodNull":
113
+ return null;
114
+ case "ZodLiteral":
115
+ return def.value;
116
+ case "ZodEnum":
117
+ case "ZodNativeEnum": {
118
+ const values = def.values ?? [];
119
+ return values.length > 0 ? pick(values, ctx.rng) : "mock";
120
+ }
121
+ case "ZodArray": {
122
+ const element = def.type ?? def.innerType;
123
+ const count = intBetween(ctx.rng, 1, 3);
124
+ const result = [];
125
+ for (let i = 0; i < count; i++) {
126
+ result.push(element ? generateMockValue(element, singular(key), ctx) : null);
127
+ }
128
+ return result;
129
+ }
130
+ case "ZodObject": {
131
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape;
132
+ const result = {};
133
+ for (const [childKey, child] of Object.entries(shape ?? {})) {
134
+ result[childKey] = generateMockValue(child, childKey, ctx);
135
+ }
136
+ return result;
137
+ }
138
+ case "ZodUnion":
139
+ case "ZodDiscriminatedUnion": {
140
+ const options = def.options ?? [];
141
+ return options.length > 0 ? generateMockValue(pick(options, ctx.rng), key, ctx) : "mock";
142
+ }
143
+ case "ZodIntersection":
144
+ return def.left ? generateMockValue(def.left, key, ctx) : "mock";
145
+ case "ZodRecord": {
146
+ return { [`mock${key}`]: def.valueType ? generateMockValue(def.valueType, key, ctx) : "mock" };
147
+ }
148
+ case "ZodTuple": {
149
+ return (def.items ?? []).map((item, index) => generateMockValue(item, `${key}${index}`, ctx));
150
+ }
151
+ case "ZodOptional":
152
+ case "ZodCatch":
153
+ case "ZodBranded": {
154
+ return def.innerType ? generateMockValue(def.innerType, key, ctx) : "mock";
155
+ }
156
+ case "ZodNullable": {
157
+ return def.innerType ? generateMockValue(def.innerType, key, ctx) : null;
158
+ }
159
+ case "ZodDefault": {
160
+ try {
161
+ return typeof def.defaultValue === "function" ? def.defaultValue() : def.defaultValue;
162
+ } catch {
163
+ return def.innerType ? generateMockValue(def.innerType, key, ctx) : "mock";
164
+ }
165
+ }
166
+ case "ZodEffects": {
167
+ const inner = def.schema ?? def.innerType;
168
+ return inner ? generateMockValue(inner, key, ctx) : "mock";
169
+ }
170
+ default:
171
+ return "mock";
172
+ }
173
+ } finally {
174
+ ctx.depth--;
175
+ }
176
+ }
177
+ export function generateMockResponse(contract, options) {
178
+ const seed = ((options?.seed ?? 42) ^ strHash(contract.name ?? contract.path)) >>> 0;
179
+ const ctx = { rng: createRng(seed), depth: 0 };
180
+ if (!contract.response) return {};
181
+ return generateMockValue(contract.response, contract.name ?? "response", ctx);
182
+ }
183
+ export function autoMockContract(contract, options) {
184
+ mockContract(contract, {
185
+ response: () => generateMockResponse(contract, options),
186
+ delay: options?.delay
187
+ });
188
+ }
package/dist/server.d.mts CHANGED
@@ -1,8 +1,9 @@
1
- export { ContractMock, MockResponseInput, buildRequestPath, clearContractRegistry, defineApiContract, getContractByName, getContractMock, isApiContract, listRegisteredContracts, mockContract, registerContract, serializeQuery, serializeQueryValue, stableStringify } from './client.mjs';
1
+ export { C as ContractMock, M as MockResponseInput, b as buildRequestPath, c as clearContractRegistry, d as defineApiContract, g as getContractByName, a as getContractMock, i as isApiContract, l as listRegisteredContracts, m as mockContract, r as registerContract } from './shared/nuxt-api-contract.BgPd-YXc.mjs';
2
2
  export { A as ApiError, a as ApiErrorPayload, B as BUILT_IN_ERROR_CODES, C as CreateApiErrorInput, V as ValidationIssue, c as createApiError, f as formatValidationMessage, i as isApiError, p as parseApiErrorPayload, s as sanitizeIssues, b as serializeApiError, t as toApiError, d as toValidationIssues } from './shared/nuxt-api-contract.D31EDcwH.mjs';
3
- import { A as AnyApiContract } from './shared/nuxt-api-contract.CPm9WbWA.mjs';
4
- export { a as API_CONTRACT_KIND, b as ApiContract, c as ApiContractDefinition, d as ApiRequestOptions, e as AuthConfig, C as ContractBodyInput, f as ContractClientResponse, g as ContractErrorCode, h as ContractFromDefinition, i as ContractHandlerResponse, j as ContractHeadersInput, k as ContractParamsInput, l as ContractPathParams, m as ContractQueryInput, E as EmptyObject, n as ExtractSchemaInput, o as ExtractSchemaOutput, H as HttpMethod, I as IsEmptyObject, M as MaybePromise, P as PathParams, R as ResolvedApiRequestOptions, S as SplitPath } from './shared/nuxt-api-contract.CPm9WbWA.mjs';
5
- export { C as ContractHandler, a as ContractHandlerContext, d as defineContractHandler } from './shared/nuxt-api-contract.B9JBCRk8.mjs';
3
+ export { s as serializeQuery, a as serializeQueryValue, b as stableStringify } from './shared/nuxt-api-contract.DZfOzVaB.mjs';
4
+ import { a as AnyApiContract } from './shared/nuxt-api-contract.CFG8gzJH.mjs';
5
+ export { A as API_CONTRACT_KIND, b as ApiContract, c as ApiContractDefinition, d as ApiRequestOptions, e as AuthConfig, C as ContractBodyInput, f as ContractClientResponse, g as ContractErrorCode, h as ContractFromDefinition, i as ContractHandlerResponse, j as ContractHeadersInput, k as ContractParamsInput, l as ContractPathParams, m as ContractQueryInput, E as EmptyObject, n as ExtractSchemaInput, o as ExtractSchemaOutput, H as HttpMethod, I as IsEmptyObject, M as MaybePromise, P as PathParams, R as ResolvedApiRequestOptions, S as SplitPath } from './shared/nuxt-api-contract.CFG8gzJH.mjs';
6
+ export { C as ContractHandler, a as ContractHandlerContext, d as defineContractHandler } from './shared/nuxt-api-contract.VCevNWQV.mjs';
6
7
  import { z, ZodType } from 'zod';
7
8
  import 'h3';
8
9
 
@@ -10,6 +11,8 @@ type ResponseValidationMode = 'never' | 'development' | 'always';
10
11
  interface RuntimeApiContractConfig {
11
12
  validateResponse?: ResponseValidationMode;
12
13
  mocks?: boolean;
14
+ /** Generate mock responses for contracts without an explicit mock. */
15
+ mocksAuto?: boolean;
13
16
  }
14
17
  /** Reads runtime contract config from the current Nitro runtime config. */
15
18
  declare function readRuntimeConfig(getConfig: () => unknown): RuntimeApiContractConfig;
package/dist/server.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- export { ContractMock, MockResponseInput, buildRequestPath, clearContractRegistry, defineApiContract, getContractByName, getContractMock, isApiContract, listRegisteredContracts, mockContract, registerContract, serializeQuery, serializeQueryValue, stableStringify } from './client.js';
1
+ export { C as ContractMock, M as MockResponseInput, b as buildRequestPath, c as clearContractRegistry, d as defineApiContract, g as getContractByName, a as getContractMock, i as isApiContract, l as listRegisteredContracts, m as mockContract, r as registerContract } from './shared/nuxt-api-contract.C7KxMQHa.js';
2
2
  export { A as ApiError, a as ApiErrorPayload, B as BUILT_IN_ERROR_CODES, C as CreateApiErrorInput, V as ValidationIssue, c as createApiError, f as formatValidationMessage, i as isApiError, p as parseApiErrorPayload, s as sanitizeIssues, b as serializeApiError, t as toApiError, d as toValidationIssues } from './shared/nuxt-api-contract.D31EDcwH.js';
3
- import { A as AnyApiContract } from './shared/nuxt-api-contract.CPm9WbWA.js';
4
- export { a as API_CONTRACT_KIND, b as ApiContract, c as ApiContractDefinition, d as ApiRequestOptions, e as AuthConfig, C as ContractBodyInput, f as ContractClientResponse, g as ContractErrorCode, h as ContractFromDefinition, i as ContractHandlerResponse, j as ContractHeadersInput, k as ContractParamsInput, l as ContractPathParams, m as ContractQueryInput, E as EmptyObject, n as ExtractSchemaInput, o as ExtractSchemaOutput, H as HttpMethod, I as IsEmptyObject, M as MaybePromise, P as PathParams, R as ResolvedApiRequestOptions, S as SplitPath } from './shared/nuxt-api-contract.CPm9WbWA.js';
5
- export { C as ContractHandler, a as ContractHandlerContext, d as defineContractHandler } from './shared/nuxt-api-contract.S1zqCiJX.js';
3
+ export { s as serializeQuery, a as serializeQueryValue, b as stableStringify } from './shared/nuxt-api-contract.DZfOzVaB.js';
4
+ import { a as AnyApiContract } from './shared/nuxt-api-contract.CFG8gzJH.js';
5
+ export { A as API_CONTRACT_KIND, b as ApiContract, c as ApiContractDefinition, d as ApiRequestOptions, e as AuthConfig, C as ContractBodyInput, f as ContractClientResponse, g as ContractErrorCode, h as ContractFromDefinition, i as ContractHandlerResponse, j as ContractHeadersInput, k as ContractParamsInput, l as ContractPathParams, m as ContractQueryInput, E as EmptyObject, n as ExtractSchemaInput, o as ExtractSchemaOutput, H as HttpMethod, I as IsEmptyObject, M as MaybePromise, P as PathParams, R as ResolvedApiRequestOptions, S as SplitPath } from './shared/nuxt-api-contract.CFG8gzJH.js';
6
+ export { C as ContractHandler, a as ContractHandlerContext, d as defineContractHandler } from './shared/nuxt-api-contract.B_UvrNC8.js';
6
7
  import { z, ZodType } from 'zod';
7
8
  import 'h3';
8
9
 
@@ -10,6 +11,8 @@ type ResponseValidationMode = 'never' | 'development' | 'always';
10
11
  interface RuntimeApiContractConfig {
11
12
  validateResponse?: ResponseValidationMode;
12
13
  mocks?: boolean;
14
+ /** Generate mock responses for contracts without an explicit mock. */
15
+ mocksAuto?: boolean;
13
16
  }
14
17
  /** Reads runtime contract config from the current Nitro runtime config. */
15
18
  declare function readRuntimeConfig(getConfig: () => unknown): RuntimeApiContractConfig;
package/dist/server.mjs CHANGED
@@ -1,9 +1,11 @@
1
- import { a as getContractMock } from './shared/nuxt-api-contract.QDGSGaVY.mjs';
2
- export { b as buildRequestPath, c as clearContractRegistry, d as defineApiContract, g as getContractByName, i as isApiContract, l as listRegisteredContracts, m as mockContract, r as registerContract, s as serializeQuery, e as serializeQueryValue, f as stableStringify } from './shared/nuxt-api-contract.QDGSGaVY.mjs';
1
+ import { a as getContractMock } from './shared/nuxt-api-contract.V15soI_f.mjs';
2
+ export { b as buildRequestPath, c as clearContractRegistry, d as defineApiContract, g as getContractByName, i as isApiContract, l as listRegisteredContracts, m as mockContract, r as registerContract } from './shared/nuxt-api-contract.V15soI_f.mjs';
3
3
  import { A as ApiError, s as serializeApiError, B as BUILT_IN_ERROR_CODES } from './shared/nuxt-api-contract.obS6uV8A.mjs';
4
4
  export { c as createApiError, i as isApiError, p as parseApiErrorPayload, t as toApiError } from './shared/nuxt-api-contract.obS6uV8A.mjs';
5
5
  export { f as formatValidationMessage, s as sanitizeIssues, t as toValidationIssues } from './shared/nuxt-api-contract.DCAU2j7t.mjs';
6
+ export { s as serializeQuery, a as serializeQueryValue, b as stableStringify } from './shared/nuxt-api-contract.Dr4tPqGB.mjs';
6
7
  import { defineEventHandler, getRequestHeaders, getQuery, readValidatedBody, setResponseStatus } from 'h3';
8
+ import { g as generateMockResponse } from './shared/nuxt-api-contract.Bd2Y7Lx0.mjs';
7
9
  import { v as validateContractInput, r as readRuntimeConfig, s as shouldValidateResponse, a as validateContractResponse } from './shared/nuxt-api-contract.DDpgZj2g.mjs';
8
10
  export { b as rawQuerySchema } from './shared/nuxt-api-contract.DDpgZj2g.mjs';
9
11
  import 'zod';
@@ -52,7 +54,8 @@ function defineContractHandler(contract, handler) {
52
54
  event
53
55
  };
54
56
  const runtimeConfig = readRuntimeConfig(() => useNitroRuntimeConfig(event));
55
- const mock = getContractMock(contract);
57
+ const explicitMock = getContractMock(contract);
58
+ const mock = explicitMock ?? (runtimeConfig.mocksAuto ? { response: () => generateMockResponse(contract) } : void 0);
56
59
  if (runtimeConfig.mocks && mock?.response) {
57
60
  const mocked = await mock.response();
58
61
  return finalize(contract, mocked, runtimeConfig);
@@ -0,0 +1,40 @@
1
+ import { ZodType } from 'zod';
2
+ import { a as AnyApiContract, i as ContractHandlerResponse } from './nuxt-api-contract.CFG8gzJH.mjs';
3
+ import { C as ContractMock } from './nuxt-api-contract.BgPd-YXc.mjs';
4
+
5
+ /**
6
+ * Deterministic mock-data generation from contract schemas (client-safe:
7
+ * only depends on zod). Used by `autoMockContract`, the `apiContract.mocks:
8
+ * 'auto'` mode and the standalone mock server.
9
+ */
10
+
11
+ interface MockGenerateOptions {
12
+ /** Seed for deterministic generation (default: 42). */
13
+ seed?: number;
14
+ }
15
+ interface RngContext {
16
+ rng: () => number;
17
+ depth: number;
18
+ }
19
+ /** Mulberry32 — small, fast, deterministic PRNG. */
20
+ declare function createRng(seed: number): () => number;
21
+ /** Walks a Zod schema and produces a plausible mock value. */
22
+ declare function generateMockValue(schema: ZodType, key: string, ctx: RngContext): unknown;
23
+ /**
24
+ * Generates a mock response matching the contract's `response` schema.
25
+ * Deterministic for a given contract + seed.
26
+ */
27
+ declare function generateMockResponse<C extends AnyApiContract>(contract: C, options?: MockGenerateOptions): ContractHandlerResponse<C>;
28
+ /**
29
+ * Registers a generated mock for a contract — the "mock preset" produced
30
+ * from the contract itself:
31
+ *
32
+ * ```ts
33
+ * import { autoMockContract } from 'nuxt-api-contract/client'
34
+ * autoMockContract(GetUser) // response generated from the schema
35
+ * ```
36
+ */
37
+ declare function autoMockContract<C extends AnyApiContract>(contract: C, options?: MockGenerateOptions & Pick<ContractMock<C>, 'delay'>): void;
38
+
39
+ export { autoMockContract as a, generateMockValue as b, createRng as c, generateMockResponse as g };
40
+ export type { MockGenerateOptions as M };
@@ -1,6 +1,6 @@
1
1
  import { H3Event, EventHandler } from 'h3';
2
2
  import { z } from 'zod';
3
- import { A as AnyApiContract, M as MaybePromise, i as ContractHandlerResponse } from './nuxt-api-contract.CPm9WbWA.js';
3
+ import { a as AnyApiContract, M as MaybePromise, i as ContractHandlerResponse } from './nuxt-api-contract.CFG8gzJH.js';
4
4
 
5
5
  type Infer<T> = T extends z.ZodType ? z.infer<T> : never;
6
6
  /**
@@ -0,0 +1,191 @@
1
+ import { m as mockContract } from './nuxt-api-contract.V15soI_f.mjs';
2
+
3
+ function zodDef(schema) {
4
+ return schema._def;
5
+ }
6
+ function createRng(seed) {
7
+ let state = seed >>> 0;
8
+ return function() {
9
+ state = state + 1831565813 | 0;
10
+ let t = state;
11
+ t = Math.imul(t ^ t >>> 15, t | 1);
12
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
13
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
14
+ };
15
+ }
16
+ function strHash(value) {
17
+ let hash = 2166136261;
18
+ for (let i = 0; i < value.length; i++) {
19
+ hash ^= value.charCodeAt(i);
20
+ hash = Math.imul(hash, 16777619);
21
+ }
22
+ return hash >>> 0;
23
+ }
24
+ function pick(items, rng) {
25
+ return items[Math.floor(rng() * items.length) % items.length];
26
+ }
27
+ function intBetween(rng, min, max) {
28
+ return Math.floor(min + rng() * (max - min + 1));
29
+ }
30
+ const FIRST_NAMES = ["John", "Jane", "Alex", "Maria", "Ivan", "Elena"];
31
+ const LAST_NAMES = ["Doe", "Smith", "Brown", "Ivanov", "Miller"];
32
+ const WORDS = ["mock", "demo", "sample", "alpha", "beta", "gamma"];
33
+ const MOCK_EPOCH = Date.UTC(2024, 0, 1);
34
+ const YEAR_MS = 365 * 24 * 3600 * 1e3;
35
+ function mockUuid(rng) {
36
+ const hex = () => Math.floor(rng() * 65535).toString(16).padStart(4, "0");
37
+ return `${hex()}${hex()}-4${hex().slice(1)}-8${hex().slice(1)}-4${hex().slice(1)}-${hex()}${hex()}${hex()}`;
38
+ }
39
+ function mockString(key, def, ctx) {
40
+ const lower = key.toLowerCase();
41
+ const checks = def.checks ?? [];
42
+ const check = (kind) => checks.find((c) => c.kind === kind)?.value;
43
+ const format = checks.find((c) => c.kind === "format")?.value;
44
+ const hasCheck = (kind) => checks.some((c) => c.kind === kind);
45
+ let value;
46
+ if (format === "email" || hasCheck("email") || lower.includes("email")) {
47
+ const name = pick(FIRST_NAMES, ctx.rng).toLowerCase();
48
+ value = `${name}.${pick(LAST_NAMES, ctx.rng).toLowerCase()}@example.com`;
49
+ } else if (hasCheck("uuid")) {
50
+ value = mockUuid(ctx.rng);
51
+ } else if (hasCheck("datetime") || lower === "createdat" || lower === "updatedat" || lower.endsWith("date") || lower.endsWith("_at")) {
52
+ value = new Date(MOCK_EPOCH - Math.floor(ctx.rng() * YEAR_MS)).toISOString();
53
+ } else if (hasCheck("url") || lower.endsWith("url") || lower.endsWith("link")) {
54
+ value = `https://example.com/${pick(WORDS, ctx.rng)}/${intBetween(ctx.rng, 1, 999)}`;
55
+ } else if (lower.includes("phone") || lower.includes("tel")) {
56
+ value = `+1 555 010 ${intBetween(ctx.rng, 1e3, 9999)}`;
57
+ } else if (lower === "id" || lower.endsWith("_id") || lower.endsWith("id")) {
58
+ value = `id-${intBetween(ctx.rng, 1, 99999)}`;
59
+ } else if (lower.includes("slug")) {
60
+ value = `${pick(WORDS, ctx.rng)}-${intBetween(ctx.rng, 1, 999)}`;
61
+ } else if (lower === "name" || lower.endsWith("name")) {
62
+ value = `${pick(FIRST_NAMES, ctx.rng)} ${pick(LAST_NAMES, ctx.rng)}`;
63
+ } else if (lower === "title") {
64
+ value = `${pick(WORDS, ctx.rng)} title`;
65
+ } else if (lower.includes("password") || lower.includes("token") || lower.includes("secret")) {
66
+ value = "********";
67
+ } else if (lower.includes("description") || lower === "bio" || lower === "text") {
68
+ value = `Mock ${pick(WORDS, ctx.rng)} description for automated testing.`;
69
+ } else {
70
+ value = `${pick(WORDS, ctx.rng)}-${intBetween(ctx.rng, 1, 9999)}`;
71
+ }
72
+ const minLength = check("min");
73
+ if (minLength !== void 0) {
74
+ while (value.length < minLength) value += "-filler";
75
+ }
76
+ const maxLength = check("max");
77
+ if (maxLength !== void 0 && value.length > maxLength) {
78
+ value = value.slice(0, maxLength);
79
+ }
80
+ return value;
81
+ }
82
+ function mockNumber(def, ctx) {
83
+ const checks = def.checks ?? [];
84
+ const isInt = checks.some((c) => c.kind === "int");
85
+ const min = checks.find((c) => c.kind === "min")?.value ?? 1;
86
+ const max = checks.find((c) => c.kind === "max")?.value ?? 100;
87
+ const multipleOf = checks.find((c) => c.kind === "multipleOf")?.value;
88
+ if (multipleOf !== void 0 && multipleOf > 0) {
89
+ const minMul = Math.max(1, Math.ceil(min / multipleOf));
90
+ const maxMul = Math.max(minMul, Math.floor(max / multipleOf));
91
+ return intBetween(ctx.rng, minMul, maxMul) * multipleOf;
92
+ }
93
+ return isInt ? intBetween(ctx.rng, min, max) : Math.round((min + ctx.rng() * (max - min)) * 100) / 100;
94
+ }
95
+ function singular(key) {
96
+ return key.endsWith("s") && key.length > 1 ? key.slice(0, -1) : key;
97
+ }
98
+ function generateMockValue(schema, key, ctx) {
99
+ if (ctx.depth > 6) return "mock";
100
+ const def = zodDef(schema);
101
+ const kind = def.typeName ?? "unknown";
102
+ ctx.depth++;
103
+ try {
104
+ switch (kind) {
105
+ case "ZodString":
106
+ return mockString(key, def, ctx);
107
+ case "ZodNumber":
108
+ return mockNumber(def, ctx);
109
+ case "ZodBoolean":
110
+ return ctx.rng() < 0.75;
111
+ case "ZodDate":
112
+ return new Date(MOCK_EPOCH - Math.floor(ctx.rng() * YEAR_MS));
113
+ case "ZodNull":
114
+ return null;
115
+ case "ZodLiteral":
116
+ return def.value;
117
+ case "ZodEnum":
118
+ case "ZodNativeEnum": {
119
+ const values = def.values ?? [];
120
+ return values.length > 0 ? pick(values, ctx.rng) : "mock";
121
+ }
122
+ case "ZodArray": {
123
+ const element = def.type ?? def.innerType;
124
+ const count = intBetween(ctx.rng, 1, 3);
125
+ const result = [];
126
+ for (let i = 0; i < count; i++) {
127
+ result.push(element ? generateMockValue(element, singular(key), ctx) : null);
128
+ }
129
+ return result;
130
+ }
131
+ case "ZodObject": {
132
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape;
133
+ const result = {};
134
+ for (const [childKey, child] of Object.entries(shape ?? {})) {
135
+ result[childKey] = generateMockValue(child, childKey, ctx);
136
+ }
137
+ return result;
138
+ }
139
+ case "ZodUnion":
140
+ case "ZodDiscriminatedUnion": {
141
+ const options = def.options ?? [];
142
+ return options.length > 0 ? generateMockValue(pick(options, ctx.rng), key, ctx) : "mock";
143
+ }
144
+ case "ZodIntersection":
145
+ return def.left ? generateMockValue(def.left, key, ctx) : "mock";
146
+ case "ZodRecord": {
147
+ return { [`mock${key}`]: def.valueType ? generateMockValue(def.valueType, key, ctx) : "mock" };
148
+ }
149
+ case "ZodTuple": {
150
+ return (def.items ?? []).map((item, index) => generateMockValue(item, `${key}${index}`, ctx));
151
+ }
152
+ case "ZodOptional":
153
+ case "ZodCatch":
154
+ case "ZodBranded": {
155
+ return def.innerType ? generateMockValue(def.innerType, key, ctx) : "mock";
156
+ }
157
+ case "ZodNullable": {
158
+ return def.innerType ? generateMockValue(def.innerType, key, ctx) : null;
159
+ }
160
+ case "ZodDefault": {
161
+ try {
162
+ return typeof def.defaultValue === "function" ? def.defaultValue() : def.defaultValue;
163
+ } catch {
164
+ return def.innerType ? generateMockValue(def.innerType, key, ctx) : "mock";
165
+ }
166
+ }
167
+ case "ZodEffects": {
168
+ const inner = def.schema ?? def.innerType;
169
+ return inner ? generateMockValue(inner, key, ctx) : "mock";
170
+ }
171
+ default:
172
+ return "mock";
173
+ }
174
+ } finally {
175
+ ctx.depth--;
176
+ }
177
+ }
178
+ function generateMockResponse(contract, options) {
179
+ const seed = ((options?.seed ?? 42) ^ strHash(contract.name ?? contract.path)) >>> 0;
180
+ const ctx = { rng: createRng(seed), depth: 0 };
181
+ if (!contract.response) return {};
182
+ return generateMockValue(contract.response, contract.name ?? "response", ctx);
183
+ }
184
+ function autoMockContract(contract, options) {
185
+ mockContract(contract, {
186
+ response: () => generateMockResponse(contract, options),
187
+ delay: options?.delay
188
+ });
189
+ }
190
+
191
+ export { autoMockContract as a, generateMockValue as b, createRng as c, generateMockResponse as g };
@@ -0,0 +1,53 @@
1
+ import * as zod from 'zod';
2
+ import { a as AnyApiContract, M as MaybePromise, i as ContractHandlerResponse, c as ApiContractDefinition, h as ContractFromDefinition } from './nuxt-api-contract.CFG8gzJH.mjs';
3
+
4
+ /**
5
+ * Registers a named contract. Called automatically by `defineApiContract`
6
+ * when a `name` is provided. Duplicate names are overwritten with a warning.
7
+ */
8
+ declare function registerContract(contract: AnyApiContract): void;
9
+ declare function getContractByName(name: string): AnyApiContract | undefined;
10
+ declare function listRegisteredContracts(): AnyApiContract[];
11
+ /** Test helper: clears the registry. */
12
+ declare function clearContractRegistry(): void;
13
+ interface ContractMock<C extends AnyApiContract> {
14
+ /** Factory producing a (validated) response for the contract. */
15
+ response?: () => MaybePromise<MockResponseInput<C>>;
16
+ /** Simulated latency in ms. */
17
+ delay?: number;
18
+ }
19
+ type MockResponseInput<C extends AnyApiContract> = C['response'] extends zod.ZodType ? ContractHandlerResponse<C> : unknown;
20
+ /**
21
+ * Registers a mock implementation for a contract. When the module option
22
+ * `apiContract.mocks` is enabled, contract handlers return the mock response
23
+ * (still validated against the response schema).
24
+ */
25
+ declare function mockContract<C extends AnyApiContract>(contract: C, mock: ContractMock<C>): void;
26
+ declare function getContractMock<C extends AnyApiContract>(contract: C): ContractMock<C> | undefined;
27
+ /**
28
+ * Defines a type-safe API contract.
29
+ *
30
+ * The contract is the single source of truth for runtime validation,
31
+ * TypeScript types, OpenAPI generation, DevTools and mocks.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * export const GetUser = defineApiContract({
36
+ * method: 'GET',
37
+ * path: '/api/users/:id',
38
+ * params: z.object({ id: z.string().uuid() }),
39
+ * response: z.object({ id: z.string(), name: z.string() }),
40
+ * })
41
+ * ```
42
+ */
43
+ declare function defineApiContract<const TDef extends ApiContractDefinition>(definition: TDef): ContractFromDefinition<TDef>;
44
+ /** Type guard for contract objects. */
45
+ declare function isApiContract(value: unknown): value is AnyApiContract;
46
+ /**
47
+ * Builds the request URL from a contract path and concrete params.
48
+ * Remaining params that are not part of the path are ignored.
49
+ */
50
+ declare function buildRequestPath(path: string, params: Record<string, unknown> | undefined): string;
51
+
52
+ export { getContractMock as a, buildRequestPath as b, clearContractRegistry as c, defineApiContract as d, getContractByName as g, isApiContract as i, listRegisteredContracts as l, mockContract as m, registerContract as r };
53
+ export type { ContractMock as C, MockResponseInput as M };
@@ -0,0 +1,40 @@
1
+ import { ZodType } from 'zod';
2
+ import { a as AnyApiContract, i as ContractHandlerResponse } from './nuxt-api-contract.CFG8gzJH.js';
3
+ import { C as ContractMock } from './nuxt-api-contract.C7KxMQHa.js';
4
+
5
+ /**
6
+ * Deterministic mock-data generation from contract schemas (client-safe:
7
+ * only depends on zod). Used by `autoMockContract`, the `apiContract.mocks:
8
+ * 'auto'` mode and the standalone mock server.
9
+ */
10
+
11
+ interface MockGenerateOptions {
12
+ /** Seed for deterministic generation (default: 42). */
13
+ seed?: number;
14
+ }
15
+ interface RngContext {
16
+ rng: () => number;
17
+ depth: number;
18
+ }
19
+ /** Mulberry32 — small, fast, deterministic PRNG. */
20
+ declare function createRng(seed: number): () => number;
21
+ /** Walks a Zod schema and produces a plausible mock value. */
22
+ declare function generateMockValue(schema: ZodType, key: string, ctx: RngContext): unknown;
23
+ /**
24
+ * Generates a mock response matching the contract's `response` schema.
25
+ * Deterministic for a given contract + seed.
26
+ */
27
+ declare function generateMockResponse<C extends AnyApiContract>(contract: C, options?: MockGenerateOptions): ContractHandlerResponse<C>;
28
+ /**
29
+ * Registers a generated mock for a contract — the "mock preset" produced
30
+ * from the contract itself:
31
+ *
32
+ * ```ts
33
+ * import { autoMockContract } from 'nuxt-api-contract/client'
34
+ * autoMockContract(GetUser) // response generated from the schema
35
+ * ```
36
+ */
37
+ declare function autoMockContract<C extends AnyApiContract>(contract: C, options?: MockGenerateOptions & Pick<ContractMock<C>, 'delay'>): void;
38
+
39
+ export { autoMockContract as a, generateMockValue as b, createRng as c, generateMockResponse as g };
40
+ export type { MockGenerateOptions as M };
@@ -0,0 +1,53 @@
1
+ import * as zod from 'zod';
2
+ import { a as AnyApiContract, M as MaybePromise, i as ContractHandlerResponse, c as ApiContractDefinition, h as ContractFromDefinition } from './nuxt-api-contract.CFG8gzJH.js';
3
+
4
+ /**
5
+ * Registers a named contract. Called automatically by `defineApiContract`
6
+ * when a `name` is provided. Duplicate names are overwritten with a warning.
7
+ */
8
+ declare function registerContract(contract: AnyApiContract): void;
9
+ declare function getContractByName(name: string): AnyApiContract | undefined;
10
+ declare function listRegisteredContracts(): AnyApiContract[];
11
+ /** Test helper: clears the registry. */
12
+ declare function clearContractRegistry(): void;
13
+ interface ContractMock<C extends AnyApiContract> {
14
+ /** Factory producing a (validated) response for the contract. */
15
+ response?: () => MaybePromise<MockResponseInput<C>>;
16
+ /** Simulated latency in ms. */
17
+ delay?: number;
18
+ }
19
+ type MockResponseInput<C extends AnyApiContract> = C['response'] extends zod.ZodType ? ContractHandlerResponse<C> : unknown;
20
+ /**
21
+ * Registers a mock implementation for a contract. When the module option
22
+ * `apiContract.mocks` is enabled, contract handlers return the mock response
23
+ * (still validated against the response schema).
24
+ */
25
+ declare function mockContract<C extends AnyApiContract>(contract: C, mock: ContractMock<C>): void;
26
+ declare function getContractMock<C extends AnyApiContract>(contract: C): ContractMock<C> | undefined;
27
+ /**
28
+ * Defines a type-safe API contract.
29
+ *
30
+ * The contract is the single source of truth for runtime validation,
31
+ * TypeScript types, OpenAPI generation, DevTools and mocks.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * export const GetUser = defineApiContract({
36
+ * method: 'GET',
37
+ * path: '/api/users/:id',
38
+ * params: z.object({ id: z.string().uuid() }),
39
+ * response: z.object({ id: z.string(), name: z.string() }),
40
+ * })
41
+ * ```
42
+ */
43
+ declare function defineApiContract<const TDef extends ApiContractDefinition>(definition: TDef): ContractFromDefinition<TDef>;
44
+ /** Type guard for contract objects. */
45
+ declare function isApiContract(value: unknown): value is AnyApiContract;
46
+ /**
47
+ * Builds the request URL from a contract path and concrete params.
48
+ * Remaining params that are not part of the path are ignored.
49
+ */
50
+ declare function buildRequestPath(path: string, params: Record<string, unknown> | undefined): string;
51
+
52
+ export { getContractMock as a, buildRequestPath as b, clearContractRegistry as c, defineApiContract as d, getContractByName as g, isApiContract as i, listRegisteredContracts as l, mockContract as m, registerContract as r };
53
+ export type { ContractMock as C, MockResponseInput as M };