@orpc/openapi 0.0.0-next.2f8ca7f → 0.0.0-next.4555a17

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.
@@ -42,8 +42,12 @@ function eachContractProcedureLeaf(options, callback, result = [], isCurrentRout
42
42
  }
43
43
  return result;
44
44
  }
45
+ function standardizeHTTPPath(path) {
46
+ return `/${path.replace(/\/{2,}/g, "/").replace(/^\/|\/$/g, "")}`;
47
+ }
45
48
 
46
49
  export {
47
- eachContractProcedureLeaf
50
+ eachContractProcedureLeaf,
51
+ standardizeHTTPPath
48
52
  };
49
- //# sourceMappingURL=chunk-KZIT2WCV.js.map
53
+ //# sourceMappingURL=chunk-7HD5IZWG.js.map
package/dist/fetch.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import {
2
- eachContractProcedureLeaf
3
- } from "./chunk-KZIT2WCV.js";
2
+ eachContractProcedureLeaf,
3
+ standardizeHTTPPath
4
+ } from "./chunk-7HD5IZWG.js";
4
5
 
5
6
  // src/fetch/base-handler.ts
6
- import { ORPC_HEADER, standardizeHTTPPath } from "@orpc/contract";
7
7
  import { createProcedureCaller, isLazy, isProcedure, LAZY_LOADER_SYMBOL, LAZY_ROUTER_PREFIX_SYMBOL, ORPCError } from "@orpc/server";
8
- import { executeWithHooks, isPlainObject, mapValues, trim, value } from "@orpc/shared";
8
+ import { executeWithHooks, isPlainObject, mapValues, ORPC_PROTOCOL_HEADER, ORPC_PROTOCOL_VALUE, trim, value } from "@orpc/shared";
9
9
  import { OpenAPIDeserializer, OpenAPISerializer, zodCoerce } from "@orpc/transformer";
