@lovrozagar/honey 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.
Files changed (131) hide show
  1. package/README.md +51 -0
  2. package/docs/api-ref/go.md +399 -0
  3. package/docs/api-ref/python.md +399 -0
  4. package/docs/api-ref/rust.md +399 -0
  5. package/docs/api-ref/typescript.md +399 -0
  6. package/docs/invalidate-spec.md +303 -0
  7. package/docs/sdk.md +722 -0
  8. package/package.json +120 -0
  9. package/src/accepts.ts +78 -0
  10. package/src/body-limit.ts +100 -0
  11. package/src/build/index.ts +174 -0
  12. package/src/cli-go/auth.go +15 -0
  13. package/src/cli-go/config.go +165 -0
  14. package/src/cli-go/errors.go +57 -0
  15. package/src/cli-go/multipart.go +55 -0
  16. package/src/cli-go/output.go +109 -0
  17. package/src/cli-go/root.go +30 -0
  18. package/src/cli-go/stream.go +88 -0
  19. package/src/cli-go/version.go +5 -0
  20. package/src/cli.ts +204 -0
  21. package/src/client/error.ts +27 -0
  22. package/src/client/http.ts +502 -0
  23. package/src/client/index.ts +127 -0
  24. package/src/client/sdk.ts +265 -0
  25. package/src/client/sse.ts +102 -0
  26. package/src/client/types.ts +211 -0
  27. package/src/client/ws.ts +115 -0
  28. package/src/client-go/errors.go +207 -0
  29. package/src/client-go/invalidation.go +373 -0
  30. package/src/client-go/realtime.go +317 -0
  31. package/src/client-go/result.go +20 -0
  32. package/src/client-go/runtime.go +413 -0
  33. package/src/client-go/sse.go +149 -0
  34. package/src/client-go/transport.go +452 -0
  35. package/src/client-go/ws.go +104 -0
  36. package/src/client-mcp/README.md +10 -0
  37. package/src/client-mcp/server.ts +94 -0
  38. package/src/client-mcp/types.ts +19 -0
  39. package/src/client-python/_errors.py +115 -0
  40. package/src/client-python/_invalidation.py +578 -0
  41. package/src/client-python/_realtime.py +156 -0
  42. package/src/client-python/_runtime.py +469 -0
  43. package/src/client-python/_sse.py +99 -0
  44. package/src/client-python/_transport.py +335 -0
  45. package/src/client-python/_ws.py +131 -0
  46. package/src/client-python/py.typed +0 -0
  47. package/src/client-rust/errors.rs +200 -0
  48. package/src/client-rust/invalidation.rs +441 -0
  49. package/src/client-rust/invalidation_sync.rs +306 -0
  50. package/src/client-rust/realtime.rs +695 -0
  51. package/src/client-rust/result.rs +22 -0
  52. package/src/client-rust/runtime.rs +547 -0
  53. package/src/client-rust/runtime_sync.rs +452 -0
  54. package/src/client-rust/sse.rs +167 -0
  55. package/src/client-rust/ws.rs +143 -0
  56. package/src/cloudflare/realtime.ts +236 -0
  57. package/src/codegen-go-cli.ts +1180 -0
  58. package/src/codegen-go.ts +1010 -0
  59. package/src/codegen-hash.ts +8 -0
  60. package/src/codegen-ir.ts +517 -0
  61. package/src/codegen-loaders.ts +53 -0
  62. package/src/codegen-mcp.ts +364 -0
  63. package/src/codegen-python.ts +1028 -0
  64. package/src/codegen-rust.ts +1652 -0
  65. package/src/codegen-sanitize.ts +67 -0
  66. package/src/codegen-schema-naming.ts +146 -0
  67. package/src/codegen.ts +5015 -0
  68. package/src/context.ts +210 -0
  69. package/src/cookie-sign.ts +58 -0
  70. package/src/cookie.ts +89 -0
  71. package/src/cors.ts +96 -0
  72. package/src/crypto.ts +19 -0
  73. package/src/csrf.ts +54 -0
  74. package/src/curl-logger.ts +235 -0
  75. package/src/detect-runtime.ts +19 -0
  76. package/src/error.ts +52 -0
  77. package/src/errors.ts +87 -0
  78. package/src/etag.ts +74 -0
  79. package/src/feature-load.ts +23 -0
  80. package/src/go-type-emitter.ts +404 -0
  81. package/src/honey-response.ts +354 -0
  82. package/src/i18n-slot.ts +20 -0
  83. package/src/i18n.ts +234 -0
  84. package/src/index.ts +3843 -0
  85. package/src/init.ts +149 -0
  86. package/src/input.ts +8 -0
  87. package/src/ip-restrict.ts +192 -0
  88. package/src/logger.ts +149 -0
  89. package/src/middleware.ts +199 -0
  90. package/src/node-request.ts +240 -0
  91. package/src/node.ts +212 -0
  92. package/src/openapi/register.ts +19 -0
  93. package/src/openapi/scalar.ts +33 -0
  94. package/src/openapi/spec-factory.ts +46 -0
  95. package/src/openapi/spec.ts +31 -0
  96. package/src/openapi/swagger.ts +34 -0
  97. package/src/plugin.ts +771 -0
  98. package/src/powered-by.ts +17 -0
  99. package/src/pretty-json.ts +39 -0
  100. package/src/proxy.ts +155 -0
  101. package/src/python-type-emitter.ts +144 -0
  102. package/src/realtime/buffer.ts +101 -0
  103. package/src/realtime/bus.ts +93 -0
  104. package/src/realtime/longpoll.ts +148 -0
  105. package/src/realtime/protocol.ts +128 -0
  106. package/src/realtime/route.ts +104 -0
  107. package/src/realtime/runtime.ts +430 -0
  108. package/src/request-id.ts +23 -0
  109. package/src/request-to-curl.ts +34 -0
  110. package/src/response.ts +414 -0
  111. package/src/rust-type-emitter.ts +412 -0
  112. package/src/secure-headers.ts +69 -0
  113. package/src/serve-register.ts +8 -0
  114. package/src/serve-slot.ts +20 -0
  115. package/src/serve.ts +141 -0
  116. package/src/server-timing.ts +66 -0
  117. package/src/static.ts +60 -0
  118. package/src/telemetry/otel.ts +139 -0
  119. package/src/testing.ts +114 -0
  120. package/src/timeout.ts +36 -0
  121. package/src/tree.ts +464 -0
  122. package/src/ts-type-emitter.ts +106 -0
  123. package/src/type-emitter.ts +524 -0
  124. package/src/type-extractor.ts +749 -0
  125. package/src/types.ts +638 -0
  126. package/src/validation.ts +300 -0
  127. package/src/ws/bun.ts +89 -0
  128. package/src/ws/cloudflare.ts +133 -0
  129. package/src/ws/deno.ts +109 -0
  130. package/src/ws/node.ts +161 -0
  131. package/src/yaml.ts +80 -0
