{"version":3,"sources":["../src/native-cooker-registry.ts"],"names":[],"mappings":"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","file":"native-cooker.mjs","sourcesContent":["import { createHash } from 'node:crypto';\nimport type {\n  ArtifactDescriptor,\n  AssetCodec,\n  AssetStageError,\n  CookProduct,\n  Result,\n} from '@forgeax/engine-types';\nimport { err, ok } from '@forgeax/engine-types';\n\nexport interface NativeCookArtifact {\n  readonly mediaType: string;\n  readonly assetCodec?: AssetCodec;\n  readonly bytes: Uint8Array;\n}\n\nexport interface NativeCookDraft<P = unknown> {\n  readonly guid: string;\n  readonly payload: P;\n  readonly refs: readonly string[];\n  readonly artifacts: Readonly<Record<string, NativeCookArtifact>>;\n  readonly inputFingerprint: string;\n  readonly sourceDependencies?: readonly string[];\n}\n\nexport interface NativeCooker<P = unknown, I = unknown> {\n  readonly key: string;\n  readonly discover?: (input: unknown) => I | Promise<I>;\n  cook(input: I): NativeCookDraft<P> | Promise<NativeCookDraft<P>>;\n}\n\nexport interface NativeCookTransactionSnapshot<P = unknown> {\n  readonly draft: NativeCookDraft<P>;\n  readonly generation: number;\n}\n\nexport interface NativeCookTransactionOptions<P = unknown, I = unknown> {\n  readonly key: string;\n  readonly input: I;\n  readonly previous?: NativeCookTransactionSnapshot<P>;\n  readonly validate?: (draft: NativeCookDraft<P>) => string | undefined;\n  readonly publish?: (draft: NativeCookDraft<P>, generation: number) => void | Promise<void>;\n}\n\nexport interface NativeCookTransactionResult<P = unknown> extends NativeCookTransactionSnapshot<P> {\n  readonly status: 'committed' | 'recovered';\n  readonly lastKnownGood: NativeCookDraft<P>;\n  readonly candidateGeneration: number;\n  readonly lastKnownGoodGeneration: number;\n  readonly recoveryHint?: string;\n}\n\nfunction canonicalize(value: unknown): unknown {\n  if (value instanceof Uint8Array) return Buffer.from(value).toString('base64');\n  if (Array.isArray(value)) return value.map(canonicalize);\n  if (typeof value !== 'object' || value === null) return value;\n  return Object.fromEntries(\n    Object.entries(value)\n      .sort(([left], [right]) => left.localeCompare(right))\n      .map(([key, nested]) => [key, canonicalize(nested)]),\n  );\n}\n\nfunction digestDraft<P>(draft: NativeCookDraft<P>): string {\n  const bytes = JSON.stringify(\n    canonicalize({\n      guid: draft.guid,\n      payload: draft.payload,\n      refs: draft.refs,\n      artifacts: draft.artifacts,\n    }),\n  );\n  return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;\n}\n\ntype NativeCookErrorDetail = Extract<\n  AssetStageError['detail'],\n  { readonly guid: string; readonly producer: string }\n>;\n\nfunction failure(key: string, detail: NativeCookErrorDetail): Result<never, AssetStageError> {\n  return err({\n    stage: 'native-cook',\n    code: 'native-cook-failed',\n    expected: 'a registered native cooker to produce a complete draft',\n    hint: 'register the cooker or repair its draft, then rerun recovery',\n    detail,\n    recovery: { action: `rerun native cooker ${key}`, retryable: true },\n  });\n}\n\nfunction transactionFailure(key: string, reason: string): Result<never, AssetStageError> {\n  return failure(key, { guid: 'unknown', producer: reason });\n}\n\nfunction thrownProducer(error: unknown): string {\n  if (error instanceof Error) return error.message;\n  if (typeof error === 'string') return error;\n  if (error !== null && typeof error === 'object') {\n    try {\n      return JSON.stringify(error);\n    } catch {\n      return Object.prototype.toString.call(error);\n    }\n  }\n  return String(error);\n}\n\nfunction recovered<P>(\n  key: string,\n  previous: NativeCookTransactionSnapshot<P>,\n): NativeCookTransactionResult<P> {\n  return {\n    ...previous,\n    status: 'recovered',\n    lastKnownGood: previous.draft,\n    candidateGeneration: previous.generation + 1,\n    lastKnownGoodGeneration: previous.generation,\n    recoveryHint: `repair ${key} and submit a new candidate generation`,\n  };\n}\n\n/** Injectable build-time table for native authored Pack producers. */\nexport class NativeCookerRegistry {\n  private readonly cookers = new Map<string, NativeCooker>();\n\n  register(cooker: NativeCooker): () => void {\n    if (typeof cooker.key !== 'string' || cooker.key.length === 0) {\n      throw new TypeError('NativeCookerRegistry.register: key must be a non-empty string');\n    }\n    if (typeof cooker.cook !== 'function') {\n      throw new TypeError(`NativeCookerRegistry.register: cooker ${cooker.key} must expose cook`);\n    }\n    if (this.cookers.has(cooker.key)) throw new TypeError(`duplicate native cooker ${cooker.key}`);\n    this.cookers.set(cooker.key, cooker);\n    return () => {\n      if (this.cookers.get(cooker.key) === cooker) this.cookers.delete(cooker.key);\n    };\n  }\n\n  get(key: string): NativeCooker | undefined {\n    return this.cookers.get(key);\n  }\n\n  registeredCookers(): readonly string[] {\n    return [...this.cookers.keys()];\n  }\n\n  async runDraft<P = unknown, I = unknown>(\n    key: string,\n    input: I,\n  ): Promise<Result<NativeCookDraft<P>, AssetStageError>> {\n    const cooker = this.cookers.get(key) as NativeCooker<P, I> | undefined;\n    if (cooker === undefined) {\n      return failure(key, { guid: 'unknown', producer: key });\n    }\n    let draft: NativeCookDraft<P>;\n    try {\n      const typedInput = cooker.discover === undefined ? input : await cooker.discover(input);\n      draft = await cooker.cook(typedInput);\n    } catch (error) {\n      return failure(key, { guid: 'unknown', producer: thrownProducer(error) });\n    }\n    if (\n      draft.guid.length === 0 ||\n      draft.inputFingerprint.length === 0 ||\n      !Array.isArray(draft.refs) ||\n      typeof draft.payload !== 'object' ||\n      draft.payload === null ||\n      typeof draft.artifacts !== 'object' ||\n      draft.artifacts === null ||\n      Object.entries(draft.artifacts).some(\n        ([, artifact]) =>\n          artifact === null ||\n          typeof artifact !== 'object' ||\n          typeof artifact.mediaType !== 'string' ||\n          artifact.mediaType.length === 0 ||\n          !(artifact.bytes instanceof Uint8Array),\n      )\n    ) {\n      return failure(key, { guid: draft.guid || 'unknown', producer: key });\n    }\n    return ok(draft);\n  }\n\n  async run<P = unknown, I = unknown>(\n    key: string,\n    input: I,\n  ): Promise<Result<CookProduct<P>, AssetStageError>> {\n    const draftResult = await this.runDraft<P, I>(key, input);\n    if (!draftResult.ok) return draftResult;\n    const draft = draftResult.value;\n    const digest = digestDraft(draft);\n    const artifacts: Record<string, ArtifactDescriptor> = {};\n    for (const [path, artifact] of Object.entries(draft.artifacts)) {\n      artifacts[path] = {\n        path,\n        mediaType: artifact.mediaType,\n        ...(artifact.assetCodec === undefined ? {} : { assetCodec: artifact.assetCodec }),\n        byteLength: artifact.bytes.byteLength,\n      };\n    }\n    const receipt = {\n      guid: draft.guid,\n      origin: 'authoredPack' as const,\n      status: 'succeeded' as const,\n      inputFingerprint: draft.inputFingerprint,\n      outputDigest: digest,\n    };\n    const product: CookProduct<P> = {\n      guid: draft.guid,\n      payload: draft.payload,\n      refs: draft.refs,\n      artifacts,\n      digest,\n      receipt,\n    };\n    return ok(product);\n  }\n\n  async runTransaction<P = unknown, I = unknown>(\n    options: NativeCookTransactionOptions<P, I>,\n  ): Promise<Result<NativeCookTransactionResult<P>, AssetStageError>> {\n    const candidate = await this.runDraft<P, I>(options.key, options.input);\n    if (!candidate.ok) {\n      return options.previous === undefined\n        ? candidate\n        : ok(recovered(options.key, options.previous));\n    }\n    const invalidReason = options.validate?.(candidate.value);\n    if (invalidReason !== undefined) {\n      return options.previous === undefined\n        ? transactionFailure(options.key, invalidReason)\n        : ok(recovered(options.key, options.previous));\n    }\n    const generation = (options.previous?.generation ?? 0) + 1;\n    try {\n      await options.publish?.(candidate.value, generation);\n    } catch {\n      return options.previous === undefined\n        ? transactionFailure(options.key, 'atomic producer publication failed')\n        : ok(recovered(options.key, options.previous));\n    }\n    return ok({\n      draft: candidate.value,\n      generation,\n      status: 'committed',\n      lastKnownGood: candidate.value,\n      candidateGeneration: generation,\n      lastKnownGoodGeneration: generation,\n    });\n  }\n}\n"]}