{"version":3,"file":"secrets-Ddmgga5B.mjs","names":["#globals","#scope","#localFields","#emit"],"sources":["../src/logger.ts","../src/tako/secrets.ts"],"sourcesContent":["import type { Logger as ViteLogger } from \"vite\";\n\ntype Level = \"debug\" | \"info\" | \"warn\" | \"error\";\ntype Fields = Record<string, unknown>;\ntype OutputWriter = (chunk: string) => boolean;\n\nfunction defaultOutputWriter(chunk: string): boolean {\n  // Server: append to stdout as a JSON line. Browser: fall back to the\n  // devtools console so the same `logger` export works either side of a\n  // tako.sh/react or isomorphic-framework boundary without a module-load\n  // or call-time crash.\n  if (typeof process !== \"undefined\" && process.stdout?.write) {\n    return process.stdout.write(chunk);\n  }\n  const trimmed = chunk.endsWith(\"\\n\") ? chunk.slice(0, -1) : chunk;\n  try {\n    const parsed = JSON.parse(trimmed) as { level?: Level; msg?: unknown; fields?: Fields };\n    const fn =\n      parsed.level === \"error\"\n        ? console.error\n        : parsed.level === \"warn\"\n          ? console.warn\n          : parsed.level === \"debug\"\n            ? console.debug\n            : console.info;\n    if (parsed.fields !== undefined) fn(parsed.msg, parsed.fields);\n    else fn(parsed.msg);\n  } catch {\n    console.log(trimmed);\n  }\n  return true;\n}\n\nlet outputWriter: OutputWriter = defaultOutputWriter;\n\nfunction autoPopulate(): Fields {\n  const fields: Fields = {};\n  if (typeof process === \"undefined\" || !process.env) return fields;\n  const build = process.env[\"TAKO_BUILD\"];\n  const instance = process.env[\"TAKO_INSTANCE_ID\"];\n  if (build !== undefined) fields[\"build\"] = build;\n  if (instance !== undefined) fields[\"instance\"] = instance;\n  return fields;\n}\n\nfunction expandErrors(fields: Fields): Fields {\n  const out: Fields = {};\n  for (const [key, value] of Object.entries(fields)) {\n    out[key] =\n      value instanceof Error\n        ? { name: value.name, message: value.message, stack: value.stack ?? \"\" }\n        : value;\n  }\n  return out;\n}\n\n/**\n * Structured JSON logger used across the Tako SDK and user apps.\n *\n * Writes one JSON object per line to `stdout` with `ts`, `level`, `scope`,\n * `msg`, and an optional `fields` bag merged from three scopes: process\n * globals (see {@link setGlobals}), logger-local fields (see {@link child}),\n * and per-call fields. `Error` values in `fields` are serialized to\n * `{ name, message, stack }` automatically.\n *\n * Obtain an instance with {@link createLogger} or import `tako.logger` from `tako.sh`.\n */\nexport class Logger {\n  static #globals: Fields = autoPopulate();\n\n  readonly #scope: string;\n  readonly #localFields: Fields;\n\n  /**\n   * @param scope - Origin tag emitted as `scope` on every line (e.g. `\"app\"`).\n   * @param localFields - Fields attached to every line from this instance.\n   */\n  constructor(scope: string, localFields: Fields = {}) {\n    this.#scope = scope;\n    this.#localFields = localFields;\n  }\n\n  /**\n   * Merge fields into the process-global bag. Every log line from every\n   * `Logger` instance will include these under `fields`. Intended for\n   * startup-time configuration (package version, region, etc.) — do not call\n   * per-request, global state leaks across concurrent work.\n   */\n  setGlobals(fields: Fields): void {\n    Logger.#globals = { ...Logger.#globals, ...fields };\n  }\n\n  /**\n   * Return a new sub-logger. Pass `scope` to rebrand the log origin, and/or\n   * `fields` to attach fields to every log line from the sub-logger. The\n   * parent is not mutated.\n   */\n  child(scope?: string, fields?: Fields): Logger {\n    return new Logger(scope ?? this.#scope, { ...this.#localFields, ...fields });\n  }\n\n  /**\n   * Emit a `debug`-level line.\n   * @param msg - Human-readable message.\n   * @param fields - Optional per-call fields merged into the `fields` bag.\n   */\n  debug(msg: string, fields?: Fields): void {\n    this.#emit(\"debug\", msg, fields);\n  }\n  /**\n   * Emit an `info`-level line.\n   * @param msg - Human-readable message.\n   * @param fields - Optional per-call fields merged into the `fields` bag.\n   */\n  info(msg: string, fields?: Fields): void {\n    this.#emit(\"info\", msg, fields);\n  }\n  /**\n   * Emit a `warn`-level line.\n   * @param msg - Human-readable message.\n   * @param fields - Optional per-call fields merged into the `fields` bag.\n   */\n  warn(msg: string, fields?: Fields): void {\n    this.#emit(\"warn\", msg, fields);\n  }\n  /**\n   * Emit an `error`-level line. Pass an `Error` in `fields` to auto-serialize it.\n   * @param msg - Human-readable message.\n   * @param fields - Optional per-call fields merged into the `fields` bag.\n   */\n  error(msg: string, fields?: Fields): void {\n    this.#emit(\"error\", msg, fields);\n  }\n\n  /**\n   * Return a Vite-compatible `Logger` adapter. Pass to `customLogger` in a\n   * Vite config to route Vite's own logs through this logger.\n   *\n   * Normalizes Vite's pretty-print conventions at this bridge: strips\n   * leading/trailing blank lines from messages and drops whitespace-only\n   * calls (Vite uses those as spacers in its default text logger). The core\n   * `Logger` itself stays verbatim — this is adapter-only.\n   */\n  toViteLogger(): ViteLogger {\n    const seenWarnings = new Set<string>();\n    const seenErrors = new WeakSet<object>();\n    // CodeQL[js/polynomial-redos]: split/join avoids the \\s/\\n overlap that\n    // makes anchored regexes like /^\\s*\\n|\\n\\s*$/g polynomial on all-newline\n    // input. Strips fully blank outer lines while preserving intra-line\n    // indentation on the first/last content lines.\n    const normalize = (msg: string): string | null => {\n      const lines = msg.split(\"\\n\");\n      let first = 0;\n      while (first < lines.length && lines[first]!.trim() === \"\") first++;\n      if (first === lines.length) return null;\n      let last = lines.length - 1;\n      while (lines[last]!.trim() === \"\") last--;\n      return lines.slice(first, last + 1).join(\"\\n\");\n    };\n    const self: ViteLogger = {\n      hasWarned: false,\n      info: (msg) => {\n        const n = normalize(msg);\n        if (n === null) return;\n        this.#emit(\"info\", n);\n      },\n      warn: (msg) => {\n        const n = normalize(msg);\n        if (n === null) return;\n        self.hasWarned = true;\n        this.#emit(\"warn\", n);\n      },\n      warnOnce: (msg) => {\n        const n = normalize(msg);\n        if (n === null) return;\n        if (seenWarnings.has(n)) return;\n        seenWarnings.add(n);\n        self.hasWarned = true;\n        this.#emit(\"warn\", n);\n      },\n      error: (msg, opts) => {\n        const err = opts?.error;\n        if (err) seenErrors.add(err);\n        const n = normalize(msg);\n        if (n === null) return;\n        this.#emit(\"error\", n);\n      },\n      clearScreen: () => {},\n      hasErrorLogged: (err) => seenErrors.has(err as object),\n    };\n    return self;\n  }\n\n  #emit(level: Level, msg: string, callFields?: Fields): void {\n    const merged = expandErrors({\n      ...Logger.#globals,\n      ...this.#localFields,\n      ...callFields,\n    });\n    const payload: Record<string, unknown> = {\n      ts: Date.now(),\n      level,\n      scope: this.#scope,\n      msg,\n    };\n    if (Object.keys(merged).length > 0) {\n      payload[\"fields\"] = merged;\n    }\n    outputWriter(`${JSON.stringify(payload)}\\n`);\n  }\n\n  /** @internal Reset static state between tests. Do not call from user code. */\n  static resetForTests(): void {\n    Logger.#globals = autoPopulate();\n  }\n}\n\n/**\n * Create a new {@link Logger} at the given scope.\n *\n * Prefer this over `new Logger(...)` so the constructor signature can evolve\n * without breaking callers.\n *\n * @param scope - Origin tag emitted as `scope` on every line.\n */\nexport function createLogger(scope: string): Logger {\n  return new Logger(scope);\n}\n\n/** @internal Install a raw writer that bypasses patched stdio streams. */\nexport function setLoggerOutputWriter(writer: OutputWriter): void {\n  outputWriter = writer;\n}\n\n/** @internal Reset logger output writer between tests. */\nexport function resetLoggerOutputWriterForTests(): void {\n  outputWriter = (chunk) => process.stdout.write(chunk);\n}\n","/**\n * Secrets + storage + internal-auth-token proxy store. Pure, isomorphic-safe — the\n * fd-pipe reader that actually populates this state lives in\n * `./secrets-fd.ts` so that `tako.sh/internal` can re-export\n * `loadSecrets` without dragging `node:fs` into consumer graphs.\n *\n * Tako spawns each app process with a pipe on fd 3 containing a JSON\n * envelope `{\"token\": ..., \"secrets\": {...}, \"storages\": {...}}`.\n * Server/worker entrypoints read the envelope and call `injectBootstrap(...)`\n * before the user's module is imported.\n *\n * The token is kept in module scope and used by the SDK to authenticate\n * server-issued `Host: <app>.tako` requests — it is not exposed to\n * user code, and it does NOT leak to processes the app spawns (unlike\n * an env var would).\n *\n * Secrets are exposed through the `tako.secrets` proxy exported from\n * `tako.sh`. Its `toString`/`toJSON`/inspect return\n * `[REDACTED]` and its property descriptors are non-enumerable, so\n * bulk-spread (`{ ...secrets }`) returns an empty object — individual\n * access via `secrets.KEY` still works through the `get` trap.\n */\n\nexport interface BootstrapEnvelope {\n  token: string | null;\n  secrets: Record<string, string>;\n  storages?: Record<string, unknown> | undefined;\n}\n\ninterface BootstrapState {\n  token: string | null;\n  secrets: Record<string, string>;\n  storages: Record<string, unknown>;\n}\n\nlet bootstrap: BootstrapState = { token: null, secrets: {}, storages: {} };\n\n/** Low-level: replace the whole bootstrap state (tests + fd-reader init). */\nexport function injectBootstrap(next: BootstrapEnvelope): void {\n  bootstrap = {\n    token: next.token,\n    secrets: Object.assign(Object.create(null), next.secrets ?? {}),\n    storages: Object.assign(Object.create(null), next.storages ?? {}),\n  };\n}\n\n/** Returns the internal auth token, or `null` when running outside Tako. */\nexport function getInternalToken(): string | null {\n  return bootstrap.token;\n}\n\n/** Returns storage binding payloads injected by Tako at process startup. */\nexport function getStorageBindings(): Record<string, unknown> {\n  return bootstrap.storages;\n}\n\n/**\n * Build the proxy-backed accessor that becomes `tako.secrets`. The generated\n * `tako.d.ts` file augments `TakoSecrets` so individual key access\n * (`tako.secrets.FOO`) is typed as a readonly field — `tako.secrets.FOO = \"x\"`\n * is a compile error.\n */\nexport function loadSecrets<T = Record<string, string>>(): Readonly<T> {\n  return new Proxy(Object.create(null) as Record<string, string>, {\n    get(_target, prop: string | symbol): unknown {\n      if (prop === \"toString\" || prop === \"toJSON\") return () => \"[REDACTED]\";\n      if (prop === Symbol.for(\"nodejs.util.inspect.custom\")) return () => \"[REDACTED]\";\n      if (prop === Symbol.toPrimitive) return () => \"[REDACTED]\";\n      if (typeof prop === \"string\") return bootstrap.secrets[prop];\n      return undefined;\n    },\n    ownKeys(): string[] {\n      return Object.keys(bootstrap.secrets);\n    },\n    getOwnPropertyDescriptor(_target, prop: string | symbol) {\n      if (typeof prop === \"string\" && prop in bootstrap.secrets) {\n        return { configurable: true, enumerable: false, value: bootstrap.secrets[prop] };\n      }\n      return undefined;\n    },\n    has(_target, prop: string | symbol): boolean {\n      return typeof prop === \"string\" && prop in bootstrap.secrets;\n    },\n  }) as Readonly<T>;\n}\n"],"mappings":"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"}