{"_id":"@bigin-io/site-contract","_rev":"2-a4c3f8b02d9d691cc603670aa55c60af","name":"@bigin-io/site-contract","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@bigin-io/site-contract","version":"1.0.0","license":"UNLICENSED","_id":"@bigin-io/site-contract@1.0.0","maintainers":[{"name":"maichitam","email":"tammai.it@gmail.com"},{"name":"tammai.bigin","email":"tam.mai@bigin.vn"}],"homepage":"https://github.com/bigin-io/ssg-site-factory#readme","bugs":{"url":"https://github.com/bigin-io/ssg-site-factory/issues"},"dist":{"shasum":"ce2fba1131467c56e4d6e0f154bc9a0043808644","tarball":"https://registry.npmjs.org/@bigin-io/site-contract/-/site-contract-1.0.0.tgz","fileCount":139,"integrity":"sha512-z4HVmIuVp9/9qwlri3qS03x/+0G/qWgOkfvk3+2YFAKrRwGT2DPqVq110U2Y+3muizNSs5W4Xo+KKE4UBMEddQ==","signatures":[{"sig":"MEUCIQDZX0Dyclg3w1JG3cW4moxRnBV7/8YIe7P7PSCAeeTi5AIgSxx+KZslqfv00KkWJPuaA8XYgIAbto25gYmx3hjW0iU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":623080},"main":"./dist/index.js","type":"module","_from":"file:C:/Users/Admin/AppData/Local/Temp/sf-publish/bigin-io-site-contract-1.0.0.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./tokens":{"types":"./dist/tokens/index.d.ts","default":"./dist/tokens/index.js"},"./content":{"types":"./dist/content/index.d.ts","default":"./dist/content/index.js"},"./fixtures":{"types":"./dist/fixtures/index.d.ts","default":"./dist/fixtures/index.js"},"./package.json":"./package.json","./site.config.schema.json":"./dist/site.config.schema.json"},"scripts":{"build":"tsc -p tsconfig.build.json && node ./scripts/emit-json-schema.mjs","clean":"node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"maichitam","email":"tammai.it@gmail.com"},"_resolved":"C:\\Users\\Admin\\AppData\\Local\\Temp\\sf-publish\\bigin-io-site-contract-1.0.0.tgz","_integrity":"sha512-z4HVmIuVp9/9qwlri3qS03x/+0G/qWgOkfvk3+2YFAKrRwGT2DPqVq110U2Y+3muizNSs5W4Xo+KKE4UBMEddQ==","repository":{"url":"git+https://github.com/bigin-io/ssg-site-factory.git","type":"git","directory":"packages/site-contract"},"_npmVersion":"11.2.0","description":"Single source of truth for site.config, content schemas, and the design-token spec","directories":{},"sideEffects":false,"_nodeVersion":"22.14.0","dependencies":{"zod":"^4.5.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/site-contract_1.0.0_1788517254990_0.49913595018691725","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"_id":"@bigin-io/site-contract@1.0.1","bugs":{"url":"https://github.com/bigin-io/ssg-site-factory/issues"},"dist":{"shasum":"7d5dae826154c08ba1a0a7fa2abbc996536b35b9","tarball":"https://registry.npmjs.org/@bigin-io/site-contract/-/site-contract-1.0.1.tgz","fileCount":139,"integrity":"sha512-SNbL9V74E3wmCBs2acVWMXKthDEXtpG6LAcufHx6lUqTTobv6/gKocz1o/FvSXy5vAKe5wCtzpye9fLTO+Nm0w==","signatures":[{"sig":"MEQCIFLwOAPo6NL3TslQ9s0Ng2kGXTH24yEED+212076m72WAiAMufPBUDZSe8T/FkFickVJfotQzM1KnML7diFONSn6Wg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIE2ua/eOyqMBUTr+IE3vCwr/HTnh8oZURevFWNr/tPQAAiEAnfk4hpRZCNkomTNgrHP3ETTnIXqst2KR3BvtmgIRJvI="}],"unpackedSize":623080},"main":"./dist/index.js","name":"@bigin-io/site-contract","type":"module","_from":"file:C:/Users/Admin/AppData/Local/Temp/sf-publish/bigin-io-site-contract-1.0.1.tgz","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./tokens":{"types":"./dist/tokens/index.d.ts","default":"./dist/tokens/index.js"},"./content":{"types":"./dist/content/index.d.ts","default":"./dist/content/index.js"},"./fixtures":{"types":"./dist/fixtures/index.d.ts","default":"./dist/fixtures/index.js"},"./package.json":"./package.json","./site.config.schema.json":"./dist/site.config.schema.json"},"license":"UNLICENSED","scripts":{"build":"tsc -p tsconfig.build.json && node ./scripts/emit-json-schema.mjs","clean":"node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"","typecheck":"tsc -p tsconfig.json --noEmit"},"version":"1.0.1","_npmUser":{"name":"maichitam","email":"tammai.it@gmail.com"},"homepage":"https://github.com/bigin-io/ssg-site-factory#readme","_resolved":"C:\\Users\\Admin\\AppData\\Local\\Temp\\sf-publish\\bigin-io-site-contract-1.0.1.tgz","_integrity":"sha512-SNbL9V74E3wmCBs2acVWMXKthDEXtpG6LAcufHx6lUqTTobv6/gKocz1o/FvSXy5vAKe5wCtzpye9fLTO+Nm0w==","repository":{"url":"git+https://github.com/bigin-io/ssg-site-factory.git","type":"git","directory":"packages/site-contract"},"_npmVersion":"11.2.0","description":"Single source of truth for site.config, content schemas, and the design-token spec","directories":{},"maintainers":[{"name":"maichitam","email":"tammai.it@gmail.com"},{"name":"tammai.bigin","email":"tam.mai@bigin.vn"}],"sideEffects":false,"_nodeVersion":"22.14.0","dependencies":{"zod":"^4.5.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/site-contract_1.0.1_1788517830312_0.16163697548042388"}}},"time":{"created":"2026-09-04T10:20:54.754Z","modified":"2026-09-04T10:30:30.594Z","1.0.0":"2026-09-04T10:20:55.138Z","1.0.1":"2026-09-04T10:30:30.426Z"},"bugs":{"url":"https://github.com/bigin-io/ssg-site-factory/issues"},"license":"UNLICENSED","homepage":"https://github.com/bigin-io/ssg-site-factory#readme","repository":{"url":"git+https://github.com/bigin-io/ssg-site-factory.git","type":"git","directory":"packages/site-contract"},"description":"Single source of truth for site.config, content schemas, and the design-token spec","maintainers":[{"name":"maichitam","email":"tammai.it@gmail.com"},{"name":"tammai.bigin","email":"tam.mai@bigin.vn"}],"readme":"# @bigin-io/site-contract\r\n\r\nSingle source of truth for `site.config`, the content/frontmatter schemas, and\r\nthe design-token spec. Both renderers (ADR-1), the site Worker (ADR-5), and\r\nevery pipeline skill read their shapes from here and nowhere else.\r\n\r\nFramework-agnostic by construction: no renderer import, no Worker import, no\r\nhost global. `zod` is the only runtime dependency.\r\n\r\n## Install\r\n\r\n```bash\r\npnpm add @bigin-io/site-contract\r\n```\r\n\r\n## Consumption modes (ADR-8)\r\n\r\n| Consumer | How it resolves |\r\n| --- | --- |\r\n| A package inside this monorepo | `\"@bigin-io/site-contract\": \"workspace:^\"` |\r\n| A client site repo | a pinned semver range from npm (public since ADR-18; GitHub Packages before it) |\r\n\r\nA site repo needs the scope mapped to the registry and a token:\r\n\r\n```ini\r\n# .npmrc\r\n# Nothing. The @bigin-io scope publishes publicly to npm (ADR-18), so a\r\n# site repo needs no registry mapping and no token at all. This block used\r\n# to read:\r\n#\r\n#   # Not needed: the scope is public on npm (ADR-18).\r\n#   //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}\r\n```\r\n\r\nVerified against a real install of `0.2.0` from the registry, from a repo outside\r\nthis workspace (story 6.5, T6). Those two lines are the whole of it — nothing\r\nelse is needed to resolve the package or any of its subpaths.\r\n\r\n**The token needs `read:packages`, and where it comes from differs.**\r\n\r\n| Where | The token |\r\n| --- | --- |\r\n| GitHub Actions, same org | the built-in `GITHUB_TOKEN`, with `permissions: packages: read` on the job |\r\n| A developer's machine | a PAT with `read:packages`, exported as `GITHUB_TOKEN` |\r\n\r\nThere is no ambient `GITHUB_TOKEN` outside Actions, so a local `npm install`\r\nfails without one. The failure is specific and worth recognising: a token\r\ncarrying `repo` but not `read:packages` returns\r\n\r\n```\r\n403 Forbidden - Permission permission_denied: The token provided does not match expected scopes.\r\n```\r\n\r\nnot a 404 or an auth prompt. `gh auth refresh -h github.com -s read:packages`\r\nadds the scope to an existing `gh` login.\r\n\r\n**Your `tsconfig` needs a `URL` global.** `zod`'s declaration files reference\r\n`URL`, so a consumer typechecking with `skipLibCheck: false` and a bare\r\n`\"lib\": [\"ES2022\"], \"types\": []` fails in `node_modules/zod`, not in its own\r\ncode. `\"types\": [\"node\"]` (or a DOM lib) resolves it. With that, the published\r\ndeclarations typecheck clean under `strict`, `noUncheckedIndexedAccess` and\r\n`exactOptionalPropertyTypes`.\r\n\r\n## Usage\r\n\r\n```ts\r\nimport { defineSiteConfig, parseSiteConfig, SCHEMA_VERSION } from '@bigin-io/site-contract'\r\n\r\nexport default defineSiteConfig({\r\n  schemaVersion: SCHEMA_VERSION,\r\n  tier: 'content',\r\n  renderer: 'nuxt',\r\n  // ...\r\n})\r\n```\r\n\r\n```ts\r\nimport { createContentSchemas } from '@bigin-io/site-contract/content'\r\nimport { toCssVars } from '@bigin-io/site-contract/tokens'\r\nimport { contentSiteConfig } from '@bigin-io/site-contract/fixtures'\r\n\r\nconst { page, post, section, collections } = createContentSchemas(config)\r\nconst cssVars = toCssVars(config.design.tokens)\r\n```\r\n\r\nContent schemas are a factory, not constants: tier and media zone decide what\r\ncontent is legal (ADR-11, ADR-12), so a simple-tier site rejects a\r\n`media.<domain>` image reference at parse time.\r\n\r\n### Two stages\r\n\r\n| Schema | Gate | Allows |\r\n| --- | --- | --- |\r\n| `siteConfigDraftSchema` | G0 (`sf-intake`) | `design.tokens`, `pages`, `collections`, and `cloudflare` still absent |\r\n| `siteConfigSchema` | G4 (build) | everything present |\r\n\r\nAnything that parses as complete also parses as draft — the cross-field rules\r\nare presence-guarded and shared between the two.\r\n\r\n## Versioning policy\r\n\r\n`schemaVersion` is the contract's major line; `CONTRACT_VERSION` is the package\r\nsemver, recorded in build manifests for NFR-6.\r\n\r\n`CONTRACT_VERSION` always equals this package's `package.json` version.\r\n`scripts/dist/bin/sync-versions.js` rewrites it during `changeset version`, so\r\nthe two move in one commit, and `test/public-api.test.ts` fails if they ever\r\npart company. Do not edit the literal by hand.\r\n\r\n| Change | Release |\r\n| --- | --- |\r\n| Additive optional field | minor, no `schemaVersion` bump |\r\n| New required field | major + bump + migration |\r\n| Removed field or changed semantics | major + bump + migration |\r\n| A `--sf-*` CSS variable rename | major + bump + migration |\r\n\r\n### Migrations shipped\r\n\r\n| To | Change | What a site repo does |\r\n| --- | --- | --- |\r\n| `2` | `site.config.budgets` removed (story 6.9) | Delete the `budgets` block and set `schemaVersion: 2`, or run `migrateSiteConfig()` |\r\n\r\n`schemaVersion: 2` is a **breaking** change from `0.4.0`. A config that keeps\r\nthe block is **refused by name**, not quietly stripped — so an upgrade cannot\r\nsilently discard a budget a site meant to keep. NFR-1's budgets and the\r\n`public/` image warning are repository constants in `@bigin-io/site-tools` now,\r\nand a site states neither. Note what that costs in **both** directions: a site\r\ncan no longer ask to be *faster* than the platform floor either. That is a\r\nplatform change, not a config field.\r\n\r\nThe `--sf-*` map and the leaf-key-name set are snapshot-locked in the test\r\nsuite. A snapshot diff means a contract change, so it needs a PR — not a\r\nsnapshot update.\r\n\r\nAfter story 1.1 the contract is **frozen**: changes go through PR + review only,\r\nand every lane rebases on the merged change before continuing\r\n(`CLAUDE.md` § Workflow).\r\n\r\n## What this package does not do\r\n\r\nIt validates *parsed objects*. Loading `site.config.ts` (a TypeScript module)\r\nand reading markdown off disk are the renderer's and pipeline's job — a\r\nfile-reading API here would be a contract-scope change.\r\n","readmeFilename":"README.md"}