fingerprint-platform-mcp 0.0.1 → 0.0.2

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.
@@ -0,0 +1 @@
1
+ {"fileNames":["../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/standard-schema.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/util.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/versions.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/schemas.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/checks.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/errors.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/core.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/parse.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/regexes.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ar.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/az.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/be.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ca.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/cs.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/de.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/en.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/eo.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/es.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/fa.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/fi.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/fr.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/fr-ca.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/he.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/hu.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/id.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/it.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ja.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/kh.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ko.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/mk.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ms.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/nl.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/no.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ota.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ps.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/pl.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/pt.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ru.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/sl.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/sv.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ta.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/th.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/tr.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ua.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/ur.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/vi.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/zh-cn.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/zh-tw.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/locales/index.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/registries.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/doc.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/function.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/api.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/json-schema.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/to-json-schema.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/index.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/errors.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/parse.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/schemas.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/checks.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/compat.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/iso.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/coerce.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/external.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/index.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/index.d.cts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/types.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/types.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/transport.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.d.ts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/typealiases.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/zoderror.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseutil.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/enumutil.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorutil.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/partialutil.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/standard-schema.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.d.cts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/index.d.cts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/types.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/responsemessage.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.d.ts","../../../node_modules/.pnpm/json-schema-typed@8.0.2/node_modules/json-schema-typed/draft_2020_12.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/types.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/uritemplate.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.d.ts","../../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.d.ts","../../../packages/sdk-snippets/dist/snippet-for-framework.d.ts","../../../packages/sdk-snippets/dist/ai-prompt.d.ts","../../../packages/sdk-snippets/dist/index.d.ts","../../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/index.d.cts","../src/util/detect-framework.ts","../src/util/detect-pm.ts","../src/tools/types.ts","../src/tools/analyze.ts","../../../node_modules/.pnpm/@types+diff@7.0.2/node_modules/@types/diff/index.d.ts","../../../node_modules/.pnpm/@types+diff@7.0.2/node_modules/@types/diff/index.d.mts","../src/util/diff.ts","../src/tools/configure.ts","../src/tools/explain.ts","../src/tools/install.ts","../src/tools/verify.ts","../src/tools/wire-init.ts","../src/server.ts","../src/cli.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/compatibility/disposable.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/compatibility/indexable.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/compatibility/iterators.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/compatibility/index.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/globals.typedarray.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/buffer.buffer.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/globals.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/web-globals/abortcontroller.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/web-globals/domexception.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/web-globals/events.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/header.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/readable.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/file.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/fetch.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/formdata.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/connector.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/client.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/errors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-dispatcher.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/global-origin.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool-stats.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/handlers.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/balanced-pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-interceptor.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-client.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-pool.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/mock-errors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/env-http-proxy-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-handler.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/retry-agent.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/api.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/interceptors.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/util.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cookies.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/patch.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/websocket.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/eventsource.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/filereader.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/diagnostics-channel.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/content-type.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/cache.d.ts","../../../node_modules/.pnpm/undici-types@6.21.0/node_modules/undici-types/index.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/web-globals/fetch.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/assert.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/assert/strict.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/async_hooks.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/buffer.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/child_process.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/cluster.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/console.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/constants.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/crypto.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/dgram.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/dns.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/dns/promises.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/domain.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/events.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/fs.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/fs/promises.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/http.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/http2.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/https.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/inspector.generated.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/module.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/net.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/os.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/path.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/process.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/punycode.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/querystring.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/readline.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/readline/promises.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/repl.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/sea.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/stream.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/stream/promises.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/stream/web.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/string_decoder.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/test.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/timers.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/timers/promises.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/tls.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/trace_events.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/tty.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/url.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/util.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/v8.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/vm.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/wasi.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/worker_threads.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/zlib.d.ts","../../../node_modules/.pnpm/@types+node@20.19.39/node_modules/@types/node/index.d.ts"],"fileIdsList":[[127,169,176,222],[152,159,160,164,165,166,167,168,176,222],[155,156,157,158,159,176,222,243],[156,159,163,176,222,243],[156,159,176,222,234,243,263],[156,158,159,176,222,243],[176,222],[156,157,159,176,222,234,243],[155,156,159,163,176,222,234,243],[155,176,222,234,243],[176,222,234,243],[162,176,222,234,243],[125,141,142,145,176,222],[125,141,143,152,176,222],[125,141,144,145,149,176,222],[125,176,222],[125,141,145,147,148,176,222],[125,126,141,143,145,149,150,151,176,222],[125,126,176,222,252],[113,140,176,222],[124,125,126,141,143,144,176,222],[123,124,176,222],[146,176,222],[161,176,222],[176,219,222],[176,221,222],[222],[176,222,227,255],[176,222,223,228,233,241,252,263],[176,222,223,224,233,241],[171,172,173,176,222],[176,222,225,264],[176,222,226,227,234,242],[176,222,227,252,260],[176,222,228,230,233,241],[176,221,222,229],[176,222,230,231],[176,222,232,233],[176,221,222,233],[176,222,233,234,235,252,263],[176,222,233,234,235,248,252,255],[176,222,230,233,236,241,252,263],[176,222,233,234,236,237,241,252,260,263],[176,222,236,238,252,260,263],[174,175,176,177,178,179,180,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269],[176,222,233,239],[176,222,240,263,268],[176,222,230,233,241,252],[176,222,242],[176,222,243],[176,221,222,244],[176,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269],[176,222,246],[176,222,247],[176,222,233,248,249],[176,222,248,250,264,266],[176,222,233,252,253,255],[176,222,254,255],[176,222,252,253],[176,222,255],[176,222,256],[176,219,222,252,257],[176,222,233,258,259],[176,222,258,259],[176,222,227,241,252,260],[176,222,261],[176,222,241,262],[176,222,236,247,263],[176,222,227,264],[176,222,252,265],[176,222,240,266],[176,222,267],[176,217,222],[176,217,222,233,235,244,252,255,263,266,268],[176,222,252,269],[176,189,193,222,263],[176,189,222,252,263],[176,184,222],[176,186,189,222,260,263],[176,222,241,260],[176,222,270],[176,184,222,270],[176,186,189,222,241,263],[176,181,182,185,188,222,233,252,263],[176,189,196,222],[176,181,187,222],[176,189,210,211,222],[176,185,189,222,255,263,270],[176,210,222,270],[176,183,184,222,270],[176,189,222],[176,183,184,185,186,187,188,189,190,191,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,211,212,213,214,215,216,222],[176,189,204,222],[176,189,196,197,222],[176,187,189,197,198,222],[176,188,222],[176,181,184,189,222],[176,189,193,197,198,222],[176,193,222],[176,187,189,192,222,263],[176,181,186,189,196,222],[176,222,252],[176,184,189,210,222,268,270],[139,176,222],[130,131,176,222],[128,129,130,132,133,138,176,222],[129,130,176,222],[138,176,222],[130,176,222],[128,129,130,133,134,135,136,137,176,222],[128,129,140,176,222],[113,176,222],[113,116,176,222],[106,113,114,115,116,117,118,119,120,176,222],[121,176,222],[113,114,176,222],[113,115,176,222],[59,61,62,63,64,176,222],[59,61,63,64,176,222],[59,61,63,176,222],[59,61,62,64,176,222],[59,61,64,176,222],[59,60,61,62,63,64,65,66,106,107,108,109,110,111,112,176,222],[61,64,176,222],[58,59,60,62,63,64,176,222],[61,107,111,176,222],[61,62,63,64,176,222],[122,176,222],[63,176,222],[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,176,222],[153,176,222],[153,154,176,222]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"309ebd217636d68cf8784cbc3272c16fb94fb8e969e18b6fe88c35200340aef1","impliedFormat":1},{"version":"91cf9887208be8641244827c18e620166edf7e1c53114930b54eaeaab588a5be","impliedFormat":1},{"version":"ef9b6279acc69002a779d0172916ef22e8be5de2d2469ff2f4bb019a21e89de2","impliedFormat":1},{"version":"71623b889c23a332292c85f9bf41469c3f2efa47f81f12c73e14edbcffa270d3","affectsGlobalScope":true,"impliedFormat":1},{"version":"88863d76039cc550f8b7688a213dd051ae80d94a883eb99389d6bc4ce21c8688","impliedFormat":1},{"version":"e9ce511dae7201b833936d13618dff01815a9db2e6c2cc28646e21520c452d6c","impliedFormat":1},{"version":"243649afb10d950e7e83ee4d53bd2fbd615bb579a74cf6c1ce10e64402cdf9bb","impliedFormat":1},{"version":"35575179030368798cbcd50da928a275234445c9a0df32d4a2c694b2b3d20439","impliedFormat":1},{"version":"c939cb12cb000b4ec9c3eca3fe7dee1fe373ccb801237631d9252bad10206d61","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"26384fb401f582cae1234213c3dc75fdc80e3d728a0a1c55b405be8a0c6dddbe","impliedFormat":1},{"version":"26384fb401f582cae1234213c3dc75fdc80e3d728a0a1c55b405be8a0c6dddbe","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"26384fb401f582cae1234213c3dc75fdc80e3d728a0a1c55b405be8a0c6dddbe","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"b42d3651103a532f7492e719a828647af97306b2356ae757ebb7f17f4a8c41e5","impliedFormat":1},{"version":"03268b4d02371bdf514f513797ed3c9eb0840b0724ff6778bda0ef74c35273be","impliedFormat":1},{"version":"3511847babb822e10715a18348d1cbb0dae73c4e4c0a1bcf7cbc12771b310d45","impliedFormat":1},{"version":"80e653fbbec818eecfe95d182dc65a1d107b343d970159a71922ac4491caa0af","impliedFormat":1},{"version":"53f00dc83ccceb8fad22eb3aade64e4bcdb082115f230c8ba3d40f79c835c30e","impliedFormat":1},{"version":"35475931e8b55c4d33bfe3abc79f5673924a0bd4224c7c6108a4e08f3521643c","impliedFormat":1},{"version":"9078205849121a5d37a642949d687565498da922508eacb0e5a0c3de427f0ae5","impliedFormat":1},{"version":"e8f8f095f137e96dc64b56e59556c02f3c31db4b354801d6ae3b90dceae60240","impliedFormat":1},{"version":"451abef2a26cebb6f54236e68de3c33691e3b47b548fd4c8fa05fd84ab2238ff","impliedFormat":1},{"version":"6042774c61ece4ba77b3bf375f15942eb054675b7957882a00c22c0e4fe5865c","impliedFormat":1},{"version":"41f185713d78f7af0253a339927dc04b485f46210d6bc0691cf908e3e8ded2a1","impliedFormat":1},{"version":"23ee410c645f68bd99717527de1586e3eb826f166d654b74250ad92b27311fde","impliedFormat":1},{"version":"ffc3e1064146c1cafda1b0686ae9679ba1fb706b2f415e057be01614bf918dba","impliedFormat":1},{"version":"995869b1ddf66bbcfdb417f7446f610198dcce3280a0ae5c8b332ed985c01855","impliedFormat":1},{"version":"58d65a2803c3b6629b0e18c8bf1bc883a686fcf0333230dd0151ab6e85b74307","impliedFormat":1},{"version":"e818471014c77c103330aee11f00a7a00b37b35500b53ea6f337aefacd6174c9","impliedFormat":1},{"version":"dca963a986285211cfa75b9bb57914538de29585d34217d03b538e6473ac4c44","impliedFormat":1},{"version":"d8bc0c5487582c6d887c32c92d8b4ffb23310146fcb1d82adf4b15c77f57c4ac","impliedFormat":1},{"version":"8cb31102790372bebfd78dd56d6752913b0f3e2cefbeb08375acd9f5ba737155","impliedFormat":1},{"version":"f17ed72d1b1882ab6dc66d45e699f757d15bba0807af2fc9c3ec98fe367611c1","impliedFormat":99},{"version":"b1067ccb56b38af060dc3299ea7c4c6362cad4f07d0d454325a74808204fc801","impliedFormat":99},{"version":"7bb43a0f0180ad87b0a944ef95be8615d4c1d621a93ae503a8fcdee2027243ef","impliedFormat":99},{"version":"f55b797d46c4268b2e42961be04e99ad10ccbe55f2cb87fc99b82979fb28121f","impliedFormat":99},{"version":"d3cfde44f8089768ebb08098c96d01ca260b88bccf238d55eee93f1c620ff5a5","impliedFormat":1},{"version":"293eadad9dead44c6fd1db6de552663c33f215c55a1bfa2802a1bceed88ff0ec","impliedFormat":1},{"version":"08b2fae7b0f553ad9f79faec864b179fc58bc172e295a70943e8585dd85f600c","impliedFormat":1},{"version":"f12edf1672a94c578eca32216839604f1e1c16b40a1896198deabf99c882b340","impliedFormat":1},{"version":"e3498cf5e428e6c6b9e97bd88736f26d6cf147dedbfa5a8ad3ed8e05e059af8a","impliedFormat":1},{"version":"dba3f34531fd9b1b6e072928b6f885aa4d28dd6789cbd0e93563d43f4b62da53","impliedFormat":1},{"version":"f672c876c1a04a223cf2023b3d91e8a52bb1544c576b81bf64a8fec82be9969c","impliedFormat":1},{"version":"e4b03ddcf8563b1c0aee782a185286ed85a255ce8a30df8453aade2188bbc904","impliedFormat":1},{"version":"2329d90062487e1eaca87b5e06abcbbeeecf80a82f65f949fd332cfcf824b87b","impliedFormat":1},{"version":"25b3f581e12ede11e5739f57a86e8668fbc0124f6649506def306cad2c59d262","impliedFormat":1},{"version":"4fdb529707247a1a917a4626bfb6a293d52cd8ee57ccf03830ec91d39d606d6d","impliedFormat":1},{"version":"a9ebb67d6bbead6044b43714b50dcb77b8f7541ffe803046fdec1714c1eba206","impliedFormat":1},{"version":"833e92c058d033cde3f29a6c7603f517001d1ddd8020bc94d2067a3bc69b2a8e","impliedFormat":1},{"version":"0648a8c200b5544e30677f7f7059b1e384d6cab716c82659716457e3f317ebae","impliedFormat":99},{"version":"ba678532514244768286bdfdc82b33f072d5de4e9d281a75bcccdba9970788d7","impliedFormat":99},{"version":"0b79f95a79497386c50f38bafbbf59154619e51d7bbe5acf61cd376d3c9d77b9","impliedFormat":99},{"version":"5993793a23b298afd20c2e1cd2bf8468cc7e9415d314d0771e93dd8b2e389d28","impliedFormat":99},{"version":"05267740a5cff4399995b08326a2e250f229e9926f453162192b9b96b853a12b","impliedFormat":99},{"version":"104fae9b53b5eaa040d9ce626e1bf0b3e6e27d269a899a98a4a28358cdcbc155","impliedFormat":99},{"version":"50a6aa665f3a2e769a4d683f9f74cd15164d0947fb957d8016331b170ab8b643","impliedFormat":99},{"version":"6b83491ca98ce7dc82ec0c54f1456705c9ea08f5a39fa8cea17134b28e2a73d7","impliedFormat":99},{"version":"33aa2f336bb0bc598652ddd1ad3095ef7a14e4dbed9cf829fa9357e989fff31a","impliedFormat":99},{"version":"d691e546590145171d00d78b341bd3ca4844c96eb34f870be84058a1cab585c3","impliedFormat":99},{"version":"c9d12ca3f67129b3ed2b81bf54537c970673cedd05ba28fbeba70c1e8aff684b","impliedFormat":99},{"version":"6f0b69f7afb2ff04a4b73fae6b43476c14349a438881c7a8c3d34cbad2c2bf3b","impliedFormat":99},{"version":"051a71b413fdcbff411a8a4cb465b9a7a63102dd63542b2e69906589bd9ecc0f","impliedFormat":99},{"version":"3b455f91cd13ccd959541bf7d7daf2bc7c125e194ff519aa12684fdfe1c138c8","impliedFormat":99},{"version":"2dfe5b9293d5fe29824bd89b72e091f9a2943f1ecfce2f42d1af15e6a294e749","impliedFormat":99},{"version":"5780b706cece027f0d4444fbb4e1af62dc51e19da7c3d3719f67b22b033859b9","impliedFormat":1},{"version":"001be7481a2fe39788fb7cd3ceef1417af0bcc64037a91af2dab91e992c6e0ae","signature":"025498bb7f25462f19889fe712cbdc1e81aa48f84f0d2707605c3c23ff1a7a18","impliedFormat":99},{"version":"ad904351d554a069d18c70acfe6fe07a9f811f92fd6aae0b8fcba1eff9937d6f","signature":"cd413ecb4108a3146411c79addbff7ff2042d632c12ceb91b3b75debeac160c6","impliedFormat":99},{"version":"29b47de13cbdc7db8e81060983a285c960a433690c99a2476604d5acece3b451","signature":"a24b64a3cce94cff4457304690b5983a2720cbc5b11ac17aa07338c88dd2c972","impliedFormat":99},{"version":"7343680aeb9774873ca0860b4ecb316735341508b5cc0392fda82382d25a1359","signature":"6e06a2739442ac8a62585ad7e8b13811a65984e943e04101988bd36095ef0b6b","impliedFormat":99},{"version":"08b61324ea33817712d1d96e908496fab7742dbb7ad61e87156e6de0835b1c37","impliedFormat":1},{"version":"97e1818573679b5d3d697406abd3e5f1e9cd00da1f2783ab236912180462f5be","impliedFormat":99},{"version":"0cde117869cb960077d3f777d548648e0f3c68161c7d5757464e9a28e883062a","signature":"51a5cf9dc2670a1241b041fe2016173759d1eb144054386f828cbf61a05e2558","impliedFormat":99},{"version":"35019d4d40662f3e41c155fad1a2a46d5da32c7661ab388a9d77f59e5ea207be","signature":"317c7ad53765dc641a14745b6c1c9fc72488c970eef5f21308821f155af04afb","impliedFormat":99},{"version":"9cdbedb37e35728e54881ed49287069726874d2826911994b710710dffed69ef","signature":"e2e2843e395853de64f6bf1986f4e0eee17d5832daddb12cb2a0dbc60725ddae","impliedFormat":99},{"version":"01af83695c52cd7d783ab55623e692160e184bbfc3650dfe201f38074d002958","signature":"e21661eebceedc0ddd7a457ea5ee9c5e24c66c95efe064a4dbae75fd794960eb","impliedFormat":99},{"version":"48d3c3d4b8d49557c6659787b8b0371a2ebd221e23fd6980b22c152751b3d088","signature":"aef47e7dd5fffeb98c53c01859b310f87057a360329778f809c22f7d4dc9caed","impliedFormat":99},{"version":"a531977f08d6aaf3421c2514f5775835a80b8068ab998385e07beabba34e72f1","signature":"3aa94187d24e79d7f0bb5de9f4a24d8e988cbe4ed17c2737a1d2a8d171804e07","impliedFormat":99},{"version":"43c8c73b62296eb054d249fdecc1bd2197cb992fefa94b3050de0a5079d61c21","signature":"6c385922b6d1106bf8cc2fa7f3398d83a30b0d3f2495126d31317e9deb5db708","impliedFormat":99},{"version":"a1838ca85a77deb731ecad19e0eeb4d2d1e7f133e703148a8d307fd505464657","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":99},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"641942a78f9063caa5d6b777c99304b7d1dc7328076038c6d94d8a0b81fc95c1","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e20d899c28ca26a2a7afc98beaa69e63ff7fba0a8bc47b4e3bf3ede5e09e424","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"372413016d17d804e1d139418aca0c68e47a83fb6669490857f4b318de8cccb3","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"085f552d005479e2e6a7311cdbbe5d8c55c497b4d19274285df161ee9684cd9c","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"007faacc9268357caa21d24169f3f3f2497af3e9241308df2d89f6e6d9bb3f2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"809821b8a065e3234a55b3a9d7846231ed18d66dd749f2494c66288d890daf7f","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7c5e2ea4a9749097c347454805e933844ed207b6eefec6b7cfd418b5f5f7b28","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1}],"root":[[157,160],[163,170]],"options":{"allowSyntheticDefaultImports":true,"alwaysStrict":true,"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"exactOptionalPropertyTypes":true,"module":199,"noFallthroughCasesInSwitch":true,"noImplicitAny":true,"noImplicitReturns":true,"noImplicitThis":true,"noUncheckedIndexedAccess":true,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./","removeComments":false,"rootDir":"../src","skipLibCheck":true,"sourceMap":true,"strict":true,"strictBindCallApply":true,"strictFunctionTypes":true,"strictNullChecks":true,"strictPropertyInitialization":true,"target":9,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[[170,1],[169,2],[160,3],[164,4],[165,5],[166,6],[159,7],[167,8],[168,9],[157,10],[158,11],[163,12],[143,13],[151,14],[148,15],[142,16],[124,7],[149,17],[152,18],[127,19],[141,20],[145,21],[144,16],[126,16],[150,7],[125,22],[147,23],[162,24],[161,7],[219,25],[220,25],[221,26],[176,27],[222,28],[223,29],[224,30],[171,7],[174,31],[172,7],[173,7],[225,32],[226,33],[227,34],[228,35],[229,36],[230,37],[231,37],[232,38],[233,39],[234,40],[235,41],[177,7],[175,7],[236,42],[237,43],[238,44],[270,45],[239,46],[240,47],[241,48],[242,49],[243,50],[244,51],[245,52],[246,53],[247,54],[248,55],[249,55],[250,56],[251,7],[252,57],[254,58],[253,59],[255,60],[256,61],[257,62],[258,63],[259,64],[260,65],[261,66],[262,67],[263,68],[264,69],[265,70],[266,71],[267,72],[178,7],[179,7],[180,7],[218,73],[268,74],[269,75],[146,7],[56,7],[57,7],[11,7],[10,7],[2,7],[12,7],[13,7],[14,7],[15,7],[16,7],[17,7],[18,7],[19,7],[3,7],[20,7],[21,7],[4,7],[22,7],[26,7],[23,7],[24,7],[25,7],[27,7],[28,7],[29,7],[5,7],[30,7],[31,7],[32,7],[33,7],[6,7],[37,7],[34,7],[35,7],[36,7],[38,7],[7,7],[39,7],[44,7],[45,7],[40,7],[41,7],[42,7],[43,7],[8,7],[49,7],[46,7],[47,7],[48,7],[50,7],[9,7],[51,7],[52,7],[53,7],[55,7],[54,7],[1,7],[196,76],[206,77],[195,76],[216,78],[187,79],[186,80],[215,81],[209,82],[214,83],[189,84],[203,85],[188,86],[212,87],[184,88],[183,81],[213,89],[185,90],[190,91],[191,7],[194,91],[181,7],[217,92],[207,93],[198,94],[199,95],[201,96],[197,97],[200,98],[210,81],[192,99],[193,100],[202,101],[182,102],[205,93],[204,91],[208,7],[211,103],[156,104],[132,105],[139,106],[134,7],[135,7],[133,107],[136,108],[128,7],[129,7],[140,104],[131,109],[137,7],[138,110],[130,111],[117,112],[120,113],[118,113],[114,112],[121,114],[122,115],[119,113],[115,116],[116,117],[110,118],[62,119],[64,120],[108,7],[63,121],[109,122],[113,123],[111,7],[65,119],[66,7],[107,124],[61,125],[58,7],[112,126],[59,127],[60,7],[123,128],[67,129],[68,129],[69,129],[70,129],[71,129],[72,129],[73,129],[74,129],[75,129],[76,129],[77,129],[79,129],[78,129],[80,129],[81,129],[82,129],[106,130],[83,129],[84,129],[85,129],[86,129],[87,129],[88,129],[89,129],[90,129],[91,129],[93,129],[92,129],[94,129],[95,129],[96,129],[97,129],[98,129],[99,129],[100,129],[101,129],[102,129],[103,129],[104,129],[105,129],[154,131],[155,132],[153,7]],"affectedFilesPendingEmit":[[170,51],[169,51],[160,51],[164,51],[165,51],[166,51],[159,51],[167,51],[168,51],[157,51],[158,51],[163,51]],"emitSignatures":[157,158,159,160,163,164,165,166,167,168,169,170],"version":"5.9.3"}
package/dist/cli.js CHANGED
@@ -435,40 +435,61 @@ Without this entry the collector rejects requests from your site with a 401 \`or
435
435
  }
436
436
  var generateCloudflareWorkerInputSchema = {
437
437
  cwd: z2.string().describe("Absolute path to the user project root \u2014 for the diff header."),
438
- collectorHost: z2.string().describe(
439
- "Hostname of the Fingerprint collector to proxy to, without scheme. E.g. `collector.yoursite.com` or `89.124.91.162`."
440
- ),
441
438
  customDomain: z2.string().describe(
442
- "Your site's domain, e.g. `yoursite.com`. The Worker routes `<customDomain>/fpjs/*`."
439
+ "Your site's apex domain, e.g. `yoursite.com`. The Worker routes `<customDomain>/fpjs/*` to the Fingerprint collector. The Worker fetches `https://fp.<customDomain>/v1/*` upstream \u2014 an A record you'll add to your DNS pointing at our collector IP (instructions in the output)."
440
+ ),
441
+ collectorIp: z2.string().default("89.124.91.162").describe(
442
+ "Fingerprint collector IP. Only override if you're running a self-hosted deployment. Defaults to the public Fingerprint Platform collector."
443
443
  )
444
444
  };
445
445
  function generateCloudflareWorker(input) {
446
446
  const cwd = resolve4(input.cwd);
447
447
  const workerPath = resolve4(cwd, "cloudflare/worker.ts");
448
448
  const wranglerPath = resolve4(cwd, "cloudflare/wrangler.toml");
449
- const host = input.collectorHost.replace(/^https?:\/\//, "").replace(/\/+$/, "");
450
449
  const domain = input.customDomain.replace(/^https?:\/\//, "").replace(/\/+$/, "");
451
- const workerScript = cloudflareWorkerTemplate(host);
450
+ const collectorIp = (input.collectorIp ?? "89.124.91.162").replace(/^https?:\/\//, "").replace(/\/+$/, "");
451
+ const upstreamHost = `fp.${domain}`;
452
+ const workerScript = cloudflareWorkerTemplate(upstreamHost);
452
453
  const wranglerToml = wranglerTomlTemplate(domain);
453
454
  const workerDiff = makeNewFileDiff({ cwd, filePath: workerPath, content: workerScript });
454
455
  const wranglerDiff = makeNewFileDiff({ cwd, filePath: wranglerPath, content: wranglerToml });
455
456
  return {
456
- summary: `Cloudflare Worker template for \`${domain}/fpjs/*\` \u2192 \`${host}\`.`,
457
- details: `Two files to write into the user's repo:
457
+ summary: `Cloudflare Worker for \`${domain}/fpjs/*\` \u2192 \`https://${upstreamHost}\` (Fingerprint collector).`,
458
+ details: `**Architecture this generates:**
459
+
460
+ \`\`\`
461
+ Browser \u2192 ${domain}/fpjs/* \u2192 CF Worker \u2192 fetch https://${upstreamHost}/v1/*
462
+ \u2193
463
+ ${collectorIp} (Fingerprint collector)
464
+ \`\`\`
465
+
466
+ Three things to set up on YOUR side:
467
+
468
+ **1. DNS record** in your zone for \`${domain}\` (e.g. Cloudflare DNS, Namecheap, Route 53):
469
+
470
+ \`\`\`text
471
+ Type: A
472
+ Name: fp
473
+ Value: ${collectorIp}
474
+ Proxy: DNS only (gray cloud if using Cloudflare \u2014 ACME needs direct access)
475
+ TTL: Auto / 300
476
+ \`\`\`
477
+
478
+ This makes \`${upstreamHost}\` resolve to our collector. Our Caddy auto-issues a Let's Encrypt cert for it on the first request.
479
+
480
+ **2. Dashboard \`allowedHosts\`**: register \`https://${domain}\` on Security \u2192 Allowed hosts. Without it our on-demand-TLS gate refuses cert issuance and the Worker's upstream fetch fails.
481
+
482
+ **3. Cloudflare Worker** \u2014 two files to write into your repo:
458
483
 
459
484
  **\`cloudflare/worker.ts\`** \u2014 the Worker script body.
460
485
  **\`cloudflare/wrangler.toml\`** \u2014 Wrangler deploy config (route + zone).
461
486
 
462
- Both diffs are pasted below. Apply with your edit tool, then run
487
+ Both diffs are below. After applying:
463
488
 
464
489
  \`\`\`bash
465
- cd cloudflare && wrangler deploy
490
+ cd cloudflare && wrangler login && wrangler deploy
466
491
  \`\`\`
467
492
 
468
- from the project root. After deploy, the Worker is live on the route
469
- pattern \`${domain}/fpjs/*\`. The SDK then loads same-origin: cookies
470
- stay first-party, ad-blockers can't pattern-match a cross-origin path.
471
-
472
493
  --- ${workerPath} ---
473
494
 
474
495
  \`\`\`diff
@@ -481,22 +502,20 @@ ${workerDiff}
481
502
  ${wranglerDiff}
482
503
  \`\`\``,
483
504
  nextSteps: [
484
- `Apply both diffs to create the cloudflare/ directory.`,
485
- `Install Wrangler: \`npm i -g wrangler\` (or use \`npx wrangler\`).`,
486
- `Authenticate: \`wrangler login\`.`,
487
- `Deploy: \`cd cloudflare && wrangler deploy\`.`,
488
- `Update \`FP_COLLECTOR_URL\` env var to \`https://${domain}/fpjs\`.`,
489
- `Add \`https://${domain}\` to dashboard allowedHosts via the Security page.`
505
+ `Add the DNS A record \`fp.${domain}\` \u2192 \`${collectorIp}\` (DNS-only, no Cloudflare proxy on that record).`,
506
+ `Add \`https://${domain}\` to dashboard \`allowedHosts\` on the Security page.`,
507
+ `Apply both diffs to create \`cloudflare/worker.ts\` + \`cloudflare/wrangler.toml\`.`,
508
+ `Run \`cd cloudflare && wrangler login && wrangler deploy\` to deploy the Worker.`,
509
+ `Update your SDK init: \`collectorUrl: 'https://${domain}/fpjs'\`.`
490
510
  ],
491
- // Single diff payload that concatenates both files — git apply
492
- // accepts multi-file unified diffs.
493
511
  artifact: { kind: "diff", content: `${workerDiff}
494
512
  ${wranglerDiff}` },
495
513
  meta: {
496
514
  workerPath,
497
515
  wranglerPath,
498
516
  route: `${domain}/fpjs/*`,
499
- collectorHost: host
517
+ upstreamHost,
518
+ collectorIp
500
519
  }
501
520
  };
502
521
  }
@@ -535,7 +554,7 @@ _Trade-off vs the Cloudflare Worker route: a dedicated subdomain is **easier for
535
554
  meta: { subdomain: input.subdomain, collectorHost: host, apex }
536
555
  };
537
556
  }
538
- function cloudflareWorkerTemplate(collectorHost) {
557
+ function cloudflareWorkerTemplate(upstreamHost) {
539
558
  return `/**
540
559
  * Fingerprint Platform same-origin proxy.
541
560
  *
@@ -550,10 +569,13 @@ function cloudflareWorkerTemplate(collectorHost) {
550
569
  *
551
570
  * The integrator's app backend is NEVER in the fingerprint request
552
571
  * path \u2014 that would couple uptime and add latency. The Worker
553
- * fans out directly to ${collectorHost}.
572
+ * fans out to ${upstreamHost} \u2014 a DNS A record you added in your
573
+ * own zone pointing at the Fingerprint collector. The collector
574
+ * issues a Let's Encrypt cert for this hostname on-demand the
575
+ * first time the Worker reaches it.
554
576
  */
