@pikku/openapi-parser 0.12.20 → 0.12.22

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 CHANGED
@@ -1,5 +1,42 @@
1
1
  # @pikku/openapi-parser
2
2
 
3
+ ## 0.12.22
4
+
5
+ ### Patch Changes
6
+
7
+ - 17d8746: An addon generated with `pikku new addon --openapi` never built. Every function file declared its zod schemas next to an import of `#pikku/function`, and `pikku all` loads the file that declares a schema to convert it. At runtime `#pikku` resolves through the addon's `imports` into `dist/`, which the first build has not written yet, so every schema failed with `Could not convert Zod schema … Cannot find module …/dist/.pikku/function/index.js` and the build stopped there. Each operation's schemas now go in a sibling `<operation>.schemas.ts` that imports only zod, and the function file imports them from it.
8
+
9
+ The generated imports also named the wrong tree. An addon's generated code lives under `.pikku/addon/`, so `#pikku/function` and `#pikku/variables/…` pointed at leaves that do not exist, and `tsc` failed even once codegen had run. They are now `#pikku/addon/function` and `#pikku/addon/variables/…`, as the hand-written addon scaffold already had them.
10
+
11
+ `pikku validate` now reports an installed Pikku package that resolves a different copy of a type-identity package (`zod`, `kysely`, `@pikku/core`, `better-auth`) than the project as an error, `skewed-type-identity-…`, and the codegen preflight warns about it as `PKU719`. Under bun's isolated layout `@pikku/cli` can carry its own `zod` beside it in the store. Codegen then reads the app's schemas with a different zod than wrote them, and correct schemas fail to convert. The existing check only looked at dependencies linked from outside the project, so it never saw this case.
12
+
13
+ The `pikku-build` skill now recognises an OpenAPI spec or an n8n export handed over with the request, says so, converts it first, then carries on building the app. `pikku-addon` gains an OpenAPI reference and corrects its addon import paths and build steps. `pikku-n8n-import` joins the `core` install group.
14
+
15
+ ## 0.12.21
16
+
17
+ ### Patch Changes
18
+
19
+ - 4c7a1b5: Run the monorepo's own scripts through bun instead of yarn. What moves is the
20
+ package manager each package's `prepublishOnly` and build scripts invoke, plus
21
+ the two manifest fixes bun needs to resolve the tree: `uWebSockets.js` is
22
+ declared with an explicit `github:` specifier, and `@pikku/uws-handler` marks
23
+ its `uWebSockets.js` peer optional so a bun install of a consumer that brings
24
+ its own uWS app does not try to fetch it from the registry.
25
+
26
+ Three published behaviours change, all of them cases where an isolated
27
+ `node_modules` or bun as the runtime had been papered over by yarn's hoisting:
28
+
29
+ - `@pikku/migrator-sql` turns foreign keys on when it opens a sqlite database
30
+ through bun. `node:sqlite` enforces them by default and `bun:sqlite` does not,
31
+ which silently turned every `ON DELETE CASCADE` into a no-op under
32
+ `bunx --bun pikku`.
33
+ - `@pikku/cli` resolves a deploy provider against the project being deployed
34
+ rather than against wherever the CLI itself is installed, which is what its
35
+ own "is not installed" error asks the user to arrange.
36
+ - `@pikku/cli` treats a specifier a runtime hands straight back — bun does this
37
+ for the modules it implements itself — as not resolved from the project, so
38
+ it falls back rather than loading the runtime's own copy.
39
+
3
40
  ## 0.12.20
4
41
 
5
42
  ### Patch Changes
