mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
fix: preserve z namespace types for sdk consumers
This commit is contained in:
21
sdk/Makefile
21
sdk/Makefile
@@ -27,16 +27,33 @@ bundle: baseDist dist | test fmt
|
||||
base/lib/exver/exver.ts: base/node_modules base/lib/exver/exver.pegjs
|
||||
cd base && npm run peggy
|
||||
|
||||
baseDist: $(PACKAGE_TS_FILES) $(BASE_TS_FILES) base/package.json base/node_modules base/README.md base/LICENSE
|
||||
baseDist: $(PACKAGE_TS_FILES) $(BASE_TS_FILES) base/package.json base/node_modules base/README.md base/LICENSE
|
||||
(cd base && npm run tsc)
|
||||
# Copy hand-written .js/.d.ts pairs (no corresponding .ts source) into the output.
|
||||
cd base/lib && find . -name '*.js' | while read f; do \
|
||||
base="$${f%.js}"; \
|
||||
if [ -f "$$base.d.ts" ] && [ ! -f "$$base.ts" ]; then \
|
||||
mkdir -p "../../baseDist/$$(dirname "$$f")"; \
|
||||
cp "$$f" "../../baseDist/$$f"; \
|
||||
cp "$$base.d.ts" "../../baseDist/$$base.d.ts"; \
|
||||
fi; \
|
||||
done
|
||||
rsync -ac base/node_modules baseDist/
|
||||
cp base/package.json baseDist/package.json
|
||||
cp base/README.md baseDist/README.md
|
||||
cp base/LICENSE baseDist/LICENSE
|
||||
touch baseDist
|
||||
|
||||
dist: $(PACKAGE_TS_FILES) $(BASE_TS_FILES) package/package.json package/.npmignore package/node_modules package/README.md package/LICENSE
|
||||
dist: $(PACKAGE_TS_FILES) $(BASE_TS_FILES) package/package.json package/.npmignore package/node_modules package/README.md package/LICENSE
|
||||
(cd package && npm run tsc)
|
||||
cd base/lib && find . -name '*.js' | while read f; do \
|
||||
base="$${f%.js}"; \
|
||||
if [ -f "$$base.d.ts" ] && [ ! -f "$$base.ts" ]; then \
|
||||
mkdir -p "../../dist/base/lib/$$(dirname "$$f")"; \
|
||||
cp "$$f" "../../dist/base/lib/$$f"; \
|
||||
cp "$$base.d.ts" "../../dist/base/lib/$$base.d.ts"; \
|
||||
fi; \
|
||||
done
|
||||
rsync -ac package/node_modules dist/
|
||||
cp package/.npmignore dist/.npmignore
|
||||
cp package/package.json dist/package.json
|
||||
|
||||
@@ -8,104 +8,6 @@ export * as types from './types'
|
||||
export * as T from './types'
|
||||
export * as yaml from 'yaml'
|
||||
export * as inits from './inits'
|
||||
import { z as _z } from 'zod'
|
||||
import { zodDeepPartial } from 'zod-deep-partial'
|
||||
import type { DeepPartial } from './types'
|
||||
|
||||
type ZodDeepPartial = <T>(a: _z.ZodType<T>) => _z.ZodType<DeepPartial<T>>
|
||||
|
||||
// Recursively make all ZodObjects in a schema loose (preserve extra keys at every nesting level).
|
||||
// Uses _zod.def.type duck-typing instead of instanceof to avoid issues with mismatched zod versions.
|
||||
function deepLoose<S extends _z.ZodType>(schema: S): S {
|
||||
const def = (schema as any)._zod?.def
|
||||
if (!def) return schema
|
||||
let result: _z.ZodType
|
||||
switch (def.type) {
|
||||
case 'optional':
|
||||
result = deepLoose(def.innerType).optional()
|
||||
break
|
||||
case 'nullable':
|
||||
result = deepLoose(def.innerType).nullable()
|
||||
break
|
||||
case 'object': {
|
||||
const newShape: Record<string, _z.ZodType> = {}
|
||||
for (const key in (schema as any).shape) {
|
||||
newShape[key] = deepLoose((schema as any).shape[key])
|
||||
}
|
||||
result = _z.looseObject(newShape)
|
||||
break
|
||||
}
|
||||
case 'array':
|
||||
result = _z.array(deepLoose(def.element))
|
||||
break
|
||||
case 'union':
|
||||
result = _z.union(def.options.map((o: _z.ZodType) => deepLoose(o)))
|
||||
break
|
||||
case 'intersection':
|
||||
result = _z.intersection(deepLoose(def.left), deepLoose(def.right))
|
||||
break
|
||||
case 'record':
|
||||
result = _z.record(def.keyType, deepLoose(def.valueType))
|
||||
break
|
||||
case 'tuple':
|
||||
result = _z.tuple(def.items.map((i: _z.ZodType) => deepLoose(i)))
|
||||
break
|
||||
case 'lazy':
|
||||
result = _z.lazy(() => deepLoose(def.getter()))
|
||||
break
|
||||
default:
|
||||
return schema
|
||||
}
|
||||
return result as S
|
||||
}
|
||||
|
||||
type ZodDeepLoose = <T>(a: _z.ZodType<T>) => _z.ZodType<T>
|
||||
|
||||
// Add deepPartial and deepLoose to z at runtime
|
||||
;(_z as any).deepPartial = <T>(a: _z.ZodType<T>) => deepLoose(zodDeepPartial(a))
|
||||
;(_z as any).deepLoose = deepLoose
|
||||
|
||||
// Augment zod's z namespace so z.deepPartial and z.deepLoose are typed
|
||||
declare module 'zod' {
|
||||
namespace z {
|
||||
const deepPartial: ZodDeepPartial
|
||||
const deepLoose: ZodDeepLoose
|
||||
}
|
||||
}
|
||||
|
||||
// Override z.object to produce loose objects by default (extra keys are preserved, not stripped).
|
||||
const _origObject = _z.object
|
||||
const _patchedObject = (...args: Parameters<typeof _z.object>) =>
|
||||
_origObject(...args).loose()
|
||||
|
||||
// In CJS (Node.js), patch the source module in require.cache where 'object' is a writable property;
|
||||
// the CJS getter chain (index → external → schemas) then relays the patched version.
|
||||
// We walk only the zod entry module's dependency tree and match by identity (=== origObject).
|
||||
try {
|
||||
const _zodModule = require.cache[require.resolve('zod')]
|
||||
for (const child of _zodModule?.children ?? []) {
|
||||
for (const grandchild of child.children ?? []) {
|
||||
const desc = Object.getOwnPropertyDescriptor(grandchild.exports, 'object')
|
||||
if (desc?.value === _origObject && desc.writable) {
|
||||
grandchild.exports.object = _patchedObject
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// Not in CJS/Node environment (e.g. browser) — require.cache unavailable
|
||||
}
|
||||
|
||||
// z.object is a non-configurable getter on the zod namespace, so we can't override it directly.
|
||||
// Shadow it by exporting a new object with _z as prototype and our patched object on the instance.
|
||||
const z: typeof _z = Object.create(_z, {
|
||||
object: {
|
||||
value: _patchedObject,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
},
|
||||
})
|
||||
|
||||
export { z }
|
||||
export { z } from './zExport'
|
||||
|
||||
export * as utils from './util'
|
||||
|
||||
14
sdk/base/lib/zExport.d.ts
vendored
Normal file
14
sdk/base/lib/zExport.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import { z as _z } from 'zod'
|
||||
import type { DeepPartial } from './types'
|
||||
|
||||
type ZodDeepPartial = <T>(a: _z.ZodType<T>) => _z.ZodType<DeepPartial<T>>
|
||||
type ZodDeepLoose = <T>(a: _z.ZodType<T>) => _z.ZodType<T>
|
||||
|
||||
declare module 'zod' {
|
||||
namespace z {
|
||||
const deepPartial: ZodDeepPartial
|
||||
const deepLoose: ZodDeepLoose
|
||||
}
|
||||
}
|
||||
|
||||
export { _z as z }
|
||||
92
sdk/base/lib/zExport.js
Normal file
92
sdk/base/lib/zExport.js
Normal file
@@ -0,0 +1,92 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
|
||||
const zod_1 = require("zod");
|
||||
const zod_deep_partial_1 = require("zod-deep-partial");
|
||||
|
||||
// Recursively make all ZodObjects in a schema loose (preserve extra keys at every nesting level).
|
||||
// Uses _zod.def.type duck-typing instead of instanceof to avoid issues with mismatched zod versions.
|
||||
function deepLoose(schema) {
|
||||
const def = schema._zod?.def;
|
||||
if (!def) return schema;
|
||||
let result;
|
||||
switch (def.type) {
|
||||
case "optional":
|
||||
result = deepLoose(def.innerType).optional();
|
||||
break;
|
||||
case "nullable":
|
||||
result = deepLoose(def.innerType).nullable();
|
||||
break;
|
||||
case "object": {
|
||||
const newShape = {};
|
||||
for (const key in schema.shape) {
|
||||
newShape[key] = deepLoose(schema.shape[key]);
|
||||
}
|
||||
result = zod_1.z.looseObject(newShape);
|
||||
break;
|
||||
}
|
||||
case "array":
|
||||
result = zod_1.z.array(deepLoose(def.element));
|
||||
break;
|
||||
case "union":
|
||||
result = zod_1.z.union(def.options.map((o) => deepLoose(o)));
|
||||
break;
|
||||
case "intersection":
|
||||
result = zod_1.z.intersection(deepLoose(def.left), deepLoose(def.right));
|
||||
break;
|
||||
case "record":
|
||||
result = zod_1.z.record(def.keyType, deepLoose(def.valueType));
|
||||
break;
|
||||
case "tuple":
|
||||
result = zod_1.z.tuple(def.items.map((i) => deepLoose(i)));
|
||||
break;
|
||||
case "lazy":
|
||||
result = zod_1.z.lazy(() => deepLoose(def.getter()));
|
||||
break;
|
||||
default:
|
||||
return schema;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Add deepPartial and deepLoose to z at runtime
|
||||
zod_1.z.deepPartial = (a) =>
|
||||
deepLoose((0, zod_deep_partial_1.zodDeepPartial)(a));
|
||||
zod_1.z.deepLoose = deepLoose;
|
||||
|
||||
// Override z.object to produce loose objects by default (extra keys are preserved, not stripped).
|
||||
const _origObject = zod_1.z.object;
|
||||
const _patchedObject = (...args) => _origObject(...args).loose();
|
||||
|
||||
// In CJS (Node.js), patch the source module in require.cache where 'object' is a writable property;
|
||||
// the CJS getter chain (index → external → schemas) then relays the patched version.
|
||||
// We walk only the zod entry module's dependency tree and match by identity (=== origObject).
|
||||
try {
|
||||
const _zodModule = require.cache[require.resolve("zod")];
|
||||
for (const child of _zodModule?.children ?? []) {
|
||||
for (const grandchild of child.children ?? []) {
|
||||
const desc = Object.getOwnPropertyDescriptor(
|
||||
grandchild.exports,
|
||||
"object",
|
||||
);
|
||||
if (desc?.value === _origObject && desc.writable) {
|
||||
grandchild.exports.object = _patchedObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// Not in CJS/Node environment (e.g. browser) — require.cache unavailable
|
||||
}
|
||||
|
||||
// z.object is a non-configurable getter on the zod namespace, so we can't override it directly.
|
||||
// Shadow it by exporting a new object with _z as prototype and our patched object on the instance.
|
||||
const z = Object.create(zod_1.z, {
|
||||
object: {
|
||||
value: _patchedObject,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
},
|
||||
});
|
||||
|
||||
exports.z = z;
|
||||
Reference in New Issue
Block a user