555
577
 
556
- const COLLECTOR_ORIGIN = "https://${collectorHost}";
578
+ const COLLECTOR_ORIGIN = "https://${upstreamHost}";
557
579
 
558
580
  export default {
559
581
  async fetch(req: Request): Promise<Response> {
@@ -1052,7 +1074,13 @@ _(run in \`${envelope.artifact.cwd}\`)_` : "")
1052
1074
  description: "Emit a `cloudflare/worker.ts` + `cloudflare/wrangler.toml` as diffs to drop into the user repo. Worker proxies SDK bundle + collector API under `<customDomain>/fpjs/*` for same-origin, ad-block-resistant delivery.",
1053
1075
  inputSchema: generateCloudflareWorkerInputSchema
1054
1076
  },
1055
- async (args) => render(generateCloudflareWorker(args))
1077
+ async (args) => render(
1078
+ generateCloudflareWorker({
1079
+ cwd: args.cwd,
1080
+ customDomain: args.customDomain,
1081
+ ...args.collectorIp ? { collectorIp: args.collectorIp } : {}
1082
+ })
1083
+ )
1056
1084
  );
1057
1085
  server.registerTool(
1058
1086
  "generate_dns_fallback",
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/server.ts","../src/tools/analyze.ts","../../../packages/sdk-snippets/src/snippet-for-framework.ts","../src/util/detect-framework.ts","../src/util/detect-pm.ts","../src/tools/configure.ts","../src/util/diff.ts","../src/tools/explain.ts","../src/tools/install.ts","../src/tools/verify.ts","../src/tools/wire-init.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\n\nimport { buildServer } from './server.js';\n\n/**\n * Stdio entrypoint for `fingerprint-platform-mcp`.\n *\n * MCP clients (Claude Desktop, Claude Code, Cursor, Continue.dev,\n * Copilot Chat via mcp-remote) spawn this binary as a subprocess\n * and speak JSON-RPC 2.0 over its stdin / stdout. We attach the\n * server to a `StdioServerTransport` and run until the parent\n * closes the pipes.\n *\n * Stderr is reserved for diagnostics (`console.error`) — MCP\n * clients route it to their own log viewer. Never log to stdout\n * here: that's the JSON-RPC channel and any stray bytes desync\n * the protocol.\n */\nasync function main(): Promise<void> {\n const server = buildServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n // McpServer.connect() resolves once the transport is bound. The\n // process stays alive because stdin holds the event loop open\n // — when the client closes its half of the pipe, Node's stdin\n // emits 'end' and the process exits naturally.\n}\n\nmain().catch((err) => {\n // Last-resort error path — anything that escapes the per-tool\n // try/catch lands here. Log to stderr (NEVER stdout) and exit\n // non-zero so the client's MCP supervisor logs it as a crash.\n console.error('[fingerprint-platform-mcp] fatal:', err);\n process.exit(1);\n});\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { analyzeInputSchema, analyzeProject } from './tools/analyze.js';\nimport {\n generateCloudflareWorker,\n generateCloudflareWorkerInputSchema,\n generateDnsFallback,\n generateDnsFallbackInputSchema,\n setCollectorUrl,\n setCollectorUrlInputSchema,\n} from './tools/configure.js';\nimport { explainInputSchema, explainTopic } from './tools/explain.js';\nimport { installInputSchema, installSdk } from './tools/install.js';\nimport { verifyInstall, verifyInstallInputSchema } from './tools/verify.js';\nimport { wireInit, wireInitInputSchema } from './tools/wire-init.js';\n\nimport type { ToolEnvelope } from './tools/types.js';\n\n/**\n * Build the Fingerprint Platform MCP server. Pure factory — no\n * side effects (no transport bind, no FS open). The caller picks\n * a transport (stdio in `cli.ts`, eventually HTTP/SSE) and calls\n * `server.connect(transport)`.\n *\n * Why a factory instead of a singleton: easier to spin up a fresh\n * server per test in the e2e suite without poisoning the registry\n * with leftover tools.\n */\nexport function buildServer(): McpServer {\n const server = new McpServer(\n {\n name: 'fingerprint-platform-mcp',\n version: '0.0.1',\n },\n {\n capabilities: {\n // We advertise tools only — no resources/prompts in v1. The\n // SDK auto-fills the capability object from the registrations\n // below, so we just declare an empty placeholder to be\n // explicit about the shape.\n tools: {},\n },\n instructions:\n 'Use these tools to install and configure the Fingerprint Platform SDK ' +\n '(`fingerprint-platform-sdk`) in a user project. Standard flow: ' +\n '`analyze_project` → `install_sdk` → `wire_init` → `set_collector_url` → ' +\n '`generate_cloudflare_worker` (recommended) or `generate_dns_fallback` → ' +\n '`verify_install`. Every tool is read-only on the filesystem and returns ' +\n 'a diff/command/env spec for the assistant to apply with its own tools. ' +\n 'Use `explain_topic` to fetch a focused brief on origin-allowlist, ' +\n 'cloudflare-proxy, dns-cname, api-keys, events-vs-identify, sync-vs-async.',\n },\n );\n\n // Helper to serialise our ToolEnvelope into the MCP CallToolResult\n // shape. We pack the structured fields (artifact / meta / nextSteps)\n // into a single markdown text block — that's what every current\n // MCP client renders directly, and it lets the AI parse the\n // structured content via simple regex/section-split prompts.\n function render(envelope: ToolEnvelope): {\n content: { type: 'text'; text: string }[];\n } {\n const parts: string[] = [envelope.summary];\n if (envelope.details) parts.push(envelope.details);\n if (envelope.nextSteps && envelope.nextSteps.length > 0) {\n parts.push(\n '## Next steps\\n\\n' + envelope.nextSteps.map((s, i) => `${i + 1}. ${s}`).join('\\n'),\n );\n }\n if (envelope.artifact) {\n switch (envelope.artifact.kind) {\n case 'diff':\n parts.push('## Diff\\n\\n```diff\\n' + envelope.artifact.content + '\\n```');\n break;\n case 'command':\n parts.push(\n '## Command\\n\\n```bash\\n' +\n envelope.artifact.content +\n '\\n```' +\n (envelope.artifact.cwd ? `\\n_(run in \\`${envelope.artifact.cwd}\\`)_` : ''),\n );\n break;\n case 'env':\n parts.push(\n '## Env vars\\n\\n```bash\\n' +\n Object.entries(envelope.artifact.content)\n .map(([k, v]) => `${k}=${v}`)\n .join('\\n') +\n '\\n```',\n );\n break;\n case 'markdown':\n // already in details when used; no double-render.\n break;\n }\n }\n return { content: [{ type: 'text', text: parts.join('\\n\\n') }] };\n }\n\n server.registerTool(\n 'analyze_project',\n {\n description:\n 'Scan the user project at `cwd` — read package.json + lockfile + framework config — to determine framework / package manager / entry file / whether the SDK is already installed. Read-only. Always call this first.',\n inputSchema: analyzeInputSchema,\n },\n async (args) => render(analyzeProject(args)),\n );\n\n server.registerTool(\n 'install_sdk',\n {\n description:\n 'Emit the install command for `fingerprint-platform-sdk` using the detected (or passed) package manager. Does NOT execute — the AI runs it via its own bash tool.',\n inputSchema: installInputSchema,\n },\n async (args) =>\n render(\n installSdk({\n cwd: args.cwd,\n source: args.source ?? 'npm',\n ...(args.packageManager ? { packageManager: args.packageManager } : {}),\n }),\n ),\n );\n\n server.registerTool(\n 'wire_init',\n {\n description:\n 'Generate a unified diff that places the framework-idiomatic SDK init() call into the right entry file. Reuses `initSnippet()` from `@fingerprint79/sdk-snippets` so the code matches what the dashboard shows.',\n inputSchema: wireInitInputSchema,\n },\n async (args) =>\n render(\n wireInit({\n cwd: args.cwd,\n framework: args.framework,\n entryFile: args.entryFile,\n apiKey: args.apiKey,\n collectorUrl: args.collectorUrl,\n source: args.source ?? 'npm',\n }),\n ),\n );\n\n server.registerTool(\n 'set_collector_url',\n {\n description:\n 'Validate a collector URL and return (a) env-var spec to add to `.env.local` and (b) the dashboard `allowedHosts` change the operator must make manually. The MCP server cannot mutate the dashboard in v1.',\n inputSchema: setCollectorUrlInputSchema,\n },\n async (args) => render(setCollectorUrl(args)),\n );\n\n server.registerTool(\n 'generate_cloudflare_worker',\n {\n description:\n 'Emit a `cloudflare/worker.ts` + `cloudflare/wrangler.toml` as diffs to drop into the user repo. Worker proxies SDK bundle + collector API under `<customDomain>/fpjs/*` for same-origin, ad-block-resistant delivery.',\n inputSchema: generateCloudflareWorkerInputSchema,\n },\n async (args) => render(generateCloudflareWorker(args)),\n );\n\n server.registerTool(\n 'generate_dns_fallback',\n {\n description:\n 'When Cloudflare is not an option, emit DNS CNAME instructions pointing a subdomain at the collector. Keeps cookies first-party but is more ad-block-prone than the Worker route.',\n inputSchema: generateDnsFallbackInputSchema,\n },\n async (args) => render(generateDnsFallback(args)),\n );\n\n server.registerTool(\n 'verify_install',\n {\n description:\n 'Run a post-install sanity checklist on the user project — SDK in deps, init() call grep-able in source, env vars set. Returns a `{ check, status, hint }[]` triple for each item.',\n inputSchema: verifyInstallInputSchema,\n },\n async (args) => render(verifyInstall(args)),\n );\n\n server.registerTool(\n 'explain_topic',\n {\n description:\n 'Return a focused markdown brief on one of: origin-allowlist, cloudflare-proxy, dns-cname, api-keys, events-vs-identify, sync-vs-async. Use when the user asks a \"why\" / \"how\" question about an advanced setup.',\n inputSchema: explainInputSchema,\n },\n async (args) => render(explainTopic(args)),\n );\n\n return server;\n}\n","import { resolve } from 'node:path';\n\nimport { frameworkLabel } from '@fingerprint79/sdk-snippets';\nimport { z } from 'zod';\n\nimport { detectFramework } from '../util/detect-framework.js';\nimport { detectPackageManager } from '../util/detect-pm.js';\n\nimport type { ToolEnvelope } from './types.js';\n\nexport const analyzeInputSchema = {\n cwd: z\n .string()\n .describe(\n 'Absolute path to the user project root. The AI assistant should pass its own current working directory or the project root it has been browsing.',\n ),\n};\n\n/**\n * `analyze_project` — read package.json + lockfile + framework config\n * to determine what we're working with. Pure read; never writes.\n *\n * Returns:\n * - framework + label (one of the 8 supported ids)\n * - packageManager (pnpm/yarn/bun/npm)\n * - entryFile (absolute path) — where wire_init will insert code\n * - hasSDK (boolean) — true if `fingerprint-platform-sdk` is already\n * in deps, in which case the AI can skip install_sdk\n * - rationale — human-readable signal used to make the call\n */\nexport function analyzeProject(input: { cwd: string }): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const scan = detectFramework(cwd);\n const pm = detectPackageManager(cwd);\n\n const nextSteps: string[] = [];\n if (!scan.hasSDK) {\n nextSteps.push(`Call \\`install_sdk\\` with cwd=\"${cwd}\" to install fingerprint-platform-sdk.`);\n }\n if (scan.entryFile) {\n nextSteps.push(\n `Call \\`wire_init\\` with cwd=\"${cwd}\", framework=\"${scan.framework}\", entryFile=\"${scan.entryFile}\" to insert the init snippet.`,\n );\n } else {\n nextSteps.push(\n `Couldn't auto-locate an entry file for ${scan.framework}. Ask the user where they want \\`fp.identify()\\` to fire on app boot, then pass that path to \\`wire_init\\`.`,\n );\n }\n nextSteps.push(\n `Call \\`set_collector_url\\` once you know the user's collector URL — typically https://<their-domain>/fpjs proxied through a Cloudflare Worker.`,\n );\n\n const details =\n `**Project scan**\\n\\n` +\n `- Framework: \\`${scan.framework}\\` (${frameworkLabel(scan.framework)})\\n` +\n `- Package manager: \\`${pm}\\` (detected from lockfile)\\n` +\n `- SDK already installed: ${scan.hasSDK ? 'yes' : 'no'}\\n` +\n `- Entry file: ${scan.entryFile ? `\\`${scan.entryFile}\\`` : '_not auto-detected_'}\\n\\n` +\n `_${scan.rationale}_`;\n\n return {\n summary: `Detected ${frameworkLabel(scan.framework)} project (${pm}, SDK ${scan.hasSDK ? 'installed' : 'missing'}).`,\n details,\n nextSteps,\n meta: {\n cwd,\n framework: scan.framework,\n packageManager: pm,\n entryFile: scan.entryFile ?? null,\n hasSDK: scan.hasSDK,\n },\n };\n}\n","/**\n * Code-snippet builder for the Install Fingerprint wizard.\n *\n * The SDK API is identical across frameworks (`init({collectorUrl,\n * projectKey})` then `fp.identify(...)`), but how an integrator\n * usually mounts it differs — Next.js needs `'use client'` + a\n * client-only dynamic import, React needs a `useEffect`, Angular a\n * service, etc. We hand out the smallest snippet that still feels\n * idiomatic for each framework so a copy-paste lands in roughly the\n * right place.\n *\n * `apiKey` is substituted into the snippet when revealed on the\n * Get-Started page; otherwise the placeholder string from the i18n\n * dictionary takes its place.\n */\n\nexport type Framework =\n | 'javascript'\n | 'javascript-spa'\n | 'nextjs'\n | 'react'\n | 'vue'\n | 'angular'\n | 'svelte'\n | 'preact';\n\nexport type SnippetSource = 'cdn' | 'npm';\n\nexport interface SnippetInput {\n readonly framework: Framework;\n readonly source: SnippetSource;\n /** Plain-text public api key, or the i18n placeholder when masked. */\n readonly apiKey: string;\n /** The customer's custom subdomain pointing at our collector, e.g.\n * `https://fp.theirsite.com`. Always shown — encourages the\n * production pattern over leaking our raw IP in browser source.\n * See `InstallFlow.tsx::Step 3` for the DNS-setup explanation. */\n readonly collectorUrl: string;\n}\n\n/** All 8 framework ids in display order. Mobile is intentionally\n * absent from this enum — that picker lives on the platform step. */\nexport const FRAMEWORKS: ReadonlyArray<{ id: Framework; label: string }> = [\n { id: 'javascript', label: 'JavaScript' },\n { id: 'javascript-spa', label: 'JavaScript SPA' },\n { id: 'nextjs', label: 'Next.js' },\n { id: 'react', label: 'React' },\n { id: 'angular', label: 'Angular' },\n { id: 'vue', label: 'Vue.js' },\n { id: 'preact', label: 'Preact' },\n { id: 'svelte', label: 'Svelte' },\n];\n\nexport function frameworkLabel(id: Framework): string {\n return FRAMEWORKS.find((f) => f.id === id)?.label ?? id;\n}\n\n/** CDN install line — same across frameworks (the bundle is plain\n * IIFE either way). Always links the obfuscated build; never link\n * `dist/fp.js` from a production page — DevTools → Sources reads it\n * in the clear and undoes the obfuscator pipeline.\n *\n * The primary line is the same-origin path served by the Cloudflare\n * Worker the integrator deploys in Step 3 («Production proxy»). The\n * unpkg URL stays as a commented-out fallback for quick dev/staging\n * — adblockers' default lists ship a rule for `unpkg.com`, so in\n * production this URL is one of the first to disappear from\n * document.scripts. */\nexport function cdnInstallSnippet(): string {\n return `<!-- Production: self-hosted through the Cloudflare Worker (Step 3 below) -->\n<script src=\"/fpjs/agent.js\" async></script>\n\n<!-- Dev / staging only — unpkg URL is on every ad-block list -->\n<!-- <script src=\"https://unpkg.com/fingerprint-platform-sdk/dist/fp.obf.js\" async></script> -->`;\n}\n\n/** NPM install line — same across frameworks. */\nexport function npmInstallSnippet(): string {\n return `npm install fingerprint-platform-sdk\n# or pnpm add fingerprint-platform-sdk\n# or yarn add fingerprint-platform-sdk`;\n}\n\n/** Initialise-and-identify snippet, framework-specific. The\n * framework parameter only changes the WRAPPER code — the\n * Fingerprint API calls inside it are identical. */\nexport function initSnippet(input: SnippetInput): string {\n const { framework, source, apiKey, collectorUrl } = input;\n const config = ` collectorUrl: '${collectorUrl}',\n projectKey: '${apiKey}',`;\n\n // CDN init — global `window.FP` from the IIFE. The init call is\n // identical across frameworks (same global, same shape); what\n // differs is WHERE the integrator drops the <script> tag. The\n // framework-specific lead comment surfaces that decision so an\n // operator switching frameworks while parked on the CDN tab sees\n // their picked framework's mounting convention spelled out.\n if (source === 'cdn') {\n return `${cdnPlacementComment(framework)}\n<script>\n // Initialize the agent at application startup.\n const fp = window.FP.init({\n${config}\n });\n\n // Get the visitor and event identifier when you need it.\n fp.identify({ event: 'pageview' }).then((r) => {\n if (r.visitorId) console.log(r.eventId, r.visitorId, r.suspectScore);\n else console.log('event queued:', r.eventId);\n });\n</script>`;\n }\n\n // NPM / bundler path — framework-specific wrapper.\n switch (framework) {\n case 'nextjs':\n return `// app/_components/FpClient.tsx — client component\n'use client';\nimport { useEffect } from 'react';\n\nexport function FpClient() {\n useEffect(() => {\n let cancelled = false;\n // Dynamic import keeps the SDK out of the server bundle — Next.js\n // SSR has no Window, the SDK throws on the canvas calls there.\n import('fingerprint-platform-sdk').then(({ init }) => {\n if (cancelled) return;\n const fp = init({\n${config.replace(/^/gm, ' ')}\n });\n void fp.identify({ event: 'pageview' });\n });\n return () => { cancelled = true; };\n }, []);\n return null;\n}\n\n// Then mount <FpClient /> in your root layout.`;\n\n case 'react':\n return `import { useEffect } from 'react';\nimport { init } from 'fingerprint-platform-sdk';\n\nexport function useFingerprint() {\n useEffect(() => {\n const fp = init({\n${config.replace(/^/gm, ' ')}\n });\n fp.identify({ event: 'pageview' }).then((r) => {\n if (r.visitorId) console.log(r.eventId, r.visitorId, r.suspectScore);\n else console.log('event queued:', r.eventId);\n });\n }, []);\n}\n\n// Call useFingerprint() once in your root component.`;\n\n case 'vue':\n return `// plugins/fingerprint.ts\nimport { init } from 'fingerprint-platform-sdk';\n\nconst fp = init({\n${config}\n});\n\nexport default {\n install(app) {\n app.config.globalProperties.$fp = fp;\n },\n};\n\n// Then in main.ts:\n// app.use(fpPlugin);\n// And from any component:\n// this.$fp.identify({ event: 'pageview' });`;\n\n case 'angular':\n return `// fingerprint.service.ts\nimport { Injectable } from '@angular/core';\nimport { init, type FpSdk } from 'fingerprint-platform-sdk';\n\n@Injectable({ providedIn: 'root' })\nexport class FingerprintService {\n readonly fp: FpSdk = init({\n${config.replace(/^/gm, ' ')}\n });\n}\n\n// Inject in components and call: this.fp.fp.identify({ event: 'pageview' });`;\n\n case 'svelte':\n return `// src/lib/fingerprint.ts\nimport { init } from 'fingerprint-platform-sdk';\n\nexport const fp = init({\n${config}\n});\n\n// In any +page.svelte:\n// <script lang=\"ts\">\n// import { onMount } from 'svelte';\n// import { fp } from '$lib/fingerprint';\n// onMount(() => { void fp.identify({ event: 'pageview' }); });\n// </script>`;\n\n case 'preact':\n return `import { useEffect } from 'preact/hooks';\nimport { init } from 'fingerprint-platform-sdk';\n\nexport function useFingerprint() {\n useEffect(() => {\n const fp = init({\n${config.replace(/^/gm, ' ')}\n });\n void fp.identify({ event: 'pageview' });\n }, []);\n}\n\n// Call useFingerprint() once in your root component.`;\n\n case 'javascript-spa':\n return `// src/fingerprint.js\n// Single-page app pattern: init once, identify() on each route change.\nimport { init } from 'fingerprint-platform-sdk';\n\nexport const fp = init({\n${config}\n});\n\n// In your router's onNavigate hook:\n// fp.identify({ event: 'route:' + path });`;\n\n case 'javascript':\n default:\n return `import { init } from 'fingerprint-platform-sdk';\n\nconst fp = init({\n${config}\n});\n\nfp.identify({ event: 'pageview' }).then((r) => {\n if (r.visitorId) console.log(r.eventId, r.visitorId, r.suspectScore);\n else console.log('event queued:', r.eventId);\n});`;\n }\n}\n\n/** Framework-specific lead-comment for the CDN snippet. The init\n * body itself is identical across frameworks (the IIFE exposes the\n * same `window.FP.init` global), but mounting conventions differ —\n * React puts the <script> in `public/index.html`, Next.js prefers\n * `<Script>` from `next/script` in the root layout, etc. Surfacing\n * the placement decision per-framework makes flipping the framework\n * picker visibly do something even when the CDN tab is parked. */\nfunction cdnPlacementComment(framework: Framework): string {\n switch (framework) {\n case 'nextjs':\n return `<!-- Next.js: prefer next/script with strategy=\"afterInteractive\" in app/layout.tsx\n rather than a raw <script>. The agent attaches to window.FP on first paint. -->`;\n case 'react':\n return `<!-- React: drop <script> in public/index.html (CRA / Vite-React).\n Access window.FP from any component after first paint. -->`;\n case 'vue':\n return `<!-- Vue.js: place <script> in public/index.html.\n Read window.FP inside onMounted / mounted hooks. -->`;\n case 'angular':\n return `<!-- Angular: add <script> to src/index.html.\n Wrap window.FP in an Injectable service for DI ergonomics. -->`;\n case 'svelte':\n return `<!-- Svelte / SvelteKit: add <script> to app.html (SvelteKit) or\n public/index.html. Use onMount() to read window.FP. -->`;\n case 'preact':\n return `<!-- Preact: drop <script> in your root index.html.\n Read window.FP from any component after mount. -->`;\n case 'javascript-spa':\n return `<!-- SPA: include once in your shell HTML. Call fp.identify()\n from your router's per-route hook to track navigation. -->`;\n case 'javascript':\n default:\n return `<!-- Vanilla JS: paste anywhere in <body>. The SDK fires\n identify() on its own once init() resolves. -->`;\n }\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport type { Framework } from '@fingerprint79/sdk-snippets';\n\n/**\n * Outcome of a project scan. `framework` is the best-match id from\n * the `Framework` union. `entryFile` is the absolute path where the\n * SDK init call should land — undefined when we couldn't locate a\n * conventional entry. `hasSDK` is a flag the AI can branch on to\n * skip `install_sdk` and jump straight to `wire_init` if needed.\n */\nexport interface ProjectScan {\n readonly framework: Framework;\n readonly entryFile: string | undefined;\n readonly hasSDK: boolean;\n /** Free-text rationale — surfaces in the analyze_project response so\n * the AI can echo it back to the user when explaining its plan. */\n readonly rationale: string;\n}\n\ninterface PackageJsonShape {\n readonly dependencies?: Record<string, string>;\n readonly devDependencies?: Record<string, string>;\n readonly peerDependencies?: Record<string, string>;\n}\n\n/**\n * Read package.json deps + the conventional config files to figure\n * out the project's framework. Order matters here: Next.js is a\n * React superset, so we must check `next` before `react`; SvelteKit\n * is a Svelte superset; Nuxt is a Vue superset. The first match\n * wins.\n *\n * When nothing matches confidently, we fall back to `'javascript'`\n * (vanilla) — that's the safest default and lets `wire_init` still\n * emit a copy-paste-able snippet rather than refusing the call.\n */\nexport function detectFramework(cwd: string): ProjectScan {\n const pkgJson = readPackageJson(cwd);\n const deps = collectDeps(pkgJson);\n const sdkInstalled = 'fingerprint-platform-sdk' in deps;\n\n // Order is intentional — check supersets first.\n if ('next' in deps) {\n return scan('nextjs', cwd, sdkInstalled, 'Detected `next` dependency in package.json.');\n }\n if ('nuxt' in deps) {\n // We don't ship a separate Nuxt snippet — Nuxt uses the same Vue\n // plugin pattern, so map to `vue`. Caller can still emit the right\n // installation path because the init code is plugin-based.\n return scan('vue', cwd, sdkInstalled, 'Detected `nuxt` — using the Vue.js plugin pattern.');\n }\n if ('@angular/core' in deps) {\n return scan('angular', cwd, sdkInstalled, 'Detected `@angular/core` dependency.');\n }\n if ('@sveltejs/kit' in deps || 'svelte' in deps) {\n return scan('svelte', cwd, sdkInstalled, 'Detected Svelte (or SvelteKit).');\n }\n if ('preact' in deps) {\n return scan('preact', cwd, sdkInstalled, 'Detected `preact` dependency.');\n }\n if ('vue' in deps) {\n return scan('vue', cwd, sdkInstalled, 'Detected `vue` dependency.');\n }\n if ('react' in deps || 'react-dom' in deps) {\n // Vite-React vs CRA vs plain React app — same snippet shape. We\n // tell apart \"this is an SPA shell\" from \"this is a React lib\"\n // by looking for an entry file; if none, the `javascript` fallback\n // would be silly when react is clearly in deps. Stick with react.\n return scan('react', cwd, sdkInstalled, 'Detected `react` dependency.');\n }\n\n // Config-file-only signals (rare — e.g. someone removed deps from\n // package.json but left the config). These are weaker, so they sit\n // after the deps checks.\n if (existsSync(resolve(cwd, 'next.config.js')) || existsSync(resolve(cwd, 'next.config.ts'))) {\n return scan('nextjs', cwd, sdkInstalled, 'Detected `next.config.*` without explicit dep.');\n }\n if (existsSync(resolve(cwd, 'angular.json'))) {\n return scan('angular', cwd, sdkInstalled, 'Detected `angular.json`.');\n }\n if (\n existsSync(resolve(cwd, 'svelte.config.js')) ||\n existsSync(resolve(cwd, 'svelte.config.ts'))\n ) {\n return scan('svelte', cwd, sdkInstalled, 'Detected `svelte.config.*`.');\n }\n\n // SPA shell with a router but no framework lib? Treat as the SPA\n // wrapper so we emit `router.onNavigate → fp.identify` per-route.\n // Heuristic: presence of a router lib in deps.\n if ('react-router' in deps || 'vue-router' in deps || 'svelte-routing' in deps) {\n return scan(\n 'javascript-spa',\n cwd,\n sdkInstalled,\n 'Detected a router library without a framework lib.',\n );\n }\n\n return scan('javascript', cwd, sdkInstalled, 'No framework signal — falling back to vanilla JS.');\n}\n\n/* ── helpers ───────────────────────────────────────────────────── */\n\nfunction readPackageJson(cwd: string): PackageJsonShape {\n const p = resolve(cwd, 'package.json');\n if (!existsSync(p)) return {};\n try {\n return JSON.parse(readFileSync(p, 'utf8')) as PackageJsonShape;\n } catch {\n // Malformed package.json — treat as empty. The user has bigger\n // problems than our analyzer; we don't want to crash.\n return {};\n }\n}\n\nfunction collectDeps(pkg: PackageJsonShape): Record<string, string> {\n return {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n ...pkg.peerDependencies,\n };\n}\n\nfunction scan(framework: Framework, cwd: string, hasSDK: boolean, rationale: string): ProjectScan {\n return {\n framework,\n entryFile: locateEntryFile(framework, cwd),\n hasSDK,\n rationale,\n };\n}\n\n/**\n * Best-effort guess at the file where the SDK init call goes.\n * Returns `undefined` when no conventional entry exists — the AI\n * will then ask the user, or the `wire_init` tool refuses with a\n * helpful error pointing to the convention for the framework.\n */\nfunction locateEntryFile(framework: Framework, cwd: string): string | undefined {\n const candidates: Record<Framework, readonly string[]> = {\n nextjs: ['app/layout.tsx', 'app/layout.jsx', 'src/app/layout.tsx', 'pages/_app.tsx'],\n react: ['src/main.tsx', 'src/main.jsx', 'src/index.tsx', 'src/index.jsx', 'src/App.tsx'],\n vue: ['src/main.ts', 'src/main.js'],\n angular: ['src/main.ts', 'src/app/app.module.ts'],\n svelte: ['src/routes/+layout.svelte', 'src/main.ts', 'src/main.js'],\n preact: ['src/main.tsx', 'src/index.tsx', 'src/index.jsx'],\n 'javascript-spa': ['src/main.js', 'src/main.ts', 'src/index.js'],\n javascript: ['index.html', 'src/index.html', 'public/index.html'],\n };\n for (const rel of candidates[framework]) {\n const abs = resolve(cwd, rel);\n if (existsSync(abs)) return abs;\n }\n return undefined;\n}\n","import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\n/**\n * Package managers we know how to emit install commands for. `npm` is\n * the safe fallback when no lockfile is present (matches what `npm\n * init` defaults to and what most tutorials assume).\n */\nexport type PackageManager = 'pnpm' | 'yarn' | 'bun' | 'npm';\n\n/**\n * Detect the package manager used by the project at `cwd` by looking\n * at lockfiles. We probe in the order pnpm → yarn → bun → npm so a\n * monorepo that has both `pnpm-lock.yaml` and a stray `package-lock.json`\n * (e.g. from a one-off `npm install` on a sub-package) doesn't get\n * misclassified — pnpm's presence is a stronger signal.\n *\n * Returns `'npm'` when nothing is present. Pure sync FS reads — fast\n * enough that this never warrants caching across tool calls, and\n * avoiding state simplifies the MCP request lifecycle.\n */\nexport function detectPackageManager(cwd: string): PackageManager {\n if (existsSync(resolve(cwd, 'pnpm-lock.yaml'))) return 'pnpm';\n if (existsSync(resolve(cwd, 'yarn.lock'))) return 'yarn';\n if (existsSync(resolve(cwd, 'bun.lockb')) || existsSync(resolve(cwd, 'bun.lock'))) return 'bun';\n return 'npm';\n}\n\n/**\n * Render the install command for a given package manager + package.\n * Centralised so the analyze, install and verify tools all emit\n * identical strings — the AI consumer can string-match them when\n * verifying that the user executed the install we proposed.\n */\nexport function renderInstallCommand(pm: PackageManager, pkg: string): string {\n switch (pm) {\n case 'pnpm':\n return `pnpm add ${pkg}`;\n case 'yarn':\n return `yarn add ${pkg}`;\n case 'bun':\n return `bun add ${pkg}`;\n case 'npm':\n default:\n return `npm install ${pkg}`;\n }\n}\n","import { resolve } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { makeNewFileDiff } from '../util/diff.js';\n\nimport type { ToolEnvelope } from './types.js';\n\n/* ── set_collector_url ─────────────────────────────────────────── */\n\nexport const setCollectorUrlInputSchema = {\n projectKey: z.string().describe(\"Project's public API key.\"),\n collectorUrl: z\n .string()\n .url()\n .describe(\n 'Same-origin collector URL — typically https://<their-domain>/fpjs (proxied by a Cloudflare Worker).',\n ),\n};\n\n/**\n * `set_collector_url` — validates the supplied URL and returns:\n * (a) env-var spec (`FP_PROJECT_KEY` + `FP_COLLECTOR_URL`) the user\n * should add to `.env.local` (we don't write the file — diff-\n * not-mutate),\n * (b) the dashboard `allowedHosts` change the operator must make\n * via the Security page (we can't mutate the dashboard from\n * the MCP server in v1).\n */\nexport function setCollectorUrl(input: { projectKey: string; collectorUrl: string }): ToolEnvelope {\n let parsed: URL;\n try {\n parsed = new URL(input.collectorUrl);\n } catch {\n return {\n summary: 'Invalid collector URL.',\n details: `\\`${input.collectorUrl}\\` is not a valid URL. Pass a full https URL like \\`https://yoursite.com/fpjs\\`.`,\n meta: { error: 'invalid_url' },\n };\n }\n if (parsed.protocol !== 'https:' && parsed.hostname !== 'localhost') {\n return {\n summary: 'Collector URL must be HTTPS.',\n details:\n 'The browser SDK uses X25519 sealing which requires a secure context (HTTPS or localhost). ' +\n `\\`${parsed.protocol}//${parsed.hostname}\\` would fail at runtime — please serve via HTTPS in production.`,\n meta: { error: 'http_in_production' },\n };\n }\n\n const originForAllowedHosts = `${parsed.protocol}//${parsed.hostname}${parsed.port ? `:${parsed.port}` : ''}`;\n\n return {\n summary: `Use \\`${input.collectorUrl}\\` as the collector URL.`,\n details:\n `**1) Add to your environment** (e.g. \\`.env.local\\`):\\n\\n` +\n '```bash\\n' +\n `FP_PROJECT_KEY=${input.projectKey}\\n` +\n `FP_COLLECTOR_URL=${input.collectorUrl}\\n` +\n '```\\n\\n' +\n `**2) Add origin to dashboard allowedHosts.** Open the Fingerprint ` +\n `dashboard → Security → Allowed hosts and add:\\n\\n` +\n `\\`${originForAllowedHosts}\\`\\n\\n` +\n `Without this entry the collector rejects requests from your site ` +\n `with a 401 \\`origin_not_allowed\\`. (We can't mutate the dashboard from ` +\n `the MCP server in v1; this step is manual.)`,\n nextSteps: [\n `Add the two env vars above to \\`.env.local\\` (or your secret manager).`,\n `Open the dashboard's Security page and add \\`${originForAllowedHosts}\\` to allowedHosts.`,\n `Call \\`generate_cloudflare_worker\\` if you want a same-origin proxy on /fpjs/*.`,\n ],\n artifact: {\n kind: 'env',\n content: {\n FP_PROJECT_KEY: input.projectKey,\n FP_COLLECTOR_URL: input.collectorUrl,\n },\n },\n meta: { origin: originForAllowedHosts, collectorUrl: input.collectorUrl },\n };\n}\n\n/* ── generate_cloudflare_worker ─────────────────────────────────── */\n\nexport const generateCloudflareWorkerInputSchema = {\n cwd: z.string().describe('Absolute path to the user project root — for the diff header.'),\n collectorHost: z\n .string()\n .describe(\n 'Hostname of the Fingerprint collector to proxy to, without scheme. E.g. `collector.yoursite.com` or `89.124.91.162`.',\n ),\n customDomain: z\n .string()\n .describe(\n \"Your site's domain, e.g. `yoursite.com`. The Worker routes `<customDomain>/fpjs/*`.\",\n ),\n};\n\n/**\n * `generate_cloudflare_worker` — produces the Worker script body\n * plus `wrangler.toml` as two diffs the AI can apply with its edit\n * tool. The Worker proxies BOTH `/fpjs/agent.js` (SDK bundle) AND\n * the collector API endpoints under `/fpjs/v1/*` (ingest, result,\n * comparison, pk). Cookies stay first-party, ad-blockers blind.\n */\nexport function generateCloudflareWorker(input: {\n cwd: string;\n collectorHost: string;\n customDomain: string;\n}): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const workerPath = resolve(cwd, 'cloudflare/worker.ts');\n const wranglerPath = resolve(cwd, 'cloudflare/wrangler.toml');\n\n // Strip protocol if the user accidentally included it.\n const host = input.collectorHost.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n const domain = input.customDomain.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n\n const workerScript = cloudflareWorkerTemplate(host);\n const wranglerToml = wranglerTomlTemplate(domain);\n\n const workerDiff = makeNewFileDiff({ cwd, filePath: workerPath, content: workerScript });\n const wranglerDiff = makeNewFileDiff({ cwd, filePath: wranglerPath, content: wranglerToml });\n\n return {\n summary: `Cloudflare Worker template for \\`${domain}/fpjs/*\\` → \\`${host}\\`.`,\n details:\n `Two files to write into the user's repo:\\n\\n` +\n `**\\`cloudflare/worker.ts\\`** — the Worker script body.\\n` +\n `**\\`cloudflare/wrangler.toml\\`** — Wrangler deploy config (route + zone).\\n\\n` +\n `Both diffs are pasted below. Apply with your edit tool, then run\\n\\n` +\n '```bash\\n' +\n 'cd cloudflare && wrangler deploy\\n' +\n '```\\n\\n' +\n `from the project root. After deploy, the Worker is live on the route\\n` +\n `pattern \\`${domain}/fpjs/*\\`. The SDK then loads same-origin: cookies\\n` +\n `stay first-party, ad-blockers can't pattern-match a cross-origin path.\\n\\n` +\n `--- ${workerPath} ---\\n\\n\\`\\`\\`diff\\n${workerDiff}\\n\\`\\`\\`\\n\\n` +\n `--- ${wranglerPath} ---\\n\\n\\`\\`\\`diff\\n${wranglerDiff}\\n\\`\\`\\``,\n nextSteps: [\n `Apply both diffs to create the cloudflare/ directory.`,\n `Install Wrangler: \\`npm i -g wrangler\\` (or use \\`npx wrangler\\`).`,\n `Authenticate: \\`wrangler login\\`.`,\n `Deploy: \\`cd cloudflare && wrangler deploy\\`.`,\n `Update \\`FP_COLLECTOR_URL\\` env var to \\`https://${domain}/fpjs\\`.`,\n `Add \\`https://${domain}\\` to dashboard allowedHosts via the Security page.`,\n ],\n // Single diff payload that concatenates both files — git apply\n // accepts multi-file unified diffs.\n artifact: { kind: 'diff', content: `${workerDiff}\\n${wranglerDiff}` },\n meta: {\n workerPath,\n wranglerPath,\n route: `${domain}/fpjs/*`,\n collectorHost: host,\n },\n };\n}\n\n/* ── generate_dns_fallback ──────────────────────────────────────── */\n\nexport const generateDnsFallbackInputSchema = {\n subdomain: z\n .string()\n .describe('Subdomain to point at the collector, e.g. `fp.yoursite.com`. Must be a FQDN.'),\n collectorHost: z.string().describe('Hostname (or IP) of the Fingerprint collector.'),\n};\n\n/**\n * `generate_dns_fallback` — when Cloudflare isn't an option,\n * point a DNS CNAME from `fp.yoursite.com` to the collector\n * directly. Less ad-block-proof than the Worker route (a dedicated\n * subdomain is easier for filter rules to catch than a same-origin\n * path) but still keeps cookies first-party.\n */\nexport function generateDnsFallback(input: {\n subdomain: string;\n collectorHost: string;\n}): ToolEnvelope {\n const host = input.collectorHost.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n // Determine the apex from the subdomain — naively split on the\n // first dot. Good enough for the DNS instructions; the user will\n // know which zone to edit.\n const apex = input.subdomain.split('.').slice(1).join('.');\n\n return {\n summary: `DNS CNAME \\`${input.subdomain}\\` → \\`${host}\\`.`,\n details:\n `Add the following DNS record in your registrar's zone editor for ` +\n `\\`${apex}\\`:\\n\\n` +\n '```text\\n' +\n `Type: CNAME\\n` +\n `Name: ${input.subdomain.replace(`.${apex}`, '')}\\n` +\n `Value: ${host}\\n` +\n `TTL: 300 (5 min — bump after verification)\\n` +\n '```\\n\\n' +\n `Once propagated, set:\\n\\n` +\n '```bash\\n' +\n `FP_COLLECTOR_URL=https://${input.subdomain}\\n` +\n '```\\n\\n' +\n `Then add \\`https://${input.subdomain}\\` to the dashboard's ` +\n `allowedHosts on the Security page.\\n\\n` +\n `_Trade-off vs the Cloudflare Worker route: a dedicated subdomain ` +\n `is **easier for ad-block filter rules to catch** than a same-origin ` +\n `path like \\`yoursite.com/fpjs/*\\`. Use the Worker if you can; this ` +\n `is the fallback when Cloudflare isn't on the table._`,\n nextSteps: [\n `Create the CNAME record in your DNS provider.`,\n `Wait for propagation (\\`dig ${input.subdomain}\\` should return the CNAME).`,\n `Update \\`FP_COLLECTOR_URL\\` and dashboard allowedHosts.`,\n ],\n meta: { subdomain: input.subdomain, collectorHost: host, apex },\n };\n}\n\n/* ── templates ─────────────────────────────────────────────────── */\n\nfunction cloudflareWorkerTemplate(collectorHost: string): string {\n return `/**\n * Fingerprint Platform same-origin proxy.\n *\n * Generated by fingerprint-platform-mcp.\n *\n * Route pattern: <yoursite>/fpjs/*\n *\n * Proxies BOTH the SDK bundle (served on /fpjs/agent.js) AND every\n * collector endpoint (/fpjs/v1/ingest, /fpjs/v1/result/<id>,\n * /fpjs/v1/pk, /fpjs/v1/comparison). Cookies stay first-party,\n * ad-blockers cannot pattern-match a same-origin path.\n *\n * The integrator's app backend is NEVER in the fingerprint request\n * path — that would couple uptime and add latency. The Worker\n * fans out directly to ${collectorHost}.\n */\n\nconst COLLECTOR_ORIGIN = \"https://${collectorHost}\";\n\nexport default {\n async fetch(req: Request): Promise<Response> {\n const url = new URL(req.url);\n\n // SDK bundle.\n if (url.pathname === \"/fpjs/agent.js\") {\n const upstream = new URL(\"/v1/agent.js\", COLLECTOR_ORIGIN);\n return forward(req, upstream);\n }\n\n // Collector API surface under /fpjs/v1/*.\n if (url.pathname.startsWith(\"/fpjs/v1/\")) {\n const upstream = new URL(url.pathname.replace(/^\\\\/fpjs/, \"\"), COLLECTOR_ORIGIN);\n upstream.search = url.search;\n return forward(req, upstream);\n }\n\n // Unknown path under /fpjs/ — 404 cleanly so misconfigured route\n // patterns don't accidentally proxy the user's whole site.\n return new Response(\"not found\", { status: 404 });\n },\n};\n\nasync function forward(req: Request, upstream: URL): Promise<Response> {\n const headers = new Headers(req.headers);\n // Preserve the original client IP for the collector's IP-class\n // enrichment — Cloudflare exposes it via cf-connecting-ip.\n const clientIp = headers.get(\"cf-connecting-ip\") ?? headers.get(\"x-forwarded-for\");\n if (clientIp) headers.set(\"x-forwarded-for\", clientIp);\n // Strip the Host header so the upstream sees its own hostname.\n headers.delete(\"host\");\n\n const init: RequestInit = {\n method: req.method,\n headers,\n body: req.method === \"GET\" || req.method === \"HEAD\" ? undefined : req.body,\n redirect: \"manual\",\n };\n return fetch(upstream.toString(), init);\n}\n`;\n}\n\nfunction wranglerTomlTemplate(customDomain: string): string {\n return `name = \"fingerprint-proxy\"\nmain = \"worker.ts\"\ncompatibility_date = \"2025-01-01\"\n\n# Attach the Worker to your domain. Replace the zone_name if it\n# differs from the domain. Wrangler will prompt for the zone on\n# first deploy if you remove the zone_name line.\nroutes = [\n { pattern = \"${customDomain}/fpjs/*\", zone_name = \"${customDomain}\" },\n]\n`;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { relative } from 'node:path';\n\nimport { createPatch } from 'diff';\n\n/**\n * Build a unified-diff patch from an existing file's current contents\n * to its proposed new contents. Returned as a string ready to drop\n * into a `git apply` invocation. The path inside the patch is\n * RELATIVE to `cwd` so the AI assistant can apply it from the\n * project root without needing to rewrite the header.\n *\n * The `diff` package's `createPatch` emits standard unified format\n * (3 lines of context by default). We pass empty `oldHeader` /\n * `newHeader` to keep the output compact — the `--- a/<path>` /\n * `+++ b/<path>` lines `git apply` cares about are generated\n * regardless.\n */\nexport function makeUnifiedDiff(opts: {\n readonly cwd: string;\n readonly filePath: string;\n readonly newContent: string;\n}): string {\n const oldContent = existsSync(opts.filePath) ? readFileSync(opts.filePath, 'utf8') : '';\n const rel = relative(opts.cwd, opts.filePath).split('\\\\').join('/');\n return createPatch(rel, oldContent, opts.newContent, '', '', { context: 3 });\n}\n\n/**\n * Build a \"new file\" diff — same shape as makeUnifiedDiff but\n * always emits a `/dev/null → b/<path>` header, suitable for files\n * the assistant should create from scratch (e.g. the Cloudflare\n * Worker template). The `diff` lib handles this automatically when\n * `oldContent` is the empty string, but we wrap it for callers who\n * want explicit intent in the call site.\n */\nexport function makeNewFileDiff(opts: {\n readonly cwd: string;\n readonly filePath: string;\n readonly content: string;\n}): string {\n const rel = relative(opts.cwd, opts.filePath).split('\\\\').join('/');\n return createPatch(rel, '', opts.content, '', '', { context: 3 });\n}\n","import { readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { z } from 'zod';\n\nimport type { ToolEnvelope } from './types.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Topic ids → bundled markdown filename. We define the union here\n * (rather than scanning `docs/` at runtime) so a typo in the input\n * fails Zod validation before we even open the FS, and so an AI\n * model can be confident the topic list matches its training memory.\n */\nconst TOPIC_FILES: Record<string, string> = {\n 'origin-allowlist': 'origin-allowlist.md',\n 'cloudflare-proxy': 'cloudflare-proxy.md',\n 'dns-cname': 'dns-cname.md',\n 'api-keys': 'api-keys.md',\n 'events-vs-identify': 'events-vs-identify.md',\n 'sync-vs-async': 'sync-vs-async.md',\n};\n\nexport const explainInputSchema = {\n topic: z\n .enum([\n 'origin-allowlist',\n 'cloudflare-proxy',\n 'dns-cname',\n 'api-keys',\n 'events-vs-identify',\n 'sync-vs-async',\n ])\n .describe(\n 'Topic id. The AI assistant picks one based on the user question. Each topic returns a focused markdown brief — pasting raw docs into the conversation tends to drown out the actionable bits.',\n ),\n};\n\n/**\n * `explain_topic` — return a focused markdown brief on one of our\n * six advanced-setup topics. Pure read of the bundled `docs/` dir.\n *\n * The `docs/` files are copied into `dist/docs/` by tsup's\n * `onSuccess` step (see `tsup.config.ts`). When running under\n * `tsx` (`pnpm dev`), we resolve back to `src/docs/`. The path\n * fallback handles both.\n */\nexport function explainTopic(input: { topic: keyof typeof TOPIC_FILES }): ToolEnvelope {\n const filename = TOPIC_FILES[input.topic];\n if (!filename) {\n return {\n summary: `Unknown topic \"${input.topic}\".`,\n details: `Known topics: ${Object.keys(TOPIC_FILES).join(', ')}.`,\n meta: { error: 'unknown_topic' },\n };\n }\n\n // dist/docs/<name>.md when bundled, src/docs/<name>.md under tsx.\n const candidates = [\n resolve(__dirname, '..', 'docs', filename),\n resolve(__dirname, 'docs', filename),\n resolve(__dirname, '..', '..', 'src', 'docs', filename),\n ];\n for (const path of candidates) {\n try {\n const content = readFileSync(path, 'utf8');\n return {\n summary: `Returned docs/${filename} (${content.length} chars).`,\n details: content,\n artifact: { kind: 'markdown', content },\n meta: { topic: input.topic, path },\n };\n } catch {\n // try next candidate\n }\n }\n\n return {\n summary: `docs/${filename} not found at runtime.`,\n details:\n `Looked at: ${candidates.join(', ')}. This is a build issue — the ` +\n `tsup config should be copying src/docs/ into dist/docs/. Re-run ` +\n `\\`pnpm build\\` and try again.`,\n meta: { error: 'doc_missing', topic: input.topic },\n };\n}\n","import { resolve } from 'node:path';\n\nimport { z } from 'zod';\n\nimport {\n detectPackageManager,\n renderInstallCommand,\n type PackageManager,\n} from '../util/detect-pm.js';\n\nimport type { ToolEnvelope } from './types.js';\n\nexport const installInputSchema = {\n cwd: z.string().describe('Absolute path to the user project root.'),\n packageManager: z\n .enum(['pnpm', 'yarn', 'bun', 'npm'])\n .optional()\n .describe(\n 'Override the auto-detected package manager. Most callers should let analyze_project decide.',\n ),\n source: z\n .enum(['npm', 'cdn'])\n .default('npm')\n .describe(\n \"Install source. `npm` is the default (recommended). `cdn` returns the <script> tag snippet instead — useful when the user explicitly doesn't want to add an npm dep.\",\n ),\n};\n\n/**\n * `install_sdk` — returns the install command (or CDN snippet) for\n * `fingerprint-platform-sdk`. Does NOT execute. The AI runs it via\n * its own bash/shell tool — this is the diff-not-mutate contract we\n * keep across every tool.\n */\nexport function installSdk(input: {\n cwd: string;\n packageManager?: PackageManager;\n source?: 'npm' | 'cdn';\n}): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const source = input.source ?? 'npm';\n\n if (source === 'cdn') {\n return {\n summary: 'CDN install — no package manager command needed.',\n details:\n 'Add the following `<script>` tag to your HTML shell ' +\n '(e.g. `public/index.html`, `app.html`, or the framework-specific ' +\n 'entry document). Once it loads, `window.FP.init({...})` is available.\\n\\n' +\n '```html\\n<script src=\"/fpjs/agent.js\" async></script>\\n```\\n\\n' +\n '_The recommended `/fpjs/agent.js` path is served by your Cloudflare ' +\n 'Worker proxy (see `generate_cloudflare_worker`). The unpkg URL ' +\n 'works for local dev but is on every ad-block list — do not ship ' +\n 'it to production._',\n nextSteps: [`Call \\`wire_init\\` to insert the init() call into the right entry file.`],\n artifact: {\n kind: 'markdown',\n content: '<script src=\"/fpjs/agent.js\" async></script>',\n },\n meta: { source: 'cdn', cwd },\n };\n }\n\n const pm = input.packageManager ?? detectPackageManager(cwd);\n const cmd = renderInstallCommand(pm, 'fingerprint-platform-sdk');\n\n return {\n summary: `Install via ${pm}: \\`${cmd}\\``,\n details:\n `Run the following command in the project root (\\`${cwd}\\`):\\n\\n` +\n '```bash\\n' +\n cmd +\n '\\n```\\n\\n' +\n `_Detected package manager: ${pm}. If this is wrong, pass \\`packageManager\\` explicitly._`,\n nextSteps: [\n `Execute the command above via your bash tool.`,\n `Then call \\`wire_init\\` to insert the SDK init() call into the right entry file.`,\n ],\n artifact: { kind: 'command', content: cmd, cwd },\n meta: { source: 'npm', packageManager: pm, cwd, command: cmd },\n };\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { detectFramework } from '../util/detect-framework.js';\n\nimport type { ToolEnvelope } from './types.js';\n\nexport const verifyInstallInputSchema = {\n cwd: z.string().describe('Absolute path to the user project root.'),\n};\n\ninterface Check {\n readonly name: string;\n readonly status: 'ok' | 'warn' | 'fail';\n readonly hint: string;\n}\n\n/**\n * `verify_install` — sanity checklist run after the AI applied the\n * `install_sdk` + `wire_init` diffs. We re-analyze the project and\n * report a structured list:\n *\n * - SDK dependency present\n * - Init call grep-able somewhere in the source tree\n * - Env vars set (FP_PROJECT_KEY + FP_COLLECTOR_URL — in shell env\n * or a `.env*` file)\n *\n * Doesn't fire a real /v1/ingest request — that would require us to\n * spawn a headless browser, and we're a Node CLI. The AI can do\n * that step itself if asked (it has Playwright tools).\n */\nexport function verifyInstall(input: { cwd: string }): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const scan = detectFramework(cwd);\n const checks: Check[] = [];\n\n // 1) SDK in deps.\n checks.push({\n name: 'fingerprint-platform-sdk in dependencies',\n status: scan.hasSDK ? 'ok' : 'fail',\n hint: scan.hasSDK\n ? `Detected via package.json.`\n : `Run \\`install_sdk\\` and apply its install command.`,\n });\n\n // 2) Init call somewhere in src/. We grep for `FP.init(` and the\n // ESM `init(` import — either signals the user's code references\n // the SDK. False positives are unlikely (we're in a project that\n // just installed `fingerprint-platform-sdk`).\n const initCallFound = grepForInitCall(cwd);\n checks.push({\n name: 'SDK `init(...)` call present in source tree',\n status: initCallFound ? 'ok' : 'warn',\n hint: initCallFound\n ? `Found a reference to \\`init({...})\\` or \\`window.FP.init\\` in the source.`\n : `Couldn't find an \\`init({...})\\` call. Either re-run \\`wire_init\\` to ` +\n `place the snippet, or confirm the user mounted the generated module.`,\n });\n\n // 3) Env vars. We accept either real env (process.env) or a `.env*`\n // file in the project root.\n const envCheck = envVarStatus(cwd);\n checks.push({\n name: 'FP_PROJECT_KEY + FP_COLLECTOR_URL configured',\n status: envCheck.both ? 'ok' : envCheck.either ? 'warn' : 'fail',\n hint: envCheck.hint,\n });\n\n const failCount = checks.filter((c) => c.status === 'fail').length;\n const warnCount = checks.filter((c) => c.status === 'warn').length;\n const summary =\n failCount > 0\n ? `${failCount} check failed, ${warnCount} warning. See checklist.`\n : warnCount > 0\n ? `Mostly good — ${warnCount} thing(s) to confirm manually.`\n : 'All checks green. Send a test event and look for it on the dashboard.';\n\n return {\n summary,\n details:\n `**Verification checklist**\\n\\n` +\n checks.map((c) => `- ${badge(c.status)} **${c.name}** — ${c.hint}`).join('\\n'),\n nextSteps:\n failCount === 0 && warnCount === 0\n ? [\n `Trigger an event by reloading the page where the SDK is mounted.`,\n `Open the dashboard → Identification view; the event should appear within ~2s.`,\n ]\n : [`Resolve the failed / warned checks above and call \\`verify_install\\` again.`],\n meta: { checks, framework: scan.framework },\n };\n}\n\n/* ── helpers ───────────────────────────────────────────────────── */\n\nfunction badge(status: 'ok' | 'warn' | 'fail'): string {\n return status === 'ok' ? '✓' : status === 'warn' ? '⚠' : '✗';\n}\n\nfunction grepForInitCall(cwd: string): boolean {\n // Single-shot tree walk capped at 5000 files to avoid runaway\n // recursion on giant monorepos. We're only sanity-checking — a\n // real grep is the user's job.\n let count = 0;\n const stack: string[] = [cwd];\n const seen = new Set<string>();\n while (stack.length > 0 && count < 5000) {\n const dir = stack.pop();\n if (!dir || seen.has(dir)) continue;\n seen.add(dir);\n if (/[\\\\/](node_modules|dist|\\.next|build|coverage|\\.turbo)$/.test(dir)) continue;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n continue;\n }\n for (const name of entries) {\n count++;\n if (count >= 5000) break;\n const abs = resolve(dir, name);\n let stat;\n try {\n stat = statSync(abs);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n stack.push(abs);\n continue;\n }\n if (!/\\.(t|j)sx?$|\\.svelte$|\\.vue$|\\.html$/.test(name)) continue;\n try {\n const raw = readFileSync(abs, 'utf8');\n if (/\\bFP\\.init\\(|\\binit\\(\\s*\\{\\s*(collectorUrl|projectKey)/m.test(raw)) {\n return true;\n }\n } catch {\n // unreadable; ignore.\n }\n }\n }\n return false;\n}\n\nfunction envVarStatus(cwd: string): { both: boolean; either: boolean; hint: string } {\n const fromProcess = {\n key: Boolean(process.env['FP_PROJECT_KEY']),\n url: Boolean(process.env['FP_COLLECTOR_URL']),\n };\n const dotenvFiles = ['.env', '.env.local', '.env.development', '.env.production'];\n const seenInDotenv = { key: false, url: false };\n for (const name of dotenvFiles) {\n const p = resolve(cwd, name);\n if (!existsSync(p)) continue;\n try {\n const raw = readFileSync(p, 'utf8');\n if (/^\\s*FP_PROJECT_KEY\\s*=/m.test(raw)) seenInDotenv.key = true;\n if (/^\\s*FP_COLLECTOR_URL\\s*=/m.test(raw)) seenInDotenv.url = true;\n } catch {\n // ignore\n }\n }\n const keyOk = fromProcess.key || seenInDotenv.key;\n const urlOk = fromProcess.url || seenInDotenv.url;\n const both = keyOk && urlOk;\n const either = keyOk || urlOk;\n const missing: string[] = [];\n if (!keyOk) missing.push('FP_PROJECT_KEY');\n if (!urlOk) missing.push('FP_COLLECTOR_URL');\n return {\n both,\n either,\n hint: both\n ? `Found both vars (in process.env or a .env file).`\n : `Missing: ${missing.join(', ')}. Add to \\`.env.local\\` via \\`set_collector_url\\`.`,\n };\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\nimport { initSnippet, frameworkLabel, type Framework } from '@fingerprint79/sdk-snippets';\nimport { z } from 'zod';\n\nimport { makeUnifiedDiff, makeNewFileDiff } from '../util/diff.js';\n\nimport type { ToolEnvelope } from './types.js';\n\nexport const wireInitInputSchema = {\n cwd: z.string().describe('Absolute path to the user project root.'),\n framework: z\n .enum(['javascript', 'javascript-spa', 'nextjs', 'react', 'vue', 'angular', 'svelte', 'preact'])\n .describe('Framework id from `analyze_project`.'),\n entryFile: z\n .string()\n .describe(\n 'Absolute path to the file that should host the SDK init call (from `analyze_project.meta.entryFile`).',\n ),\n apiKey: z\n .string()\n .describe(\n \"Project's public API key. Substitute the value from the dashboard's API keys page or env.FP_PROJECT_KEY.\",\n ),\n collectorUrl: z\n .string()\n .url()\n .describe(\n 'Same-origin collector URL — typically https://<their-domain>/fpjs (proxied by a Cloudflare Worker).',\n ),\n source: z\n .enum(['npm', 'cdn'])\n .default('npm')\n .describe('Match whatever `install_sdk` ran with. Defaults to `npm`.'),\n};\n\n/**\n * `wire_init` — produce a unified diff that inserts the framework-\n * idiomatic init snippet into the user's entry file. Reuses\n * `initSnippet()` from `@fingerprint79/sdk-snippets` so the dashboard's\n * snippet panel and this MCP tool emit byte-identical code.\n *\n * Strategy per framework:\n * - `nextjs` / `react` / `preact`: insert as a NEW client component\n * file `app/_components/FpClient.tsx` (or\n * `src/components/FpClient.tsx`) — much safer than splicing into\n * an existing `app/layout.tsx` whose JSX shape we can't predict.\n * Caller mounts <FpClient /> in their root tree as a follow-up.\n * - `vue` / `svelte`: insert as a NEW plugin module the user\n * registers.\n * - `angular`: insert as a NEW Injectable service.\n * - `javascript` / `javascript-spa`: append the script to the\n * entry file directly (the file is already a script entry).\n *\n * For HTML entries (vanilla source=cdn), we splice a `<script>` tag\n * into the existing file using `makeUnifiedDiff` against the actual\n * file contents.\n */\nexport function wireInit(input: {\n cwd: string;\n framework: Framework;\n entryFile: string;\n apiKey: string;\n collectorUrl: string;\n source?: 'npm' | 'cdn';\n}): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const entryFile = resolve(input.entryFile);\n const source = input.source ?? 'npm';\n\n const snippet = initSnippet({\n framework: input.framework,\n source,\n apiKey: input.apiKey,\n collectorUrl: input.collectorUrl,\n });\n\n // CDN flow: append <script> tag to the entry HTML.\n if (source === 'cdn') {\n if (!existsSync(entryFile)) {\n return missingEntryFile(entryFile, input.framework);\n }\n const current = readFileSync(entryFile, 'utf8');\n const next = appendBeforeBodyClose(current, snippet);\n const diff = makeUnifiedDiff({ cwd, filePath: entryFile, newContent: next });\n return successDiff(diff, entryFile, input.framework, source, [\n `Apply the diff to \\`${entryFile}\\` via your edit tool.`,\n `Reload the page and confirm \\`window.FP.init\\` is defined in DevTools.`,\n ]);\n }\n\n // NPM flow: emit a NEW file with the per-framework module wrapper.\n // The chosen path follows each framework's convention.\n const targetFile = perFrameworkTargetFile(input.framework, cwd);\n const diff = makeNewFileDiff({ cwd, filePath: targetFile, content: snippet });\n\n const mountHint = perFrameworkMountHint(input.framework);\n return successDiff(diff, targetFile, input.framework, source, [\n `Apply the diff to create \\`${targetFile}\\` via your edit tool.`,\n mountHint,\n `Run the app and confirm the SDK boots — open DevTools, you should see the eventId / visitorId logged.`,\n ]);\n}\n\n/* ── helpers ───────────────────────────────────────────────────── */\n\nfunction successDiff(\n diff: string,\n filePath: string,\n framework: Framework,\n source: 'npm' | 'cdn',\n nextSteps: string[],\n): ToolEnvelope {\n return {\n summary: `Wrote ${source} init for ${frameworkLabel(framework)} into \\`${filePath}\\`.`,\n details:\n `Apply the unified diff below with \\`git apply\\` (or your AI ` +\n `assistant's edit tool). The patch is against \\`${filePath}\\` and ` +\n `is generated from the same \\`initSnippet()\\` helper the dashboard's ` +\n `Get Started page uses — so what you see here matches the install ` +\n `snippet shown there byte-for-byte.\\n\\n` +\n '```diff\\n' +\n diff +\n '\\n```',\n nextSteps,\n artifact: { kind: 'diff', content: diff },\n meta: { framework, source, filePath },\n };\n}\n\nfunction missingEntryFile(entryFile: string, framework: Framework): ToolEnvelope {\n return {\n summary: `Entry file \\`${entryFile}\\` not found.`,\n details:\n `The path we were given doesn't exist. Re-run \\`analyze_project\\` ` +\n `to refresh the detection, or ask the user where their ${frameworkLabel(framework)} ` +\n `entry document lives (typically \\`public/index.html\\`, \\`app.html\\`, or the ` +\n `framework's root template).`,\n nextSteps: [`Call \\`analyze_project\\` again to re-detect, or accept the user's manual path.`],\n meta: { error: 'entry_not_found', entryFile },\n };\n}\n\n/**\n * Per-framework target path for the NEW init module. Mirrors the\n * code comments inside `initSnippet()` (\"// app/_components/FpClient.tsx\",\n * \"// plugins/fingerprint.ts\", etc.).\n */\nfunction perFrameworkTargetFile(framework: Framework, cwd: string): string {\n const map: Record<Framework, string> = {\n nextjs: 'app/_components/FpClient.tsx',\n react: 'src/hooks/useFingerprint.ts',\n vue: 'src/plugins/fingerprint.ts',\n angular: 'src/app/fingerprint.service.ts',\n svelte: 'src/lib/fingerprint.ts',\n preact: 'src/hooks/useFingerprint.ts',\n 'javascript-spa': 'src/fingerprint.ts',\n javascript: 'src/fingerprint.ts',\n };\n // Use `dirname` once to be safe across platforms before joining.\n return resolve(cwd, map[framework]);\n}\n\nfunction perFrameworkMountHint(framework: Framework): string {\n switch (framework) {\n case 'nextjs':\n return 'Mount `<FpClient />` once in `app/layout.tsx` so it boots on every route.';\n case 'react':\n case 'preact':\n return 'Call `useFingerprint()` once in your root `App` component.';\n case 'vue':\n return 'In `main.ts`: `import fpPlugin from \"./plugins/fingerprint\"; app.use(fpPlugin);`. Then from any component call `this.$fp.identify({ event: \"pageview\" })`.';\n case 'angular':\n return 'Inject `FingerprintService` in any component and call `this.fp.fp.identify({ event: \"pageview\" })`.';\n case 'svelte':\n return 'In a `+page.svelte`: `import { fp } from \"$lib/fingerprint\"; onMount(() => fp.identify({ event: \"pageview\" }));`.';\n case 'javascript-spa':\n return \"Hook your router's `onNavigate` to call `fp.identify({ event: 'route:' + path })`.\";\n case 'javascript':\n default:\n return 'Import the module from your entry point so the `fp.identify()` call fires on load.';\n }\n}\n\n/**\n * Splice the snippet immediately before the closing `</body>` tag.\n * If no `</body>` is present (loose HTML or a server-rendered shell\n * that doesn't include it), append at end-of-file.\n */\nfunction appendBeforeBodyClose(html: string, snippet: string): string {\n const lower = html.toLowerCase();\n const idx = lower.lastIndexOf('</body>');\n if (idx === -1) {\n const trailingNewline = html.endsWith('\\n') ? '' : '\\n';\n return `${html}${trailingNewline}${snippet}\\n`;\n }\n const before = html.slice(0, idx);\n const after = html.slice(idx);\n return `${before}${snippet}\\n${after}`;\n}\n\n// Pin `dirname` so unused-imports lint doesn't strip it (we want the\n// helper available for future per-framework heuristics that need the\n// directory of the entry file).\nvoid dirname;\n"],"mappings":"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","names":["resolve","existsSync","resolve","resolve","scan","resolve","z","existsSync","readFileSync","z","resolve","readFileSync","resolve","z","resolve","z","z","resolve","existsSync","readFileSync","resolve","z","z","resolve","scan","readFileSync","existsSync","existsSync","readFileSync","dirname","resolve","z","z","resolve","existsSync","readFileSync","diff"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/server.ts","../src/tools/analyze.ts","../../../packages/sdk-snippets/src/snippet-for-framework.ts","../src/util/detect-framework.ts","../src/util/detect-pm.ts","../src/tools/configure.ts","../src/util/diff.ts","../src/tools/explain.ts","../src/tools/install.ts","../src/tools/verify.ts","../src/tools/wire-init.ts"],"sourcesContent":["import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\n\nimport { buildServer } from './server.js';\n\n/**\n * Stdio entrypoint for `fingerprint-platform-mcp`.\n *\n * MCP clients (Claude Desktop, Claude Code, Cursor, Continue.dev,\n * Copilot Chat via mcp-remote) spawn this binary as a subprocess\n * and speak JSON-RPC 2.0 over its stdin / stdout. We attach the\n * server to a `StdioServerTransport` and run until the parent\n * closes the pipes.\n *\n * Stderr is reserved for diagnostics (`console.error`) — MCP\n * clients route it to their own log viewer. Never log to stdout\n * here: that's the JSON-RPC channel and any stray bytes desync\n * the protocol.\n */\nasync function main(): Promise<void> {\n const server = buildServer();\n const transport = new StdioServerTransport();\n await server.connect(transport);\n // McpServer.connect() resolves once the transport is bound. The\n // process stays alive because stdin holds the event loop open\n // — when the client closes its half of the pipe, Node's stdin\n // emits 'end' and the process exits naturally.\n}\n\nmain().catch((err) => {\n // Last-resort error path — anything that escapes the per-tool\n // try/catch lands here. Log to stderr (NEVER stdout) and exit\n // non-zero so the client's MCP supervisor logs it as a crash.\n console.error('[fingerprint-platform-mcp] fatal:', err);\n process.exit(1);\n});\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nimport { analyzeInputSchema, analyzeProject } from './tools/analyze.js';\nimport {\n generateCloudflareWorker,\n generateCloudflareWorkerInputSchema,\n generateDnsFallback,\n generateDnsFallbackInputSchema,\n setCollectorUrl,\n setCollectorUrlInputSchema,\n} from './tools/configure.js';\nimport { explainInputSchema, explainTopic } from './tools/explain.js';\nimport { installInputSchema, installSdk } from './tools/install.js';\nimport { verifyInstall, verifyInstallInputSchema } from './tools/verify.js';\nimport { wireInit, wireInitInputSchema } from './tools/wire-init.js';\n\nimport type { ToolEnvelope } from './tools/types.js';\n\n/**\n * Build the Fingerprint Platform MCP server. Pure factory — no\n * side effects (no transport bind, no FS open). The caller picks\n * a transport (stdio in `cli.ts`, eventually HTTP/SSE) and calls\n * `server.connect(transport)`.\n *\n * Why a factory instead of a singleton: easier to spin up a fresh\n * server per test in the e2e suite without poisoning the registry\n * with leftover tools.\n */\nexport function buildServer(): McpServer {\n const server = new McpServer(\n {\n name: 'fingerprint-platform-mcp',\n version: '0.0.1',\n },\n {\n capabilities: {\n // We advertise tools only — no resources/prompts in v1. The\n // SDK auto-fills the capability object from the registrations\n // below, so we just declare an empty placeholder to be\n // explicit about the shape.\n tools: {},\n },\n instructions:\n 'Use these tools to install and configure the Fingerprint Platform SDK ' +\n '(`fingerprint-platform-sdk`) in a user project. Standard flow: ' +\n '`analyze_project` → `install_sdk` → `wire_init` → `set_collector_url` → ' +\n '`generate_cloudflare_worker` (recommended) or `generate_dns_fallback` → ' +\n '`verify_install`. Every tool is read-only on the filesystem and returns ' +\n 'a diff/command/env spec for the assistant to apply with its own tools. ' +\n 'Use `explain_topic` to fetch a focused brief on origin-allowlist, ' +\n 'cloudflare-proxy, dns-cname, api-keys, events-vs-identify, sync-vs-async.',\n },\n );\n\n // Helper to serialise our ToolEnvelope into the MCP CallToolResult\n // shape. We pack the structured fields (artifact / meta / nextSteps)\n // into a single markdown text block — that's what every current\n // MCP client renders directly, and it lets the AI parse the\n // structured content via simple regex/section-split prompts.\n function render(envelope: ToolEnvelope): {\n content: { type: 'text'; text: string }[];\n } {\n const parts: string[] = [envelope.summary];\n if (envelope.details) parts.push(envelope.details);\n if (envelope.nextSteps && envelope.nextSteps.length > 0) {\n parts.push(\n '## Next steps\\n\\n' + envelope.nextSteps.map((s, i) => `${i + 1}. ${s}`).join('\\n'),\n );\n }\n if (envelope.artifact) {\n switch (envelope.artifact.kind) {\n case 'diff':\n parts.push('## Diff\\n\\n```diff\\n' + envelope.artifact.content + '\\n```');\n break;\n case 'command':\n parts.push(\n '## Command\\n\\n```bash\\n' +\n envelope.artifact.content +\n '\\n```' +\n (envelope.artifact.cwd ? `\\n_(run in \\`${envelope.artifact.cwd}\\`)_` : ''),\n );\n break;\n case 'env':\n parts.push(\n '## Env vars\\n\\n```bash\\n' +\n Object.entries(envelope.artifact.content)\n .map(([k, v]) => `${k}=${v}`)\n .join('\\n') +\n '\\n```',\n );\n break;\n case 'markdown':\n // already in details when used; no double-render.\n break;\n }\n }\n return { content: [{ type: 'text', text: parts.join('\\n\\n') }] };\n }\n\n server.registerTool(\n 'analyze_project',\n {\n description:\n 'Scan the user project at `cwd` — read package.json + lockfile + framework config — to determine framework / package manager / entry file / whether the SDK is already installed. Read-only. Always call this first.',\n inputSchema: analyzeInputSchema,\n },\n async (args) => render(analyzeProject(args)),\n );\n\n server.registerTool(\n 'install_sdk',\n {\n description:\n 'Emit the install command for `fingerprint-platform-sdk` using the detected (or passed) package manager. Does NOT execute — the AI runs it via its own bash tool.',\n inputSchema: installInputSchema,\n },\n async (args) =>\n render(\n installSdk({\n cwd: args.cwd,\n source: args.source ?? 'npm',\n ...(args.packageManager ? { packageManager: args.packageManager } : {}),\n }),\n ),\n );\n\n server.registerTool(\n 'wire_init',\n {\n description:\n 'Generate a unified diff that places the framework-idiomatic SDK init() call into the right entry file. Reuses `initSnippet()` from `@fingerprint79/sdk-snippets` so the code matches what the dashboard shows.',\n inputSchema: wireInitInputSchema,\n },\n async (args) =>\n render(\n wireInit({\n cwd: args.cwd,\n framework: args.framework,\n entryFile: args.entryFile,\n apiKey: args.apiKey,\n collectorUrl: args.collectorUrl,\n source: args.source ?? 'npm',\n }),\n ),\n );\n\n server.registerTool(\n 'set_collector_url',\n {\n description:\n 'Validate a collector URL and return (a) env-var spec to add to `.env.local` and (b) the dashboard `allowedHosts` change the operator must make manually. The MCP server cannot mutate the dashboard in v1.',\n inputSchema: setCollectorUrlInputSchema,\n },\n async (args) => render(setCollectorUrl(args)),\n );\n\n server.registerTool(\n 'generate_cloudflare_worker',\n {\n description:\n 'Emit a `cloudflare/worker.ts` + `cloudflare/wrangler.toml` as diffs to drop into the user repo. Worker proxies SDK bundle + collector API under `<customDomain>/fpjs/*` for same-origin, ad-block-resistant delivery.',\n inputSchema: generateCloudflareWorkerInputSchema,\n },\n async (args) =>\n render(\n generateCloudflareWorker({\n cwd: args.cwd,\n customDomain: args.customDomain,\n ...(args.collectorIp ? { collectorIp: args.collectorIp } : {}),\n }),\n ),\n );\n\n server.registerTool(\n 'generate_dns_fallback',\n {\n description:\n 'When Cloudflare is not an option, emit DNS CNAME instructions pointing a subdomain at the collector. Keeps cookies first-party but is more ad-block-prone than the Worker route.',\n inputSchema: generateDnsFallbackInputSchema,\n },\n async (args) => render(generateDnsFallback(args)),\n );\n\n server.registerTool(\n 'verify_install',\n {\n description:\n 'Run a post-install sanity checklist on the user project — SDK in deps, init() call grep-able in source, env vars set. Returns a `{ check, status, hint }[]` triple for each item.',\n inputSchema: verifyInstallInputSchema,\n },\n async (args) => render(verifyInstall(args)),\n );\n\n server.registerTool(\n 'explain_topic',\n {\n description:\n 'Return a focused markdown brief on one of: origin-allowlist, cloudflare-proxy, dns-cname, api-keys, events-vs-identify, sync-vs-async. Use when the user asks a \"why\" / \"how\" question about an advanced setup.',\n inputSchema: explainInputSchema,\n },\n async (args) => render(explainTopic(args)),\n );\n\n return server;\n}\n","import { resolve } from 'node:path';\n\nimport { frameworkLabel } from '@fingerprint79/sdk-snippets';\nimport { z } from 'zod';\n\nimport { detectFramework } from '../util/detect-framework.js';\nimport { detectPackageManager } from '../util/detect-pm.js';\n\nimport type { ToolEnvelope } from './types.js';\n\nexport const analyzeInputSchema = {\n cwd: z\n .string()\n .describe(\n 'Absolute path to the user project root. The AI assistant should pass its own current working directory or the project root it has been browsing.',\n ),\n};\n\n/**\n * `analyze_project` — read package.json + lockfile + framework config\n * to determine what we're working with. Pure read; never writes.\n *\n * Returns:\n * - framework + label (one of the 8 supported ids)\n * - packageManager (pnpm/yarn/bun/npm)\n * - entryFile (absolute path) — where wire_init will insert code\n * - hasSDK (boolean) — true if `fingerprint-platform-sdk` is already\n * in deps, in which case the AI can skip install_sdk\n * - rationale — human-readable signal used to make the call\n */\nexport function analyzeProject(input: { cwd: string }): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const scan = detectFramework(cwd);\n const pm = detectPackageManager(cwd);\n\n const nextSteps: string[] = [];\n if (!scan.hasSDK) {\n nextSteps.push(`Call \\`install_sdk\\` with cwd=\"${cwd}\" to install fingerprint-platform-sdk.`);\n }\n if (scan.entryFile) {\n nextSteps.push(\n `Call \\`wire_init\\` with cwd=\"${cwd}\", framework=\"${scan.framework}\", entryFile=\"${scan.entryFile}\" to insert the init snippet.`,\n );\n } else {\n nextSteps.push(\n `Couldn't auto-locate an entry file for ${scan.framework}. Ask the user where they want \\`fp.identify()\\` to fire on app boot, then pass that path to \\`wire_init\\`.`,\n );\n }\n nextSteps.push(\n `Call \\`set_collector_url\\` once you know the user's collector URL — typically https://<their-domain>/fpjs proxied through a Cloudflare Worker.`,\n );\n\n const details =\n `**Project scan**\\n\\n` +\n `- Framework: \\`${scan.framework}\\` (${frameworkLabel(scan.framework)})\\n` +\n `- Package manager: \\`${pm}\\` (detected from lockfile)\\n` +\n `- SDK already installed: ${scan.hasSDK ? 'yes' : 'no'}\\n` +\n `- Entry file: ${scan.entryFile ? `\\`${scan.entryFile}\\`` : '_not auto-detected_'}\\n\\n` +\n `_${scan.rationale}_`;\n\n return {\n summary: `Detected ${frameworkLabel(scan.framework)} project (${pm}, SDK ${scan.hasSDK ? 'installed' : 'missing'}).`,\n details,\n nextSteps,\n meta: {\n cwd,\n framework: scan.framework,\n packageManager: pm,\n entryFile: scan.entryFile ?? null,\n hasSDK: scan.hasSDK,\n },\n };\n}\n","/**\n * Code-snippet builder for the Install Fingerprint wizard.\n *\n * The SDK API is identical across frameworks (`init({collectorUrl,\n * projectKey})` then `fp.identify(...)`), but how an integrator\n * usually mounts it differs — Next.js needs `'use client'` + a\n * client-only dynamic import, React needs a `useEffect`, Angular a\n * service, etc. We hand out the smallest snippet that still feels\n * idiomatic for each framework so a copy-paste lands in roughly the\n * right place.\n *\n * `apiKey` is substituted into the snippet when revealed on the\n * Get-Started page; otherwise the placeholder string from the i18n\n * dictionary takes its place.\n */\n\nexport type Framework =\n | 'javascript'\n | 'javascript-spa'\n | 'nextjs'\n | 'react'\n | 'vue'\n | 'angular'\n | 'svelte'\n | 'preact';\n\nexport type SnippetSource = 'cdn' | 'npm';\n\nexport interface SnippetInput {\n readonly framework: Framework;\n readonly source: SnippetSource;\n /** Plain-text public api key, or the i18n placeholder when masked. */\n readonly apiKey: string;\n /** The customer's custom subdomain pointing at our collector, e.g.\n * `https://fp.theirsite.com`. Always shown — encourages the\n * production pattern over leaking our raw IP in browser source.\n * See `InstallFlow.tsx::Step 3` for the DNS-setup explanation. */\n readonly collectorUrl: string;\n}\n\n/** All 8 framework ids in display order. Mobile is intentionally\n * absent from this enum — that picker lives on the platform step. */\nexport const FRAMEWORKS: ReadonlyArray<{ id: Framework; label: string }> = [\n { id: 'javascript', label: 'JavaScript' },\n { id: 'javascript-spa', label: 'JavaScript SPA' },\n { id: 'nextjs', label: 'Next.js' },\n { id: 'react', label: 'React' },\n { id: 'angular', label: 'Angular' },\n { id: 'vue', label: 'Vue.js' },\n { id: 'preact', label: 'Preact' },\n { id: 'svelte', label: 'Svelte' },\n];\n\nexport function frameworkLabel(id: Framework): string {\n return FRAMEWORKS.find((f) => f.id === id)?.label ?? id;\n}\n\n/** CDN install line — same across frameworks (the bundle is plain\n * IIFE either way). Always links the obfuscated build; never link\n * `dist/fp.js` from a production page — DevTools → Sources reads it\n * in the clear and undoes the obfuscator pipeline.\n *\n * The primary line is the same-origin path served by the Cloudflare\n * Worker the integrator deploys in Step 3 («Production proxy»). The\n * unpkg URL stays as a commented-out fallback for quick dev/staging\n * — adblockers' default lists ship a rule for `unpkg.com`, so in\n * production this URL is one of the first to disappear from\n * document.scripts. */\nexport function cdnInstallSnippet(): string {\n return `<!-- Production: self-hosted through the Cloudflare Worker (Step 3 below) -->\n<script src=\"/fpjs/agent.js\" async></script>\n\n<!-- Dev / staging only — unpkg URL is on every ad-block list -->\n<!-- <script src=\"https://unpkg.com/fingerprint-platform-sdk/dist/fp.obf.js\" async></script> -->`;\n}\n\n/** NPM install line — same across frameworks. */\nexport function npmInstallSnippet(): string {\n return `npm install fingerprint-platform-sdk\n# or pnpm add fingerprint-platform-sdk\n# or yarn add fingerprint-platform-sdk`;\n}\n\n/** Initialise-and-identify snippet, framework-specific. The\n * framework parameter only changes the WRAPPER code — the\n * Fingerprint API calls inside it are identical. */\nexport function initSnippet(input: SnippetInput): string {\n const { framework, source, apiKey, collectorUrl } = input;\n const config = ` collectorUrl: '${collectorUrl}',\n projectKey: '${apiKey}',`;\n\n // CDN init — global `window.FP` from the IIFE. The init call is\n // identical across frameworks (same global, same shape); what\n // differs is WHERE the integrator drops the <script> tag. The\n // framework-specific lead comment surfaces that decision so an\n // operator switching frameworks while parked on the CDN tab sees\n // their picked framework's mounting convention spelled out.\n if (source === 'cdn') {\n return `${cdnPlacementComment(framework)}\n<script>\n // Initialize the agent at application startup.\n const fp = window.FP.init({\n${config}\n });\n\n // Get the visitor and event identifier when you need it.\n fp.identify({ event: 'pageview' }).then((r) => {\n if (r.visitorId) console.log(r.eventId, r.visitorId, r.suspectScore);\n else console.log('event queued:', r.eventId);\n });\n</script>`;\n }\n\n // NPM / bundler path — framework-specific wrapper.\n switch (framework) {\n case 'nextjs':\n return `// app/_components/FpClient.tsx — client component\n'use client';\nimport { useEffect } from 'react';\n\nexport function FpClient() {\n useEffect(() => {\n let cancelled = false;\n // Dynamic import keeps the SDK out of the server bundle — Next.js\n // SSR has no Window, the SDK throws on the canvas calls there.\n import('fingerprint-platform-sdk').then(({ init }) => {\n if (cancelled) return;\n const fp = init({\n${config.replace(/^/gm, ' ')}\n });\n void fp.identify({ event: 'pageview' });\n });\n return () => { cancelled = true; };\n }, []);\n return null;\n}\n\n// Then mount <FpClient /> in your root layout.`;\n\n case 'react':\n return `import { useEffect } from 'react';\nimport { init } from 'fingerprint-platform-sdk';\n\nexport function useFingerprint() {\n useEffect(() => {\n const fp = init({\n${config.replace(/^/gm, ' ')}\n });\n fp.identify({ event: 'pageview' }).then((r) => {\n if (r.visitorId) console.log(r.eventId, r.visitorId, r.suspectScore);\n else console.log('event queued:', r.eventId);\n });\n }, []);\n}\n\n// Call useFingerprint() once in your root component.`;\n\n case 'vue':\n return `// plugins/fingerprint.ts\nimport { init } from 'fingerprint-platform-sdk';\n\nconst fp = init({\n${config}\n});\n\nexport default {\n install(app) {\n app.config.globalProperties.$fp = fp;\n },\n};\n\n// Then in main.ts:\n// app.use(fpPlugin);\n// And from any component:\n// this.$fp.identify({ event: 'pageview' });`;\n\n case 'angular':\n return `// fingerprint.service.ts\nimport { Injectable } from '@angular/core';\nimport { init, type FpSdk } from 'fingerprint-platform-sdk';\n\n@Injectable({ providedIn: 'root' })\nexport class FingerprintService {\n readonly fp: FpSdk = init({\n${config.replace(/^/gm, ' ')}\n });\n}\n\n// Inject in components and call: this.fp.fp.identify({ event: 'pageview' });`;\n\n case 'svelte':\n return `// src/lib/fingerprint.ts\nimport { init } from 'fingerprint-platform-sdk';\n\nexport const fp = init({\n${config}\n});\n\n// In any +page.svelte:\n// <script lang=\"ts\">\n// import { onMount } from 'svelte';\n// import { fp } from '$lib/fingerprint';\n// onMount(() => { void fp.identify({ event: 'pageview' }); });\n// </script>`;\n\n case 'preact':\n return `import { useEffect } from 'preact/hooks';\nimport { init } from 'fingerprint-platform-sdk';\n\nexport function useFingerprint() {\n useEffect(() => {\n const fp = init({\n${config.replace(/^/gm, ' ')}\n });\n void fp.identify({ event: 'pageview' });\n }, []);\n}\n\n// Call useFingerprint() once in your root component.`;\n\n case 'javascript-spa':\n return `// src/fingerprint.js\n// Single-page app pattern: init once, identify() on each route change.\nimport { init } from 'fingerprint-platform-sdk';\n\nexport const fp = init({\n${config}\n});\n\n// In your router's onNavigate hook:\n// fp.identify({ event: 'route:' + path });`;\n\n case 'javascript':\n default:\n return `import { init } from 'fingerprint-platform-sdk';\n\nconst fp = init({\n${config}\n});\n\nfp.identify({ event: 'pageview' }).then((r) => {\n if (r.visitorId) console.log(r.eventId, r.visitorId, r.suspectScore);\n else console.log('event queued:', r.eventId);\n});`;\n }\n}\n\n/** Framework-specific lead-comment for the CDN snippet. The init\n * body itself is identical across frameworks (the IIFE exposes the\n * same `window.FP.init` global), but mounting conventions differ —\n * React puts the <script> in `public/index.html`, Next.js prefers\n * `<Script>` from `next/script` in the root layout, etc. Surfacing\n * the placement decision per-framework makes flipping the framework\n * picker visibly do something even when the CDN tab is parked. */\nfunction cdnPlacementComment(framework: Framework): string {\n switch (framework) {\n case 'nextjs':\n return `<!-- Next.js: prefer next/script with strategy=\"afterInteractive\" in app/layout.tsx\n rather than a raw <script>. The agent attaches to window.FP on first paint. -->`;\n case 'react':\n return `<!-- React: drop <script> in public/index.html (CRA / Vite-React).\n Access window.FP from any component after first paint. -->`;\n case 'vue':\n return `<!-- Vue.js: place <script> in public/index.html.\n Read window.FP inside onMounted / mounted hooks. -->`;\n case 'angular':\n return `<!-- Angular: add <script> to src/index.html.\n Wrap window.FP in an Injectable service for DI ergonomics. -->`;\n case 'svelte':\n return `<!-- Svelte / SvelteKit: add <script> to app.html (SvelteKit) or\n public/index.html. Use onMount() to read window.FP. -->`;\n case 'preact':\n return `<!-- Preact: drop <script> in your root index.html.\n Read window.FP from any component after mount. -->`;\n case 'javascript-spa':\n return `<!-- SPA: include once in your shell HTML. Call fp.identify()\n from your router's per-route hook to track navigation. -->`;\n case 'javascript':\n default:\n return `<!-- Vanilla JS: paste anywhere in <body>. The SDK fires\n identify() on its own once init() resolves. -->`;\n }\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport type { Framework } from '@fingerprint79/sdk-snippets';\n\n/**\n * Outcome of a project scan. `framework` is the best-match id from\n * the `Framework` union. `entryFile` is the absolute path where the\n * SDK init call should land — undefined when we couldn't locate a\n * conventional entry. `hasSDK` is a flag the AI can branch on to\n * skip `install_sdk` and jump straight to `wire_init` if needed.\n */\nexport interface ProjectScan {\n readonly framework: Framework;\n readonly entryFile: string | undefined;\n readonly hasSDK: boolean;\n /** Free-text rationale — surfaces in the analyze_project response so\n * the AI can echo it back to the user when explaining its plan. */\n readonly rationale: string;\n}\n\ninterface PackageJsonShape {\n readonly dependencies?: Record<string, string>;\n readonly devDependencies?: Record<string, string>;\n readonly peerDependencies?: Record<string, string>;\n}\n\n/**\n * Read package.json deps + the conventional config files to figure\n * out the project's framework. Order matters here: Next.js is a\n * React superset, so we must check `next` before `react`; SvelteKit\n * is a Svelte superset; Nuxt is a Vue superset. The first match\n * wins.\n *\n * When nothing matches confidently, we fall back to `'javascript'`\n * (vanilla) — that's the safest default and lets `wire_init` still\n * emit a copy-paste-able snippet rather than refusing the call.\n */\nexport function detectFramework(cwd: string): ProjectScan {\n const pkgJson = readPackageJson(cwd);\n const deps = collectDeps(pkgJson);\n const sdkInstalled = 'fingerprint-platform-sdk' in deps;\n\n // Order is intentional — check supersets first.\n if ('next' in deps) {\n return scan('nextjs', cwd, sdkInstalled, 'Detected `next` dependency in package.json.');\n }\n if ('nuxt' in deps) {\n // We don't ship a separate Nuxt snippet — Nuxt uses the same Vue\n // plugin pattern, so map to `vue`. Caller can still emit the right\n // installation path because the init code is plugin-based.\n return scan('vue', cwd, sdkInstalled, 'Detected `nuxt` — using the Vue.js plugin pattern.');\n }\n if ('@angular/core' in deps) {\n return scan('angular', cwd, sdkInstalled, 'Detected `@angular/core` dependency.');\n }\n if ('@sveltejs/kit' in deps || 'svelte' in deps) {\n return scan('svelte', cwd, sdkInstalled, 'Detected Svelte (or SvelteKit).');\n }\n if ('preact' in deps) {\n return scan('preact', cwd, sdkInstalled, 'Detected `preact` dependency.');\n }\n if ('vue' in deps) {\n return scan('vue', cwd, sdkInstalled, 'Detected `vue` dependency.');\n }\n if ('react' in deps || 'react-dom' in deps) {\n // Vite-React vs CRA vs plain React app — same snippet shape. We\n // tell apart \"this is an SPA shell\" from \"this is a React lib\"\n // by looking for an entry file; if none, the `javascript` fallback\n // would be silly when react is clearly in deps. Stick with react.\n return scan('react', cwd, sdkInstalled, 'Detected `react` dependency.');\n }\n\n // Config-file-only signals (rare — e.g. someone removed deps from\n // package.json but left the config). These are weaker, so they sit\n // after the deps checks.\n if (existsSync(resolve(cwd, 'next.config.js')) || existsSync(resolve(cwd, 'next.config.ts'))) {\n return scan('nextjs', cwd, sdkInstalled, 'Detected `next.config.*` without explicit dep.');\n }\n if (existsSync(resolve(cwd, 'angular.json'))) {\n return scan('angular', cwd, sdkInstalled, 'Detected `angular.json`.');\n }\n if (\n existsSync(resolve(cwd, 'svelte.config.js')) ||\n existsSync(resolve(cwd, 'svelte.config.ts'))\n ) {\n return scan('svelte', cwd, sdkInstalled, 'Detected `svelte.config.*`.');\n }\n\n // SPA shell with a router but no framework lib? Treat as the SPA\n // wrapper so we emit `router.onNavigate → fp.identify` per-route.\n // Heuristic: presence of a router lib in deps.\n if ('react-router' in deps || 'vue-router' in deps || 'svelte-routing' in deps) {\n return scan(\n 'javascript-spa',\n cwd,\n sdkInstalled,\n 'Detected a router library without a framework lib.',\n );\n }\n\n return scan('javascript', cwd, sdkInstalled, 'No framework signal — falling back to vanilla JS.');\n}\n\n/* ── helpers ───────────────────────────────────────────────────── */\n\nfunction readPackageJson(cwd: string): PackageJsonShape {\n const p = resolve(cwd, 'package.json');\n if (!existsSync(p)) return {};\n try {\n return JSON.parse(readFileSync(p, 'utf8')) as PackageJsonShape;\n } catch {\n // Malformed package.json — treat as empty. The user has bigger\n // problems than our analyzer; we don't want to crash.\n return {};\n }\n}\n\nfunction collectDeps(pkg: PackageJsonShape): Record<string, string> {\n return {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n ...pkg.peerDependencies,\n };\n}\n\nfunction scan(framework: Framework, cwd: string, hasSDK: boolean, rationale: string): ProjectScan {\n return {\n framework,\n entryFile: locateEntryFile(framework, cwd),\n hasSDK,\n rationale,\n };\n}\n\n/**\n * Best-effort guess at the file where the SDK init call goes.\n * Returns `undefined` when no conventional entry exists — the AI\n * will then ask the user, or the `wire_init` tool refuses with a\n * helpful error pointing to the convention for the framework.\n */\nfunction locateEntryFile(framework: Framework, cwd: string): string | undefined {\n const candidates: Record<Framework, readonly string[]> = {\n nextjs: ['app/layout.tsx', 'app/layout.jsx', 'src/app/layout.tsx', 'pages/_app.tsx'],\n react: ['src/main.tsx', 'src/main.jsx', 'src/index.tsx', 'src/index.jsx', 'src/App.tsx'],\n vue: ['src/main.ts', 'src/main.js'],\n angular: ['src/main.ts', 'src/app/app.module.ts'],\n svelte: ['src/routes/+layout.svelte', 'src/main.ts', 'src/main.js'],\n preact: ['src/main.tsx', 'src/index.tsx', 'src/index.jsx'],\n 'javascript-spa': ['src/main.js', 'src/main.ts', 'src/index.js'],\n javascript: ['index.html', 'src/index.html', 'public/index.html'],\n };\n for (const rel of candidates[framework]) {\n const abs = resolve(cwd, rel);\n if (existsSync(abs)) return abs;\n }\n return undefined;\n}\n","import { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\n/**\n * Package managers we know how to emit install commands for. `npm` is\n * the safe fallback when no lockfile is present (matches what `npm\n * init` defaults to and what most tutorials assume).\n */\nexport type PackageManager = 'pnpm' | 'yarn' | 'bun' | 'npm';\n\n/**\n * Detect the package manager used by the project at `cwd` by looking\n * at lockfiles. We probe in the order pnpm → yarn → bun → npm so a\n * monorepo that has both `pnpm-lock.yaml` and a stray `package-lock.json`\n * (e.g. from a one-off `npm install` on a sub-package) doesn't get\n * misclassified — pnpm's presence is a stronger signal.\n *\n * Returns `'npm'` when nothing is present. Pure sync FS reads — fast\n * enough that this never warrants caching across tool calls, and\n * avoiding state simplifies the MCP request lifecycle.\n */\nexport function detectPackageManager(cwd: string): PackageManager {\n if (existsSync(resolve(cwd, 'pnpm-lock.yaml'))) return 'pnpm';\n if (existsSync(resolve(cwd, 'yarn.lock'))) return 'yarn';\n if (existsSync(resolve(cwd, 'bun.lockb')) || existsSync(resolve(cwd, 'bun.lock'))) return 'bun';\n return 'npm';\n}\n\n/**\n * Render the install command for a given package manager + package.\n * Centralised so the analyze, install and verify tools all emit\n * identical strings — the AI consumer can string-match them when\n * verifying that the user executed the install we proposed.\n */\nexport function renderInstallCommand(pm: PackageManager, pkg: string): string {\n switch (pm) {\n case 'pnpm':\n return `pnpm add ${pkg}`;\n case 'yarn':\n return `yarn add ${pkg}`;\n case 'bun':\n return `bun add ${pkg}`;\n case 'npm':\n default:\n return `npm install ${pkg}`;\n }\n}\n","import { resolve } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { makeNewFileDiff } from '../util/diff.js';\n\nimport type { ToolEnvelope } from './types.js';\n\n/* ── set_collector_url ─────────────────────────────────────────── */\n\nexport const setCollectorUrlInputSchema = {\n projectKey: z.string().describe(\"Project's public API key.\"),\n collectorUrl: z\n .string()\n .url()\n .describe(\n 'Same-origin collector URL — typically https://<their-domain>/fpjs (proxied by a Cloudflare Worker).',\n ),\n};\n\n/**\n * `set_collector_url` — validates the supplied URL and returns:\n * (a) env-var spec (`FP_PROJECT_KEY` + `FP_COLLECTOR_URL`) the user\n * should add to `.env.local` (we don't write the file — diff-\n * not-mutate),\n * (b) the dashboard `allowedHosts` change the operator must make\n * via the Security page (we can't mutate the dashboard from\n * the MCP server in v1).\n */\nexport function setCollectorUrl(input: { projectKey: string; collectorUrl: string }): ToolEnvelope {\n let parsed: URL;\n try {\n parsed = new URL(input.collectorUrl);\n } catch {\n return {\n summary: 'Invalid collector URL.',\n details: `\\`${input.collectorUrl}\\` is not a valid URL. Pass a full https URL like \\`https://yoursite.com/fpjs\\`.`,\n meta: { error: 'invalid_url' },\n };\n }\n if (parsed.protocol !== 'https:' && parsed.hostname !== 'localhost') {\n return {\n summary: 'Collector URL must be HTTPS.',\n details:\n 'The browser SDK uses X25519 sealing which requires a secure context (HTTPS or localhost). ' +\n `\\`${parsed.protocol}//${parsed.hostname}\\` would fail at runtime — please serve via HTTPS in production.`,\n meta: { error: 'http_in_production' },\n };\n }\n\n const originForAllowedHosts = `${parsed.protocol}//${parsed.hostname}${parsed.port ? `:${parsed.port}` : ''}`;\n\n return {\n summary: `Use \\`${input.collectorUrl}\\` as the collector URL.`,\n details:\n `**1) Add to your environment** (e.g. \\`.env.local\\`):\\n\\n` +\n '```bash\\n' +\n `FP_PROJECT_KEY=${input.projectKey}\\n` +\n `FP_COLLECTOR_URL=${input.collectorUrl}\\n` +\n '```\\n\\n' +\n `**2) Add origin to dashboard allowedHosts.** Open the Fingerprint ` +\n `dashboard → Security → Allowed hosts and add:\\n\\n` +\n `\\`${originForAllowedHosts}\\`\\n\\n` +\n `Without this entry the collector rejects requests from your site ` +\n `with a 401 \\`origin_not_allowed\\`. (We can't mutate the dashboard from ` +\n `the MCP server in v1; this step is manual.)`,\n nextSteps: [\n `Add the two env vars above to \\`.env.local\\` (or your secret manager).`,\n `Open the dashboard's Security page and add \\`${originForAllowedHosts}\\` to allowedHosts.`,\n `Call \\`generate_cloudflare_worker\\` if you want a same-origin proxy on /fpjs/*.`,\n ],\n artifact: {\n kind: 'env',\n content: {\n FP_PROJECT_KEY: input.projectKey,\n FP_COLLECTOR_URL: input.collectorUrl,\n },\n },\n meta: { origin: originForAllowedHosts, collectorUrl: input.collectorUrl },\n };\n}\n\n/* ── generate_cloudflare_worker ─────────────────────────────────── */\n\nexport const generateCloudflareWorkerInputSchema = {\n cwd: z.string().describe('Absolute path to the user project root — for the diff header.'),\n customDomain: z\n .string()\n .describe(\n \"Your site's apex domain, e.g. `yoursite.com`. The Worker routes `<customDomain>/fpjs/*` to the Fingerprint collector. The Worker fetches `https://fp.<customDomain>/v1/*` upstream — an A record you'll add to your DNS pointing at our collector IP (instructions in the output).\",\n ),\n collectorIp: z\n .string()\n .default('89.124.91.162')\n .describe(\n \"Fingerprint collector IP. Only override if you're running a self-hosted deployment. Defaults to the public Fingerprint Platform collector.\",\n ),\n};\n\n/**\n * `generate_cloudflare_worker` — produces the Worker script + wrangler\n * config that route the customer's same-origin `/fpjs/*` path to the\n * Fingerprint collector. The Worker fetches `https://fp.<customDomain>`\n * upstream, which is a DNS A record the customer adds on THEIR domain\n * pointing at the collector IP. Our Caddy (with on-demand TLS) issues\n * a Let's Encrypt cert for that subdomain on the first request,\n * gated by the dashboard's allowedHosts list.\n *\n * No hostname-of-ours is exposed to the integrator — every URL in the\n * generated config references their own domain. That's the «no domain\n * on our side» pattern: customers' Cloudflare Workers fan out to our\n * IP through a subdomain on their own DNS zone.\n */\nexport function generateCloudflareWorker(input: {\n cwd: string;\n customDomain: string;\n collectorIp?: string;\n}): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const workerPath = resolve(cwd, 'cloudflare/worker.ts');\n const wranglerPath = resolve(cwd, 'cloudflare/wrangler.toml');\n\n const domain = input.customDomain.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n const collectorIp = (input.collectorIp ?? '89.124.91.162').replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n const upstreamHost = `fp.${domain}`;\n\n const workerScript = cloudflareWorkerTemplate(upstreamHost);\n const wranglerToml = wranglerTomlTemplate(domain);\n\n const workerDiff = makeNewFileDiff({ cwd, filePath: workerPath, content: workerScript });\n const wranglerDiff = makeNewFileDiff({ cwd, filePath: wranglerPath, content: wranglerToml });\n\n return {\n summary: `Cloudflare Worker for \\`${domain}/fpjs/*\\` → \\`https://${upstreamHost}\\` (Fingerprint collector).`,\n details:\n `**Architecture this generates:**\\n\\n` +\n '```\\n' +\n `Browser → ${domain}/fpjs/* → CF Worker → fetch https://${upstreamHost}/v1/*\\n` +\n ` ↓\\n` +\n ` ${collectorIp} (Fingerprint collector)\\n` +\n '```\\n\\n' +\n `Three things to set up on YOUR side:\\n\\n` +\n `**1. DNS record** in your zone for \\`${domain}\\` (e.g. Cloudflare DNS, Namecheap, Route 53):\\n\\n` +\n '```text\\n' +\n `Type: A\\n` +\n `Name: fp\\n` +\n `Value: ${collectorIp}\\n` +\n `Proxy: DNS only (gray cloud if using Cloudflare — ACME needs direct access)\\n` +\n `TTL: Auto / 300\\n` +\n '```\\n\\n' +\n `This makes \\`${upstreamHost}\\` resolve to our collector. Our Caddy ` +\n `auto-issues a Let's Encrypt cert for it on the first request.\\n\\n` +\n `**2. Dashboard \\`allowedHosts\\`**: register \\`https://${domain}\\` on Security → Allowed hosts. ` +\n `Without it our on-demand-TLS gate refuses cert issuance and the Worker's upstream fetch fails.\\n\\n` +\n `**3. Cloudflare Worker** — two files to write into your repo:\\n\\n` +\n `**\\`cloudflare/worker.ts\\`** — the Worker script body.\\n` +\n `**\\`cloudflare/wrangler.toml\\`** — Wrangler deploy config (route + zone).\\n\\n` +\n `Both diffs are below. After applying:\\n\\n` +\n '```bash\\n' +\n 'cd cloudflare && wrangler login && wrangler deploy\\n' +\n '```\\n\\n' +\n `--- ${workerPath} ---\\n\\n\\`\\`\\`diff\\n${workerDiff}\\n\\`\\`\\`\\n\\n` +\n `--- ${wranglerPath} ---\\n\\n\\`\\`\\`diff\\n${wranglerDiff}\\n\\`\\`\\``,\n nextSteps: [\n `Add the DNS A record \\`fp.${domain}\\` → \\`${collectorIp}\\` (DNS-only, no Cloudflare proxy on that record).`,\n `Add \\`https://${domain}\\` to dashboard \\`allowedHosts\\` on the Security page.`,\n `Apply both diffs to create \\`cloudflare/worker.ts\\` + \\`cloudflare/wrangler.toml\\`.`,\n `Run \\`cd cloudflare && wrangler login && wrangler deploy\\` to deploy the Worker.`,\n `Update your SDK init: \\`collectorUrl: 'https://${domain}/fpjs'\\`.`,\n ],\n artifact: { kind: 'diff', content: `${workerDiff}\\n${wranglerDiff}` },\n meta: {\n workerPath,\n wranglerPath,\n route: `${domain}/fpjs/*`,\n upstreamHost,\n collectorIp,\n },\n };\n}\n\n/* ── generate_dns_fallback ──────────────────────────────────────── */\n\nexport const generateDnsFallbackInputSchema = {\n subdomain: z\n .string()\n .describe('Subdomain to point at the collector, e.g. `fp.yoursite.com`. Must be a FQDN.'),\n collectorHost: z.string().describe('Hostname (or IP) of the Fingerprint collector.'),\n};\n\n/**\n * `generate_dns_fallback` — when Cloudflare isn't an option,\n * point a DNS CNAME from `fp.yoursite.com` to the collector\n * directly. Less ad-block-proof than the Worker route (a dedicated\n * subdomain is easier for filter rules to catch than a same-origin\n * path) but still keeps cookies first-party.\n */\nexport function generateDnsFallback(input: {\n subdomain: string;\n collectorHost: string;\n}): ToolEnvelope {\n const host = input.collectorHost.replace(/^https?:\\/\\//, '').replace(/\\/+$/, '');\n // Determine the apex from the subdomain — naively split on the\n // first dot. Good enough for the DNS instructions; the user will\n // know which zone to edit.\n const apex = input.subdomain.split('.').slice(1).join('.');\n\n return {\n summary: `DNS CNAME \\`${input.subdomain}\\` → \\`${host}\\`.`,\n details:\n `Add the following DNS record in your registrar's zone editor for ` +\n `\\`${apex}\\`:\\n\\n` +\n '```text\\n' +\n `Type: CNAME\\n` +\n `Name: ${input.subdomain.replace(`.${apex}`, '')}\\n` +\n `Value: ${host}\\n` +\n `TTL: 300 (5 min — bump after verification)\\n` +\n '```\\n\\n' +\n `Once propagated, set:\\n\\n` +\n '```bash\\n' +\n `FP_COLLECTOR_URL=https://${input.subdomain}\\n` +\n '```\\n\\n' +\n `Then add \\`https://${input.subdomain}\\` to the dashboard's ` +\n `allowedHosts on the Security page.\\n\\n` +\n `_Trade-off vs the Cloudflare Worker route: a dedicated subdomain ` +\n `is **easier for ad-block filter rules to catch** than a same-origin ` +\n `path like \\`yoursite.com/fpjs/*\\`. Use the Worker if you can; this ` +\n `is the fallback when Cloudflare isn't on the table._`,\n nextSteps: [\n `Create the CNAME record in your DNS provider.`,\n `Wait for propagation (\\`dig ${input.subdomain}\\` should return the CNAME).`,\n `Update \\`FP_COLLECTOR_URL\\` and dashboard allowedHosts.`,\n ],\n meta: { subdomain: input.subdomain, collectorHost: host, apex },\n };\n}\n\n/* ── templates ─────────────────────────────────────────────────── */\n\nfunction cloudflareWorkerTemplate(upstreamHost: string): string {\n return `/**\n * Fingerprint Platform same-origin proxy.\n *\n * Generated by fingerprint-platform-mcp.\n *\n * Route pattern: <yoursite>/fpjs/*\n *\n * Proxies BOTH the SDK bundle (served on /fpjs/agent.js) AND every\n * collector endpoint (/fpjs/v1/ingest, /fpjs/v1/result/<id>,\n * /fpjs/v1/pk, /fpjs/v1/comparison). Cookies stay first-party,\n * ad-blockers cannot pattern-match a same-origin path.\n *\n * The integrator's app backend is NEVER in the fingerprint request\n * path — that would couple uptime and add latency. The Worker\n * fans out to ${upstreamHost} — a DNS A record you added in your\n * own zone pointing at the Fingerprint collector. The collector\n * issues a Let's Encrypt cert for this hostname on-demand the\n * first time the Worker reaches it.\n */\n\nconst COLLECTOR_ORIGIN = \"https://${upstreamHost}\";\n\nexport default {\n async fetch(req: Request): Promise<Response> {\n const url = new URL(req.url);\n\n // SDK bundle.\n if (url.pathname === \"/fpjs/agent.js\") {\n const upstream = new URL(\"/v1/agent.js\", COLLECTOR_ORIGIN);\n return forward(req, upstream);\n }\n\n // Collector API surface under /fpjs/v1/*.\n if (url.pathname.startsWith(\"/fpjs/v1/\")) {\n const upstream = new URL(url.pathname.replace(/^\\\\/fpjs/, \"\"), COLLECTOR_ORIGIN);\n upstream.search = url.search;\n return forward(req, upstream);\n }\n\n // Unknown path under /fpjs/ — 404 cleanly so misconfigured route\n // patterns don't accidentally proxy the user's whole site.\n return new Response(\"not found\", { status: 404 });\n },\n};\n\nasync function forward(req: Request, upstream: URL): Promise<Response> {\n const headers = new Headers(req.headers);\n // Preserve the original client IP for the collector's IP-class\n // enrichment — Cloudflare exposes it via cf-connecting-ip.\n const clientIp = headers.get(\"cf-connecting-ip\") ?? headers.get(\"x-forwarded-for\");\n if (clientIp) headers.set(\"x-forwarded-for\", clientIp);\n // Strip the Host header so the upstream sees its own hostname.\n headers.delete(\"host\");\n\n const init: RequestInit = {\n method: req.method,\n headers,\n body: req.method === \"GET\" || req.method === \"HEAD\" ? undefined : req.body,\n redirect: \"manual\",\n };\n return fetch(upstream.toString(), init);\n}\n`;\n}\n\nfunction wranglerTomlTemplate(customDomain: string): string {\n return `name = \"fingerprint-proxy\"\nmain = \"worker.ts\"\ncompatibility_date = \"2025-01-01\"\n\n# Attach the Worker to your domain. Replace the zone_name if it\n# differs from the domain. Wrangler will prompt for the zone on\n# first deploy if you remove the zone_name line.\nroutes = [\n { pattern = \"${customDomain}/fpjs/*\", zone_name = \"${customDomain}\" },\n]\n`;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { relative } from 'node:path';\n\nimport { createPatch } from 'diff';\n\n/**\n * Build a unified-diff patch from an existing file's current contents\n * to its proposed new contents. Returned as a string ready to drop\n * into a `git apply` invocation. The path inside the patch is\n * RELATIVE to `cwd` so the AI assistant can apply it from the\n * project root without needing to rewrite the header.\n *\n * The `diff` package's `createPatch` emits standard unified format\n * (3 lines of context by default). We pass empty `oldHeader` /\n * `newHeader` to keep the output compact — the `--- a/<path>` /\n * `+++ b/<path>` lines `git apply` cares about are generated\n * regardless.\n */\nexport function makeUnifiedDiff(opts: {\n readonly cwd: string;\n readonly filePath: string;\n readonly newContent: string;\n}): string {\n const oldContent = existsSync(opts.filePath) ? readFileSync(opts.filePath, 'utf8') : '';\n const rel = relative(opts.cwd, opts.filePath).split('\\\\').join('/');\n return createPatch(rel, oldContent, opts.newContent, '', '', { context: 3 });\n}\n\n/**\n * Build a \"new file\" diff — same shape as makeUnifiedDiff but\n * always emits a `/dev/null → b/<path>` header, suitable for files\n * the assistant should create from scratch (e.g. the Cloudflare\n * Worker template). The `diff` lib handles this automatically when\n * `oldContent` is the empty string, but we wrap it for callers who\n * want explicit intent in the call site.\n */\nexport function makeNewFileDiff(opts: {\n readonly cwd: string;\n readonly filePath: string;\n readonly content: string;\n}): string {\n const rel = relative(opts.cwd, opts.filePath).split('\\\\').join('/');\n return createPatch(rel, '', opts.content, '', '', { context: 3 });\n}\n","import { readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { z } from 'zod';\n\nimport type { ToolEnvelope } from './types.js';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Topic ids → bundled markdown filename. We define the union here\n * (rather than scanning `docs/` at runtime) so a typo in the input\n * fails Zod validation before we even open the FS, and so an AI\n * model can be confident the topic list matches its training memory.\n */\nconst TOPIC_FILES: Record<string, string> = {\n 'origin-allowlist': 'origin-allowlist.md',\n 'cloudflare-proxy': 'cloudflare-proxy.md',\n 'dns-cname': 'dns-cname.md',\n 'api-keys': 'api-keys.md',\n 'events-vs-identify': 'events-vs-identify.md',\n 'sync-vs-async': 'sync-vs-async.md',\n};\n\nexport const explainInputSchema = {\n topic: z\n .enum([\n 'origin-allowlist',\n 'cloudflare-proxy',\n 'dns-cname',\n 'api-keys',\n 'events-vs-identify',\n 'sync-vs-async',\n ])\n .describe(\n 'Topic id. The AI assistant picks one based on the user question. Each topic returns a focused markdown brief — pasting raw docs into the conversation tends to drown out the actionable bits.',\n ),\n};\n\n/**\n * `explain_topic` — return a focused markdown brief on one of our\n * six advanced-setup topics. Pure read of the bundled `docs/` dir.\n *\n * The `docs/` files are copied into `dist/docs/` by tsup's\n * `onSuccess` step (see `tsup.config.ts`). When running under\n * `tsx` (`pnpm dev`), we resolve back to `src/docs/`. The path\n * fallback handles both.\n */\nexport function explainTopic(input: { topic: keyof typeof TOPIC_FILES }): ToolEnvelope {\n const filename = TOPIC_FILES[input.topic];\n if (!filename) {\n return {\n summary: `Unknown topic \"${input.topic}\".`,\n details: `Known topics: ${Object.keys(TOPIC_FILES).join(', ')}.`,\n meta: { error: 'unknown_topic' },\n };\n }\n\n // dist/docs/<name>.md when bundled, src/docs/<name>.md under tsx.\n const candidates = [\n resolve(__dirname, '..', 'docs', filename),\n resolve(__dirname, 'docs', filename),\n resolve(__dirname, '..', '..', 'src', 'docs', filename),\n ];\n for (const path of candidates) {\n try {\n const content = readFileSync(path, 'utf8');\n return {\n summary: `Returned docs/${filename} (${content.length} chars).`,\n details: content,\n artifact: { kind: 'markdown', content },\n meta: { topic: input.topic, path },\n };\n } catch {\n // try next candidate\n }\n }\n\n return {\n summary: `docs/${filename} not found at runtime.`,\n details:\n `Looked at: ${candidates.join(', ')}. This is a build issue — the ` +\n `tsup config should be copying src/docs/ into dist/docs/. Re-run ` +\n `\\`pnpm build\\` and try again.`,\n meta: { error: 'doc_missing', topic: input.topic },\n };\n}\n","import { resolve } from 'node:path';\n\nimport { z } from 'zod';\n\nimport {\n detectPackageManager,\n renderInstallCommand,\n type PackageManager,\n} from '../util/detect-pm.js';\n\nimport type { ToolEnvelope } from './types.js';\n\nexport const installInputSchema = {\n cwd: z.string().describe('Absolute path to the user project root.'),\n packageManager: z\n .enum(['pnpm', 'yarn', 'bun', 'npm'])\n .optional()\n .describe(\n 'Override the auto-detected package manager. Most callers should let analyze_project decide.',\n ),\n source: z\n .enum(['npm', 'cdn'])\n .default('npm')\n .describe(\n \"Install source. `npm` is the default (recommended). `cdn` returns the <script> tag snippet instead — useful when the user explicitly doesn't want to add an npm dep.\",\n ),\n};\n\n/**\n * `install_sdk` — returns the install command (or CDN snippet) for\n * `fingerprint-platform-sdk`. Does NOT execute. The AI runs it via\n * its own bash/shell tool — this is the diff-not-mutate contract we\n * keep across every tool.\n */\nexport function installSdk(input: {\n cwd: string;\n packageManager?: PackageManager;\n source?: 'npm' | 'cdn';\n}): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const source = input.source ?? 'npm';\n\n if (source === 'cdn') {\n return {\n summary: 'CDN install — no package manager command needed.',\n details:\n 'Add the following `<script>` tag to your HTML shell ' +\n '(e.g. `public/index.html`, `app.html`, or the framework-specific ' +\n 'entry document). Once it loads, `window.FP.init({...})` is available.\\n\\n' +\n '```html\\n<script src=\"/fpjs/agent.js\" async></script>\\n```\\n\\n' +\n '_The recommended `/fpjs/agent.js` path is served by your Cloudflare ' +\n 'Worker proxy (see `generate_cloudflare_worker`). The unpkg URL ' +\n 'works for local dev but is on every ad-block list — do not ship ' +\n 'it to production._',\n nextSteps: [`Call \\`wire_init\\` to insert the init() call into the right entry file.`],\n artifact: {\n kind: 'markdown',\n content: '<script src=\"/fpjs/agent.js\" async></script>',\n },\n meta: { source: 'cdn', cwd },\n };\n }\n\n const pm = input.packageManager ?? detectPackageManager(cwd);\n const cmd = renderInstallCommand(pm, 'fingerprint-platform-sdk');\n\n return {\n summary: `Install via ${pm}: \\`${cmd}\\``,\n details:\n `Run the following command in the project root (\\`${cwd}\\`):\\n\\n` +\n '```bash\\n' +\n cmd +\n '\\n```\\n\\n' +\n `_Detected package manager: ${pm}. If this is wrong, pass \\`packageManager\\` explicitly._`,\n nextSteps: [\n `Execute the command above via your bash tool.`,\n `Then call \\`wire_init\\` to insert the SDK init() call into the right entry file.`,\n ],\n artifact: { kind: 'command', content: cmd, cwd },\n meta: { source: 'npm', packageManager: pm, cwd, command: cmd },\n };\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { detectFramework } from '../util/detect-framework.js';\n\nimport type { ToolEnvelope } from './types.js';\n\nexport const verifyInstallInputSchema = {\n cwd: z.string().describe('Absolute path to the user project root.'),\n};\n\ninterface Check {\n readonly name: string;\n readonly status: 'ok' | 'warn' | 'fail';\n readonly hint: string;\n}\n\n/**\n * `verify_install` — sanity checklist run after the AI applied the\n * `install_sdk` + `wire_init` diffs. We re-analyze the project and\n * report a structured list:\n *\n * - SDK dependency present\n * - Init call grep-able somewhere in the source tree\n * - Env vars set (FP_PROJECT_KEY + FP_COLLECTOR_URL — in shell env\n * or a `.env*` file)\n *\n * Doesn't fire a real /v1/ingest request — that would require us to\n * spawn a headless browser, and we're a Node CLI. The AI can do\n * that step itself if asked (it has Playwright tools).\n */\nexport function verifyInstall(input: { cwd: string }): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const scan = detectFramework(cwd);\n const checks: Check[] = [];\n\n // 1) SDK in deps.\n checks.push({\n name: 'fingerprint-platform-sdk in dependencies',\n status: scan.hasSDK ? 'ok' : 'fail',\n hint: scan.hasSDK\n ? `Detected via package.json.`\n : `Run \\`install_sdk\\` and apply its install command.`,\n });\n\n // 2) Init call somewhere in src/. We grep for `FP.init(` and the\n // ESM `init(` import — either signals the user's code references\n // the SDK. False positives are unlikely (we're in a project that\n // just installed `fingerprint-platform-sdk`).\n const initCallFound = grepForInitCall(cwd);\n checks.push({\n name: 'SDK `init(...)` call present in source tree',\n status: initCallFound ? 'ok' : 'warn',\n hint: initCallFound\n ? `Found a reference to \\`init({...})\\` or \\`window.FP.init\\` in the source.`\n : `Couldn't find an \\`init({...})\\` call. Either re-run \\`wire_init\\` to ` +\n `place the snippet, or confirm the user mounted the generated module.`,\n });\n\n // 3) Env vars. We accept either real env (process.env) or a `.env*`\n // file in the project root.\n const envCheck = envVarStatus(cwd);\n checks.push({\n name: 'FP_PROJECT_KEY + FP_COLLECTOR_URL configured',\n status: envCheck.both ? 'ok' : envCheck.either ? 'warn' : 'fail',\n hint: envCheck.hint,\n });\n\n const failCount = checks.filter((c) => c.status === 'fail').length;\n const warnCount = checks.filter((c) => c.status === 'warn').length;\n const summary =\n failCount > 0\n ? `${failCount} check failed, ${warnCount} warning. See checklist.`\n : warnCount > 0\n ? `Mostly good — ${warnCount} thing(s) to confirm manually.`\n : 'All checks green. Send a test event and look for it on the dashboard.';\n\n return {\n summary,\n details:\n `**Verification checklist**\\n\\n` +\n checks.map((c) => `- ${badge(c.status)} **${c.name}** — ${c.hint}`).join('\\n'),\n nextSteps:\n failCount === 0 && warnCount === 0\n ? [\n `Trigger an event by reloading the page where the SDK is mounted.`,\n `Open the dashboard → Identification view; the event should appear within ~2s.`,\n ]\n : [`Resolve the failed / warned checks above and call \\`verify_install\\` again.`],\n meta: { checks, framework: scan.framework },\n };\n}\n\n/* ── helpers ───────────────────────────────────────────────────── */\n\nfunction badge(status: 'ok' | 'warn' | 'fail'): string {\n return status === 'ok' ? '✓' : status === 'warn' ? '⚠' : '✗';\n}\n\nfunction grepForInitCall(cwd: string): boolean {\n // Single-shot tree walk capped at 5000 files to avoid runaway\n // recursion on giant monorepos. We're only sanity-checking — a\n // real grep is the user's job.\n let count = 0;\n const stack: string[] = [cwd];\n const seen = new Set<string>();\n while (stack.length > 0 && count < 5000) {\n const dir = stack.pop();\n if (!dir || seen.has(dir)) continue;\n seen.add(dir);\n if (/[\\\\/](node_modules|dist|\\.next|build|coverage|\\.turbo)$/.test(dir)) continue;\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n continue;\n }\n for (const name of entries) {\n count++;\n if (count >= 5000) break;\n const abs = resolve(dir, name);\n let stat;\n try {\n stat = statSync(abs);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n stack.push(abs);\n continue;\n }\n if (!/\\.(t|j)sx?$|\\.svelte$|\\.vue$|\\.html$/.test(name)) continue;\n try {\n const raw = readFileSync(abs, 'utf8');\n if (/\\bFP\\.init\\(|\\binit\\(\\s*\\{\\s*(collectorUrl|projectKey)/m.test(raw)) {\n return true;\n }\n } catch {\n // unreadable; ignore.\n }\n }\n }\n return false;\n}\n\nfunction envVarStatus(cwd: string): { both: boolean; either: boolean; hint: string } {\n const fromProcess = {\n key: Boolean(process.env['FP_PROJECT_KEY']),\n url: Boolean(process.env['FP_COLLECTOR_URL']),\n };\n const dotenvFiles = ['.env', '.env.local', '.env.development', '.env.production'];\n const seenInDotenv = { key: false, url: false };\n for (const name of dotenvFiles) {\n const p = resolve(cwd, name);\n if (!existsSync(p)) continue;\n try {\n const raw = readFileSync(p, 'utf8');\n if (/^\\s*FP_PROJECT_KEY\\s*=/m.test(raw)) seenInDotenv.key = true;\n if (/^\\s*FP_COLLECTOR_URL\\s*=/m.test(raw)) seenInDotenv.url = true;\n } catch {\n // ignore\n }\n }\n const keyOk = fromProcess.key || seenInDotenv.key;\n const urlOk = fromProcess.url || seenInDotenv.url;\n const both = keyOk && urlOk;\n const either = keyOk || urlOk;\n const missing: string[] = [];\n if (!keyOk) missing.push('FP_PROJECT_KEY');\n if (!urlOk) missing.push('FP_COLLECTOR_URL');\n return {\n both,\n either,\n hint: both\n ? `Found both vars (in process.env or a .env file).`\n : `Missing: ${missing.join(', ')}. Add to \\`.env.local\\` via \\`set_collector_url\\`.`,\n };\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\nimport { initSnippet, frameworkLabel, type Framework } from '@fingerprint79/sdk-snippets';\nimport { z } from 'zod';\n\nimport { makeUnifiedDiff, makeNewFileDiff } from '../util/diff.js';\n\nimport type { ToolEnvelope } from './types.js';\n\nexport const wireInitInputSchema = {\n cwd: z.string().describe('Absolute path to the user project root.'),\n framework: z\n .enum(['javascript', 'javascript-spa', 'nextjs', 'react', 'vue', 'angular', 'svelte', 'preact'])\n .describe('Framework id from `analyze_project`.'),\n entryFile: z\n .string()\n .describe(\n 'Absolute path to the file that should host the SDK init call (from `analyze_project.meta.entryFile`).',\n ),\n apiKey: z\n .string()\n .describe(\n \"Project's public API key. Substitute the value from the dashboard's API keys page or env.FP_PROJECT_KEY.\",\n ),\n collectorUrl: z\n .string()\n .url()\n .describe(\n 'Same-origin collector URL — typically https://<their-domain>/fpjs (proxied by a Cloudflare Worker).',\n ),\n source: z\n .enum(['npm', 'cdn'])\n .default('npm')\n .describe('Match whatever `install_sdk` ran with. Defaults to `npm`.'),\n};\n\n/**\n * `wire_init` — produce a unified diff that inserts the framework-\n * idiomatic init snippet into the user's entry file. Reuses\n * `initSnippet()` from `@fingerprint79/sdk-snippets` so the dashboard's\n * snippet panel and this MCP tool emit byte-identical code.\n *\n * Strategy per framework:\n * - `nextjs` / `react` / `preact`: insert as a NEW client component\n * file `app/_components/FpClient.tsx` (or\n * `src/components/FpClient.tsx`) — much safer than splicing into\n * an existing `app/layout.tsx` whose JSX shape we can't predict.\n * Caller mounts <FpClient /> in their root tree as a follow-up.\n * - `vue` / `svelte`: insert as a NEW plugin module the user\n * registers.\n * - `angular`: insert as a NEW Injectable service.\n * - `javascript` / `javascript-spa`: append the script to the\n * entry file directly (the file is already a script entry).\n *\n * For HTML entries (vanilla source=cdn), we splice a `<script>` tag\n * into the existing file using `makeUnifiedDiff` against the actual\n * file contents.\n */\nexport function wireInit(input: {\n cwd: string;\n framework: Framework;\n entryFile: string;\n apiKey: string;\n collectorUrl: string;\n source?: 'npm' | 'cdn';\n}): ToolEnvelope {\n const cwd = resolve(input.cwd);\n const entryFile = resolve(input.entryFile);\n const source = input.source ?? 'npm';\n\n const snippet = initSnippet({\n framework: input.framework,\n source,\n apiKey: input.apiKey,\n collectorUrl: input.collectorUrl,\n });\n\n // CDN flow: append <script> tag to the entry HTML.\n if (source === 'cdn') {\n if (!existsSync(entryFile)) {\n return missingEntryFile(entryFile, input.framework);\n }\n const current = readFileSync(entryFile, 'utf8');\n const next = appendBeforeBodyClose(current, snippet);\n const diff = makeUnifiedDiff({ cwd, filePath: entryFile, newContent: next });\n return successDiff(diff, entryFile, input.framework, source, [\n `Apply the diff to \\`${entryFile}\\` via your edit tool.`,\n `Reload the page and confirm \\`window.FP.init\\` is defined in DevTools.`,\n ]);\n }\n\n // NPM flow: emit a NEW file with the per-framework module wrapper.\n // The chosen path follows each framework's convention.\n const targetFile = perFrameworkTargetFile(input.framework, cwd);\n const diff = makeNewFileDiff({ cwd, filePath: targetFile, content: snippet });\n\n const mountHint = perFrameworkMountHint(input.framework);\n return successDiff(diff, targetFile, input.framework, source, [\n `Apply the diff to create \\`${targetFile}\\` via your edit tool.`,\n mountHint,\n `Run the app and confirm the SDK boots — open DevTools, you should see the eventId / visitorId logged.`,\n ]);\n}\n\n/* ── helpers ───────────────────────────────────────────────────── */\n\nfunction successDiff(\n diff: string,\n filePath: string,\n framework: Framework,\n source: 'npm' | 'cdn',\n nextSteps: string[],\n): ToolEnvelope {\n return {\n summary: `Wrote ${source} init for ${frameworkLabel(framework)} into \\`${filePath}\\`.`,\n details:\n `Apply the unified diff below with \\`git apply\\` (or your AI ` +\n `assistant's edit tool). The patch is against \\`${filePath}\\` and ` +\n `is generated from the same \\`initSnippet()\\` helper the dashboard's ` +\n `Get Started page uses — so what you see here matches the install ` +\n `snippet shown there byte-for-byte.\\n\\n` +\n '```diff\\n' +\n diff +\n '\\n```',\n nextSteps,\n artifact: { kind: 'diff', content: diff },\n meta: { framework, source, filePath },\n };\n}\n\nfunction missingEntryFile(entryFile: string, framework: Framework): ToolEnvelope {\n return {\n summary: `Entry file \\`${entryFile}\\` not found.`,\n details:\n `The path we were given doesn't exist. Re-run \\`analyze_project\\` ` +\n `to refresh the detection, or ask the user where their ${frameworkLabel(framework)} ` +\n `entry document lives (typically \\`public/index.html\\`, \\`app.html\\`, or the ` +\n `framework's root template).`,\n nextSteps: [`Call \\`analyze_project\\` again to re-detect, or accept the user's manual path.`],\n meta: { error: 'entry_not_found', entryFile },\n };\n}\n\n/**\n * Per-framework target path for the NEW init module. Mirrors the\n * code comments inside `initSnippet()` (\"// app/_components/FpClient.tsx\",\n * \"// plugins/fingerprint.ts\", etc.).\n */\nfunction perFrameworkTargetFile(framework: Framework, cwd: string): string {\n const map: Record<Framework, string> = {\n nextjs: 'app/_components/FpClient.tsx',\n react: 'src/hooks/useFingerprint.ts',\n vue: 'src/plugins/fingerprint.ts',\n angular: 'src/app/fingerprint.service.ts',\n svelte: 'src/lib/fingerprint.ts',\n preact: 'src/hooks/useFingerprint.ts',\n 'javascript-spa': 'src/fingerprint.ts',\n javascript: 'src/fingerprint.ts',\n };\n // Use `dirname` once to be safe across platforms before joining.\n return resolve(cwd, map[framework]);\n}\n\nfunction perFrameworkMountHint(framework: Framework): string {\n switch (framework) {\n case 'nextjs':\n return 'Mount `<FpClient />` once in `app/layout.tsx` so it boots on every route.';\n case 'react':\n case 'preact':\n return 'Call `useFingerprint()` once in your root `App` component.';\n case 'vue':\n return 'In `main.ts`: `import fpPlugin from \"./plugins/fingerprint\"; app.use(fpPlugin);`. Then from any component call `this.$fp.identify({ event: \"pageview\" })`.';\n case 'angular':\n return 'Inject `FingerprintService` in any component and call `this.fp.fp.identify({ event: \"pageview\" })`.';\n case 'svelte':\n return 'In a `+page.svelte`: `import { fp } from \"$lib/fingerprint\"; onMount(() => fp.identify({ event: \"pageview\" }));`.';\n case 'javascript-spa':\n return \"Hook your router's `onNavigate` to call `fp.identify({ event: 'route:' + path })`.\";\n case 'javascript':\n default:\n return 'Import the module from your entry point so the `fp.identify()` call fires on load.';\n }\n}\n\n/**\n * Splice the snippet immediately before the closing `</body>` tag.\n * If no `</body>` is present (loose HTML or a server-rendered shell\n * that doesn't include it), append at end-of-file.\n */\nfunction appendBeforeBodyClose(html: string, snippet: string): string {\n const lower = html.toLowerCase();\n const idx = lower.lastIndexOf('</body>');\n if (idx === -1) {\n const trailingNewline = html.endsWith('\\n') ? '' : '\\n';\n return `${html}${trailingNewline}${snippet}\\n`;\n }\n const before = html.slice(0, idx);\n const after = html.slice(idx);\n return `${before}${snippet}\\n${after}`;\n}\n\n// Pin `dirname` so unused-imports lint doesn't strip it (we want the\n// helper available for future per-framework heuristics that need the\n// directory of the entry file).\nvoid dirname;\n"],"mappings":"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","names":["resolve","existsSync","resolve","resolve","scan","resolve","z","existsSync","readFileSync","z","resolve","readFileSync","resolve","z","resolve","z","z","resolve","existsSync","readFileSync","resolve","z","z","resolve","scan","readFileSync","existsSync","existsSync","readFileSync","dirname","resolve","z","z","resolve","existsSync","readFileSync","diff"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fingerprint-platform-mcp",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Model Context Protocol server that lets Claude / Cursor / Copilot Chat install and configure the Fingerprint Platform SDK in a user's project — analyze the codebase, propose a diff, generate the Cloudflare Worker proxy, verify the install.",
5
5
  "type": "module",
6
6
  "main": "./dist/cli.js",