10
10
  function createOpenAPIHandler(createHonoRouter) {
11
11
  const resolveRouter = createResolveRouter(createHonoRouter);
12
12
  return async (options) => {
13
- if (options.request.headers.get(ORPC_HEADER) !== null) {
13
+ if (options.request.headers.get(ORPC_PROTOCOL_HEADER)?.includes(ORPC_PROTOCOL_VALUE)) {
14
14
  return void 0;
15
15
  }
16
16
  const context = await value(options.context);
@@ -33,8 +33,8 @@ function createOpenAPIHandler(createHonoRouter) {
33
33
  message: "Not found"
34
34
  });
35
35
  }
36
- const params = procedure.zz$p.contract.zz$cp.InputSchema ? zodCoerce(
37
- procedure.zz$p.contract.zz$cp.InputSchema,
36
+ const params = procedure.zz$p.contract["~orpc"].InputSchema ? zodCoerce(
37
+ procedure.zz$p.contract["~orpc"].InputSchema,
38
38
  match.params,
39
39
  { bracketNotation: true }
40
40
  ) : match.params;
@@ -88,8 +88,8 @@ var pendingCache = /* @__PURE__ */ new Map();
88
88
  function createResolveRouter(createHonoRouter) {
89
89
  const addRoutes = (routing, pending, options) => {
90
90
  const lazies = eachContractProcedureLeaf(options, ({ path, contract }) => {
91
- const method = contract.zz$cp.method ?? "POST";
92
- const httpPath = contract.zz$cp.path ? openAPIPathToRouterPath(contract.zz$cp.path) : `/${path.map(encodeURIComponent).join("/")}`;
91
+ const method = contract["~orpc"].route?.method ?? "POST";
92
+ const httpPath = contract["~orpc"].route?.path ? openAPIPathToRouterPath(contract["~orpc"].route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
93
93
  routing.add(method, httpPath, path);
94
94
  });
95
95
  pending.ref.push(...lazies);
@@ -164,7 +164,7 @@ function mergeParamsAndInput(coercedParams, input) {
164
164
  }
165
165
  async function deserializeInput(request, procedure) {
166
166
  const deserializer = new OpenAPIDeserializer({
167
- schema: procedure.zz$p.contract.zz$cp.InputSchema
167
+ schema: procedure.zz$p.contract["~orpc"].InputSchema
168
168
  });
169
169
  try {
170
170
  return await deserializer.deserialize(request);
@@ -702,7 +702,6 @@ export {
702
702
  createOpenAPIHandler,
703
703
  createOpenAPIServerHandler,
704
704
  createOpenAPIServerlessHandler,
705
- createResolveRouter,
706
- openAPIPathToRouterPath
705
+ createResolveRouter
707
706
  };
708
707
  //# sourceMappingURL=fetch.js.map
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
- eachContractProcedureLeaf
3
- } from "./chunk-KZIT2WCV.js";
2
+ eachContractProcedureLeaf,
3
+ standardizeHTTPPath
4
+ } from "./chunk-7HD5IZWG.js";
4
5
 
5
6
  // src/generator.ts
6
7
  import { isContractProcedure } from "@orpc/contract";
@@ -3943,10 +3944,15 @@ var NON_LOGIC_KEYWORDS = [
3943
3944
  var UNSUPPORTED_JSON_SCHEMA = { not: {} };
3944
3945
  var UNDEFINED_JSON_SCHEMA = { const: "undefined" };
3945
3946
  function zodToJsonSchema(schema, options) {
3947
+ if (schema["~standard"].vendor !== "zod") {
3948
+ console.warn(`Generate JSON schema not support ${schema["~standard"].vendor} yet`);
3949
+ return {};
3950
+ }
3951
+ const schema__ = schema;
3946
3952
  if (!options?.isHandledCustomJSONSchema) {
3947
- const customJSONSchema = getCustomJSONSchema(schema._def, options);
3953
+ const customJSONSchema = getCustomJSONSchema(schema__._def, options);
3948
3954
  if (customJSONSchema) {
3949
- const json = zodToJsonSchema(schema, {
3955
+ const json = zodToJsonSchema(schema__, {
3950
3956
  ...options,
3951
3957
  isHandledCustomJSONSchema: true
3952
3958
  });
@@ -3957,13 +3963,13 @@ function zodToJsonSchema(schema, options) {
3957
3963
  }
3958
3964
  }
3959
3965
  const childOptions = { ...options, isHandledCustomJSONSchema: false };
3960
- const customType = getCustomZodType(schema._def);
3966
+ const customType = getCustomZodType(schema__._def);
3961
3967
  switch (customType) {
3962
3968
  case "Blob": {
3963
3969
  return { type: "string", contentMediaType: "*/*" };
3964
3970
  }
3965
3971
  case "File": {
3966
- const mimeType = getCustomZodFileMimeType(schema._def) ?? "*/*";
3972
+ const mimeType = getCustomZodFileMimeType(schema__._def) ?? "*/*";
3967
3973
  return { type: "string", contentMediaType: mimeType };
3968
3974
  }
3969
3975
  case "Invalid Date": {
@@ -3980,10 +3986,10 @@ function zodToJsonSchema(schema, options) {
3980
3986
  }
3981
3987
  }
3982
3988
  const _expectedCustomType = customType;
3983
- const typeName = schema._def.typeName;
3989
+ const typeName = schema__._def.typeName;
3984
3990
  switch (typeName) {
3985
3991
  case ZodFirstPartyTypeKind.ZodString: {
3986
- const schema_ = schema;
3992
+ const schema_ = schema__;
3987
3993
  const json = { type: "string" };
3988
3994
  for (const check of schema_._def.checks) {
3989
3995
  switch (check.kind) {
@@ -4051,6 +4057,12 @@ function zodToJsonSchema(schema, options) {
4051
4057
  case "ip":
4052
4058
  json.format = Format.IPv4;
4053
4059
  break;
4060
+ case "jwt":
4061
+ json.pattern = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$";
4062
+ break;
4063
+ case "base64url":
4064
+ json.pattern = "^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$";
4065
+ break;
4054
4066
  default: {
4055
4067
  const _expect = check.kind;
4056
4068
  }
@@ -4059,7 +4071,7 @@ function zodToJsonSchema(schema, options) {
4059
4071
  return json;
4060
4072
  }
4061
4073
  case ZodFirstPartyTypeKind.ZodNumber: {
4062
- const schema_ = schema;
4074
+ const schema_ = schema__;
4063
4075
  const json = { type: "number" };
4064
4076
  for (const check of schema_._def.checks) {
4065
4077
  switch (check.kind) {
@@ -4104,23 +4116,23 @@ function zodToJsonSchema(schema, options) {
4104
4116
  return UNDEFINED_JSON_SCHEMA;
4105
4117
  }
4106
4118
  case ZodFirstPartyTypeKind.ZodLiteral: {
4107
- const schema_ = schema;
4119
+ const schema_ = schema__;
4108
4120
  return { const: schema_._def.value };
4109
4121
  }
4110
4122
  case ZodFirstPartyTypeKind.ZodEnum: {
4111
- const schema_ = schema;
4123
+ const schema_ = schema__;
4112
4124
  return {
4113
4125
  enum: schema_._def.values
4114
4126
  };
4115
4127
  }
4116
4128
  case ZodFirstPartyTypeKind.ZodNativeEnum: {
4117
- const schema_ = schema;
4129
+ const schema_ = schema__;
4118
4130
  return {
4119
4131
  enum: Object.values(schema_._def.values)
4120
4132
  };
4121
4133
  }
4122
4134
  case ZodFirstPartyTypeKind.ZodArray: {
4123
- const schema_ = schema;
4135
+ const schema_ = schema__;
4124
4136
  const def = schema_._def;
4125
4137
  const json = { type: "array" };
4126
4138
  if (def.exactLength) {
@@ -4136,7 +4148,7 @@ function zodToJsonSchema(schema, options) {
4136
4148
  return json;
4137
4149
  }
4138
4150
  case ZodFirstPartyTypeKind.ZodTuple: {
4139
- const schema_ = schema;
4151
+ const schema_ = schema__;
4140
4152
  const prefixItems = [];
4141
4153
  const json = { type: "array" };
4142
4154
  for (const item of schema_._def.items) {
@@ -4154,7 +4166,7 @@ function zodToJsonSchema(schema, options) {
4154
4166
  return json;
4155
4167
  }
4156
4168
  case ZodFirstPartyTypeKind.ZodObject: {
4157
- const schema_ = schema;
4169
+ const schema_ = schema__;
4158
4170
  const json = { type: "object" };
4159
4171
  const properties = {};
4160
4172
  const required = [];
@@ -4190,7 +4202,7 @@ function zodToJsonSchema(schema, options) {
4190
4202
  return json;
4191
4203
  }
4192
4204
  case ZodFirstPartyTypeKind.ZodRecord: {
4193
- const schema_ = schema;
4205
+ const schema_ = schema__;
4194
4206
  const json = { type: "object" };
4195
4207
  json.additionalProperties = zodToJsonSchema(
4196
4208
  schema_._def.valueType,
@@ -4199,14 +4211,14 @@ function zodToJsonSchema(schema, options) {
4199
4211
  return json;
4200
4212
  }
4201
4213
  case ZodFirstPartyTypeKind.ZodSet: {
4202
- const schema_ = schema;
4214
+ const schema_ = schema__;
4203
4215
  return {
4204
4216
  type: "array",
4205
4217
  items: zodToJsonSchema(schema_._def.valueType, childOptions)
4206
4218
  };
4207
4219
  }
4208
4220
  case ZodFirstPartyTypeKind.ZodMap: {
4209
- const schema_ = schema;
4221
+ const schema_ = schema__;
4210
4222
  return {
4211
4223
  type: "array",
4212
4224
  items: {
@@ -4222,7 +4234,7 @@ function zodToJsonSchema(schema, options) {
4222
4234
  }
4223
4235
  case ZodFirstPartyTypeKind.ZodUnion:
4224
4236
  case ZodFirstPartyTypeKind.ZodDiscriminatedUnion: {
4225
- const schema_ = schema;
4237
+ const schema_ = schema__;
4226
4238
  const anyOf = [];
4227
4239
  for (const s of schema_._def.options) {
4228
4240
  anyOf.push(zodToJsonSchema(s, childOptions));
@@ -4230,7 +4242,7 @@ function zodToJsonSchema(schema, options) {
4230
4242
  return { anyOf };
4231
4243
  }
4232
4244
  case ZodFirstPartyTypeKind.ZodIntersection: {
4233
- const schema_ = schema;
4245
+ const schema_ = schema__;
4234
4246
  const allOf = [];
4235
4247
  for (const s of [schema_._def.left, schema_._def.right]) {
4236
4248
  allOf.push(zodToJsonSchema(s, childOptions));
@@ -4238,7 +4250,7 @@ function zodToJsonSchema(schema, options) {
4238
4250
  return { allOf };
4239
4251
  }
4240
4252
  case ZodFirstPartyTypeKind.ZodLazy: {
4241
- const schema_ = schema;
4253
+ const schema_ = schema__;
4242
4254
  const maxLazyDepth = childOptions?.maxLazyDepth ?? 5;
4243
4255
  const lazyDepth = childOptions?.lazyDepth ?? 0;
4244
4256
  if (lazyDepth > maxLazyDepth) {
@@ -4255,44 +4267,44 @@ function zodToJsonSchema(schema, options) {
4255
4267
  return {};
4256
4268
  }
4257
4269
  case ZodFirstPartyTypeKind.ZodOptional: {
4258
- const schema_ = schema;
4270
+ const schema_ = schema__;
4259
4271
  const inner = zodToJsonSchema(schema_._def.innerType, childOptions);
4260
4272
  return {
4261
4273
  anyOf: [UNDEFINED_JSON_SCHEMA, inner]
4262
4274
  };
4263
4275
  }
4264
4276
  case ZodFirstPartyTypeKind.ZodReadonly: {
4265
- const schema_ = schema;
4277
+ const schema_ = schema__;
4266
4278
  return zodToJsonSchema(schema_._def.innerType, childOptions);
4267
4279
  }
4268
4280
  case ZodFirstPartyTypeKind.ZodDefault: {
4269
- const schema_ = schema;
4281
+ const schema_ = schema__;
4270
4282
  return zodToJsonSchema(schema_._def.innerType, childOptions);
4271
4283
  }
4272
4284
  case ZodFirstPartyTypeKind.ZodEffects: {
4273
- const schema_ = schema;
4285
+ const schema_ = schema__;
4274
4286
  if (schema_._def.effect.type === "transform" && childOptions?.mode === "output") {
4275
4287
  return {};
4276
4288
  }
4277
4289
  return zodToJsonSchema(schema_._def.schema, childOptions);
4278
4290
  }
4279
4291
  case ZodFirstPartyTypeKind.ZodCatch: {
4280
- const schema_ = schema;
4292
+ const schema_ = schema__;
4281
4293
  return zodToJsonSchema(schema_._def.innerType, childOptions);
4282
4294
  }
4283
4295
  case ZodFirstPartyTypeKind.ZodBranded: {
4284
- const schema_ = schema;
4296
+ const schema_ = schema__;
4285
4297
  return zodToJsonSchema(schema_._def.type, childOptions);
4286
4298
  }
4287
4299
  case ZodFirstPartyTypeKind.ZodPipeline: {
4288
- const schema_ = schema;
4300
+ const schema_ = schema__;
4289
4301
  return zodToJsonSchema(
4290
4302
  childOptions?.mode === "output" ? schema_._def.out : schema_._def.in,
4291
4303
  childOptions
4292
4304
  );
4293
4305
  }
4294
4306
  case ZodFirstPartyTypeKind.ZodNullable: {
4295
- const schema_ = schema;
4307
+ const schema_ = schema__;
4296
4308
  const inner = zodToJsonSchema(schema_._def.innerType, childOptions);
4297
4309
  return {
4298
4310
  anyOf: [{ type: "null" }, inner]
@@ -4361,12 +4373,12 @@ async function generateOpenAPI(opts, options) {
4361
4373
  if (!isContractProcedure(contract)) {
4362
4374
  return;
4363
4375
  }
4364
- const internal = contract.zz$cp;
4365
- if (ignoreUndefinedPathProcedures && internal.path === void 0) {
4376
+ const internal = contract["~orpc"];
4377
+ if (ignoreUndefinedPathProcedures && internal.route?.path === void 0) {
4366
4378
  return;
4367
4379
  }
4368
- const httpPath = internal.path ?? `/${path.map(encodeURIComponent).join("/")}`;
4369
- const method = internal.method ?? "POST";
4380
+ const httpPath = internal.route?.path ? standardizeHTTPPath(internal.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
4381
+ const method = internal.route?.method ?? "POST";
4370
4382
  let inputSchema = internal.InputSchema ? zodToJsonSchema(internal.InputSchema, { mode: "input" }) : {};
4371
4383
  const outputSchema = internal.OutputSchema ? zodToJsonSchema(internal.OutputSchema, { mode: "output" }) : {};
4372
4384
  const params = (() => {
@@ -4501,7 +4513,9 @@ async function generateOpenAPI(opts, options) {
4501
4513
  };
4502
4514
  }
4503
4515
  return {
4504
- required: Boolean(internal.InputSchema?.isOptional()),
4516
+ required: Boolean(
4517
+ internal.InputSchema && "isOptional" in internal.InputSchema && typeof internal.InputSchema.isOptional === "function" ? internal.InputSchema.isOptional() : false
4518
+ ),
4505
4519
  content
4506
4520
  };
4507
4521
  })();
@@ -4526,8 +4540,8 @@ async function generateOpenAPI(opts, options) {
4526
4540
  content
4527
4541
  };
4528
4542
  })();
4529
- if (throwOnMissingTagDefinition && internal.tags) {
4530
- const missingTag = internal.tags.find((tag) => !rootTags.includes(tag));
4543
+ if (throwOnMissingTagDefinition && internal.route?.tags) {
4544
+ const missingTag = internal.route?.tags.find((tag) => !rootTags.includes(tag));
4531
4545
  if (missingTag !== void 0) {
4532
4546
  throw new Error(
4533
4547
  `Tag "${missingTag}" is missing definition. Please define it in OpenAPI root tags object. [${path.join(".")}]`
@@ -4535,10 +4549,10 @@ async function generateOpenAPI(opts, options) {
4535
4549
  }
4536
4550
  }
4537
4551
  const operation = {
4538
- summary: internal.summary,
4539
- description: internal.description,
4540
- deprecated: internal.deprecated,
4541
- tags: internal.tags,
4552
+ summary: internal.route?.summary,
4553
+ description: internal.route?.description,
4554
+ deprecated: internal.route?.deprecated,
4555
+ tags: internal.route?.tags,
4542
4556
  operationId: path.join("."),
4543
4557
  parameters: parameters.length ? parameters : void 0,
4544
4558
  requestBody,
@@ -1,4 +1,3 @@
1
- import type { HTTPPath } from '@orpc/contract';
2
1
  import type { ANY_LAZY_PROCEDURE, ANY_PROCEDURE, Router } from '@orpc/server';
3
2
  import type { FetchHandler } from '@orpc/server/fetch';
4
3
  import type { Router as HonoRouter } from 'hono/router';
@@ -10,6 +9,5 @@ export type ResolveRouter = (router: Router<any>, method: string, pathname: stri
10
9
  type Routing = HonoRouter<string[]>;
11
10
  export declare function createOpenAPIHandler(createHonoRouter: () => Routing): FetchHandler;
12
11
  export declare function createResolveRouter(createHonoRouter: () => Routing): ResolveRouter;
13
- export declare function openAPIPathToRouterPath(path: HTTPPath): string;
14
12
  export {};
15
13
  //# sourceMappingURL=base-handler.d.ts.map
@@ -1,7 +1,7 @@
1
- import type { ContractProcedure, ContractRouter, WELL_CONTRACT_PROCEDURE } from '@orpc/contract';
1
+ import type { ANY_CONTRACT_PROCEDURE, ContractRouter, HTTPPath, WELL_CONTRACT_PROCEDURE } from '@orpc/contract';
2
2
  import type { ANY_LAZY_PROCEDURE, ANY_PROCEDURE, Lazy, Router } from '@orpc/server';
3
3
  export interface EachLeafOptions {
4
- router: ANY_PROCEDURE | Router<any> | ContractRouter | ContractProcedure<any, any>;
4
+ router: ANY_PROCEDURE | Router<any> | ContractRouter | ANY_CONTRACT_PROCEDURE;
5
5
  path: string[];
6
6
  }
7
7
  export interface EachLeafCallbackOptions {
@@ -13,4 +13,5 @@ export interface EachContractLeafResultItem {
13
13
  path: string[];
14
14
  }
15
15
  export declare function eachContractProcedureLeaf(options: EachLeafOptions, callback: (options: EachLeafCallbackOptions) => void, result?: EachContractLeafResultItem[], isCurrentRouterContract?: boolean): EachContractLeafResultItem[];
16
+ export declare function standardizeHTTPPath(path: HTTPPath): HTTPPath;
16
17
  //# sourceMappingURL=utils.d.ts.map
@@ -1,5 +1,5 @@
1
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
1
2
  import { type JSONSchema } from 'json-schema-typed/draft-2020-12';
2
- import { type ZodTypeAny } from 'zod';
3
3
  export declare const NON_LOGIC_KEYWORDS: ("$anchor" | "$comment" | "$defs" | "$dynamicAnchor" | "$dynamicRef" | "$id" | "$schema" | "$vocabulary" | "contentEncoding" | "contentMediaType" | "default" | "definitions" | "deprecated" | "description" | "examples" | "format" | "readOnly" | "title" | "writeOnly")[];
4
4
  export declare const UNSUPPORTED_JSON_SCHEMA: {
5
5
  not: {};
@@ -35,7 +35,7 @@ export interface ZodToJsonSchemaOptions {
35
35
  */
36
36
  isHandledCustomJSONSchema?: boolean;
37
37
  }
38
- export declare function zodToJsonSchema(schema: ZodTypeAny, options?: ZodToJsonSchemaOptions): Exclude<JSONSchema, boolean>;
38
+ export declare function zodToJsonSchema(schema: StandardSchemaV1, options?: ZodToJsonSchemaOptions): Exclude<JSONSchema, boolean>;
39
39
  export declare function extractJSONSchema(schema: JSONSchema, check: (schema: JSONSchema) => boolean, matches?: JSONSchema[]): {
40
40
  schema: JSONSchema | undefined;
41
41
  matches: JSONSchema[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/openapi",
3
3
  "type": "module",
4
- "version": "0.0.0-next.2f8ca7f",
4
+ "version": "0.0.0-next.4555a17",
5
5
  "license": "MIT",
6
6
  "homepage": "https://orpc.unnoq.com",
7
7
  "repository": {
@@ -34,19 +34,20 @@
34
34
  "dist"
35
35
  ],
36
36
  "dependencies": {
37
+ "@standard-schema/spec": "1.0.0-beta.4",
37
38
  "escape-string-regexp": "^5.0.0",
38
39
  "json-schema-typed": "^8.0.1",
39
40
  "openapi3-ts": "^4.4.0",
40
- "@orpc/contract": "0.0.0-next.2f8ca7f",
41
- "@orpc/shared": "0.0.0-next.2f8ca7f",
42
- "@orpc/server": "0.0.0-next.2f8ca7f",
43
- "@orpc/transformer": "0.0.0-next.2f8ca7f",
44
- "@orpc/zod": "0.0.0-next.2f8ca7f"
41
+ "@orpc/contract": "0.0.0-next.4555a17",
42
+ "@orpc/server": "0.0.0-next.4555a17",
43
+ "@orpc/shared": "0.0.0-next.4555a17",
44
+ "@orpc/transformer": "0.0.0-next.4555a17",
45
+ "@orpc/zod": "0.0.0-next.4555a17"
45
46
  },
46
47
  "devDependencies": {
47
48
  "@readme/openapi-parser": "^2.6.0",
48
49
  "hono": "^4.6.12",
49
- "zod": "^3.23.8"
50
+ "zod": "^3.24.1"
50
51
  },
51
52
  "scripts": {
52
53
  "build": "tsup --clean --sourcemap --entry.index=src/index.ts --entry.fetch=src/fetch/index.ts --format=esm --onSuccess='tsc -b --noCheck'",