@@ -14,9 +14,9 @@ export declare const DelegatedLoginSchema: z.ZodObject<{
14
14
  loginPath: z.ZodString;
15
15
  loginMethod: z.ZodDefault<z.ZodString>;
16
16
  credentials: z.ZodDefault<z.ZodArray<z.ZodEnum<{
17
+ apiKey: "apiKey";
17
18
  email: "email";
18
19
  password: "password";
19
- apiKey: "apiKey";
20
20
  }>>>;
21
21
  apiKeyHeader: z.ZodDefault<z.ZodString>;
22
22
  tokenPath: z.ZodString;
@@ -36,17 +36,17 @@ export declare const DelegatedLoginSchema: z.ZodObject<{
36
36
  export declare const AuthConfigSchema: z.ZodObject<{
37
37
  headerName: z.ZodOptional<z.ZodString>;
38
38
  headerFormat: z.ZodOptional<z.ZodEnum<{
39
- raw: "raw";
40
39
  bearer: "bearer";
40
+ raw: "raw";
41
41
  }>>;
42
42
  extraHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
43
43
  delegated: z.ZodOptional<z.ZodObject<{
44
44
  loginPath: z.ZodString;
45
45
  loginMethod: z.ZodDefault<z.ZodString>;
46
46
  credentials: z.ZodDefault<z.ZodArray<z.ZodEnum<{
47
+ apiKey: "apiKey";
47
48
  email: "email";
48
49
  password: "password";
49
- apiKey: "apiKey";
50
50
  }>>>;
51
51
  apiKeyHeader: z.ZodDefault<z.ZodString>;
52
52
  tokenPath: z.ZodString;
package/dist/codegen.js CHANGED
@@ -281,8 +281,11 @@ export function generateAddonFromOpenAPI(spec, vars, flags) {
281
281
  camelCase: flags.camelCase,
282
282
  });
283
283
  const inlineSchemas = singleSchemasPerOp.get(i) ?? new Set();
284
- const funcCode = generateFunctionFile(named, parsed, vars, funcCtx, spec, flags, inlineSchemas, sharedWithDeps, schemaIdentityMap);
285
- files[`src/functions/${named.functionName}.function.ts`] = funcCode;
284
+ const { functionFile, schemasFile } = generateFunctionFile(named, parsed, vars, funcCtx, spec, flags, inlineSchemas, sharedWithDeps, schemaIdentityMap);
285
+ files[`src/functions/${named.functionName}.function.ts`] = functionFile;
286
+ if (schemasFile) {
287
+ files[`src/functions/${named.functionName}.schemas.ts`] = schemasFile;
288
+ }
286
289
  functionExports.push(named.functionName);
287
290
  }
288
291
  // Delegated login: emit the upstream authenticate() implementation
@@ -516,14 +519,19 @@ function generateFunctionFile(named, parsed, vars, ctx, spec, flags, inlineSchem
516
519
  }
517
520
  // Determine error imports needed
518
521
  const errorClasses = getErrorClassesForResponses(parsed.errorResponses);
519
- const needsZod = hasInput || !!parsed.responseSchema || inlineSchemas.size > 0;
520
- if (needsZod) {
521
- lines.push("import { z } from 'zod'");
522
- }
523
- lines.push("import { pikkuSessionlessFunc } from '#pikku/function'");
522
+ const schemaExports = [
523
+ ...(hasInput && inputCode ? [inputName] : []),
524
+ ...(parsed.responseSchema && outputCode ? [outputName] : []),
525
+ ];
526
+ lines.push("import { pikkuSessionlessFunc } from '#pikku/addon/function'");
524
527
  if (errorClasses.length > 0) {
525
528
  lines.push(`import { ${errorClasses.join(', ')} } from '@pikku/core/errors'`);
526
529
  }
530
+ if (schemaExports.length > 0) {
531
+ lines.push(`import { ${schemaExports.join(', ')} } from './${named.functionName}.schemas.js'`);
532
+ }
533
+ lines.push('');
534
+ const schemaLines = ["import { z } from 'zod'"];
527
535
  // Import referenced component schemas from the types file.
528
536
  // Only import schemas that are in the shared set (not inlined ones).
529
537
  // In addition to the refs tracked through usedRefs, scan the generated Zod
@@ -543,10 +551,10 @@ function generateFunctionFile(named, parsed, vars, ctx, spec, flags, inlineSchem
543
551
  .filter(Boolean)),
544
552
  ].sort();
545
553
  if (schemaImports.length > 0) {
546
- lines.push(`import { ${schemaImports.join(', ')} } from '../${name}.types.js'`);
554
+ schemaLines.push(`import { ${schemaImports.join(', ')} } from '../${name}.types.js'`);
547
555
  }
548
556
  }
549
- lines.push('');
557
+ schemaLines.push('');
550
558
  // Emit inline (single-use) schema definitions before input/output