@@ -0,0 +1,67 @@
1
+ /** OpenAPI cleanup of Zod JSON Schema. Not a package export. */
2
+
3
+ const SCHEMA_VALUE_KEYS = new Set([
4
+ "additionalProperties",
5
+ "contains",
6
+ "else",
7
+ "if",
8
+ "items",
9
+ "not",
10
+ "propertyNames",
11
+ "then",
12
+ "unevaluatedItems",
13
+ "unevaluatedProperties",
14
+ ])
15
+
16
+ const SCHEMA_MAP_KEYS = new Set([
17
+ "$defs",
18
+ "definitions",
19
+ "dependentSchemas",
20
+ "patternProperties",
21
+ "properties",
22
+ ])
23
+
24
+ const SCHEMA_ARRAY_KEYS = new Set(["allOf", "anyOf", "oneOf", "prefixItems"])
25
+
26
+ function asRecord(value: unknown): value is Record<string, unknown> {
27
+ return value !== null && typeof value === "object" && !Array.isArray(value)
28
+ }
29
+
30
+ function sanitizeSchemaValue(value: unknown): unknown {
31
+ if (typeof value === "boolean") return value
32
+ if (asRecord(value)) return sanitizeZodJsonSchema(value)
33
+ return value
34
+ }
35
+
36
+ export function sanitizeZodJsonSchema(obj: Record<string, unknown>): Record<string, unknown> {
37
+ const out: Record<string, unknown> = {}
38
+ for (const [key, val] of Object.entries(obj)) {
39
+ if (key === "$schema" || key === "~standard") continue
40
+ if (key === "anyOf" && Array.isArray(val)) {
41
+ out.oneOf = val.map((item) => sanitizeSchemaValue(item))
42
+ continue
43
+ }
44
+ if (SCHEMA_MAP_KEYS.has(key) && asRecord(val)) {
45
+ const mapped: Record<string, unknown> = {}
46
+ for (const [childKey, child] of Object.entries(val)) {
47
+ mapped[childKey] = sanitizeSchemaValue(child)
48
+ }
49
+ out[key] = mapped
50
+ continue
51
+ }
52
+ if (SCHEMA_ARRAY_KEYS.has(key) && Array.isArray(val)) {
53
+ out[key] = val.map((item) => sanitizeSchemaValue(item))
54
+ continue
55
+ }
56
+ if (SCHEMA_VALUE_KEYS.has(key)) {
57
+ if (key === "items" && Array.isArray(val)) {
58
+ out[key] = val.map((item) => sanitizeSchemaValue(item))
59
+ } else {
60
+ out[key] = sanitizeSchemaValue(val)
61
+ }
62
+ continue
63
+ }
64
+ out[key] = val
65
+ }
66
+ return out
67
+ }
@@ -0,0 +1,146 @@
1
+ import { hashString } from "./codegen-hash.ts"
2
+
3
+ export type SchemaRole = "request" | "response"
4
+
5
+ export type SchemaNameContext =
6
+ | { method: string; path: string; role: "request"; fieldPath?: string[] }
7
+ | { method: string; path: string; role: "response"; status: number; fieldPath?: string[] }
8
+
9
+ const KNOWN_ACTIONS = new Set(["accept", "cancel", "refresh", "verify", "confirm", "reset", "revoke", "invite"])
10
+
11
+ /** Returns 6-char lowercase hex derived from content hash. */
12
+ export function shortHash(canonical: string): string {
13
+ return hashString(canonical).slice(0, 6)
14
+ }
15
+
16
+ function toPascal(segment: string): string {
17
+ return segment
18
+ .replace(/[-_](.)/g, (_, c: string) => c.toUpperCase())
19
+ .replace(/^(.)/, (_, c: string) => c.toUpperCase())
20
+ }
21
+
22
+ function stripPathPrefix(path: string): string[] {
23
+ const raw = path.replace(/^\//, "").split("/")
24
+ /* drop leading version segment like v1, v2, v10 */
25
+ if (raw.length > 0 && /^v\d+$/.test(raw[0])) raw.shift()
26
+ return raw
27
+ }
28
+
29
+ function isParam(segment: string): boolean {
30
+ return segment.startsWith("{") && segment.endsWith("}")
31
+ }
32
+
33
+ /*
34
+ * Drop "variant qualifier": when the last raw segment is a non-param non-action
35
+ * literal that follows DIRECTLY after a plural collection noun (no {param} between
36
+ * them), it's a discriminator (e.g. "github"/"stripe" in /webhooks/github).
37
+ * Dropping it ensures both routes derive the same base name so collision detection
38
+ * kicks in and hash-suffix disambiguates their distinct shapes.
39
+ */
40
+ function dropVariantQualifier(rawSegments: string[]): string[] {
41
+ if (rawSegments.length < 2) return rawSegments
42
+ const last = rawSegments[rawSegments.length - 1]
43
+ const prev = rawSegments[rawSegments.length - 2]
44
+ if (!isParam(last) && !isParam(prev) && !KNOWN_ACTIONS.has(last.toLowerCase())) {
45
+ const prevPascal = toPascal(prev)
46
+ /* prev must be a collection noun (ends in 's' after PascalCase) */
47
+ if (prevPascal.endsWith("s")) {
48
+ return rawSegments.slice(0, -1)
49
+ }
50
+ }
51
+ return rawSegments
52
+ }
53
+
54
+ function deriveVerb(method: string, rawSegments: string[]): string {
55
+ const lastRaw = rawSegments[rawSegments.length - 1]
56
+
57
+ if (method === "get") {
58
+ if (lastRaw && isParam(lastRaw)) return "Get"
59
+ return "List"
60
+ }
61
+ if (method === "patch") return "Update"
62
+ if (method === "put") return "Replace"
63
+ if (method === "delete") return "Delete"
64
+
65
+ /* POST */
66
+ if (lastRaw && KNOWN_ACTIONS.has(lastRaw.toLowerCase())) {
67
+ return toPascal(lastRaw)
68
+ }
69
+ return "Create"
70
+ }
71
+
72
+ function buildResourcePart(rawSegments: string[], verb: string): string {
73
+ const nonParam = rawSegments.filter((s) => !isParam(s))
74
+ const lastSeg = rawSegments[rawSegments.length - 1]
75
+
76
+ if (lastSeg && KNOWN_ACTIONS.has(lastSeg.toLowerCase()) && verb === toPascal(lastSeg)) {
77
+ /* last segment is the action verb — drop it; it's already the verb prefix */
78
+ return nonParam.slice(0, -1).map(toPascal).join("")
79
+ }
80
+
81
+ const parts = nonParam.map(toPascal)
82
+
83
+ /* singularize last noun for non-List verbs */
84
+ if (verb !== "List" && parts.length > 0) {
85
+ const last = parts[parts.length - 1]
86
+ if (last.endsWith("s") && last.length > 2) {
87
+ parts[parts.length - 1] = last.slice(0, -1)
88
+ }
89
+ }
90
+
91
+ return parts.join("")
92
+ }
93
+
94
+ function roleSuffix(ctx: SchemaNameContext): string {
95
+ if (ctx.role === "request") return "Request"
96
+ return `Response${ctx.status}`
97
+ }
98
+
99
+ /** Returns true if schema matches anyrow-style error envelope shape. */
100
+ export function isErrorEnvelope(schema: Record<string, unknown>): boolean {
101
+ if (schema.type !== "object" && !schema.properties) return false
102
+ const props = schema.properties as Record<string, Record<string, unknown>> | undefined
103
+ if (!props) return false
104
+ if (!props.error_key || !props.status || !props.success) return false
105
+ const successDef = props.success
106
+ const isFalseConst = successDef.const === false
107
+ const isFalseEnum = Array.isArray(successDef.enum) && successDef.enum.length === 1 && successDef.enum[0] === false
108
+ return isFalseConst || isFalseEnum
109
+ }
110
+
111
+ /** Derives a canonical name for a shared error envelope (e.g. `Err400InvalidInput`). */
112
+ export function deriveErrorEnvelopeName(schema: Record<string, unknown>, fallbackStatus?: number): string {
113
+ const props = schema.properties as Record<string, Record<string, unknown>>
114
+ const statusProp = props.status
115
+ let status: number | undefined
116
+ if (typeof statusProp.const === "number") status = statusProp.const
117
+ else if (Array.isArray(statusProp.enum) && statusProp.enum.length === 1 && typeof statusProp.enum[0] === "number") status = statusProp.enum[0]
118
+ else if (fallbackStatus !== undefined) status = fallbackStatus
119
+ else throw new Error("deriveErrorEnvelopeName: no status")
120
+
121
+ const keyProp = props.error_key
122
+ const keys: string[] = Array.isArray(keyProp?.enum)
123
+ ? [...keyProp.enum].filter((k): k is string => typeof k === "string").sort()
124
+ : []
125
+
126
+ if (keys.length === 0) return `Err${status}`
127
+ const keysPascal = keys
128
+ .map((k) => k.split(/[_-]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(""))
129
+ .join("")
130
+ return `Err${status}${keysPascal}`
131
+ }
132
+
133
+ /** Derives a human-readable schema component name from operation context. */
134
+ export function deriveSchemaName(ctx: SchemaNameContext): string {
135
+ const rawSegments = dropVariantQualifier(stripPathPrefix(ctx.path))
136
+ const verb = deriveVerb(ctx.method, rawSegments)
137
+ const resource = buildResourcePart(rawSegments, verb)
138
+ const base = `${verb}${resource}`
139
+
140
+ if (ctx.fieldPath && ctx.fieldPath.length > 0) {
141
+ const fieldPart = ctx.fieldPath.map(toPascal).join("")
142
+ return `${base}${fieldPart}`
143
+ }
144
+
145
+ return `${base}${roleSuffix(ctx)}`
146
+ }