551
559
  if (inlineSchemas.size > 0) {
552
560
  // Build a mini component schemas map for just the inline schemas
@@ -607,7 +615,7 @@ function generateFunctionFile(named, parsed, vars, ctx, spec, flags, inlineSchem
607
615
  const emittedTypeNames = new Set();
608
616
  // Forward declarations for cycles and forward references within inline schemas
609
617
  if (forwardRefs.size > 0) {
610
- lines.push('// Forward declarations for circular references');
618
+ schemaLines.push('// Forward declarations for circular references');
611
619
  for (const sName of forwardRefs) {
612
620
  if (!inlineSchemas.has(sName))
613
621
  continue;
@@ -615,8 +623,8 @@ function generateFunctionFile(named, parsed, vars, ctx, spec, flags, inlineSchem
615
623
  const typeN = sanitizeTypeName(sName);
616
624
  emittedVarNames.add(varN);
617
625
  emittedTypeNames.add(typeN);
618
- lines.push(`const ${varN}: z.ZodType<any> = z.lazy(() => _${varN})`);
619
- lines.push('');
626
+ schemaLines.push(`const ${varN}: z.ZodType<any> = z.lazy(() => _${varN})`);
627
+ schemaLines.push('');
620
628
  }
621
629
  }
622
630
  for (const sName of inlineSorted) {
@@ -624,24 +632,24 @@ function generateFunctionFile(named, parsed, vars, ctx, spec, flags, inlineSchem
624
632
  emittedVarNames.add(varN);
625
633
  const zodCode = generatedCode.get(sName);
626
634
  if (forwardRefs.has(sName)) {
627
- lines.push(`const _${varN} = ${zodCode}`);
635
+ schemaLines.push(`const _${varN} = ${zodCode}`);
628
636
  }
629
637
  else {
630
- lines.push(`const ${varN} = ${zodCode}`);
638
+ schemaLines.push(`const ${varN} = ${zodCode}`);
631
639
  }
632
- lines.push('');
640
+ schemaLines.push('');
633
641
  }
634
642
  }
635
643
  }
636
644
  // Build Input schema (exported for pikku schema discovery)
637
645
  if (hasInput && inputCode) {
638
- lines.push(`export const ${inputName} = ${inputCode}`);
639
- lines.push('');
646
+ schemaLines.push(`export const ${inputName} = ${inputCode}`);
647
+ schemaLines.push('');
640
648
  }
641
649
  // Build Output schema (exported for pikku schema discovery)
642
650
  if (parsed.responseSchema && outputCode) {
643
- lines.push(`export const ${outputName} = ${outputCode}`);
644
- lines.push('');
651
+ schemaLines.push(`export const ${outputName} = ${outputCode}`);
652
+ schemaLines.push('');
645
653
  }
646
654
  const description = humanDescription(parsed);
647
655
  const method = parsed.method.toUpperCase();
@@ -671,7 +679,10 @@ function generateFunctionFile(named, parsed, vars, ctx, spec, flags, inlineSchem
671
679
  lines.push(funcConfig.join('\n'));
672
680
  lines.push('})');
673
681
  lines.push('');
674
- return lines.join('\n');
682
+ return {
683
+ functionFile: lines.join('\n'),
684
+ schemasFile: schemaExports.length > 0 ? schemaLines.join('\n') : undefined,
685
+ };
675
686
  }
676
687
  function buildInputSchema(parsed, ctx) {
677
688
  const props = [];
@@ -950,7 +961,7 @@ function generateServiceFile(spec, opPairs, vars, flags) {
950
961
  if (allErrorClasses.size > 0) {
951
962
  lines.push(`import { ${[...allErrorClasses].sort().join(', ')} } from '@pikku/core/errors'`);
952
963
  }
953
- lines.push(`import type { TypedVariablesService } from '#pikku/variables/pikku-variables.gen.js'`);
964
+ lines.push(`import type { TypedVariablesService } from '#pikku/addon/variables/pikku-variables.gen.js'`);
954
965
  lines.push('');
955
966
  // Generate route map from parsed operations
956
967
  const routes = {};
package/package.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "name": "@pikku/openapi-parser",
3
- "version": "0.12.20",
3
+ "version": "0.12.22",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/pikkujs/pikku.git",
7
+ "directory": "packages/openapi-parser"
8
+ },
4
9
  "description": "OpenAPI spec parser and code generator for Pikku",
5
10
  "author": "yasser.fadl@gmail.com",
6
11
  "license": "MIT",
@@ -12,7 +17,7 @@
12
17
  "ncu": "npx npm-check-updates",
13
18
  "build": "tsc -b",
14
19
  "test": "node --import tsx --test src/**/*.test.ts",
15
- "prepublishOnly": "yarn build"
20
+ "prepublishOnly": "bun run build"
16
21
  },
17
22
  "exports": {
18
23
  ".": "./dist/index.js"
@@ -20,8 +25,5 @@
20
25
  "dependencies": {
21
26
  "yaml": "^2.9.0",
22
27
  "zod": "^4"
23
- },
24
- "devDependencies": {
25
- "typescript": "^6.0.3"
26
28
  }
27
- }
29
+ }
@@ -1,94 +0,0 @@
1
- /**
2
- * Operator/agent-supplied auth configuration that overrides or augments an
3
- * OpenAPI spec's securitySchemes. Needed for real-world enterprise specs that
4
- * carry no machine-readable auth at all (auth described only in prose), or
5
- * that use a custom auth header the spec doesn't declare.
6
- */
7
- import { readFile } from 'fs/promises'
8
- import { z } from 'zod'
9
-
10
- export const DelegatedClaimsSchema = z.object({
11
- /** Where identity claims live: the decoded login-JWT payload, or the login response body. */
12
- source: z.enum(['jwt', 'response']),
13
- /** Dot-path to the stable upstream user id (e.g. 'user._id'). */
14
- externalId: z.string(),
15
- email: z.string(),
16
- /** One dot-path, or several joined with a space (e.g. first + last name). */
17
- name: z.union([z.string(), z.array(z.string())]).optional(),
18
- role: z.string().optional(),
19
- tenantId: z.string().optional(),
20
- })
21
-
22
- export const DelegatedLoginSchema = z.object({
23
- /** Spec-relative path of the login operation (e.g. '/users/login'). */
24
- loginPath: z.string(),
25
- loginMethod: z.string().default('post'),
26
- /** Which credential fields the login accepts. email/password go in the JSON body; apiKey in a header. */
27
- credentials: z
28
- .array(z.enum(['email', 'password', 'apiKey']))
29
- .default(['email', 'password']),
30
- /** Header carrying the apiKey when 'apiKey' is a supported credential. */
31
- apiKeyHeader: z.string().default('x-api-key'),
32
- /** Dot-path to the token in the login response (e.g. 'token'). */
33
- tokenPath: z.string(),
34
- /** Dot-path to an epoch-seconds expiry in the response; defaults to the JWT `exp` claim when source is jwt. */
35
- expiresAtPath: z.string().optional(),
36
- claims: DelegatedClaimsSchema,
37
- })
38
-
39
- export const AuthConfigSchema = z.object({
40
- /** Auth header the API expects on authenticated calls (e.g. 'authentication'). Overrides the spec. */
41
- headerName: z.string().optional(),
42
- /** 'raw' sends the bare token; 'bearer' prefixes it. Default: bearer for Authorization, raw for custom headers. */
43
- headerFormat: z.enum(['raw', 'bearer']).optional(),
44
- /**
45
- * Static headers sent on EVERY request — the delegated login call and all
46
- * proxied API calls. Needed for upstreams that route on a header, e.g. a
47
- * multi-tenant API that resolves the tenant from an `Origin` header and
48
- * rejects requests without it.
49
- */
50
- extraHeaders: z.record(z.string(), z.string()).optional(),
51
- /** Present when end-users sign in with their existing upstream credentials (delegated login). */
52
- delegated: DelegatedLoginSchema.optional(),
53
- })
54
-
55
- export type DelegatedLoginConfig = z.infer<typeof DelegatedLoginSchema>
56
- export type AuthConfig = z.infer<typeof AuthConfigSchema>
57
-
58
- /** The effective value template for the auth header. */
59
- export const authHeaderValue = (
60
- config: AuthConfig,
61
- tokenExpr: string
62
- ): { header: string; value: string } => {
63
- const header = config.headerName ?? 'Authorization'
64
- const format =
65
- config.headerFormat ??
66
- (config.headerName && config.headerName !== 'Authorization'
67
- ? 'raw'
68
- : 'bearer')
69
- return {
70
- header,
71
- value: format === 'bearer' ? `\`Bearer \${${tokenExpr}}\`` : tokenExpr,
72
- }
73
- }
74
-
75
- /** Load and validate an auth-config JSON file; throws with the zod issue list on mismatch. */
76
- export async function loadAuthConfig(filePath: string): Promise<AuthConfig> {
77
- const raw = await readFile(filePath, 'utf-8')
78
- let parsed: unknown
79
- try {
80
- parsed = JSON.parse(raw)
81
- } catch (error) {
82
- throw new Error(
83
- `Auth config ${filePath} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`
84
- )
85
- }
86
- const result = AuthConfigSchema.safeParse(parsed)
87
- if (!result.success) {
88
- const issues = result.error.issues
89
- .map((i) => ` ${i.path.join('.') || '(root)'}: ${i.message}`)
90
- .join('\n')
91
- throw new Error(`Auth config ${filePath} is invalid:\n${issues}`)
92
- }
93
- return result.data
94
- }