From ae18c23d8bf6586ac90650d1f6820d57da570666 Mon Sep 17 00:00:00 2001 From: callumflack Date: Mon, 13 Jul 2026 19:09:34 +1000 Subject: [PATCH 1/2] Publish scope catalog as versioned npm package --- .github/workflows/publish-scope-catalog.yml | 255 ++++ package.json | 4 + packages/scope-catalog/CHANGELOG.md | 11 + packages/scope-catalog/README.md | 43 + .../amazon/schemas/amazon.orders.json | 42 + .../amazon/schemas/amazon.profile.json | 16 + .../schemas/claude.conversations.json | 225 +++ .../anthropic/schemas/claude.projects.json | 92 ++ .../apple/schemas/icloud_notes.folders.json | 27 + .../apple/schemas/icloud_notes.notes.json | 35 + .../doordash/schemas/doordash.orders.json | 75 + .../github/schemas/github.contributions.json | 62 + .../github/schemas/github.events.json | 38 + .../github/schemas/github.history.json | 70 + .../github/schemas/github.profile.json | 67 + .../github/schemas/github.repositories.json | 36 + .../github/schemas/github.starred.json | 30 + .../google/schemas/youtube.history.json | 32 + .../google/schemas/youtube.likes.json | 31 + .../google/schemas/youtube.playlistItems.json | 44 + .../google/schemas/youtube.playlists.json | 32 + .../google/schemas/youtube.profile.json | 26 + .../google/schemas/youtube.subscriptions.json | 34 + .../google/schemas/youtube.watchLater.json | 31 + .../connectors/heb/schemas/heb.nutrition.json | 78 + .../connectors/heb/schemas/heb.orders.json | 46 + .../connectors/heb/schemas/heb.profile.json | 26 + .../schemas/linkedin.connections.json | 28 + .../linkedin/schemas/linkedin.education.json | 29 + .../linkedin/schemas/linkedin.experience.json | 29 + .../linkedin/schemas/linkedin.languages.json | 26 + .../linkedin/schemas/linkedin.profile.json | 21 + .../linkedin/schemas/linkedin.skills.json | 26 + .../meta/schemas/instagram.ads.json | 47 + .../meta/schemas/instagram.following.json | 31 + .../meta/schemas/instagram.posts.json | 41 + .../meta/schemas/instagram.profile.json | 25 + .../openai/schemas/chatgpt.conversations.json | 46 + .../openai/schemas/chatgpt.memories.json | 30 + .../oura/schemas/oura.activity.json | 49 + .../oura/schemas/oura.readiness.json | 43 + .../connectors/oura/schemas/oura.sleep.json | 69 + .../shopify/schemas/shop.orders.json | 37 + .../spotify/schemas/spotify.playlists.json | 62 + .../spotify/schemas/spotify.profile.json | 23 + .../spotify/schemas/spotify.savedTracks.json | 60 + .../uber/schemas/uber.receipts.json | 34 + .../connectors/uber/schemas/uber.trips.json | 35 + .../valve/schemas/steam.friends.json | 20 + .../connectors/valve/schemas/steam.games.json | 42 + .../valve/schemas/steam.profile.json | 24 + .../schemas/wholefoods.nutrition.json | 44 + .../wholefoods/schemas/wholefoods.orders.json | 46 + .../schemas/wholefoods.profile.json | 16 + packages/scope-catalog/package.json | 33 + packages/scope-catalog/release.json | 212 +++ .../schemas/scope-catalog.schema.json | 211 +++ packages/scope-catalog/scope-catalog.json | 1287 +++++++++++++++++ scripts/build-scope-catalog-package.mjs | 153 ++ scripts/check-scope-catalog-package.mjs | 152 ++ scripts/diff-scope-catalog-package.mjs | 506 +++++++ scripts/scope-catalog-package.test.mjs | 760 ++++++++++ 62 files changed, 5805 insertions(+) create mode 100644 .github/workflows/publish-scope-catalog.yml create mode 100644 packages/scope-catalog/CHANGELOG.md create mode 100644 packages/scope-catalog/README.md create mode 100644 packages/scope-catalog/connectors/amazon/schemas/amazon.orders.json create mode 100644 packages/scope-catalog/connectors/amazon/schemas/amazon.profile.json create mode 100644 packages/scope-catalog/connectors/anthropic/schemas/claude.conversations.json create mode 100644 packages/scope-catalog/connectors/anthropic/schemas/claude.projects.json create mode 100644 packages/scope-catalog/connectors/apple/schemas/icloud_notes.folders.json create mode 100644 packages/scope-catalog/connectors/apple/schemas/icloud_notes.notes.json create mode 100644 packages/scope-catalog/connectors/doordash/schemas/doordash.orders.json create mode 100644 packages/scope-catalog/connectors/github/schemas/github.contributions.json create mode 100644 packages/scope-catalog/connectors/github/schemas/github.events.json create mode 100644 packages/scope-catalog/connectors/github/schemas/github.history.json create mode 100644 packages/scope-catalog/connectors/github/schemas/github.profile.json create mode 100644 packages/scope-catalog/connectors/github/schemas/github.repositories.json create mode 100644 packages/scope-catalog/connectors/github/schemas/github.starred.json create mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.history.json create mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.likes.json create mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.playlistItems.json create mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.playlists.json create mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.profile.json create mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.subscriptions.json create mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.watchLater.json create mode 100644 packages/scope-catalog/connectors/heb/schemas/heb.nutrition.json create mode 100644 packages/scope-catalog/connectors/heb/schemas/heb.orders.json create mode 100644 packages/scope-catalog/connectors/heb/schemas/heb.profile.json create mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.connections.json create mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.education.json create mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.experience.json create mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.languages.json create mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.profile.json create mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.skills.json create mode 100644 packages/scope-catalog/connectors/meta/schemas/instagram.ads.json create mode 100644 packages/scope-catalog/connectors/meta/schemas/instagram.following.json create mode 100644 packages/scope-catalog/connectors/meta/schemas/instagram.posts.json create mode 100644 packages/scope-catalog/connectors/meta/schemas/instagram.profile.json create mode 100644 packages/scope-catalog/connectors/openai/schemas/chatgpt.conversations.json create mode 100644 packages/scope-catalog/connectors/openai/schemas/chatgpt.memories.json create mode 100644 packages/scope-catalog/connectors/oura/schemas/oura.activity.json create mode 100644 packages/scope-catalog/connectors/oura/schemas/oura.readiness.json create mode 100644 packages/scope-catalog/connectors/oura/schemas/oura.sleep.json create mode 100644 packages/scope-catalog/connectors/shopify/schemas/shop.orders.json create mode 100644 packages/scope-catalog/connectors/spotify/schemas/spotify.playlists.json create mode 100644 packages/scope-catalog/connectors/spotify/schemas/spotify.profile.json create mode 100644 packages/scope-catalog/connectors/spotify/schemas/spotify.savedTracks.json create mode 100644 packages/scope-catalog/connectors/uber/schemas/uber.receipts.json create mode 100644 packages/scope-catalog/connectors/uber/schemas/uber.trips.json create mode 100644 packages/scope-catalog/connectors/valve/schemas/steam.friends.json create mode 100644 packages/scope-catalog/connectors/valve/schemas/steam.games.json create mode 100644 packages/scope-catalog/connectors/valve/schemas/steam.profile.json create mode 100644 packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.nutrition.json create mode 100644 packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.orders.json create mode 100644 packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.profile.json create mode 100644 packages/scope-catalog/package.json create mode 100644 packages/scope-catalog/release.json create mode 100644 packages/scope-catalog/schemas/scope-catalog.schema.json create mode 100644 packages/scope-catalog/scope-catalog.json create mode 100644 scripts/build-scope-catalog-package.mjs create mode 100644 scripts/check-scope-catalog-package.mjs create mode 100644 scripts/diff-scope-catalog-package.mjs create mode 100644 scripts/scope-catalog-package.test.mjs diff --git a/.github/workflows/publish-scope-catalog.yml b/.github/workflows/publish-scope-catalog.yml new file mode 100644 index 0000000..c13af71 --- /dev/null +++ b/.github/workflows/publish-scope-catalog.yml @@ -0,0 +1,255 @@ +name: Publish Scope Catalog + +on: + workflow_dispatch: + inputs: + confirmInitialPublish: + description: "Confirm Callum approved the first @opendatalabs/scope-catalog@1.0.0 publish" + required: true + type: boolean + default: false + push: + branches: [main] + paths: + - ".github/workflows/publish-scope-catalog.yml" + - "connectors/**/*-playwright.json" + - "connectors/**/schemas/*.json" + - "packages/scope-catalog/**" + - "registry.json" + - "schemas/manifest.schema.json" + - "schemas/scope-catalog.schema.json" + - "schemas/web-scope-capabilities.schema.json" + - "scope-catalog.json" + - "scopes/web-capabilities.json" + - "scripts/build-scope-catalog-package.mjs" + - "scripts/check-scope-catalog-package.mjs" + - "scripts/diff-scope-catalog-package.mjs" + - "scripts/generate-scope-catalog.mjs" + - "scripts/generate-scope-catalog.test.mjs" + - "scripts/scope-catalog-package.test.mjs" + - "package.json" + - "package-lock.json" + +permissions: + contents: read + id-token: write + +concurrency: + group: publish-scope-catalog + cancel-in-progress: false + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "24.4.0" + registry-url: https://registry.npmjs.org + + - name: Pin trusted-publishing-compatible npm + run: npm install --global npm@11.5.1 + + - name: Install dependencies + run: npm ci + + - name: Validate BUI-705 manifest and schema inputs + run: | + node scripts/validate-manifests.mjs + node scripts/normalize-manifests.mjs --check + node scripts/validate-scope-schemas.mjs + + - name: Test BUI-705 catalog contract + run: npm run scope-catalog:test + + - name: Check BUI-705 generated catalog + run: npm run scope-catalog:check + + - name: Resolve exact previous package + id: previous + env: + PACKAGE_NAME: "@opendatalabs/scope-catalog" + run: | + set -euo pipefail + previous_dir="$RUNNER_TEMP/scope-catalog-previous" + mkdir -p "$previous_dir/packed" "$previous_dir/unpacked" + + set +e + npm view "$PACKAGE_NAME" version --json > "$previous_dir/version.json" 2> "$previous_dir/view-error.log" + view_status=$? + set -e + + if [ "$view_status" -eq 0 ]; then + previous_version="$(node -p "JSON.parse(require('fs').readFileSync(process.argv[1], 'utf8'))" "$previous_dir/version.json")" + npm pack "$PACKAGE_NAME@$previous_version" --pack-destination "$previous_dir/packed" --json > "$previous_dir/pack.json" + tarball="$(node -p "JSON.parse(require('fs').readFileSync(process.argv[1], 'utf8'))[0].filename" "$previous_dir/pack.json")" + tar -xzf "$previous_dir/packed/$tarball" -C "$previous_dir/unpacked" + echo "exists=true" >> "$GITHUB_OUTPUT" + echo "version=$previous_version" >> "$GITHUB_OUTPUT" + echo "root=$previous_dir/unpacked/package" >> "$GITHUB_OUTPUT" + elif grep -q "E404" "$previous_dir/view-error.log"; then + echo "exists=false" >> "$GITHUB_OUTPUT" + echo "version=" >> "$GITHUB_OUTPUT" + echo "root=" >> "$GITHUB_OUTPUT" + else + cat "$previous_dir/view-error.log" >&2 + exit "$view_status" + fi + + - name: Build package and semantic release metadata + env: + PACKAGE_EXISTS: ${{ steps.previous.outputs.exists }} + PREVIOUS_PACKAGE_ROOT: ${{ steps.previous.outputs.root }} + run: | + if [ "$PACKAGE_EXISTS" = "true" ]; then + npm run scope-catalog-package:build -- --previous-package "$PREVIOUS_PACKAGE_ROOT" + else + npm run scope-catalog-package:build + fi + + - name: Check deterministic package + env: + PACKAGE_EXISTS: ${{ steps.previous.outputs.exists }} + PREVIOUS_PACKAGE_ROOT: ${{ steps.previous.outputs.root }} + run: | + if [ "$PACKAGE_EXISTS" = "true" ]; then + npm run scope-catalog-package:check -- --previous-package "$PREVIOUS_PACKAGE_ROOT" + else + npm run scope-catalog-package:check + fi + + - name: Test package contract and release gates + run: npm run scope-catalog-package:test + + - name: Decide whether publication is allowed + id: release + env: + EVENT_NAME: ${{ github.event_name }} + INITIAL_CONFIRMED: ${{ github.event_name == 'workflow_dispatch' && inputs.confirmInitialPublish == true }} + PACKAGE_EXISTS: ${{ steps.previous.outputs.exists }} + run: | + set -euo pipefail + decision="$(node --input-type=module <<'NODE' + import { readFileSync } from "node:fs"; + import { decideScopeCatalogPublication } from "./scripts/diff-scope-catalog-package.mjs"; + + const release = JSON.parse( + readFileSync("./packages/scope-catalog/release.json", "utf8"), + ); + const decision = decideScopeCatalogPublication({ + eventName: process.env.EVENT_NAME, + packageExists: process.env.PACKAGE_EXISTS === "true", + initialConfirmed: process.env.INITIAL_CONFIRMED === "true", + release, + }); + process.stdout.write(JSON.stringify({ ...decision, release })); + NODE + )" + impact="$(node -p "JSON.parse(process.argv[1]).release.impact" "$decision")" + version="$(node -p "JSON.parse(process.argv[1]).release.currentVersion" "$decision")" + should_publish="$(node -p "JSON.parse(process.argv[1]).shouldPublish" "$decision")" + authentication="$(node -p "JSON.parse(process.argv[1]).authentication" "$decision")" + reason="$(node -p "JSON.parse(process.argv[1]).reason" "$decision")" + + echo "impact=$impact" >> "$GITHUB_OUTPUT" + echo "version=$version" >> "$GITHUB_OUTPUT" + echo "should_publish=$should_publish" >> "$GITHUB_OUTPUT" + echo "authentication=$authentication" >> "$GITHUB_OUTPUT" + echo "reason=$reason" >> "$GITHUB_OUTPUT" + + { + echo "### Scope catalog package" + echo "- Version: \`$version\`" + echo "- Impact: \`$impact\`" + echo "- Publish: \`$should_publish\`" + echo "- Authentication: \`$authentication\`" + echo "- Reason: $reason" + if [ "$authentication" = "bootstrap-token" ]; then + echo "- After 1.0.0: configure npm trusted publishing, delete the NPM_TOKEN GitHub secret, and revoke the bootstrap token." + elif [ "$authentication" = "oidc-trusted-publishing" ]; then + echo "- NPM_TOKEN is not passed; npm trusted publishing must already be configured for this workflow." + fi + } >> "$GITHUB_STEP_SUMMARY" + + - name: Pack exact package contents + id: pack + run: | + set -euo pipefail + pack_dir="$RUNNER_TEMP/scope-catalog-pack" + mkdir -p "$pack_dir" + npm pack ./packages/scope-catalog --pack-destination "$pack_dir" --json > "$pack_dir/pack.json" + filename="$(node -p "JSON.parse(require('fs').readFileSync(process.argv[1], 'utf8'))[0].filename" "$pack_dir/pack.json")" + echo "tarball=$pack_dir/$filename" >> "$GITHUB_OUTPUT" + + - name: Smoke-test every package export + env: + TARBALL: ${{ steps.pack.outputs.tarball }} + run: | + set -euo pipefail + consumer="$RUNNER_TEMP/scope-catalog-consumer" + mkdir -p "$consumer" + cd "$consumer" + npm init -y >/dev/null + npm install --ignore-scripts "$TARBALL" + node --input-type=module <<'NODE' + import { createRequire } from "node:module"; + + const require = createRequire(import.meta.url); + const catalog = require("@opendatalabs/scope-catalog/scope-catalog.json"); + require("@opendatalabs/scope-catalog/schemas/scope-catalog.schema.json"); + require("@opendatalabs/scope-catalog/release.json"); + require("@opendatalabs/scope-catalog/package.json"); + for (const scope of catalog.scopes) { + require(`@opendatalabs/scope-catalog/${scope.schema.path}`); + } + console.log(`Imported all required exports and ${catalog.scopes.length} payload schemas.`); + NODE + + - name: Publish initial package with bootstrap token + if: >- + steps.release.outputs.should_publish == 'true' && + steps.release.outputs.authentication == 'bootstrap-token' && + steps.previous.outputs.exists != 'true' && + github.event_name == 'workflow_dispatch' && + inputs.confirmInitialPublish == true + env: + CHECKED_OUT_SHA: ${{ github.sha }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + set -euo pipefail + current_main_sha="$(git ls-remote --exit-code origin refs/heads/main | awk '{ print $1 }')" + if [ "$CHECKED_OUT_SHA" != "$current_main_sha" ]; then + { + echo "### Scope catalog publication skipped" + echo "- Reason: this run no longer represents current main." + echo "- Checked-out SHA: \`$CHECKED_OUT_SHA\`" + echo "- Current main SHA: \`$current_main_sha\`" + } >> "$GITHUB_STEP_SUMMARY" + exit 0 + fi + + npm publish "${{ steps.pack.outputs.tarball }}" --access public --provenance + + - name: Publish later package with trusted publishing + if: >- + steps.release.outputs.should_publish == 'true' && + steps.release.outputs.authentication == 'oidc-trusted-publishing' && + steps.previous.outputs.exists == 'true' + env: + CHECKED_OUT_SHA: ${{ github.sha }} + run: | + set -euo pipefail + current_main_sha="$(git ls-remote --exit-code origin refs/heads/main | awk '{ print $1 }')" + if [ "$CHECKED_OUT_SHA" != "$current_main_sha" ]; then + { + echo "### Scope catalog publication skipped" + echo "- Reason: this run no longer represents current main." + echo "- Checked-out SHA: \`$CHECKED_OUT_SHA\`" + echo "- Current main SHA: \`$current_main_sha\`" + } >> "$GITHUB_STEP_SUMMARY" + exit 0 + fi + + npm publish "${{ steps.pack.outputs.tarball }}" --access public --provenance diff --git a/package.json b/package.json index a4cf082..9ed39fd 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,10 @@ "scope-catalog:generate": "node ./scripts/generate-scope-catalog.mjs", "scope-catalog:check": "node ./scripts/generate-scope-catalog.mjs --check", "scope-catalog:test": "node --test ./scripts/generate-scope-catalog.test.mjs", + "scope-catalog-package:build": "node ./scripts/build-scope-catalog-package.mjs", + "scope-catalog-package:check": "node ./scripts/check-scope-catalog-package.mjs", + "scope-catalog-package:diff": "node ./scripts/diff-scope-catalog-package.mjs", + "scope-catalog-package:test": "node --test ./scripts/scope-catalog-package.test.mjs", "release:sign": "node ./scripts/sign-release-assets.mjs" }, "devDependencies": { diff --git a/packages/scope-catalog/CHANGELOG.md b/packages/scope-catalog/CHANGELOG.md new file mode 100644 index 0000000..bb451e3 --- /dev/null +++ b/packages/scope-catalog/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable public scope-catalog contract changes are recorded here. + +## 1.0.0 + +- Impact: minor +- Contract fingerprint: `sha256:0c1ab8a19b236cd2b1d1a6ae19a2acee53519812d1fd7b4e443cdf5f7755fb09` +- Added pairs: `amazon/amazon.orders`, `amazon/amazon.profile`, `chatgpt/chatgpt.conversations`, `chatgpt/chatgpt.memories`, `claude/claude.conversations`, `claude/claude.projects`, `doordash/doordash.orders`, `github/github.contributions`, `github/github.events`, `github/github.history`, `github/github.profile`, `github/github.repositories`, `github/github.starred`, `heb/heb.nutrition`, `heb/heb.orders`, `heb/heb.profile`, `icloud_notes/icloud_notes.folders`, `icloud_notes/icloud_notes.notes`, `instagram/instagram.ads`, `instagram/instagram.following`, `instagram/instagram.posts`, `instagram/instagram.profile`, `linkedin/linkedin.connections`, `linkedin/linkedin.education`, `linkedin/linkedin.experience`, `linkedin/linkedin.languages`, `linkedin/linkedin.profile`, `linkedin/linkedin.skills`, `oura/oura.activity`, `oura/oura.readiness`, `oura/oura.sleep`, `shop/shop.orders`, `spotify/spotify.playlists`, `spotify/spotify.profile`, `spotify/spotify.savedTracks`, `steam/steam.friends`, `steam/steam.games`, `steam/steam.profile`, `uber/uber.receipts`, `uber/uber.trips`, `wholefoods/wholefoods.nutrition`, `wholefoods/wholefoods.orders`, `wholefoods/wholefoods.profile`, `youtube/youtube.history`, `youtube/youtube.likes`, `youtube/youtube.playlistItems`, `youtube/youtube.playlists`, `youtube/youtube.profile`, `youtube/youtube.subscriptions`, `youtube/youtube.watchLater` +- Removed pairs: None +- Changed pairs: 0 diff --git a/packages/scope-catalog/README.md b/packages/scope-catalog/README.md new file mode 100644 index 0000000..ee14b70 --- /dev/null +++ b/packages/scope-catalog/README.md @@ -0,0 +1,43 @@ +# `@opendatalabs/scope-catalog` + +Versioned, JSON-first distribution of Vana's public source and scope contract. + +Install an exact version: + +```sh +npm install --save-exact @opendatalabs/scope-catalog@1.0.0 +``` + +Import the catalog and release metadata: + +```js +import { createRequire } from "node:module"; + +const require = createRequire(import.meta.url); +const catalog = require("@opendatalabs/scope-catalog/scope-catalog.json"); +const release = require("@opendatalabs/scope-catalog/release.json"); +``` + +Each `scope.schema.path` is relative to the package root and is exported at the same package subpath. For example, resolve `connectors/github/schemas/github.profile.json` as: + +```js +const schema = require( + "@opendatalabs/scope-catalog/connectors/github/schemas/github.profile.json", +); +``` + +`catalogVersion` versions the catalog JSON format. The npm package version independently versions changes to the published public contract. + +## Exports + +- `@opendatalabs/scope-catalog/scope-catalog.json` +- `@opendatalabs/scope-catalog/schemas/scope-catalog.schema.json` +- `@opendatalabs/scope-catalog/connectors/*` +- `@opendatalabs/scope-catalog/release.json` +- `@opendatalabs/scope-catalog/package.json` + +## Release metadata + +`release.json` records the current and previous package versions and contract fingerprints, added and removed `[sourceId, scopeId]` pairs, per-pair old/current field changes, and the selected `major`, `minor`, `patch`, or `none` impact. + +The package supports Node.js 20 or later and npm-compatible package managers. The Dependabot dependency name is `@opendatalabs/scope-catalog`. diff --git a/packages/scope-catalog/connectors/amazon/schemas/amazon.orders.json b/packages/scope-catalog/connectors/amazon/schemas/amazon.orders.json new file mode 100644 index 0000000..19aca0e --- /dev/null +++ b/packages/scope-catalog/connectors/amazon/schemas/amazon.orders.json @@ -0,0 +1,42 @@ +{ + "name": "Amazon Orders", + "version": "1.0.0", + "scope": "amazon.orders", + "dialect": "json", + "description": "Amazon order history including items, prices, dates, and delivery status", + "schema": { + "type": "object", + "properties": { + "orders": { + "type": "array", + "items": { + "type": "object", + "properties": { + "orderId": { "type": "string" }, + "orderDate": { "type": "string" }, + "orderTotal": { "type": "string" }, + "deliveryStatus": { "type": "string" }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "url": { "type": "string" }, + "price": { "type": "string" } + }, + "required": ["name"], + "additionalProperties": false + } + } + }, + "required": ["orderId", "items"], + "additionalProperties": false + } + }, + "total": { "type": "number" } + }, + "required": ["orders", "total"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/amazon/schemas/amazon.profile.json b/packages/scope-catalog/connectors/amazon/schemas/amazon.profile.json new file mode 100644 index 0000000..333ddbc --- /dev/null +++ b/packages/scope-catalog/connectors/amazon/schemas/amazon.profile.json @@ -0,0 +1,16 @@ +{ + "name": "Amazon Profile", + "version": "1.0.0", + "scope": "amazon.profile", + "dialect": "json", + "description": "Amazon account profile information including name and Prime membership status", + "schema": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "isPrime": { "type": "boolean" } + }, + "required": ["name"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/anthropic/schemas/claude.conversations.json b/packages/scope-catalog/connectors/anthropic/schemas/claude.conversations.json new file mode 100644 index 0000000..130fd23 --- /dev/null +++ b/packages/scope-catalog/connectors/anthropic/schemas/claude.conversations.json @@ -0,0 +1,225 @@ +{ + "name": "Claude Conversations", + "version": "2.0.0", + "scope": "claude.conversations", + "dialect": "json", + "description": "Claude conversations including chat ids, titles, URLs, and full thread messages when the authenticated conversation API is available.", + "schema": { + "type": "object", + "properties": { + "profile": { + "type": "object", + "properties": { + "name": { + "type": [ + "string", + "null" + ], + "description": "Display name shown in the Claude user menu." + }, + "plan": { + "type": [ + "string", + "null" + ], + "description": "Current Claude plan label shown in the user menu." + } + }, + "required": [ + "name", + "plan" + ], + "additionalProperties": false + }, + "organizationId": { + "type": [ + "string", + "null" + ], + "description": "Active Claude organization id used for authenticated API requests." + }, + "conversations": { + "type": "array", + "description": "Chats collected from Claude, enriched with full thread data when possible.", + "items": { + "type": "object", + "properties": { + "id": { + "type": [ + "string", + "null" + ], + "description": "Chat identifier parsed from the sidebar route when available." + }, + "title": { + "type": "string", + "description": "Conversation title shown in the Claude sidebar." + }, + "href": { + "type": "string", + "description": "Relative Claude route for the conversation." + }, + "createdAt": { + "type": [ + "string", + "null" + ], + "description": "Conversation creation timestamp if Claude returned one." + }, + "updatedAt": { + "type": [ + "string", + "null" + ], + "description": "Conversation update timestamp if Claude returned one." + }, + "starred": { + "type": [ + "boolean", + "null" + ], + "description": "Whether Claude marked the conversation as starred, when available." + }, + "projectId": { + "type": [ + "string", + "null" + ], + "description": "Associated Claude project id, when present." + }, + "messageCount": { + "type": [ + "number", + "null" + ], + "description": "Number of messages collected for the conversation." + }, + "messages": { + "type": "array", + "description": "Thread messages collected from Claude's conversation API.", + "items": { + "type": "object", + "properties": { + "id": { + "type": [ + "string", + "null" + ], + "description": "Claude message id." + }, + "sender": { + "type": [ + "string", + "null" + ], + "description": "Message sender role, such as human or assistant." + }, + "parentId": { + "type": [ + "string", + "null" + ], + "description": "Parent message id in the conversation tree." + }, + "createdAt": { + "type": [ + "string", + "null" + ], + "description": "Message creation timestamp if available." + }, + "updatedAt": { + "type": [ + "string", + "null" + ], + "description": "Message update timestamp if available." + }, + "content": { + "type": "string", + "description": "Flattened text content extracted from the Claude message payload." + }, + "rawContent": { + "description": "Original Claude message content payload.", + "type": [ + "array", + "object", + "string", + "null" + ] + }, + "attachments": { + "type": "array", + "description": "Message attachments returned by Claude, if any.", + "items": { + "type": [ + "object", + "string" + ] + } + } + }, + "required": [ + "id", + "sender", + "parentId", + "createdAt", + "updatedAt", + "content", + "attachments" + ], + "additionalProperties": false + } + }, + "fetchError": { + "type": [ + "string", + "null" + ], + "description": "Error captured when Claude conversation detail could not be fetched." + } + }, + "required": [ + "id", + "title", + "href", + "createdAt", + "updatedAt", + "starred", + "messageCount", + "messages" + ], + "additionalProperties": false + } + }, + "total": { + "type": "number", + "description": "Number of conversations exported." + }, + "messageTotal": { + "type": "number", + "description": "Total number of messages exported across all conversations." + }, + "source": { + "type": "string", + "description": "How the data was collected for this export." + }, + "apiError": { + "type": [ + "string", + "null" + ], + "description": "Top-level API error message when Claude conversation APIs were unavailable." + } + }, + "required": [ + "profile", + "organizationId", + "conversations", + "total", + "messageTotal", + "source" + ], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/anthropic/schemas/claude.projects.json b/packages/scope-catalog/connectors/anthropic/schemas/claude.projects.json new file mode 100644 index 0000000..8a632d9 --- /dev/null +++ b/packages/scope-catalog/connectors/anthropic/schemas/claude.projects.json @@ -0,0 +1,92 @@ +{ + "name": "Claude Projects", + "version": "2.0.0", + "scope": "claude.projects", + "dialect": "json", + "description": "Claude projects including project ids, titles, labels, relative URLs, and project detail when the authenticated project API is available.", + "schema": { + "type": "object", + "properties": { + "profile": { + "type": "object", + "properties": { + "name": { + "type": ["string", "null"], + "description": "Display name shown in the Claude user menu." + }, + "plan": { + "type": ["string", "null"], + "description": "Current Claude plan label shown in the user menu." + } + }, + "required": ["name", "plan"], + "additionalProperties": false + }, + "organizationId": { + "type": ["string", "null"], + "description": "Active Claude organization id used for authenticated API requests." + }, + "projects": { + "type": "array", + "description": "Projects collected from Claude, enriched with project detail when possible.", + "items": { + "type": "object", + "properties": { + "id": { + "type": ["string", "null"], + "description": "Project identifier parsed from the sidebar route when available." + }, + "title": { + "type": "string", + "description": "Project title shown in the Claude sidebar." + }, + "href": { + "type": "string", + "description": "Relative Claude route for the project." + }, + "label": { + "type": ["string", "null"], + "description": "Accessible label for the project entry, if present." + }, + "createdAt": { + "type": ["string", "null"], + "description": "Project creation timestamp if Claude returned one." + }, + "updatedAt": { + "type": ["string", "null"], + "description": "Project update timestamp if Claude returned one." + }, + "archived": { + "type": ["boolean", "null"], + "description": "Whether the project appears archived." + }, + "detail": { + "description": "Raw Claude project detail payload when fetched successfully.", + "type": ["object", "array", "null"] + }, + "fetchError": { + "type": ["string", "null"], + "description": "Error captured when Claude project detail could not be fetched." + } + }, + "required": ["id", "title", "href", "label", "createdAt", "updatedAt", "archived"], + "additionalProperties": false + } + }, + "total": { + "type": "number", + "description": "Number of projects exported." + }, + "source": { + "type": "string", + "description": "How the data was collected for this export." + }, + "apiError": { + "type": ["string", "null"], + "description": "Top-level API error message when Claude project APIs were unavailable." + } + }, + "required": ["profile", "organizationId", "projects", "total", "source"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/apple/schemas/icloud_notes.folders.json b/packages/scope-catalog/connectors/apple/schemas/icloud_notes.folders.json new file mode 100644 index 0000000..643611a --- /dev/null +++ b/packages/scope-catalog/connectors/apple/schemas/icloud_notes.folders.json @@ -0,0 +1,27 @@ +{ + "name": "iCloud Notes Folders", + "version": "1.2.0", + "scope": "icloud_notes.folders", + "dialect": "json", + "description": "Folder structure used to organize iCloud Notes. Field shape reflects the data the CG-in-prod iCloud Notes script emits: one object per folder with its CloudKit recordName and display title.", + "schema": { + "type": "object", + "properties": { + "folders": { + "type": "array", + "items": { + "type": "object", + "properties": { + "recordName": { "type": "string" }, + "title": { "type": "string" } + }, + "required": ["recordName", "title"], + "additionalProperties": true + } + }, + "total": { "type": "number" } + }, + "required": ["folders"], + "additionalProperties": true + } +} diff --git a/packages/scope-catalog/connectors/apple/schemas/icloud_notes.notes.json b/packages/scope-catalog/connectors/apple/schemas/icloud_notes.notes.json new file mode 100644 index 0000000..9ca2cb1 --- /dev/null +++ b/packages/scope-catalog/connectors/apple/schemas/icloud_notes.notes.json @@ -0,0 +1,35 @@ +{ + "name": "iCloud Notes", + "version": "1.2.0", + "scope": "icloud_notes.notes", + "dialect": "json", + "description": "Notes exported from iCloud. Field shape reflects the data the CG-in-prod iCloud Notes script emits: one object per note with recordName, title, snippet, folder, pin state, created/modified dates, attachment flag, and extracted text content.", + "schema": { + "type": "object", + "properties": { + "notes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "recordName": { "type": "string" }, + "title": { "type": ["string", "null"] }, + "snippet": { "type": ["string", "null"] }, + "folder": { "type": ["string", "null"] }, + "isPinned": { "type": "boolean" }, + "createdDate": { "type": ["string", "null"], "format": "date-time" }, + "modifiedDate": { "type": ["string", "null"], "format": "date-time" }, + "hasAttachments": { "type": "boolean" }, + "textContent": { "type": ["string", "null"] } + }, + "required": ["recordName", "title"], + "additionalProperties": true + } + }, + "total": { "type": "number" }, + "userName": { "type": ["string", "null"] } + }, + "required": ["notes"], + "additionalProperties": true + } +} diff --git a/packages/scope-catalog/connectors/doordash/schemas/doordash.orders.json b/packages/scope-catalog/connectors/doordash/schemas/doordash.orders.json new file mode 100644 index 0000000..831ef27 --- /dev/null +++ b/packages/scope-catalog/connectors/doordash/schemas/doordash.orders.json @@ -0,0 +1,75 @@ +{ + "name": "DoorDash Order History", + "version": "1.0.0", + "scope": "doordash.orders", + "dialect": "json", + "description": "DoorDash order history including restaurant names, items ordered with prices, dates, totals, delivery addresses, and delivery status", + "schema": { + "type": "object", + "properties": { + "orders": { + "type": "array", + "description": "List of DoorDash orders", + "items": { + "type": "object", + "properties": { + "orderId": { + "type": "string", + "description": "Unique identifier for the order (UUID)" + }, + "restaurant": { + "type": "string", + "description": "Name of the restaurant or store" + }, + "date": { + "type": "string", + "format": "date-time", + "description": "When the order was placed (ISO 8601)" + }, + "total": { + "type": "string", + "description": "Total amount charged for the order" + }, + "itemCount": { + "type": "string", + "description": "Number of items in the order" + }, + "items": { + "type": "array", + "description": "Individual items in the order", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the item" + }, + "quantity": { + "type": "number", + "description": "Quantity ordered" + }, + "price": { + "type": "string", + "description": "Price per item" + } + }, + "additionalProperties": true + } + }, + "status": { + "type": "string", + "description": "Delivery status (e.g., Delivered, Cancelled, Refunded)" + }, + "deliveryAddress": { + "type": "string", + "description": "Delivery address for the order" + } + }, + "additionalProperties": true + } + } + }, + "required": ["orders"], + "additionalProperties": true + } +} diff --git a/packages/scope-catalog/connectors/github/schemas/github.contributions.json b/packages/scope-catalog/connectors/github/schemas/github.contributions.json new file mode 100644 index 0000000..361b46d --- /dev/null +++ b/packages/scope-catalog/connectors/github/schemas/github.contributions.json @@ -0,0 +1,62 @@ +{ + "name": "GitHub Contributions", + "version": "1.0.0", + "scope": "github.contributions", + "dialect": "json", + "description": "GitHub contribution graph (daily commit counts for the last year) plus aggregate streak and month totals.", + "schema": { + "type": "object", + "properties": { + "totalContributionsLastYear": { "type": ["number", "null"] }, + "yearTotals": { + "type": "array", + "items": { + "type": "object", + "properties": { + "year": { "type": "number" }, + "total": { "type": "number" } + }, + "required": ["year", "total"], + "additionalProperties": false + } + }, + "days": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date": { "type": "string" }, + "count": { "type": "number" }, + "level": { "type": ["number", "null"] } + }, + "required": ["date", "count"], + "additionalProperties": false + } + }, + "monthlyTotals": { + "type": "array", + "items": { + "type": "object", + "properties": { + "month": { "type": "string" }, + "count": { "type": "number" } + }, + "required": ["month", "count"], + "additionalProperties": false + } + }, + "topDay": { + "type": ["object", "null"], + "properties": { + "date": { "type": "string" }, + "count": { "type": "number" } + }, + "required": ["date", "count"], + "additionalProperties": false + }, + "fetchedAt": { "type": "string" } + }, + "required": ["days", "fetchedAt"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/github/schemas/github.events.json b/packages/scope-catalog/connectors/github/schemas/github.events.json new file mode 100644 index 0000000..6b2fd91 --- /dev/null +++ b/packages/scope-catalog/connectors/github/schemas/github.events.json @@ -0,0 +1,38 @@ +{ + "name": "GitHub Activity Events", + "version": "1.0.0", + "scope": "github.events", + "dialect": "json", + "description": "Recent public activity (pushes, pull requests, issues, comments, branches, releases, stars, forks) across every repository the user has touched — including organization-owned repos invisible to github.repositories.", + "schema": { + "type": "object", + "properties": { + "events": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "type": { "type": "string" }, + "createdAt": { "type": "string" }, + "repo": { "type": "string" }, + "repoUrl": { "type": "string" }, + "action": { "type": ["string", "null"] }, + "title": { "type": ["string", "null"] }, + "body": { "type": ["string", "null"] }, + "url": { "type": ["string", "null"] }, + "branch": { "type": ["string", "null"] }, + "commits": { "type": ["number", "null"] }, + "isPublic": { "type": "boolean" } + }, + "required": ["id", "type", "createdAt", "repo", "isPublic"], + "additionalProperties": false + } + }, + "fetchedAt": { "type": "string" }, + "windowDescription": { "type": "string" } + }, + "required": ["events", "fetchedAt"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/github/schemas/github.history.json b/packages/scope-catalog/connectors/github/schemas/github.history.json new file mode 100644 index 0000000..0789635 --- /dev/null +++ b/packages/scope-catalog/connectors/github/schemas/github.history.json @@ -0,0 +1,70 @@ +{ + "name": "GitHub Authored History", + "version": "1.0.0", + "scope": "github.history", + "dialect": "json", + "description": "Full lifetime of pull requests and issues authored by the user, fetched via the GitHub Search API. Covers any repository the user has authored in (including organizations and forks) — far broader than the 90-day Events window. Up to 1000 items per type per query.", + "schema": { + "type": "object", + "properties": { + "pullRequests": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "type": { "type": "string" }, + "number": { "type": ["number", "null"] }, + "title": { "type": ["string", "null"] }, + "body": { "type": ["string", "null"] }, + "state": { "type": ["string", "null"] }, + "createdAt": { "type": ["string", "null"] }, + "updatedAt": { "type": ["string", "null"] }, + "closedAt": { "type": ["string", "null"] }, + "mergedAt": { "type": ["string", "null"] }, + "url": { "type": ["string", "null"] }, + "repo": { "type": "string" }, + "repoUrl": { "type": ["string", "null"] }, + "labels": { "type": "array", "items": { "type": "string" } }, + "comments": { "type": "number" }, + "reactionsTotal": { "type": "number" }, + "isDraft": { "type": "boolean" } + }, + "required": ["id", "type", "repo"], + "additionalProperties": false + } + }, + "issues": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "type": { "type": "string" }, + "number": { "type": ["number", "null"] }, + "title": { "type": ["string", "null"] }, + "body": { "type": ["string", "null"] }, + "state": { "type": ["string", "null"] }, + "createdAt": { "type": ["string", "null"] }, + "updatedAt": { "type": ["string", "null"] }, + "closedAt": { "type": ["string", "null"] }, + "mergedAt": { "type": ["string", "null"] }, + "url": { "type": ["string", "null"] }, + "repo": { "type": "string" }, + "repoUrl": { "type": ["string", "null"] }, + "labels": { "type": "array", "items": { "type": "string" } }, + "comments": { "type": "number" }, + "reactionsTotal": { "type": "number" }, + "isDraft": { "type": "boolean" } + }, + "required": ["id", "type", "repo"], + "additionalProperties": false + } + }, + "fetchedAt": { "type": "string" }, + "windowDescription": { "type": "string" } + }, + "required": ["pullRequests", "issues", "fetchedAt"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/github/schemas/github.profile.json b/packages/scope-catalog/connectors/github/schemas/github.profile.json new file mode 100644 index 0000000..f784250 --- /dev/null +++ b/packages/scope-catalog/connectors/github/schemas/github.profile.json @@ -0,0 +1,67 @@ +{ + "name": "GitHub Profile", + "version": "1.1.0", + "scope": "github.profile", + "dialect": "json", + "description": "GitHub user profile information, including pinned repositories, organization memberships, and achievement badges", + "schema": { + "type": "object", + "properties": { + "username": { "type": "string" }, + "fullName": { "type": "string" }, + "bio": { "type": "string" }, + "company": { "type": "string" }, + "location": { "type": "string" }, + "website": { "type": "string" }, + "avatarUrl": { "type": "string" }, + "followers": { "type": "number" }, + "following": { "type": "number" }, + "repositoryCount": { "type": "number" }, + "profileUrl": { "type": "string" }, + "pinnedRepositories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fullName": { "type": "string" }, + "url": { "type": ["string", "null"] }, + "description": { "type": "string" }, + "language": { "type": ["string", "null"] }, + "stars": { "type": "number" } + }, + "required": ["fullName"], + "additionalProperties": false + } + }, + "organizations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "login": { "type": "string" }, + "label": { "type": "string" }, + "url": { "type": "string" }, + "avatarUrl": { "type": ["string", "null"] } + }, + "required": ["login"], + "additionalProperties": false + } + }, + "achievements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "iconUrl": { "type": ["string", "null"] } + }, + "required": ["name"], + "additionalProperties": false + } + }, + "contributionsLastYear": { "type": ["number", "null"] } + }, + "required": ["username", "profileUrl"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/github/schemas/github.repositories.json b/packages/scope-catalog/connectors/github/schemas/github.repositories.json new file mode 100644 index 0000000..9e80ca4 --- /dev/null +++ b/packages/scope-catalog/connectors/github/schemas/github.repositories.json @@ -0,0 +1,36 @@ +{ + "name": "GitHub Repositories", + "version": "1.0.0", + "scope": "github.repositories", + "dialect": "json", + "description": "GitHub repositories visible in the user's repositories tab", + "schema": { + "type": "object", + "properties": { + "repositories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "url": { "type": "string" }, + "description": { "type": "string" }, + "language": { "type": "string" }, + "stars": { "type": "number" }, + "forks": { "type": "number" }, + "visibility": { "type": "string" }, + "topics": { + "type": "array", + "items": { "type": "string" } + }, + "updatedAt": { "type": ["string", "null"] } + }, + "required": ["name", "url"], + "additionalProperties": false + } + } + }, + "required": ["repositories"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/github/schemas/github.starred.json b/packages/scope-catalog/connectors/github/schemas/github.starred.json new file mode 100644 index 0000000..edc061b --- /dev/null +++ b/packages/scope-catalog/connectors/github/schemas/github.starred.json @@ -0,0 +1,30 @@ +{ + "name": "GitHub Starred Repositories", + "version": "1.0.0", + "scope": "github.starred", + "dialect": "json", + "description": "GitHub repositories starred by the user", + "schema": { + "type": "object", + "properties": { + "starred": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fullName": { "type": "string" }, + "url": { "type": "string" }, + "description": { "type": "string" }, + "language": { "type": "string" }, + "stars": { "type": "number" }, + "updatedAt": { "type": ["string", "null"] } + }, + "required": ["fullName", "url"], + "additionalProperties": false + } + } + }, + "required": ["starred"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.history.json b/packages/scope-catalog/connectors/google/schemas/youtube.history.json new file mode 100644 index 0000000..fbd1087 --- /dev/null +++ b/packages/scope-catalog/connectors/google/schemas/youtube.history.json @@ -0,0 +1,32 @@ +{ + "name": "YouTube Watch History (Recent)", + "version": "1.0.0", + "scope": "youtube.history", + "dialect": "json", + "description": "Most recent watch history entries (top 50) collected from the YouTube History page.", + "schema": { + "type": "object", + "properties": { + "timeWindow": { "type": "string" }, + "history": { + "type": "array", + "items": { + "type": "object", + "properties": { + "watchedAtText": { "type": ["string", "null"], "description": "Section date header e.g. Today, Yesterday, Jan 23 2026" }, + "videoId": { "type": ["string", "null"] }, + "videoUrl": { "type": "string" }, + "videoTitle": { "type": ["string", "null"] }, + "channelTitle": { "type": ["string", "null"] }, + "views": { "type": ["string", "null"], "description": "Raw view count text e.g. '97k views'" }, + "description": { "type": ["string", "null"], "description": "Short video description snippet shown in history" } + }, + "required": ["videoUrl"], + "additionalProperties": false + } + } + }, + "required": ["timeWindow", "history"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.likes.json b/packages/scope-catalog/connectors/google/schemas/youtube.likes.json new file mode 100644 index 0000000..43fc8e8 --- /dev/null +++ b/packages/scope-catalog/connectors/google/schemas/youtube.likes.json @@ -0,0 +1,31 @@ +{ + "name": "YouTube Liked Videos", + "version": "1.0.0", + "scope": "youtube.likes", + "dialect": "json", + "description": "Videos liked by the user (Liked videos).", + "schema": { + "type": "object", + "properties": { + "likedVideos": { + "type": "array", + "items": { + "type": "object", + "properties": { + "videoId": { "type": ["string", "null"] }, + "videoUrl": { "type": "string" }, + "videoTitle": { "type": "string" }, + "channelTitle": { "type": ["string", "null"] }, + "channelUrl": { "type": ["string", "null"] }, + "durationText": { "type": ["string", "null"] }, + "thumbnailUrl": { "type": ["string", "null"] } + }, + "required": ["videoUrl", "videoTitle"], + "additionalProperties": false + } + } + }, + "required": ["likedVideos"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.playlistItems.json b/packages/scope-catalog/connectors/google/schemas/youtube.playlistItems.json new file mode 100644 index 0000000..8bfd5c6 --- /dev/null +++ b/packages/scope-catalog/connectors/google/schemas/youtube.playlistItems.json @@ -0,0 +1,44 @@ +{ + "name": "YouTube Playlist Items", + "version": "1.0.0", + "scope": "youtube.playlistItems", + "dialect": "json", + "description": "Videos inside user playlists, including video titles and URLs.", + "schema": { + "type": "object", + "properties": { + "playlists": { + "type": "array", + "items": { + "type": "object", + "properties": { + "playlistId": { "type": "string" }, + "playlistTitle": { "type": ["string", "null"] }, + "playlistUrl": { "type": ["string", "null"] }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "videoId": { "type": ["string", "null"] }, + "videoUrl": { "type": "string" }, + "videoTitle": { "type": "string" }, + "channelTitle": { "type": ["string", "null"] }, + "channelUrl": { "type": ["string", "null"] }, + "durationText": { "type": ["string", "null"] }, + "thumbnailUrl": { "type": ["string", "null"] } + }, + "required": ["videoUrl", "videoTitle"], + "additionalProperties": false + } + } + }, + "required": ["playlistId", "items"], + "additionalProperties": false + } + } + }, + "required": ["playlists"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.playlists.json b/packages/scope-catalog/connectors/google/schemas/youtube.playlists.json new file mode 100644 index 0000000..04c2fff --- /dev/null +++ b/packages/scope-catalog/connectors/google/schemas/youtube.playlists.json @@ -0,0 +1,32 @@ +{ + "name": "YouTube Playlists", + "version": "1.0.0", + "scope": "youtube.playlists", + "dialect": "json", + "description": "User-created playlists (excludes Liked Videos and Watch Later).", + "schema": { + "type": "object", + "properties": { + "playlists": { + "type": "array", + "items": { + "type": "object", + "properties": { + "playlistId": { "type": "string" }, + "url": { "type": "string" }, + "title": { "type": ["string", "null"] }, + "owner": { "type": ["string", "null"], "description": "Display name of playlist owner" }, + "ownerUrl": { "type": ["string", "null"], "description": "Channel URL of owner" }, + "privacy": { "type": ["string", "null"], "enum": ["Public", "Private", "Unlisted", null] }, + "videoCount": { "type": ["number", "null"] }, + "views": { "type": ["number", "null"], "description": "0 for 'No views'" } + }, + "required": ["playlistId", "url"], + "additionalProperties": false + } + } + }, + "required": ["playlists"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.profile.json b/packages/scope-catalog/connectors/google/schemas/youtube.profile.json new file mode 100644 index 0000000..b52fbb0 --- /dev/null +++ b/packages/scope-catalog/connectors/google/schemas/youtube.profile.json @@ -0,0 +1,26 @@ +{ + "name": "YouTube Profile", + "version": "1.0.0", + "scope": "youtube.profile", + "dialect": "json", + "description": "Basic YouTube profile information including email, channel URL, handle, and joined date.", + "schema": { + "type": "object", + "properties": { + "email": { "type": ["string", "null"] }, + "channelUrl": { "type": ["string", "null"] }, + "handle": { "type": ["string", "null"] }, + "joinedDate": { "type": ["string", "null"] }, + "channelTitle": { "type": ["string", "null"] }, + "channelId": { "type": ["string", "null"] }, + "avatarUrl": { "type": ["string", "null"] }, + "description": { "type": ["string", "null"] }, + "country": { "type": ["string", "null"] }, + "subscriberCount": { "type": ["number", "null"] }, + "viewCount": { "type": ["number", "null"] }, + "videoCount": { "type": ["number", "null"] } + }, + "required": [], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.subscriptions.json b/packages/scope-catalog/connectors/google/schemas/youtube.subscriptions.json new file mode 100644 index 0000000..ad3200b --- /dev/null +++ b/packages/scope-catalog/connectors/google/schemas/youtube.subscriptions.json @@ -0,0 +1,34 @@ +{ + "name": "YouTube Subscriptions", + "version": "1.0.0", + "scope": "youtube.subscriptions", + "dialect": "json", + "description": "Channels the user is subscribed to.", + "schema": { + "type": "object", + "properties": { + "subscriptions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "channelTitle": { "type": "string" }, + "channelUrl": { "type": "string" }, + "handle": { "type": ["string", "null"] }, + "channelId": { "type": ["string", "null"] }, + "avatarUrl": { "type": ["string", "null"] }, + "subscriberCountText": { "type": ["string", "null"], "description": "Raw text e.g. '5.3m subscribers'" }, + "subscriberCount": { "type": ["number", "null"], "description": "Parsed integer subscriber count" }, + "description": { "type": ["string", "null"] }, + "isVerified": { "type": "boolean" }, + "isBellNotification": { "type": "boolean", "description": "True when 'All notifications' bell is active" } + }, + "required": ["channelTitle", "channelUrl"], + "additionalProperties": false + } + } + }, + "required": ["subscriptions"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.watchLater.json b/packages/scope-catalog/connectors/google/schemas/youtube.watchLater.json new file mode 100644 index 0000000..81d7255 --- /dev/null +++ b/packages/scope-catalog/connectors/google/schemas/youtube.watchLater.json @@ -0,0 +1,31 @@ +{ + "name": "YouTube Watch Later", + "version": "1.0.0", + "scope": "youtube.watchLater", + "dialect": "json", + "description": "Videos saved to Watch Later.", + "schema": { + "type": "object", + "properties": { + "watchLater": { + "type": "array", + "items": { + "type": "object", + "properties": { + "videoId": { "type": ["string", "null"] }, + "videoUrl": { "type": "string" }, + "videoTitle": { "type": "string" }, + "channelTitle": { "type": ["string", "null"] }, + "channelUrl": { "type": ["string", "null"] }, + "durationText": { "type": ["string", "null"] }, + "thumbnailUrl": { "type": ["string", "null"] } + }, + "required": ["videoUrl", "videoTitle"], + "additionalProperties": false + } + } + }, + "required": ["watchLater"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/heb/schemas/heb.nutrition.json b/packages/scope-catalog/connectors/heb/schemas/heb.nutrition.json new file mode 100644 index 0000000..403aa4f --- /dev/null +++ b/packages/scope-catalog/connectors/heb/schemas/heb.nutrition.json @@ -0,0 +1,78 @@ +{ + "name": "H-E-B Nutrition", + "version": "1.0.0", + "scope": "heb.nutrition", + "dialect": "json", + "description": "Nutrition facts per product ordered from H-E-B, including macros, micronutrients, ingredients, and allergens", + "schema": { + "type": "object", + "properties": { + "items": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "source": { "type": "string", "enum": ["heb_product_page", "usda_fdc", "not_found", "error", "blocked"] }, + "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, + "calories": { "type": ["number", "null"] }, + "protein_g": { "type": ["number", "null"] }, + "carbs_g": { "type": ["number", "null"] }, + "fat_g": { "type": ["number", "null"] }, + "sodium_mg": { "type": ["number", "null"] }, + "fiber_g": { "type": ["number", "null"] }, + "sugar_g": { "type": ["number", "null"] }, + "saturated_fat_g": { "type": ["number", "null"] }, + "trans_fat_g": { "type": ["number", "null"] }, + "cholesterol_mg": { "type": ["number", "null"] }, + "added_sugar_g": { "type": ["number", "null"] }, + "calcium_mg": { "type": ["number", "null"] }, + "iron_mg": { "type": ["number", "null"] }, + "potassium_mg": { "type": ["number", "null"] }, + "vitamin_d_mcg": { "type": ["number", "null"] }, + "servingSize": { "type": ["string", "null"] }, + "servingsPerContainer": { "type": ["string", "null"] }, + "upc": { "type": ["string", "null"] }, + "ingredients": { "type": ["string", "null"] }, + "allergens": { "type": ["string", "null"] }, + "category": { + "oneOf": [ + { "type": "string" }, + { "type": "array", "items": { "type": "string" } }, + { "type": "null" } + ] + }, + "highlights": { + "type": ["array", "null"], + "items": { "type": "string" } + }, + "images": { + "oneOf": [ + { "type": "string" }, + { + "type": "object", + "properties": { + "full": { "type": "string" }, + "thumbnail": { "type": "string" } + } + }, + { "type": "null" } + ] + } + }, + "required": ["name", "source"] + } + }, + "coverage": { + "type": "object", + "properties": { + "total": { "type": "number" }, + "found": { "type": "number" }, + "foundUSDA": { "type": "number" }, + "percentCovered": { "type": "number" } + } + } + }, + "required": ["items", "coverage"] + } +} diff --git a/packages/scope-catalog/connectors/heb/schemas/heb.orders.json b/packages/scope-catalog/connectors/heb/schemas/heb.orders.json new file mode 100644 index 0000000..b5f2502 --- /dev/null +++ b/packages/scope-catalog/connectors/heb/schemas/heb.orders.json @@ -0,0 +1,46 @@ +{ + "name": "H-E-B Orders", + "version": "1.0.0", + "scope": "heb.orders", + "dialect": "json", + "description": "H-E-B curbside and delivery order history with item details", + "schema": { + "type": "object", + "properties": { + "orders": { + "type": "array", + "items": { + "type": "object", + "properties": { + "orderId": { "type": "string" }, + "orderUrl": { "type": "string" }, + "orderDate": { "type": ["string", "null"] }, + "total": { "type": ["number", "null"] }, + "itemCount": { "type": ["number", "null"] }, + "status": { "type": ["string", "null"] }, + "address": { "type": ["string", "null"] }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "productId": { "type": "string" }, + "productUrl": { "type": ["string", "null"] }, + "imageUrl": { "type": ["string", "null"] }, + "quantity": { "type": ["string", "null"] }, + "price": { "type": ["number", "null"] } + }, + "required": ["name", "productId"] + } + } + }, + "required": ["orderId", "items"] + } + }, + "totalOrders": { "type": "number" }, + "totalItems": { "type": "number" } + }, + "required": ["orders", "totalOrders", "totalItems"] + } +} diff --git a/packages/scope-catalog/connectors/heb/schemas/heb.profile.json b/packages/scope-catalog/connectors/heb/schemas/heb.profile.json new file mode 100644 index 0000000..11de11b --- /dev/null +++ b/packages/scope-catalog/connectors/heb/schemas/heb.profile.json @@ -0,0 +1,26 @@ +{ + "name": "H-E-B Profile", + "version": "1.0.0", + "scope": "heb.profile", + "dialect": "json", + "description": "H-E-B account profile including name, email, phone, and delivery addresses", + "schema": { + "type": "object", + "properties": { + "name": { "type": ["string", "null"] }, + "email": { "type": ["string", "null"] }, + "phone": { "type": ["string", "null"] }, + "deliveryAddresses": { + "type": "array", + "items": { + "type": "object", + "properties": { + "address": { "type": "string" }, + "label": { "type": ["string", "null"] }, + "isPrimary": { "type": "boolean" } + } + } + } + } + } +} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.connections.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.connections.json new file mode 100644 index 0000000..9ab5ad4 --- /dev/null +++ b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.connections.json @@ -0,0 +1,28 @@ +{ + "name": "LinkedIn Connections", + "version": "1.0.0", + "scope": "linkedin.connections", + "dialect": "json", + "description": "LinkedIn connections with names, headlines, profile URLs, and date connected", + "schema": { + "type": "object", + "properties": { + "connections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fullName": { "type": "string" }, + "headline": { "type": "string" }, + "profileUrl": { "type": "string" }, + "dateConnected": { "type": "string" } + }, + "required": ["fullName", "headline", "profileUrl", "dateConnected"], + "additionalProperties": false + } + } + }, + "required": ["connections"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.education.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.education.json new file mode 100644 index 0000000..ca5b76b --- /dev/null +++ b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.education.json @@ -0,0 +1,29 @@ +{ + "name": "LinkedIn Education", + "version": "1.0.0", + "scope": "linkedin.education", + "dialect": "json", + "description": "LinkedIn education history including schools, degrees, years, grades, and logos", + "schema": { + "type": "object", + "properties": { + "education": { + "type": "array", + "items": { + "type": "object", + "properties": { + "schoolName": { "type": "string" }, + "degree": { "type": "string" }, + "years": { "type": "string" }, + "grade": { "type": "string" }, + "logoUrl": { "type": "string" } + }, + "required": ["schoolName", "degree", "years", "grade", "logoUrl"], + "additionalProperties": false + } + } + }, + "required": ["education"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.experience.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.experience.json new file mode 100644 index 0000000..4ec0bf6 --- /dev/null +++ b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.experience.json @@ -0,0 +1,29 @@ +{ + "name": "LinkedIn Experience", + "version": "1.0.0", + "scope": "linkedin.experience", + "dialect": "json", + "description": "LinkedIn work experience including job titles, companies, dates, locations, and descriptions", + "schema": { + "type": "object", + "properties": { + "experiences": { + "type": "array", + "items": { + "type": "object", + "properties": { + "jobTitle": { "type": "string" }, + "companyName": { "type": "string" }, + "dates": { "type": "string" }, + "location": { "type": "string" }, + "description": { "type": "string" } + }, + "required": ["jobTitle", "companyName", "dates", "location", "description"], + "additionalProperties": false + } + } + }, + "required": ["experiences"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.languages.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.languages.json new file mode 100644 index 0000000..8003db8 --- /dev/null +++ b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.languages.json @@ -0,0 +1,26 @@ +{ + "name": "LinkedIn Languages", + "version": "1.0.0", + "scope": "linkedin.languages", + "dialect": "json", + "description": "LinkedIn languages with proficiency levels", + "schema": { + "type": "object", + "properties": { + "languages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "proficiency": { "type": "string" } + }, + "required": ["name", "proficiency"], + "additionalProperties": false + } + } + }, + "required": ["languages"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.profile.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.profile.json new file mode 100644 index 0000000..8bbf790 --- /dev/null +++ b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.profile.json @@ -0,0 +1,21 @@ +{ + "name": "LinkedIn Profile", + "version": "1.0.0", + "scope": "linkedin.profile", + "dialect": "json", + "description": "LinkedIn profile including name, headline, location, about, connections count, and profile picture", + "schema": { + "type": "object", + "properties": { + "profileUrl": { "type": "string" }, + "fullName": { "type": "string" }, + "headline": { "type": "string" }, + "location": { "type": "string" }, + "connections": { "type": "string" }, + "profilePictureUrl": { "type": "string" }, + "about": { "type": "string" } + }, + "required": ["profileUrl", "fullName", "headline", "location", "connections", "profilePictureUrl", "about"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.skills.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.skills.json new file mode 100644 index 0000000..a48de00 --- /dev/null +++ b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.skills.json @@ -0,0 +1,26 @@ +{ + "name": "LinkedIn Skills", + "version": "1.0.0", + "scope": "linkedin.skills", + "dialect": "json", + "description": "LinkedIn skills with endorsement counts", + "schema": { + "type": "object", + "properties": { + "skills": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "endorsements": { "type": "string" } + }, + "required": ["name", "endorsements"], + "additionalProperties": false + } + } + }, + "required": ["skills"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/meta/schemas/instagram.ads.json b/packages/scope-catalog/connectors/meta/schemas/instagram.ads.json new file mode 100644 index 0000000..9b0838e --- /dev/null +++ b/packages/scope-catalog/connectors/meta/schemas/instagram.ads.json @@ -0,0 +1,47 @@ +{ + "name": "Instagram Ad Interests", + "version": "1.0.0", + "scope": "instagram.ads", + "dialect": "json", + "description": "Advertisers the user has seen ads from, ad topic interests, and targeting categories based on their Instagram activity", + "schema": { + "type": "object", + "properties": { + "advertisers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" } + }, + "required": ["name"], + "additionalProperties": false + } + }, + "ad_topics": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" } + }, + "required": ["name"], + "additionalProperties": false + } + }, + "categories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "description": { "type": ["string", "null"] } + }, + "required": ["name"] + } + } + }, + "required": ["advertisers", "ad_topics"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/meta/schemas/instagram.following.json b/packages/scope-catalog/connectors/meta/schemas/instagram.following.json new file mode 100644 index 0000000..ad7a39d --- /dev/null +++ b/packages/scope-catalog/connectors/meta/schemas/instagram.following.json @@ -0,0 +1,31 @@ +{ + "name": "Instagram Following", + "version": "1.0.0", + "scope": "instagram.following", + "dialect": "json", + "description": "The list of Instagram accounts the user follows, as returned by the Instagram friendships/following endpoint.", + "schema": { + "type": "object", + "properties": { + "accounts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "username": { "type": "string" }, + "full_name": { "type": "string" }, + "pk": { "type": "string" }, + "is_private": { "type": "boolean" }, + "is_verified": { "type": "boolean" }, + "profile_pic_url": { "type": ["string", "null"] } + }, + "required": ["username"], + "additionalProperties": false + } + }, + "total": { "type": "number" } + }, + "required": ["accounts"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/meta/schemas/instagram.posts.json b/packages/scope-catalog/connectors/meta/schemas/instagram.posts.json new file mode 100644 index 0000000..6b28a92 --- /dev/null +++ b/packages/scope-catalog/connectors/meta/schemas/instagram.posts.json @@ -0,0 +1,41 @@ +{ + "name": "Instagram Posts", + "version": "2.0.0", + "scope": "instagram.posts", + "dialect": "json", + "description": "User's Instagram posts including images, captions, and like engagement data", + "schema": { + "type": "object", + "properties": { + "posts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "img_url": { "type": "string" }, + "caption": { "type": "string" }, + "num_of_likes": { "type": "number" }, + "taken_at": { "type": "string" }, + "who_liked": { + "type": "array", + "items": { + "type": "object", + "properties": { + "profile_pic_url": { "type": "string" }, + "pk": { "type": "string" }, + "username": { "type": "string" }, + "id": { "type": "string" } + }, + "additionalProperties": false + } + } + }, + "required": ["img_url", "caption", "num_of_likes"], + "additionalProperties": false + } + } + }, + "required": ["posts"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/meta/schemas/instagram.profile.json b/packages/scope-catalog/connectors/meta/schemas/instagram.profile.json new file mode 100644 index 0000000..274bdff --- /dev/null +++ b/packages/scope-catalog/connectors/meta/schemas/instagram.profile.json @@ -0,0 +1,25 @@ +{ + "name": "Instagram Profile", + "version": "2.0.0", + "scope": "instagram.profile", + "dialect": "json", + "description": "Basic Instagram profile information including username, bio, and follower counts", + "schema": { + "type": "object", + "properties": { + "username": { "type": "string" }, + "full_name": { "type": "string" }, + "bio": { "type": "string" }, + "profile_pic_url": { "type": "string" }, + "external_url": { "type": "string" }, + "follower_count": { "type": "number" }, + "following_count": { "type": "number" }, + "media_count": { "type": "number" }, + "is_private": { "type": "boolean" }, + "is_verified": { "type": "boolean" }, + "is_business": { "type": "boolean" } + }, + "required": ["username", "full_name"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/openai/schemas/chatgpt.conversations.json b/packages/scope-catalog/connectors/openai/schemas/chatgpt.conversations.json new file mode 100644 index 0000000..2c8bb33 --- /dev/null +++ b/packages/scope-catalog/connectors/openai/schemas/chatgpt.conversations.json @@ -0,0 +1,46 @@ +{ + "name": "ChatGPT Conversations", + "version": "2.0.0", + "scope": "chatgpt.conversations", + "dialect": "json", + "description": "Conversation history from ChatGPT including full message threads with user and assistant messages", + "schema": { + "type": "object", + "properties": { + "conversations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "create_time": { "type": "string" }, + "update_time": { "type": "string" }, + "message_count": { "type": "number" }, + "messages": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "role": { "type": "string" }, + "content": { "type": "string" }, + "content_type": { "type": "string" }, + "create_time": { "type": ["string", "null"] }, + "model": { "type": ["string", "null"] } + }, + "required": ["id", "role", "content"], + "additionalProperties": false + } + } + }, + "required": ["id", "title", "create_time", "update_time", "message_count", "messages"], + "additionalProperties": false + } + }, + "total": { "type": "number" } + }, + "required": ["conversations", "total"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/openai/schemas/chatgpt.memories.json b/packages/scope-catalog/connectors/openai/schemas/chatgpt.memories.json new file mode 100644 index 0000000..76bca75 --- /dev/null +++ b/packages/scope-catalog/connectors/openai/schemas/chatgpt.memories.json @@ -0,0 +1,30 @@ +{ + "name": "ChatGPT Memories", + "version": "2.0.0", + "scope": "chatgpt.memories", + "dialect": "json", + "description": "Saved memories from ChatGPT including user preferences and context the model remembers", + "schema": { + "type": "object", + "properties": { + "memories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "content": { "type": "string" }, + "created_at": { "type": "string" }, + "updated_at": { "type": "string" }, + "type": { "type": "string" } + }, + "required": ["id", "content", "created_at"], + "additionalProperties": false + } + }, + "total": { "type": "number" } + }, + "required": ["memories", "total"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/oura/schemas/oura.activity.json b/packages/scope-catalog/connectors/oura/schemas/oura.activity.json new file mode 100644 index 0000000..b3fddd2 --- /dev/null +++ b/packages/scope-catalog/connectors/oura/schemas/oura.activity.json @@ -0,0 +1,49 @@ +{ + "name": "Oura Activity", + "version": "1.0.0", + "scope": "oura.activity", + "dialect": "json", + "description": "Daily activity data from Oura Ring including activity scores, step counts, calorie expenditure, and time spent at different activity levels.", + "schema": { + "type": "object", + "properties": { + "days": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "day": { "type": "string", "format": "date", "description": "Date in YYYY-MM-DD format" }, + "score": { "type": ["integer", "null"], "minimum": 0, "maximum": 100, "description": "Overall activity score (0-100)" }, + "timestamp": { "type": "string", "format": "date-time" }, + "activeCalories": { "type": ["integer", "null"], "description": "Calories burned through activity" }, + "totalCalories": { "type": ["integer", "null"], "description": "Total calories burned including BMR" }, + "steps": { "type": ["integer", "null"], "description": "Total step count" }, + "equivalentWalkingDistance": { "type": ["integer", "null"], "description": "Equivalent walking distance in meters" }, + "highActivityTime": { "type": ["integer", "null"], "description": "Time in high activity in seconds" }, + "mediumActivityTime": { "type": ["integer", "null"], "description": "Time in medium activity in seconds" }, + "lowActivityTime": { "type": ["integer", "null"], "description": "Time in low activity in seconds" }, + "sedentaryTime": { "type": ["integer", "null"], "description": "Sedentary time in seconds" }, + "restingTime": { "type": ["integer", "null"], "description": "Resting time in seconds" }, + "inactivityAlerts": { "type": ["integer", "null"], "description": "Number of inactivity alerts received" }, + "contributors": { + "type": "object", + "properties": { + "meet_daily_targets": { "type": ["integer", "null"], "description": "Meeting daily targets score (0-100)" }, + "move_every_hour": { "type": ["integer", "null"], "description": "Hourly movement score (0-100)" }, + "recovery_time": { "type": ["integer", "null"], "description": "Recovery time score (0-100)" }, + "stay_active": { "type": ["integer", "null"], "description": "Stay active score (0-100)" }, + "training_frequency": { "type": ["integer", "null"], "description": "Training frequency score (0-100)" }, + "training_volume": { "type": ["integer", "null"], "description": "Training volume score (0-100)" } + }, + "additionalProperties": true + } + }, + "required": ["day", "score"] + } + } + }, + "required": ["days"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/oura/schemas/oura.readiness.json b/packages/scope-catalog/connectors/oura/schemas/oura.readiness.json new file mode 100644 index 0000000..64ce099 --- /dev/null +++ b/packages/scope-catalog/connectors/oura/schemas/oura.readiness.json @@ -0,0 +1,43 @@ +{ + "name": "Oura Readiness", + "version": "1.0.0", + "scope": "oura.readiness", + "dialect": "json", + "description": "Daily readiness scores from Oura Ring, including overall score and contributing factors like HRV balance, resting heart rate, recovery index, and body temperature.", + "schema": { + "type": "object", + "properties": { + "days": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "day": { "type": "string", "format": "date", "description": "Date in YYYY-MM-DD format" }, + "score": { "type": ["integer", "null"], "minimum": 0, "maximum": 100, "description": "Overall readiness score (0-100)" }, + "timestamp": { "type": "string", "format": "date-time" }, + "temperatureDeviation": { "type": ["number", "null"], "description": "Body temperature deviation from baseline in degrees Celsius" }, + "temperatureTrendDeviation": { "type": ["number", "null"], "description": "Temperature trend deviation from baseline" }, + "contributors": { + "type": "object", + "properties": { + "activity_balance": { "type": ["integer", "null"], "description": "Activity balance contributor score (0-100)" }, + "body_temperature": { "type": ["integer", "null"], "description": "Body temperature contributor score (0-100)" }, + "hrv_balance": { "type": ["integer", "null"], "description": "HRV balance contributor score (0-100)" }, + "previous_day_activity": { "type": ["integer", "null"], "description": "Previous day activity contributor score (0-100)" }, + "previous_night": { "type": ["integer", "null"], "description": "Previous night sleep contributor score (0-100)" }, + "recovery_index": { "type": ["integer", "null"], "description": "Recovery index contributor score (0-100)" }, + "resting_heart_rate": { "type": ["integer", "null"], "description": "Resting heart rate contributor score (0-100)" }, + "sleep_balance": { "type": ["integer", "null"], "description": "Sleep balance contributor score (0-100)" } + }, + "additionalProperties": true + } + }, + "required": ["day", "score"] + } + } + }, + "required": ["days"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/oura/schemas/oura.sleep.json b/packages/scope-catalog/connectors/oura/schemas/oura.sleep.json new file mode 100644 index 0000000..e8ae730 --- /dev/null +++ b/packages/scope-catalog/connectors/oura/schemas/oura.sleep.json @@ -0,0 +1,69 @@ +{ + "name": "Oura Sleep", + "version": "1.0.0", + "scope": "oura.sleep", + "dialect": "json", + "description": "Sleep data from Oura Ring including daily sleep scores with contributor breakdowns and detailed sleep period data with durations, stages, heart rate, and HRV.", + "schema": { + "type": "object", + "properties": { + "dailyScores": { + "type": "array", + "description": "Daily sleep score summaries", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "day": { "type": "string", "format": "date", "description": "Date in YYYY-MM-DD format" }, + "score": { "type": ["integer", "null"], "minimum": 0, "maximum": 100, "description": "Overall sleep score (0-100)" }, + "timestamp": { "type": "string", "format": "date-time" }, + "contributors": { + "type": "object", + "properties": { + "deep_sleep": { "type": ["integer", "null"], "description": "Deep sleep contributor score (0-100)" }, + "efficiency": { "type": ["integer", "null"], "description": "Sleep efficiency contributor score (0-100)" }, + "latency": { "type": ["integer", "null"], "description": "Sleep latency contributor score (0-100)" }, + "rem_sleep": { "type": ["integer", "null"], "description": "REM sleep contributor score (0-100)" }, + "restfulness": { "type": ["integer", "null"], "description": "Restfulness contributor score (0-100)" }, + "timing": { "type": ["integer", "null"], "description": "Sleep timing contributor score (0-100)" }, + "total_sleep": { "type": ["integer", "null"], "description": "Total sleep contributor score (0-100)" } + }, + "additionalProperties": true + } + }, + "required": ["day", "score"] + } + }, + "sleepPeriods": { + "type": "array", + "description": "Detailed sleep period records", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "day": { "type": "string", "format": "date", "description": "Date in YYYY-MM-DD format" }, + "type": { "type": "string", "enum": ["long_sleep", "short_sleep", "rest"], "description": "Type of sleep period" }, + "bedtimeStart": { "type": ["string", "null"], "format": "date-time", "description": "Bedtime start in ISO 8601" }, + "bedtimeEnd": { "type": ["string", "null"], "format": "date-time", "description": "Bedtime end in ISO 8601" }, + "totalSleepDuration": { "type": ["integer", "null"], "description": "Total sleep duration in seconds" }, + "timeInBed": { "type": ["integer", "null"], "description": "Total time in bed in seconds" }, + "deepSleepDuration": { "type": ["integer", "null"], "description": "Deep sleep duration in seconds" }, + "lightSleepDuration": { "type": ["integer", "null"], "description": "Light sleep duration in seconds" }, + "remSleepDuration": { "type": ["integer", "null"], "description": "REM sleep duration in seconds" }, + "awakeTime": { "type": ["integer", "null"], "description": "Awake time during sleep in seconds" }, + "efficiency": { "type": ["integer", "null"], "description": "Sleep efficiency percentage" }, + "latency": { "type": ["integer", "null"], "description": "Sleep onset latency in seconds" }, + "averageHeartRate": { "type": ["number", "null"], "description": "Average heart rate during sleep in BPM" }, + "averageHrv": { "type": ["integer", "null"], "description": "Average heart rate variability during sleep in ms" }, + "lowestHeartRate": { "type": ["integer", "null"], "description": "Lowest heart rate during sleep in BPM" }, + "averageBreath": { "type": ["number", "null"], "description": "Average breathing rate during sleep in breaths/min" }, + "restlessPeriods": { "type": ["integer", "null"], "description": "Number of restless periods during sleep" } + }, + "required": ["day"] + } + } + }, + "required": ["dailyScores", "sleepPeriods"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/shopify/schemas/shop.orders.json b/packages/scope-catalog/connectors/shopify/schemas/shop.orders.json new file mode 100644 index 0000000..4cf512f --- /dev/null +++ b/packages/scope-catalog/connectors/shopify/schemas/shop.orders.json @@ -0,0 +1,37 @@ +{ + "name": "Shop Order History", + "version": "1.0.0", + "scope": "shop.orders", + "dialect": "json", + "description": "Order history from the Shop app (Shopify) including merchant names, item counts, totals, and delivery status", + "schema": { + "type": "object", + "properties": { + "orders": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "orderNumber": { "type": "string" }, + "placedAt": { "type": "string", "format": "date-time" }, + "merchantName": { "type": "string" }, + "total": { "type": "number" }, + "currency": { "type": "string" }, + "status": { "type": "string" }, + "itemCount": { "type": "number" }, + "lineItemTitles": { + "type": "array", + "items": { "type": "string" } + }, + "detailUrl": { "type": "string" } + }, + "required": ["id"], + "additionalProperties": false + } + } + }, + "required": ["orders"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/spotify/schemas/spotify.playlists.json b/packages/scope-catalog/connectors/spotify/schemas/spotify.playlists.json new file mode 100644 index 0000000..7335d80 --- /dev/null +++ b/packages/scope-catalog/connectors/spotify/schemas/spotify.playlists.json @@ -0,0 +1,62 @@ +{ + "name": "Spotify Playlists", + "version": "1.0.0", + "scope": "spotify.playlists", + "dialect": "json", + "description": "User's Spotify playlists including track listings with artist and album details", + "schema": { + "type": "object", + "properties": { + "playlists": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "description": { "type": "string" }, + "owner": { "type": "string" }, + "uri": { "type": "string" }, + "followers": { "type": "number" }, + "images": { + "type": "array", + "items": { "type": "string" } + }, + "tracks_total": { "type": "number" }, + "tracks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "added_at": { "type": "string" }, + "added_by": { "type": "string" }, + "name": { "type": "string" }, + "artists": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" } + }, + "required": ["name"], + "additionalProperties": false + } + }, + "album": { "type": "string" }, + "duration_ms": { "type": "number" }, + "uri": { "type": "string" } + }, + "required": ["name", "artists"], + "additionalProperties": false + } + } + }, + "required": ["name", "tracks"], + "additionalProperties": false + } + }, + "total": { "type": "number" } + }, + "required": ["playlists", "total"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/spotify/schemas/spotify.profile.json b/packages/scope-catalog/connectors/spotify/schemas/spotify.profile.json new file mode 100644 index 0000000..2397278 --- /dev/null +++ b/packages/scope-catalog/connectors/spotify/schemas/spotify.profile.json @@ -0,0 +1,23 @@ +{ + "name": "Spotify Profile", + "version": "1.0.0", + "scope": "spotify.profile", + "dialect": "json", + "description": "Basic Spotify profile information including display name, followers, and following counts", + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "display_name": { "type": "string" }, + "uri": { "type": "string" }, + "followers": { "type": "number" }, + "following": { "type": "number" }, + "images": { + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["id", "display_name"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/spotify/schemas/spotify.savedTracks.json b/packages/scope-catalog/connectors/spotify/schemas/spotify.savedTracks.json new file mode 100644 index 0000000..70d3623 --- /dev/null +++ b/packages/scope-catalog/connectors/spotify/schemas/spotify.savedTracks.json @@ -0,0 +1,60 @@ +{ + "name": "Spotify Saved Tracks", + "version": "1.0.0", + "scope": "spotify.savedTracks", + "dialect": "json", + "description": "User's saved (liked) tracks from Spotify including artist, album, and track details", + "schema": { + "type": "object", + "properties": { + "savedTracks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "added_at": { "type": "string" }, + "name": { "type": "string" }, + "artists": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" } + }, + "required": ["name"], + "additionalProperties": false + } + }, + "album": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "artists": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" } + }, + "required": ["name"], + "additionalProperties": false + } + } + }, + "required": ["name"], + "additionalProperties": false + }, + "duration_ms": { "type": "number" }, + "uri": { "type": "string" }, + "explicit": { "type": "boolean" } + }, + "required": ["name", "artists"], + "additionalProperties": false + } + }, + "total": { "type": "number" } + }, + "required": ["savedTracks", "total"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/uber/schemas/uber.receipts.json b/packages/scope-catalog/connectors/uber/schemas/uber.receipts.json new file mode 100644 index 0000000..d31cc72 --- /dev/null +++ b/packages/scope-catalog/connectors/uber/schemas/uber.receipts.json @@ -0,0 +1,34 @@ +{ + "name": "Uber Receipts", + "version": "1.0.0", + "scope": "uber.receipts", + "dialect": "json", + "description": "Detailed fare breakdowns and receipt information for each Uber trip", + "schema": { + "type": "object", + "properties": { + "receipts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tripId": { "type": "string" }, + "fare": { "type": "string" }, + "currencyCode": { "type": "string" }, + "distance": { "type": "string" }, + "distanceLabel": { "type": "string" }, + "duration": { "type": "string" }, + "durationLabel": { "type": "string" }, + "vehicleType": { "type": "string" }, + "surgeMultiplier": { "type": "string" }, + "fareBreakdown": { "type": "string" } + }, + "required": ["tripId"], + "additionalProperties": false + } + } + }, + "required": ["receipts"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/uber/schemas/uber.trips.json b/packages/scope-catalog/connectors/uber/schemas/uber.trips.json new file mode 100644 index 0000000..6474672 --- /dev/null +++ b/packages/scope-catalog/connectors/uber/schemas/uber.trips.json @@ -0,0 +1,35 @@ +{ + "name": "Uber Trip History", + "version": "1.0.0", + "scope": "uber.trips", + "dialect": "json", + "description": "Complete history of Uber rides including pickup/dropoff locations, dates, fares, and vehicle types", + "schema": { + "type": "object", + "properties": { + "trips": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "status": { "type": "string" }, + "requestTime": { "type": "string" }, + "dropoffTime": { "type": "string" }, + "pickupAddress": { "type": "string" }, + "dropoffAddress": { "type": "string" }, + "fare": { "type": "string" }, + "currencyCode": { "type": "string" }, + "vehicleType": { "type": "string" }, + "city": { "type": "string" }, + "isSurge": { "type": "boolean" } + }, + "required": ["id"], + "additionalProperties": false + } + } + }, + "required": ["trips"], + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/connectors/valve/schemas/steam.friends.json b/packages/scope-catalog/connectors/valve/schemas/steam.friends.json new file mode 100644 index 0000000..0dbcba2 --- /dev/null +++ b/packages/scope-catalog/connectors/valve/schemas/steam.friends.json @@ -0,0 +1,20 @@ +{ + "name": "Steam Friends", + "scope": "steam.friends", + "description": "Steam friend list with persona names, avatars, and friendship dates", + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "steamId": { "type": "string", "description": "Friend's 64-bit Steam ID" }, + "personaName": { "type": ["string", "null"], "description": "Friend's display name" }, + "avatarUrl": { "type": ["string", "null"], "format": "uri", "description": "URL to the friend's avatar image" }, + "profileUrl": { "type": ["string", "null"], "format": "uri", "description": "URL to the friend's Steam Community profile" }, + "friendSince": { "type": ["string", "null"], "format": "date-time", "description": "When the friendship was established" }, + "relationship": { "type": "string", "description": "Relationship type (usually 'friend')" } + }, + "required": ["steamId"] + } + } +} diff --git a/packages/scope-catalog/connectors/valve/schemas/steam.games.json b/packages/scope-catalog/connectors/valve/schemas/steam.games.json new file mode 100644 index 0000000..05d064d --- /dev/null +++ b/packages/scope-catalog/connectors/valve/schemas/steam.games.json @@ -0,0 +1,42 @@ +{ + "name": "Steam Games", + "scope": "steam.games", + "description": "Owned games with playtime statistics and recently played games", + "schema": { + "type": "object", + "properties": { + "owned": { + "type": "array", + "description": "All games owned by the user, sorted by playtime descending", + "items": { + "type": "object", + "properties": { + "appId": { "type": "integer", "description": "Steam application ID" }, + "name": { "type": "string", "description": "Game title" }, + "playtimeMinutes": { "type": "integer", "description": "Total playtime in minutes" }, + "playtimeHours": { "type": "number", "description": "Total playtime in hours (rounded to 1 decimal)" }, + "playtimeTwoWeeksMinutes": { "type": "integer", "description": "Playtime in the last two weeks in minutes" }, + "iconUrl": { "type": ["string", "null"], "format": "uri", "description": "URL to the game's icon image" }, + "lastPlayed": { "type": ["string", "null"], "format": "date-time", "description": "When the game was last played" } + }, + "required": ["appId", "name", "playtimeMinutes"] + } + }, + "recentlyPlayed": { + "type": "array", + "description": "Games played in the last two weeks", + "items": { + "type": "object", + "properties": { + "appId": { "type": "integer", "description": "Steam application ID" }, + "name": { "type": "string", "description": "Game title" }, + "playtimeTwoWeeksMinutes": { "type": "integer", "description": "Playtime in last two weeks in minutes" }, + "playtimeForeverMinutes": { "type": "integer", "description": "Total playtime in minutes" } + }, + "required": ["appId", "name"] + } + } + }, + "required": ["owned", "recentlyPlayed"] + } +} diff --git a/packages/scope-catalog/connectors/valve/schemas/steam.profile.json b/packages/scope-catalog/connectors/valve/schemas/steam.profile.json new file mode 100644 index 0000000..fc901e6 --- /dev/null +++ b/packages/scope-catalog/connectors/valve/schemas/steam.profile.json @@ -0,0 +1,24 @@ +{ + "name": "Steam Profile", + "scope": "steam.profile", + "description": "Steam user profile including persona name, avatar, level, location, and account metadata", + "schema": { + "type": "object", + "properties": { + "steamId": { "type": "string", "description": "64-bit Steam ID" }, + "personaName": { "type": "string", "description": "Display name on Steam" }, + "profileUrl": { "type": "string", "format": "uri", "description": "URL to the user's Steam Community profile" }, + "avatarUrl": { "type": "string", "format": "uri", "description": "URL to the user's full-size avatar image" }, + "realName": { "type": ["string", "null"], "description": "Real name if set by the user" }, + "country": { "type": ["string", "null"], "description": "ISO 3166-1 alpha-2 country code" }, + "state": { "type": ["string", "null"], "description": "State/region code" }, + "cityId": { "type": ["integer", "null"], "description": "Steam internal city identifier" }, + "steamLevel": { "type": ["integer", "null"], "description": "Steam profile level" }, + "accountCreated": { "type": ["string", "null"], "format": "date-time", "description": "When the Steam account was created" }, + "lastLogoff": { "type": ["string", "null"], "format": "date-time", "description": "Last time the user was seen online" }, + "personaState": { "type": "integer", "description": "Online status (0=offline, 1=online, 2=busy, 3=away, 4=snooze, 5=looking to trade, 6=looking to play)" }, + "communityVisibilityState": { "type": "integer", "description": "Profile visibility (1=private, 3=public)" } + }, + "required": ["steamId", "personaName", "profileUrl"] + } +} diff --git a/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.nutrition.json b/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.nutrition.json new file mode 100644 index 0000000..7614ed6 --- /dev/null +++ b/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.nutrition.json @@ -0,0 +1,44 @@ +{ + "name": "Whole Foods Nutrition", + "version": "1.0.0", + "scope": "wholefoods.nutrition", + "dialect": "json", + "definitionUrl": "https://raw.githubusercontent.com/vana-com/data-connectors/main/connectors/wholefoods/schemas/wholefoods.nutrition.json", + "description": "Nutrition facts per unique product ordered from Whole Foods Market, aligned to Schema.org NutritionInformation", + "schema": { + "type": "object", + "properties": { + "items": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "source": { "type": "string", "enum": ["wholefoods_product_page", "wholefoods_structured_data", "amazon_product_page", "usda_fdc", "not_found", "error", "blocked"] }, + "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, + "calories": { "type": ["number", "null"] }, + "protein_g": { "type": ["number", "null"] }, + "carbs_g": { "type": ["number", "null"] }, + "fat_g": { "type": ["number", "null"] }, + "sodium_mg": { "type": ["number", "null"] }, + "fiber_g": { "type": ["number", "null"] }, + "sugar_g": { "type": ["number", "null"] }, + "servingSize": { "type": ["string", "null"] }, + "servingsPerContainer": { "type": ["string", "null"] } + }, + "required": ["name", "source"] + } + }, + "coverage": { + "type": "object", + "properties": { + "total": { "type": "number" }, + "found": { "type": "number" }, + "foundUSDA": { "type": "number" }, + "percentCovered": { "type": "number" } + } + } + }, + "required": ["items", "coverage"] + } +} diff --git a/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.orders.json b/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.orders.json new file mode 100644 index 0000000..26bbd8f --- /dev/null +++ b/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.orders.json @@ -0,0 +1,46 @@ +{ + "name": "Whole Foods Orders", + "version": "1.0.0", + "scope": "wholefoods.orders", + "dialect": "json", + "definitionUrl": "https://raw.githubusercontent.com/vana-com/data-connectors/main/connectors/wholefoods/schemas/wholefoods.orders.json", + "description": "Whole Foods Market delivery and pickup order history with item details", + "schema": { + "type": "object", + "properties": { + "orders": { + "type": "array", + "items": { + "type": "object", + "properties": { + "orderId": { "type": "string" }, + "orderUrl": { "type": "string" }, + "orderDate": { "type": ["string", "null"] }, + "total": { "type": ["number", "null"] }, + "itemCount": { "type": ["number", "null"] }, + "status": { "type": ["string", "null"] }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "productId": { "type": "string" }, + "productUrl": { "type": "string" }, + "imageUrl": { "type": "string" }, + "quantity": { "type": ["string", "null"] }, + "price": { "type": ["number", "null"] } + }, + "required": ["name", "productId"] + } + } + }, + "required": ["orderId", "items"] + } + }, + "totalOrders": { "type": "number" }, + "totalItems": { "type": "number" } + }, + "required": ["orders", "totalOrders", "totalItems"] + } +} diff --git a/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.profile.json b/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.profile.json new file mode 100644 index 0000000..9db460c --- /dev/null +++ b/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.profile.json @@ -0,0 +1,16 @@ +{ + "name": "Whole Foods Profile", + "version": "1.0.0", + "scope": "wholefoods.profile", + "dialect": "json", + "definitionUrl": "https://raw.githubusercontent.com/vana-com/data-connectors/main/connectors/wholefoods/schemas/wholefoods.profile.json", + "description": "Amazon account information associated with Whole Foods Market orders", + "schema": { + "type": "object", + "properties": { + "name": { "type": ["string", "null"] }, + "email": { "type": ["string", "null"] } + }, + "additionalProperties": false + } +} diff --git a/packages/scope-catalog/package.json b/packages/scope-catalog/package.json new file mode 100644 index 0000000..c69c246 --- /dev/null +++ b/packages/scope-catalog/package.json @@ -0,0 +1,33 @@ +{ + "name": "@opendatalabs/scope-catalog", + "version": "1.0.0", + "description": "Versioned public Vana source and scope catalog", + "type": "module", + "repository": { + "type": "git", + "url": "https://github.com/vana-com/data-connectors.git", + "directory": "packages/scope-catalog" + }, + "engines": { + "node": ">=20" + }, + "files": [ + "CHANGELOG.md", + "README.md", + "connectors", + "release.json", + "schemas", + "scope-catalog.json" + ], + "exports": { + "./scope-catalog.json": "./scope-catalog.json", + "./schemas/scope-catalog.schema.json": "./schemas/scope-catalog.schema.json", + "./connectors/*": "./connectors/*", + "./release.json": "./release.json", + "./package.json": "./package.json" + }, + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + } +} diff --git a/packages/scope-catalog/release.json b/packages/scope-catalog/release.json new file mode 100644 index 0000000..6d6a5a2 --- /dev/null +++ b/packages/scope-catalog/release.json @@ -0,0 +1,212 @@ +{ + "schemaVersion": "1.0.0", + "currentVersion": "1.0.0", + "previousVersion": null, + "currentContractFingerprint": "sha256:0c1ab8a19b236cd2b1d1a6ae19a2acee53519812d1fd7b4e443cdf5f7755fb09", + "previousContractFingerprint": null, + "added": [ + [ + "amazon", + "amazon.orders" + ], + [ + "amazon", + "amazon.profile" + ], + [ + "chatgpt", + "chatgpt.conversations" + ], + [ + "chatgpt", + "chatgpt.memories" + ], + [ + "claude", + "claude.conversations" + ], + [ + "claude", + "claude.projects" + ], + [ + "doordash", + "doordash.orders" + ], + [ + "github", + "github.contributions" + ], + [ + "github", + "github.events" + ], + [ + "github", + "github.history" + ], + [ + "github", + "github.profile" + ], + [ + "github", + "github.repositories" + ], + [ + "github", + "github.starred" + ], + [ + "heb", + "heb.nutrition" + ], + [ + "heb", + "heb.orders" + ], + [ + "heb", + "heb.profile" + ], + [ + "icloud_notes", + "icloud_notes.folders" + ], + [ + "icloud_notes", + "icloud_notes.notes" + ], + [ + "instagram", + "instagram.ads" + ], + [ + "instagram", + "instagram.following" + ], + [ + "instagram", + "instagram.posts" + ], + [ + "instagram", + "instagram.profile" + ], + [ + "linkedin", + "linkedin.connections" + ], + [ + "linkedin", + "linkedin.education" + ], + [ + "linkedin", + "linkedin.experience" + ], + [ + "linkedin", + "linkedin.languages" + ], + [ + "linkedin", + "linkedin.profile" + ], + [ + "linkedin", + "linkedin.skills" + ], + [ + "oura", + "oura.activity" + ], + [ + "oura", + "oura.readiness" + ], + [ + "oura", + "oura.sleep" + ], + [ + "shop", + "shop.orders" + ], + [ + "spotify", + "spotify.playlists" + ], + [ + "spotify", + "spotify.profile" + ], + [ + "spotify", + "spotify.savedTracks" + ], + [ + "steam", + "steam.friends" + ], + [ + "steam", + "steam.games" + ], + [ + "steam", + "steam.profile" + ], + [ + "uber", + "uber.receipts" + ], + [ + "uber", + "uber.trips" + ], + [ + "wholefoods", + "wholefoods.nutrition" + ], + [ + "wholefoods", + "wholefoods.orders" + ], + [ + "wholefoods", + "wholefoods.profile" + ], + [ + "youtube", + "youtube.history" + ], + [ + "youtube", + "youtube.likes" + ], + [ + "youtube", + "youtube.playlistItems" + ], + [ + "youtube", + "youtube.playlists" + ], + [ + "youtube", + "youtube.profile" + ], + [ + "youtube", + "youtube.subscriptions" + ], + [ + "youtube", + "youtube.watchLater" + ] + ], + "removed": [], + "changes": [], + "impact": "minor" +} diff --git a/packages/scope-catalog/schemas/scope-catalog.schema.json b/packages/scope-catalog/schemas/scope-catalog.schema.json new file mode 100644 index 0000000..fbb282b --- /dev/null +++ b/packages/scope-catalog/schemas/scope-catalog.schema.json @@ -0,0 +1,211 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:vana:data-connectors:scope-catalog:1.0.0", + "title": "Vana public source and scope catalog", + "type": "object", + "required": ["catalogSchema", "distribution", "catalogVersion", "generatedBy", "generatedFrom", "scopes"], + "properties": { + "catalogSchema": { + "type": "object", + "required": ["path", "releaseAsset"], + "properties": { + "path": { "const": "schemas/scope-catalog.schema.json" }, + "releaseAsset": { "const": "scope-catalog.schema.json" } + }, + "additionalProperties": false + }, + "catalogVersion": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" }, + "distribution": { + "type": "object", + "required": ["repository"], + "properties": { + "repository": { "const": "https://github.com/vana-com/data-connectors" }, + "sourceCommit": { "type": "string", "pattern": "^[0-9a-f]{40}$" }, + "releaseTag": { "type": "string", "pattern": "^connectors-[0-9a-f]{12}$" } + }, + "dependentRequired": { + "sourceCommit": ["releaseTag"], + "releaseTag": ["sourceCommit"] + }, + "additionalProperties": false + }, + "generatedBy": { "const": "scripts/generate-scope-catalog.mjs" }, + "generatedFrom": { + "type": "object", + "required": ["publishability", "manifests", "webCapabilities"], + "properties": { + "publishability": { + "type": "object", + "required": ["path", "manifestSelector"], + "properties": { + "path": { "const": "registry.json" }, + "manifestSelector": { "const": "connectors[].files.metadata" } + }, + "additionalProperties": false + }, + "manifests": { + "type": "array", + "items": { "type": "string", "pattern": "^connectors/.+-playwright\\.json$" }, + "uniqueItems": true + }, + "webCapabilities": { "const": "scopes/web-capabilities.json" } + }, + "additionalProperties": false + }, + "scopes": { + "type": "array", + "items": { "$ref": "#/$defs/scope" } + } + }, + "$defs": { + "connector": { + "type": "object", + "required": ["id", "status"], + "properties": { + "id": { "type": "string", "minLength": 1 }, + "status": { "type": "string", "enum": ["stable", "beta", "experimental"] }, + "limits": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/limit" } + } + }, + "additionalProperties": false + }, + "limit": { + "type": "object", + "required": ["type", "value", "unit", "description"], + "properties": { + "type": { "type": "string", "enum": ["maxItems", "timeWindow"] }, + "value": { "type": "integer", "minimum": 1 }, + "unit": { "type": "string", "minLength": 1 }, + "description": { "type": "string", "minLength": 1 } + }, + "additionalProperties": false + }, + "blocker": { + "type": "object", + "required": ["id", "description", "requiredCapture"], + "properties": { + "id": { "type": "string", "minLength": 1 }, + "description": { "type": "string", "minLength": 1 }, + "requiredCapture": { + "type": "array", + "minItems": 1, + "items": { "type": "string", "minLength": 1 } + } + }, + "additionalProperties": false + }, + "scope": { + "type": "object", + "required": ["sourceId", "scopeId", "description", "schema", "maturity", "fulfillment"], + "properties": { + "sourceId": { "type": "string", "pattern": "^[a-z0-9_-]+$" }, + "scopeId": { "type": "string", "pattern": "^[a-z0-9_-]+\\.[A-Za-z0-9_.-]+$" }, + "description": { "type": "string", "minLength": 1 }, + "schema": { + "type": "object", + "required": ["path"], + "properties": { + "path": { "type": "string", "pattern": "^connectors/.+/schemas/.+\\.json$" }, + "url": { "type": "string", "pattern": "^https://raw\\.githubusercontent\\.com/vana-com/data-connectors/[0-9a-f]{40}/connectors/.+/schemas/.+\\.json$" } + }, + "additionalProperties": false + }, + "maturity": { "type": "string", "enum": ["stable", "beta", "experimental"] }, + "fulfillment": { + "type": "object", + "required": ["desktop", "web"], + "properties": { + "desktop": { + "type": "object", + "required": ["status", "connectors"], + "properties": { + "status": { "const": "supported" }, + "connectors": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/connector" }, + "uniqueItems": true + } + }, + "additionalProperties": false + }, + "web": { + "type": "object", + "required": ["status"], + "properties": { + "status": { "type": "string", "enum": ["supported", "unsupported", "blocked"] }, + "limits": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#/$defs/limit" } + }, + "blocker": { "$ref": "#/$defs/blocker" } + }, + "allOf": [ + { + "if": { "properties": { "status": { "const": "blocked" } }, "required": ["status"] }, + "then": { + "properties": { "blocker": { "$ref": "#/$defs/blocker" } }, + "required": ["blocker"] + }, + "else": { "not": { "required": ["blocker"] } } + }, + { + "if": { "properties": { "status": { "const": "supported" } }, "required": ["status"] }, + "else": { + "not": { + "properties": { "limits": { "type": "array" } }, + "required": ["limits"] + } + } + } + ], + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "allOf": [ + { + "if": { + "properties": { + "distribution": { + "type": "object", + "properties": { + "sourceCommit": { "type": "string" } + }, + "required": ["sourceCommit"] + } + }, + "required": ["distribution"] + }, + "then": { + "properties": { + "scopes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "schema": { + "type": "object", + "properties": { + "url": { "type": "string" } + }, + "required": ["url"] + } + } + } + } + } + } + } + ], + "additionalProperties": false +} diff --git a/packages/scope-catalog/scope-catalog.json b/packages/scope-catalog/scope-catalog.json new file mode 100644 index 0000000..49b5657 --- /dev/null +++ b/packages/scope-catalog/scope-catalog.json @@ -0,0 +1,1287 @@ +{ + "catalogSchema": { + "path": "schemas/scope-catalog.schema.json", + "releaseAsset": "scope-catalog.schema.json" + }, + "distribution": { + "repository": "https://github.com/vana-com/data-connectors" + }, + "catalogVersion": "1.0.0", + "generatedBy": "scripts/generate-scope-catalog.mjs", + "generatedFrom": { + "publishability": { + "path": "registry.json", + "manifestSelector": "connectors[].files.metadata" + }, + "manifests": [ + "connectors/amazon/amazon-playwright.json", + "connectors/anthropic/claude-export-playwright.json", + "connectors/apple/icloud-notes-playwright.json", + "connectors/doordash/doordash-playwright.json", + "connectors/github/github-playwright.json", + "connectors/google/youtube-playwright.json", + "connectors/heb/heb-playwright.json", + "connectors/linkedin/linkedin-playwright.json", + "connectors/meta/instagram-ads-playwright.json", + "connectors/meta/instagram-playwright.json", + "connectors/openai/chatgpt-playwright.json", + "connectors/oura/oura-playwright.json", + "connectors/shopify/shop-playwright.json", + "connectors/spotify/spotify-playwright.json", + "connectors/uber/uber-playwright.json", + "connectors/valve/steam-playwright.json", + "connectors/wholefoods/wholefoods-playwright.json" + ], + "webCapabilities": "scopes/web-capabilities.json" + }, + "scopes": [ + { + "sourceId": "amazon", + "scopeId": "amazon.orders", + "description": "Order history including items, prices, dates, and delivery status", + "schema": { + "path": "connectors/amazon/schemas/amazon.orders.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "amazon-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "amazon", + "scopeId": "amazon.profile", + "description": "Account name and Prime membership status", + "schema": { + "path": "connectors/amazon/schemas/amazon.profile.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "amazon-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "chatgpt", + "scopeId": "chatgpt.conversations", + "description": "All conversation history including messages with ChatGPT", + "schema": { + "path": "connectors/openai/schemas/chatgpt.conversations.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "chatgpt-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "chatgpt", + "scopeId": "chatgpt.memories", + "description": "Saved memories that ChatGPT uses to personalize responses", + "schema": { + "path": "connectors/openai/schemas/chatgpt.memories.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "chatgpt-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "claude", + "scopeId": "claude.conversations", + "description": "All Claude conversations with full message threads, from Anthropic's official data export.", + "schema": { + "path": "connectors/anthropic/schemas/claude.conversations.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "claude-export-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "claude", + "scopeId": "claude.projects", + "description": "Claude projects and their detail, from Anthropic's official data export.", + "schema": { + "path": "connectors/anthropic/schemas/claude.projects.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "claude-export-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "doordash", + "scopeId": "doordash.orders", + "description": "Complete order history with restaurant names, items ordered, dates, totals, and delivery status", + "schema": { + "path": "connectors/doordash/schemas/doordash.orders.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "doordash-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "github", + "scopeId": "github.contributions", + "description": "Daily contribution counts for the last 4 years (per-year scrape, not just rolling 12 months), monthly totals, per-year totals, and your top day", + "schema": { + "path": "connectors/github/schemas/github.contributions.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "github-playwright", + "status": "stable", + "limits": [ + { + "type": "timeWindow", + "value": 4, + "unit": "years", + "description": "The Desktop connector collects the four most recent calendar years." + } + ] + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "github", + "scopeId": "github.events", + "description": "Recent public activity (pushes, pull requests, issues, comments, branches, releases) across every repository you have touched, including organization-owned repos", + "schema": { + "path": "connectors/github/schemas/github.events.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "github-playwright", + "status": "stable", + "limits": [ + { + "type": "maxItems", + "value": 300, + "unit": "events", + "description": "The Desktop connector returns at most 300 public events." + }, + { + "type": "timeWindow", + "value": 90, + "unit": "days", + "description": "The GitHub public-events API covers at most the previous 90 days." + } + ] + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "github", + "scopeId": "github.history", + "description": "Pull requests and issues you have authored across public repositories via the GitHub Search API, including title, body, dates, repository, labels, and state.", + "schema": { + "path": "connectors/github/schemas/github.history.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "github-playwright", + "status": "stable", + "limits": [ + { + "type": "maxItems", + "value": 1000, + "unit": "items per type", + "description": "The GitHub Search API returns at most 1,000 pull requests and 1,000 issues per query." + } + ] + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "github", + "scopeId": "github.profile", + "description": "Account profile information such as name, bio, follower counts, pinned repositories, organization memberships, and achievement badges", + "schema": { + "path": "connectors/github/schemas/github.profile.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "github-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "supported" + } + } + }, + { + "sourceId": "github", + "scopeId": "github.repositories", + "description": "Your repository list with metadata like language, stars, and update time", + "schema": { + "path": "connectors/github/schemas/github.repositories.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "github-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "github", + "scopeId": "github.starred", + "description": "Repositories you have starred on GitHub", + "schema": { + "path": "connectors/github/schemas/github.starred.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "github-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "heb", + "scopeId": "heb.nutrition", + "description": "Nutrition facts (calories, macros, sodium, fiber, vitamins) for each product ordered. Aligned to Schema.org NutritionInformation.", + "schema": { + "path": "connectors/heb/schemas/heb.nutrition.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "heb-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "heb", + "scopeId": "heb.orders", + "description": "Curbside and delivery orders with item names, quantities, prices, and order dates", + "schema": { + "path": "connectors/heb/schemas/heb.orders.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "heb-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "heb", + "scopeId": "heb.profile", + "description": "Your name, email, phone number, and saved delivery addresses", + "schema": { + "path": "connectors/heb/schemas/heb.profile.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "heb-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "icloud_notes", + "scopeId": "icloud_notes.folders", + "description": "Folder structure for organizing notes", + "schema": { + "path": "connectors/apple/schemas/icloud_notes.folders.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "icloud-notes-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "icloud_notes", + "scopeId": "icloud_notes.notes", + "description": "Note content, titles, created/modified timestamps, and folder assignment", + "schema": { + "path": "connectors/apple/schemas/icloud_notes.notes.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "icloud-notes-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "instagram", + "scopeId": "instagram.ads", + "description": "Advertisers the user has seen ads from and ad topic interests based on their Instagram activity", + "schema": { + "path": "connectors/meta/schemas/instagram.ads.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "instagram-playwright", + "status": "stable" + }, + { + "id": "instagram-ads-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "instagram", + "scopeId": "instagram.following", + "description": "The list of Instagram accounts you follow", + "schema": { + "path": "connectors/meta/schemas/instagram.following.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "instagram-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "instagram", + "scopeId": "instagram.posts", + "description": "Published posts from your feed", + "schema": { + "path": "connectors/meta/schemas/instagram.posts.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "instagram-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "supported", + "limits": [ + { + "type": "maxItems", + "value": 150, + "unit": "posts", + "description": "The Web path returns at most the 150 most recent posts." + } + ] + } + } + }, + { + "sourceId": "instagram", + "scopeId": "instagram.profile", + "description": "Profile information including bio and follower counts", + "schema": { + "path": "connectors/meta/schemas/instagram.profile.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "instagram-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "supported" + } + } + }, + { + "sourceId": "linkedin", + "scopeId": "linkedin.connections", + "description": "Your LinkedIn connections with names, headlines, profile URLs, and date connected", + "schema": { + "path": "connectors/linkedin/schemas/linkedin.connections.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "linkedin-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "blocked", + "blocker": { + "id": "linkedin-live-output", + "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", + "requiredCapture": [ + "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", + "The resulting Personal Server scope inventory for the same run and user after sync." + ] + } + } + } + }, + { + "sourceId": "linkedin", + "scopeId": "linkedin.education", + "description": "Your education history including schools, degrees, years, and grades", + "schema": { + "path": "connectors/linkedin/schemas/linkedin.education.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "linkedin-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "blocked", + "blocker": { + "id": "linkedin-live-output", + "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", + "requiredCapture": [ + "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", + "The resulting Personal Server scope inventory for the same run and user after sync." + ] + } + } + } + }, + { + "sourceId": "linkedin", + "scopeId": "linkedin.experience", + "description": "Your work experience including job titles, companies, dates, locations, and descriptions", + "schema": { + "path": "connectors/linkedin/schemas/linkedin.experience.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "linkedin-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "blocked", + "blocker": { + "id": "linkedin-live-output", + "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", + "requiredCapture": [ + "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", + "The resulting Personal Server scope inventory for the same run and user after sync." + ] + } + } + } + }, + { + "sourceId": "linkedin", + "scopeId": "linkedin.languages", + "description": "Your languages and proficiency levels", + "schema": { + "path": "connectors/linkedin/schemas/linkedin.languages.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "linkedin-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "blocked", + "blocker": { + "id": "linkedin-live-output", + "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", + "requiredCapture": [ + "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", + "The resulting Personal Server scope inventory for the same run and user after sync." + ] + } + } + } + }, + { + "sourceId": "linkedin", + "scopeId": "linkedin.profile", + "description": "Your LinkedIn profile including name, headline, location, about, and profile picture", + "schema": { + "path": "connectors/linkedin/schemas/linkedin.profile.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "linkedin-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "blocked", + "blocker": { + "id": "linkedin-live-output", + "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", + "requiredCapture": [ + "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", + "The resulting Personal Server scope inventory for the same run and user after sync." + ] + } + } + } + }, + { + "sourceId": "linkedin", + "scopeId": "linkedin.skills", + "description": "Your skills and endorsement counts", + "schema": { + "path": "connectors/linkedin/schemas/linkedin.skills.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "linkedin-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "blocked", + "blocker": { + "id": "linkedin-live-output", + "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", + "requiredCapture": [ + "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", + "The resulting Personal Server scope inventory for the same run and user after sync." + ] + } + } + } + }, + { + "sourceId": "oura", + "scopeId": "oura.activity", + "description": "Daily activity scores, step counts, calorie burn, and activity level breakdowns", + "schema": { + "path": "connectors/oura/schemas/oura.activity.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "oura-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "oura", + "scopeId": "oura.readiness", + "description": "Daily readiness scores and contributing factors like HRV balance, resting heart rate, recovery, and body temperature", + "schema": { + "path": "connectors/oura/schemas/oura.readiness.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "oura-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "oura", + "scopeId": "oura.sleep", + "description": "Daily sleep scores with contributor breakdowns and detailed sleep period data including duration, stages, heart rate, and HRV", + "schema": { + "path": "connectors/oura/schemas/oura.sleep.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "oura-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "shop", + "scopeId": "shop.orders", + "description": "Complete order history from the Shop app including merchants, items, totals, and delivery status", + "schema": { + "path": "connectors/shopify/schemas/shop.orders.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "shop-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "spotify", + "scopeId": "spotify.playlists", + "description": "Playlists and their tracks", + "schema": { + "path": "connectors/spotify/schemas/spotify.playlists.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "spotify-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "spotify", + "scopeId": "spotify.profile", + "description": "Profile information", + "schema": { + "path": "connectors/spotify/schemas/spotify.profile.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "spotify-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "supported" + } + } + }, + { + "sourceId": "spotify", + "scopeId": "spotify.savedTracks", + "description": "Saved/liked tracks in your library", + "schema": { + "path": "connectors/spotify/schemas/spotify.savedTracks.json" + }, + "maturity": "stable", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "spotify-playwright", + "status": "stable" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "steam", + "scopeId": "steam.friends", + "description": "Friend list with persona names, avatars, and friendship dates", + "schema": { + "path": "connectors/valve/schemas/steam.friends.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "steam-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "steam", + "scopeId": "steam.games", + "description": "Owned games with playtime statistics, plus recently played games", + "schema": { + "path": "connectors/valve/schemas/steam.games.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "steam-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "steam", + "scopeId": "steam.profile", + "description": "Steam profile including persona name, avatar, level, country, and account age", + "schema": { + "path": "connectors/valve/schemas/steam.profile.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "steam-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "uber", + "scopeId": "uber.receipts", + "description": "Fare breakdowns and receipt details for each trip", + "schema": { + "path": "connectors/uber/schemas/uber.receipts.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "uber-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "uber", + "scopeId": "uber.trips", + "description": "Complete history of your Uber rides including pickup/dropoff locations, dates, and driver info", + "schema": { + "path": "connectors/uber/schemas/uber.trips.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "uber-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "wholefoods", + "scopeId": "wholefoods.nutrition", + "description": "Nutrition facts (calories, macros, sodium, fiber, vitamins) for each product ordered. Aligned to Schema.org NutritionInformation.", + "schema": { + "path": "connectors/wholefoods/schemas/wholefoods.nutrition.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "wholefoods-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "wholefoods", + "scopeId": "wholefoods.orders", + "description": "Whole Foods delivery and pickup orders with item names, quantities, prices, and order dates", + "schema": { + "path": "connectors/wholefoods/schemas/wholefoods.orders.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "wholefoods-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "wholefoods", + "scopeId": "wholefoods.profile", + "description": "Your Amazon account name and email associated with Whole Foods orders", + "schema": { + "path": "connectors/wholefoods/schemas/wholefoods.profile.json" + }, + "maturity": "experimental", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "wholefoods-playwright", + "status": "experimental" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "youtube", + "scopeId": "youtube.history", + "description": "Raw watch history entries for the top 50 most recent items", + "schema": { + "path": "connectors/google/schemas/youtube.history.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "youtube-playwright", + "status": "beta", + "limits": [ + { + "type": "maxItems", + "value": 50, + "unit": "items", + "description": "The Desktop connector returns at most the 50 most recent watch history items." + } + ] + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "youtube", + "scopeId": "youtube.likes", + "description": "Videos you have liked", + "schema": { + "path": "connectors/google/schemas/youtube.likes.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "youtube-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "youtube", + "scopeId": "youtube.playlistItems", + "description": "Videos inside your playlists, including titles and URLs", + "schema": { + "path": "connectors/google/schemas/youtube.playlistItems.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "youtube-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "youtube", + "scopeId": "youtube.playlists", + "description": "Playlists visible in your YouTube Library", + "schema": { + "path": "connectors/google/schemas/youtube.playlists.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "youtube-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "youtube", + "scopeId": "youtube.profile", + "description": "Email, channel URL, handle, and joined date (plus optional channel fields like title, avatar, and stats)", + "schema": { + "path": "connectors/google/schemas/youtube.profile.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "youtube-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "supported" + } + } + }, + { + "sourceId": "youtube", + "scopeId": "youtube.subscriptions", + "description": "Channels you are subscribed to", + "schema": { + "path": "connectors/google/schemas/youtube.subscriptions.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "youtube-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + }, + { + "sourceId": "youtube", + "scopeId": "youtube.watchLater", + "description": "Videos saved to Watch Later", + "schema": { + "path": "connectors/google/schemas/youtube.watchLater.json" + }, + "maturity": "beta", + "fulfillment": { + "desktop": { + "status": "supported", + "connectors": [ + { + "id": "youtube-playwright", + "status": "beta" + } + ] + }, + "web": { + "status": "unsupported" + } + } + } + ] +} diff --git a/scripts/build-scope-catalog-package.mjs b/scripts/build-scope-catalog-package.mjs new file mode 100644 index 0000000..155ae94 --- /dev/null +++ b/scripts/build-scope-catalog-package.mjs @@ -0,0 +1,153 @@ +#!/usr/bin/env node + +import { + copyFileSync, + existsSync, + mkdirSync, + readFileSync, + rmSync, + writeFileSync, +} from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +import { + compareScopeCatalogContracts, + readContractSnapshot, +} from "./diff-scope-catalog-package.mjs"; + +const scriptDir = dirname(fileURLToPath(import.meta.url)); +const defaultRepoRoot = join(scriptDir, ".."); +const defaultPackageRoot = join(defaultRepoRoot, "packages", "scope-catalog"); +const changelogPreamble = + "All notable public scope-catalog contract changes are recorded here.\n\n"; + +function readJson(path) { + return JSON.parse(readFileSync(path, "utf8")); +} + +function writeJson(path, value) { + mkdirSync(dirname(path), { recursive: true }); + writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`); +} + +function formatPairs(pairs) { + return pairs.length > 0 + ? pairs.map(([sourceId, scopeId]) => `\`${sourceId}/${scopeId}\``).join(", ") + : "None"; +} + +function renderChangelog(release, previousPackageRoot) { + if (release.impact === "none" && previousPackageRoot) { + const previousChangelogPath = join(previousPackageRoot, "CHANGELOG.md"); + if (!existsSync(previousChangelogPath)) { + throw new Error("Previous package is missing CHANGELOG.md"); + } + return readFileSync(previousChangelogPath, "utf8"); + } + + const entry = `## ${release.currentVersion}\n\n- Impact: ${release.impact}\n- Contract fingerprint: \`${release.currentContractFingerprint}\`\n- Added pairs: ${formatPairs(release.added)}\n- Removed pairs: ${formatPairs(release.removed)}\n- Changed pairs: ${release.changes.length}\n`; + if (!previousPackageRoot) { + return `# Changelog\n\n${changelogPreamble}${entry}`; + } + + const previousChangelogPath = join(previousPackageRoot, "CHANGELOG.md"); + if (!existsSync(previousChangelogPath)) { + throw new Error("Previous package is missing CHANGELOG.md"); + } + const previousChangelog = readFileSync(previousChangelogPath, "utf8"); + const prefix = "# Changelog\n"; + if (!previousChangelog.startsWith(prefix)) { + throw new Error("Previous package CHANGELOG.md must begin with # Changelog"); + } + const previousBody = previousChangelog.slice(prefix.length).trimStart(); + const previousEntries = previousBody.startsWith(changelogPreamble) + ? previousBody.slice(changelogPreamble.length) + : previousBody; + return `${prefix}\n${changelogPreamble}${entry}\n${previousEntries}`; +} + +export function buildScopeCatalogPackage({ + repoRoot = defaultRepoRoot, + packageRoot = defaultPackageRoot, + previousPackageRoot = null, +} = {}) { + const packageJsonPath = join(packageRoot, "package.json"); + const readmePath = join(packageRoot, "README.md"); + if (!existsSync(packageJsonPath) || !existsSync(readmePath)) { + throw new Error("Package root must contain authored package.json and README.md"); + } + const packageJson = readJson(packageJsonPath); + if (packageJson.name !== "@opendatalabs/scope-catalog") { + throw new Error("Package name must remain @opendatalabs/scope-catalog"); + } + + const current = readContractSnapshot(repoRoot); + const previous = previousPackageRoot ? readContractSnapshot(previousPackageRoot) : null; + const release = compareScopeCatalogContracts({ current, previous }); + + for (const path of [ + "CHANGELOG.md", + "connectors", + "release.json", + "schemas", + "scope-catalog.json", + ]) { + rmSync(join(packageRoot, path), { force: true, recursive: true }); + } + + writeJson(packageJsonPath, { ...packageJson, version: release.currentVersion }); + copyFileSync(join(repoRoot, "scope-catalog.json"), join(packageRoot, "scope-catalog.json")); + mkdirSync(join(packageRoot, "schemas"), { recursive: true }); + copyFileSync( + join(repoRoot, current.catalog.catalogSchema.path), + join(packageRoot, current.catalog.catalogSchema.path), + ); + for (const path of current.payloadSchemas.keys()) { + mkdirSync(dirname(join(packageRoot, path)), { recursive: true }); + copyFileSync(join(repoRoot, path), join(packageRoot, path)); + } + writeJson(join(packageRoot, "release.json"), release); + writeFileSync( + join(packageRoot, "CHANGELOG.md"), + renderChangelog(release, previousPackageRoot), + ); + + const built = readContractSnapshot(packageRoot); + if (built.fingerprint !== current.fingerprint) { + throw new Error("Built package contract fingerprint differs from repository input"); + } + if (built.payloadSchemas.size !== current.payloadSchemas.size) { + throw new Error("Built package contains a different referenced payload-schema set"); + } + return release; +} + +function parseArgs(argv) { + const result = { previousPackageRoot: null }; + for (let index = 0; index < argv.length; index += 1) { + if (argv[index] === "--previous-package" && argv[index + 1]) { + result.previousPackageRoot = resolve(argv[++index]); + } else { + throw new Error( + "Usage: node scripts/build-scope-catalog-package.mjs [--previous-package ]", + ); + } + } + return result; +} + +if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) { + try { + const { previousPackageRoot } = parseArgs(process.argv.slice(2)); + const release = buildScopeCatalogPackage({ previousPackageRoot }); + console.log( + `Built @opendatalabs/scope-catalog ${release.currentVersion} (${release.impact}, ${release.currentContractFingerprint}).`, + ); + } catch (error) { + console.error( + `[build-scope-catalog-package] ERROR: ${error instanceof Error ? error.message : String(error)}`, + ); + process.exit(1); + } +} diff --git a/scripts/check-scope-catalog-package.mjs b/scripts/check-scope-catalog-package.mjs new file mode 100644 index 0000000..57c155f --- /dev/null +++ b/scripts/check-scope-catalog-package.mjs @@ -0,0 +1,152 @@ +#!/usr/bin/env node + +import assert from "node:assert/strict"; +import { + cpSync, + mkdtempSync, + readdirSync, + readFileSync, + statSync, +} from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join, relative, resolve } from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +import { buildScopeCatalogPackage } from "./build-scope-catalog-package.mjs"; +import { + compareScopeCatalogContracts, + readContractSnapshot, +} from "./diff-scope-catalog-package.mjs"; + +const scriptDir = dirname(fileURLToPath(import.meta.url)); +const defaultRepoRoot = join(scriptDir, ".."); +const defaultPackageRoot = join(defaultRepoRoot, "packages", "scope-catalog"); +const requiredExports = { + "./scope-catalog.json": "./scope-catalog.json", + "./schemas/scope-catalog.schema.json": "./schemas/scope-catalog.schema.json", + "./connectors/*": "./connectors/*", + "./release.json": "./release.json", + "./package.json": "./package.json", +}; +const requiredFiles = [ + "CHANGELOG.md", + "README.md", + "connectors", + "release.json", + "schemas", + "scope-catalog.json", +]; + +function readJson(path) { + return JSON.parse(readFileSync(path, "utf8")); +} + +function listFiles(root, directory = root) { + return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { + const path = join(directory, entry.name); + return entry.isDirectory() ? listFiles(root, path) : [relative(root, path)]; + }); +} + +function assertSameFileTree(actualRoot, expectedRoot) { + const actualFiles = listFiles(actualRoot).sort(); + const expectedFiles = listFiles(expectedRoot).sort(); + assert.deepEqual(actualFiles, expectedFiles, "package file set is not deterministic"); + for (const path of actualFiles) { + assert.ok( + readFileSync(join(actualRoot, path)).equals(readFileSync(join(expectedRoot, path))), + `package file differs from deterministic build: ${path}`, + ); + } +} + +export function checkScopeCatalogPackage({ + repoRoot = defaultRepoRoot, + packageRoot = defaultPackageRoot, + previousPackageRoot = null, +} = {}) { + const packageJson = readJson(join(packageRoot, "package.json")); + assert.equal(packageJson.name, "@opendatalabs/scope-catalog"); + assert.deepEqual(packageJson.files, requiredFiles); + assert.deepEqual(packageJson.exports, requiredExports); + assert.deepEqual(packageJson.publishConfig, { + access: "public", + registry: "https://registry.npmjs.org", + }); + assert.deepEqual(packageJson.repository, { + type: "git", + url: "https://github.com/vana-com/data-connectors.git", + directory: "packages/scope-catalog", + }); + + const packageSnapshot = readContractSnapshot(packageRoot); + const repoSnapshot = readContractSnapshot(repoRoot); + assert.equal(packageSnapshot.fingerprint, repoSnapshot.fingerprint); + const previousSnapshot = previousPackageRoot + ? readContractSnapshot(previousPackageRoot) + : null; + const expectedRelease = compareScopeCatalogContracts({ + current: repoSnapshot, + previous: previousSnapshot, + }); + assert.deepEqual(readJson(join(packageRoot, "release.json")), expectedRelease); + assert.equal(packageJson.version, expectedRelease.currentVersion); + + const expectedFiles = new Set([ + "CHANGELOG.md", + "README.md", + "package.json", + "release.json", + "scope-catalog.json", + packageSnapshot.catalog.catalogSchema.path, + ...packageSnapshot.payloadSchemas.keys(), + ]); + for (const path of listFiles(packageRoot)) { + if (!expectedFiles.has(path)) throw new Error(`unexpected package file: ${path}`); + } + for (const path of expectedFiles) { + if (!statSync(join(packageRoot, path)).isFile()) { + throw new Error(`missing package file: ${path}`); + } + } + + const expectedRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-check-")); + cpSync(join(packageRoot, "package.json"), join(expectedRoot, "package.json")); + cpSync(join(packageRoot, "README.md"), join(expectedRoot, "README.md")); + buildScopeCatalogPackage({ + repoRoot, + packageRoot: expectedRoot, + previousPackageRoot, + }); + assertSameFileTree(packageRoot, expectedRoot); + return expectedRelease; +} + +function parseArgs(argv) { + const result = { previousPackageRoot: null }; + for (let index = 0; index < argv.length; index += 1) { + if (argv[index] === "--previous-package" && argv[index + 1]) { + result.previousPackageRoot = resolve(argv[++index]); + } else { + throw new Error( + "Usage: node scripts/check-scope-catalog-package.mjs [--previous-package ]", + ); + } + } + return result; +} + +if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) { + try { + const { previousPackageRoot } = parseArgs(process.argv.slice(2)); + const release = checkScopeCatalogPackage({ previousPackageRoot }); + console.log( + `Scope catalog package is deterministic and complete (${release.currentVersion}, ${release.impact}).`, + ); + } catch (error) { + console.error( + `[check-scope-catalog-package] ERROR: ${error instanceof Error ? error.message : String(error)}`, + ); + process.exit(1); + } +} diff --git a/scripts/diff-scope-catalog-package.mjs b/scripts/diff-scope-catalog-package.mjs new file mode 100644 index 0000000..948fcce --- /dev/null +++ b/scripts/diff-scope-catalog-package.mjs @@ -0,0 +1,506 @@ +#!/usr/bin/env node + +import { createHash } from "node:crypto"; +import { existsSync, readFileSync } from "node:fs"; +import { dirname, isAbsolute, join, normalize, resolve } from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +const scriptDir = dirname(fileURLToPath(import.meta.url)); +const defaultRepoRoot = join(scriptDir, ".."); +const maturityRank = new Map([ + ["experimental", 0], + ["beta", 1], + ["stable", 2], +]); +const impactRank = new Map([ + ["none", 0], + ["patch", 1], + ["minor", 2], + ["major", 3], +]); + +function compareCodeUnits(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function readJson(path) { + return JSON.parse(readFileSync(path, "utf8")); +} + +function stableValue(value) { + if (Array.isArray(value)) return value.map(stableValue); + if (value && typeof value === "object") { + return Object.fromEntries( + Object.keys(value) + .filter((key) => value[key] !== undefined) + .sort(compareCodeUnits) + .map((key) => [key, stableValue(value[key])]), + ); + } + return value; +} + +function stableJson(value) { + return JSON.stringify(stableValue(value)); +} + +function normalizeLimits(limits) { + if (!Array.isArray(limits)) return limits; + return limits + .map(stableValue) + .sort((left, right) => compareCodeUnits(stableJson(left), stableJson(right))); +} + +function normalizeDesktop(desktop) { + if (!desktop) return desktop; + const normalized = structuredClone(desktop); + normalized.limits = normalizeLimits(normalized.limits); + normalized.connectors = normalized.connectors?.map((connector) => ({ + ...connector, + limits: normalizeLimits(connector.limits), + })); + normalized.connectors?.sort((left, right) => + compareCodeUnits(`${left.id}\0${left.status}`, `${right.id}\0${right.status}`), + ); + return stableValue(normalized); +} + +function normalizeWeb(web) { + if (!web) return web; + return stableValue({ ...structuredClone(web), limits: normalizeLimits(web.limits) }); +} + +function assertPackageRelativePath(path, label) { + if ( + typeof path !== "string" || + path.length === 0 || + isAbsolute(path) || + normalize(path).startsWith("..") || + normalize(path) !== path + ) { + throw new Error(`${label} must be a normalized package-relative path: ${path}`); + } +} + +function normalizeCatalog(catalog) { + const normalized = structuredClone(catalog); + delete normalized.generatedFrom; + if (normalized.distribution) { + delete normalized.distribution.sourceCommit; + delete normalized.distribution.releaseTag; + } + for (const scope of normalized.scopes ?? []) { + delete scope.schema?.url; + if (scope.fulfillment) { + scope.fulfillment.desktop = normalizeDesktop(scope.fulfillment.desktop); + scope.fulfillment.web = normalizeWeb(scope.fulfillment.web); + } + } + normalized.scopes?.sort((left, right) => + compareCodeUnits( + `${left.sourceId}\0${left.scopeId}`, + `${right.sourceId}\0${right.scopeId}`, + ), + ); + return stableValue(normalized); +} + +function pair(scope) { + return [scope.sourceId, scope.scopeId]; +} + +function pairKey(scopeOrPair) { + return JSON.stringify(Array.isArray(scopeOrPair) ? scopeOrPair : pair(scopeOrPair)); +} + +function buffersEqual(left, right) { + return left.length === right.length && left.equals(right); +} + +function bytesFingerprint(bytes) { + return `sha256:${createHash("sha256").update(bytes).digest("hex")}`; +} + +function valuesEqual(left, right) { + return stableJson(left) === stableJson(right); +} + +function maxImpact(current, candidate) { + return impactRank.get(candidate) > impactRank.get(current) ? candidate : current; +} + +function classifyMaturity(previous, current) { + const previousRank = maturityRank.get(previous); + const currentRank = maturityRank.get(current); + if (previousRank === undefined || currentRank === undefined) return "major"; + if (currentRank < previousRank) return "major"; + if (currentRank > previousRank) return "minor"; + return "none"; +} + +function connectorById(desktop) { + return new Map((desktop?.connectors ?? []).map((connector) => [connector.id, connector])); +} + +function classifyDesktop(previous, current) { + previous = normalizeDesktop(previous); + current = normalizeDesktop(current); + let impact = "none"; + if (previous?.status !== current?.status) { + if (previous?.status === "supported") impact = maxImpact(impact, "major"); + else if (current?.status === "supported") impact = maxImpact(impact, "minor"); + else impact = maxImpact(impact, "patch"); + } + if (!valuesEqual(previous?.limits, current?.limits)) { + const supportedPathAdded = previous?.status !== "supported" && current?.status === "supported"; + if (!supportedPathAdded) impact = maxImpact(impact, "major"); + } + + const previousConnectors = connectorById(previous); + const currentConnectors = connectorById(current); + for (const id of previousConnectors.keys()) { + if (!currentConnectors.has(id)) impact = maxImpact(impact, "major"); + } + for (const id of currentConnectors.keys()) { + if (!previousConnectors.has(id)) impact = maxImpact(impact, "minor"); + } + for (const [id, previousConnector] of previousConnectors) { + const currentConnector = currentConnectors.get(id); + if (!currentConnector) continue; + if (previousConnector.status !== currentConnector.status) { + impact = maxImpact( + impact, + classifyMaturity(previousConnector.status, currentConnector.status), + ); + } + if (!valuesEqual(previousConnector.limits, currentConnector.limits)) { + impact = maxImpact(impact, "major"); + } + const { status: _previousStatus, limits: _previousLimits, ...previousMetadata } = + previousConnector; + const { status: _currentStatus, limits: _currentLimits, ...currentMetadata } = + currentConnector; + if (!valuesEqual(previousMetadata, currentMetadata)) { + impact = maxImpact(impact, "patch"); + } + } + return impact; +} + +function classifyWeb(previous, current) { + previous = normalizeWeb(previous); + current = normalizeWeb(current); + let impact = "none"; + if (previous?.status !== current?.status) { + if (previous?.status === "supported") impact = maxImpact(impact, "major"); + else if (current?.status === "supported") impact = maxImpact(impact, "minor"); + else impact = maxImpact(impact, "patch"); + } + if (!valuesEqual(previous?.limits, current?.limits)) { + const supportedPathAdded = previous?.status !== "supported" && current?.status === "supported"; + if (!supportedPathAdded) impact = maxImpact(impact, "major"); + } + if (!valuesEqual(previous?.blocker, current?.blocker)) { + impact = maxImpact(impact, "patch"); + } + const { status: _previousStatus, limits: _previousLimits, blocker: _previousBlocker, ...previousMetadata } = + previous ?? {}; + const { status: _currentStatus, limits: _currentLimits, blocker: _currentBlocker, ...currentMetadata } = + current ?? {}; + if (!valuesEqual(previousMetadata, currentMetadata)) { + impact = maxImpact(impact, "patch"); + } + return impact; +} + +function bumpVersion(version, impact) { + const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version ?? ""); + if (!match) throw new Error(`Previous package version is not plain semver: ${version}`); + const [, majorText, minorText, patchText] = match; + const major = Number(majorText); + const minor = Number(minorText); + const patch = Number(patchText); + if (impact === "none") return version; + if (impact === "major") return `${major + 1}.0.0`; + if (impact === "minor") return `${major}.${minor + 1}.0`; + return `${major}.${minor}.${patch + 1}`; +} + +export function readContractSnapshot(root) { + const catalogPath = join(root, "scope-catalog.json"); + if (!existsSync(catalogPath)) throw new Error(`Missing scope-catalog.json in ${root}`); + const catalog = readJson(catalogPath); + if (!Array.isArray(catalog.scopes)) throw new Error("scope-catalog.json must contain scopes"); + assertPackageRelativePath(catalog.catalogSchema?.path, "catalogSchema.path"); + + const scopes = new Map(); + const payloadSchemas = new Map(); + for (const scope of catalog.scopes) { + if (!scope?.sourceId || !scope?.scopeId) { + throw new Error("Every catalog scope must contain sourceId and scopeId"); + } + const key = pairKey(scope); + const connectorIds = new Set(); + const duplicateConnectorIds = new Set(); + for (const connector of scope.fulfillment?.desktop?.connectors ?? []) { + if (connectorIds.has(connector.id)) duplicateConnectorIds.add(connector.id); + connectorIds.add(connector.id); + } + if (duplicateConnectorIds.size > 0) { + const duplicates = [...duplicateConnectorIds].sort(compareCodeUnits); + throw new Error( + `Duplicate Desktop connector ID${duplicates.length === 1 ? "" : "s"} for catalog pair ${key}: ${duplicates.join(", ")}`, + ); + } + if (scopes.has(key)) throw new Error(`Duplicate catalog pair: ${key}`); + scopes.set(key, scope); + assertPackageRelativePath(scope.schema?.path, `${scope.scopeId} schema.path`); + if (payloadSchemas.has(scope.schema.path)) { + throw new Error(`Duplicate referenced payload schema: ${scope.schema.path}`); + } + const path = join(root, scope.schema.path); + if (!existsSync(path)) throw new Error(`Missing referenced payload schema: ${scope.schema.path}`); + payloadSchemas.set(scope.schema.path, readFileSync(path)); + } + + const catalogSchemaPath = join(root, catalog.catalogSchema.path); + if (!existsSync(catalogSchemaPath)) { + throw new Error(`Missing catalog schema: ${catalog.catalogSchema.path}`); + } + const packageJsonPath = join(root, "package.json"); + const version = existsSync(packageJsonPath) ? readJson(packageJsonPath).version ?? null : null; + const normalizedCatalog = normalizeCatalog(catalog); + const fingerprintInput = { + catalog: normalizedCatalog, + catalogSchema: { + path: catalog.catalogSchema.path, + bytes: readFileSync(catalogSchemaPath).toString("base64"), + }, + payloadSchemas: [...payloadSchemas] + .sort(([left], [right]) => compareCodeUnits(left, right)) + .map(([path, bytes]) => ({ path, bytes: bytes.toString("base64") })), + }; + const fingerprint = `sha256:${createHash("sha256").update(stableJson(fingerprintInput)).digest("hex")}`; + + return { + root, + version, + catalog, + normalizedCatalog, + catalogSchemaBytes: readFileSync(catalogSchemaPath), + payloadSchemas, + scopes, + fingerprint, + }; +} + +function changedField(previous, current) { + return valuesEqual(previous, current) ? null : { previous, current }; +} + +function schemaReleaseValue(snapshot, scope) { + return { + path: scope.schema.path, + fingerprint: bytesFingerprint(snapshot.payloadSchemas.get(scope.schema.path)), + }; +} + +export function compareScopeCatalogContracts({ current, previous }) { + const added = [...current.scopes] + .filter(([key]) => !previous?.scopes.has(key)) + .map(([, scope]) => pair(scope)) + .sort((left, right) => compareCodeUnits(pairKey(left), pairKey(right))); + const removed = previous + ? [...previous.scopes] + .filter(([key]) => !current.scopes.has(key)) + .map(([, scope]) => pair(scope)) + .sort((left, right) => compareCodeUnits(pairKey(left), pairKey(right))) + : []; + const changes = []; + let impact = previous ? "none" : "minor"; + + if (previous && current.fingerprint !== previous.fingerprint) { + if (!buffersEqual(current.catalogSchemaBytes, previous.catalogSchemaBytes)) { + impact = maxImpact(impact, "major"); + } + if (removed.length > 0) impact = maxImpact(impact, "major"); + if (added.length > 0) impact = maxImpact(impact, "minor"); + + for (const [key, currentScope] of current.scopes) { + const previousScope = previous.scopes.get(key); + if (!previousScope) continue; + const change = { pair: pair(currentScope) }; + const description = changedField(previousScope.description, currentScope.description); + const previousSchemaMetadata = { ...previousScope.schema }; + const currentSchemaMetadata = { ...currentScope.schema }; + delete previousSchemaMetadata.url; + delete currentSchemaMetadata.url; + const schema = changedField(previousSchemaMetadata, currentSchemaMetadata); + const maturity = changedField(previousScope.maturity, currentScope.maturity); + const desktop = changedField( + normalizeDesktop(previousScope.fulfillment?.desktop), + normalizeDesktop(currentScope.fulfillment?.desktop), + ); + const web = changedField( + normalizeWeb(previousScope.fulfillment?.web), + normalizeWeb(currentScope.fulfillment?.web), + ); + if (description) { + change.description = description; + impact = maxImpact(impact, "patch"); + } + if (schema) { + change.schema = { + previous: schemaReleaseValue(previous, previousScope), + current: schemaReleaseValue(current, currentScope), + }; + impact = maxImpact(impact, "major"); + } + if (maturity) { + change.maturity = maturity; + impact = maxImpact( + impact, + classifyMaturity(previousScope.maturity, currentScope.maturity), + ); + } + if (desktop) { + change.desktop = desktop; + impact = maxImpact( + impact, + classifyDesktop( + previousScope.fulfillment?.desktop, + currentScope.fulfillment?.desktop, + ), + ); + } + if (web) { + change.web = web; + impact = maxImpact( + impact, + classifyWeb(previousScope.fulfillment?.web, currentScope.fulfillment?.web), + ); + } + const previousSchemaBytes = previous.payloadSchemas.get(previousScope.schema.path); + const currentSchemaBytes = current.payloadSchemas.get(currentScope.schema.path); + if (!buffersEqual(previousSchemaBytes, currentSchemaBytes)) { + impact = maxImpact(impact, "major"); + if (!change.schema) { + change.schema = { + previous: schemaReleaseValue(previous, previousScope), + current: schemaReleaseValue(current, currentScope), + }; + } + } + if (Object.keys(change).length > 1) changes.push(change); + } + + const previousTopLevel = structuredClone(previous.normalizedCatalog); + const currentTopLevel = structuredClone(current.normalizedCatalog); + delete previousTopLevel.scopes; + delete currentTopLevel.scopes; + if (!valuesEqual(previousTopLevel, currentTopLevel)) { + const breakingTopLevelChange = + previousTopLevel.catalogVersion !== currentTopLevel.catalogVersion || + !valuesEqual(previousTopLevel.catalogSchema, currentTopLevel.catalogSchema); + impact = maxImpact(impact, breakingTopLevelChange ? "major" : "patch"); + } + if (impact === "none") impact = "patch"; + } + + if (previous && current.fingerprint === previous.fingerprint) { + impact = "none"; + } + const previousVersion = previous?.version ?? null; + const currentVersion = previousVersion ? bumpVersion(previousVersion, impact) : "1.0.0"; + return { + schemaVersion: "1.0.0", + currentVersion, + previousVersion, + currentContractFingerprint: current.fingerprint, + previousContractFingerprint: previous?.fingerprint ?? null, + added, + removed, + changes, + impact, + }; +} + +export function decideScopeCatalogPublication({ + eventName, + packageExists, + initialConfirmed, + release, +}) { + if (!["push", "workflow_dispatch"].includes(eventName)) { + throw new Error(`Unsupported publication event: ${eventName}`); + } + if (!["major", "minor", "patch", "none"].includes(release?.impact)) { + throw new Error(`Unsupported release impact: ${release?.impact}`); + } + if (release.impact === "none") { + return { + shouldPublish: false, + authentication: "none", + reason: "Public contract fingerprint is unchanged.", + }; + } + if (packageExists) { + if (!release.previousVersion) { + throw new Error("A published predecessor requires previousVersion"); + } + return { + shouldPublish: true, + authentication: "oidc-trusted-publishing", + reason: `Published predecessor ${release.previousVersion} exists; release impact is ${release.impact}.`, + }; + } + if (eventName === "workflow_dispatch" && initialConfirmed) { + if (release.currentVersion !== "1.0.0" || release.previousVersion !== null) { + throw new Error("Initial publication must be 1.0.0 with no previous version"); + } + return { + shouldPublish: true, + authentication: "bootstrap-token", + reason: "Initial 1.0.0 publication explicitly confirmed by Callum.", + }; + } + return { + shouldPublish: false, + authentication: "none", + reason: + "Initial package does not exist; push and unconfirmed dispatch runs validate and pack but cannot publish.", + }; +} + +function parseArgs(argv) { + const result = { currentRoot: defaultRepoRoot, previousRoot: null }; + for (let index = 0; index < argv.length; index += 1) { + const argument = argv[index]; + if (argument === "--current-package" && argv[index + 1]) { + result.currentRoot = resolve(argv[++index]); + } else if (argument === "--previous-package" && argv[index + 1]) { + result.previousRoot = resolve(argv[++index]); + } else { + throw new Error( + "Usage: node scripts/diff-scope-catalog-package.mjs [--current-package ] [--previous-package ]", + ); + } + } + return result; +} + +if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) { + try { + const { currentRoot, previousRoot } = parseArgs(process.argv.slice(2)); + const release = compareScopeCatalogContracts({ + current: readContractSnapshot(currentRoot), + previous: previousRoot ? readContractSnapshot(previousRoot) : null, + }); + process.stdout.write(`${JSON.stringify(release, null, 2)}\n`); + } catch (error) { + console.error( + `[diff-scope-catalog-package] ERROR: ${error instanceof Error ? error.message : String(error)}`, + ); + process.exit(1); + } +} diff --git a/scripts/scope-catalog-package.test.mjs b/scripts/scope-catalog-package.test.mjs new file mode 100644 index 0000000..90ce500 --- /dev/null +++ b/scripts/scope-catalog-package.test.mjs @@ -0,0 +1,760 @@ +import assert from "node:assert/strict"; +import { + cpSync, + mkdtempSync, + mkdirSync, + readFileSync, + writeFileSync, +} from "node:fs"; +import { tmpdir } from "node:os"; +import { dirname, join } from "node:path"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import test from "node:test"; + +import { buildScopeCatalogPackage } from "./build-scope-catalog-package.mjs"; +import { checkScopeCatalogPackage } from "./check-scope-catalog-package.mjs"; +import { + compareScopeCatalogContracts, + decideScopeCatalogPublication, + readContractSnapshot, +} from "./diff-scope-catalog-package.mjs"; + +const repoRoot = join(dirname(fileURLToPath(import.meta.url)), ".."); + +function writeJson(path, value) { + mkdirSync(dirname(path), { recursive: true }); + writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`); +} + +function makeContractFixture() { + const root = mkdtempSync(join(tmpdir(), "scope-catalog-package-contract-")); + writeJson(join(root, "schemas", "scope-catalog.schema.json"), { + $schema: "https://json-schema.org/draft/2020-12/schema", + type: "object", + }); + writeJson(join(root, "connectors", "alpha", "schemas", "alpha.profile.json"), { + $schema: "https://json-schema.org/draft/2020-12/schema", + scope: "alpha.profile", + type: "object", + }); + writeJson(join(root, "scope-catalog.json"), { + catalogVersion: "1.0.0", + catalogSchema: { path: "schemas/scope-catalog.schema.json" }, + distribution: { repository: "https://example.test/catalog" }, + generatedFrom: { manifests: ["connectors/alpha/alpha-playwright.json"] }, + scopes: [ + { + sourceId: "alpha", + scopeId: "alpha.profile", + description: "Alpha profile.", + schema: { path: "connectors/alpha/schemas/alpha.profile.json" }, + maturity: "beta", + fulfillment: { + desktop: { + status: "supported", + connectors: [{ id: "alpha-playwright", status: "beta" }], + }, + web: { status: "unsupported" }, + }, + }, + ], + }); + return root; +} + +function cloneFixture(root) { + const clone = mkdtempSync(join(tmpdir(), "scope-catalog-package-clone-")); + cpSync(root, clone, { recursive: true }); + return clone; +} + +function readJson(path) { + return JSON.parse(readFileSync(path, "utf8")); +} + +function compareFixtureMutation({ preparePrevious, mutateCurrent }) { + const previousRoot = makeContractFixture(); + writeJson(join(previousRoot, "package.json"), { version: "2.4.6" }); + preparePrevious?.(previousRoot); + const currentRoot = cloneFixture(previousRoot); + mutateCurrent(currentRoot); + return compareScopeCatalogContracts({ + current: readContractSnapshot(currentRoot), + previous: readContractSnapshot(previousRoot), + }); +} + +function mutateCatalog(root, mutate) { + const path = join(root, "scope-catalog.json"); + const catalog = readJson(path); + mutate(catalog); + writeJson(path, catalog); +} + +function readContractFingerprintInLocale(root, locale) { + const result = spawnSync( + process.execPath, + [ + join(repoRoot, "scripts", "diff-scope-catalog-package.mjs"), + "--current-package", + root, + ], + { + encoding: "utf8", + env: { ...process.env, LANG: locale, LC_ALL: locale }, + }, + ); + assert.equal(result.status, 0, result.stderr); + return JSON.parse(result.stdout).currentContractFingerprint; +} + +test("initial, unchanged, major, minor and patch contracts select deterministic versions", () => { + const initialRoot = makeContractFixture(); + const initial = compareScopeCatalogContracts({ + current: readContractSnapshot(initialRoot), + previous: null, + }); + assert.equal(initial.impact, "minor"); + assert.equal(initial.currentVersion, "1.0.0"); + assert.equal(initial.previousVersion, null); + assert.deepEqual(initial.added, [["alpha", "alpha.profile"]]); + + writeJson(join(initialRoot, "package.json"), { version: "2.4.6" }); + const unchangedRoot = cloneFixture(initialRoot); + const unchangedCatalog = readJson(join(unchangedRoot, "scope-catalog.json")); + unchangedCatalog.distribution.sourceCommit = "a".repeat(40); + unchangedCatalog.distribution.releaseTag = "connectors-aaaaaaaaaaaa"; + unchangedCatalog.generatedFrom.manifests = ["a-different-provenance-path.json"]; + unchangedCatalog.scopes[0].schema.url = + "https://raw.githubusercontent.com/example/repo/aaaaaaaa/schema.json"; + writeJson(join(unchangedRoot, "scope-catalog.json"), unchangedCatalog); + writeFileSync(join(unchangedRoot, "connector-implementation.js"), "changed only\n"); + const unchanged = compareScopeCatalogContracts({ + current: readContractSnapshot(unchangedRoot), + previous: readContractSnapshot(initialRoot), + }); + assert.equal(unchanged.impact, "none"); + assert.equal(unchanged.currentVersion, "2.4.6"); + + const majorRoot = cloneFixture(initialRoot); + writeJson( + join(majorRoot, "connectors", "alpha", "schemas", "alpha.profile.json"), + { scope: "alpha.profile", type: "object", required: ["id"] }, + ); + const major = compareScopeCatalogContracts({ + current: readContractSnapshot(majorRoot), + previous: readContractSnapshot(initialRoot), + }); + assert.equal(major.impact, "major"); + assert.equal(major.currentVersion, "3.0.0"); + assert.equal(major.changes[0].schema.previous.path, "connectors/alpha/schemas/alpha.profile.json"); + assert.match(major.changes[0].schema.previous.fingerprint, /^sha256:[a-f0-9]{64}$/); + assert.notEqual( + major.changes[0].schema.previous.fingerprint, + major.changes[0].schema.current.fingerprint, + ); + + const minorRoot = cloneFixture(initialRoot); + const minorCatalog = readJson(join(minorRoot, "scope-catalog.json")); + minorCatalog.scopes[0].fulfillment.web = { status: "supported" }; + writeJson(join(minorRoot, "scope-catalog.json"), minorCatalog); + const minor = compareScopeCatalogContracts({ + current: readContractSnapshot(minorRoot), + previous: readContractSnapshot(initialRoot), + }); + assert.equal(minor.impact, "minor"); + assert.equal(minor.currentVersion, "2.5.0"); + + const patchRoot = cloneFixture(initialRoot); + const patchCatalog = readJson(join(patchRoot, "scope-catalog.json")); + patchCatalog.scopes[0].description = "A clearer Alpha profile description."; + writeJson(join(patchRoot, "scope-catalog.json"), patchCatalog); + const patch = compareScopeCatalogContracts({ + current: readContractSnapshot(patchRoot), + previous: readContractSnapshot(initialRoot), + }); + assert.equal(patch.impact, "patch"); + assert.equal(patch.currentVersion, "2.4.7"); + assert.deepEqual(patch.changes, [ + { + pair: ["alpha", "alpha.profile"], + description: { + previous: "Alpha profile.", + current: "A clearer Alpha profile description.", + }, + }, + ]); +}); + +test("package build preserves package-relative paths and check rejects extra payload schemas", () => { + const packageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-output-")); + cpSync(join(repoRoot, "packages", "scope-catalog", "package.json"), join(packageRoot, "package.json")); + cpSync(join(repoRoot, "packages", "scope-catalog", "README.md"), join(packageRoot, "README.md")); + + buildScopeCatalogPackage({ repoRoot, packageRoot }); + const catalog = readJson(join(packageRoot, "scope-catalog.json")); + const release = readJson(join(packageRoot, "release.json")); + const packageJson = readJson(join(packageRoot, "package.json")); + + assert.equal(packageJson.name, "@opendatalabs/scope-catalog"); + assert.equal(packageJson.version, "1.0.0"); + assert.equal(release.currentVersion, "1.0.0"); + assert.equal(release.previousVersion, null); + assert.match(release.currentContractFingerprint, /^sha256:[a-f0-9]{64}$/); + assert.equal(catalog.catalogVersion, "1.0.0"); + for (const scope of catalog.scopes) { + assert.ok(readFileSync(join(packageRoot, scope.schema.path)).length > 0); + } + assert.doesNotThrow(() => checkScopeCatalogPackage({ repoRoot, packageRoot })); + + writeJson(join(packageRoot, "connectors", "extra", "schemas", "extra.json"), { + type: "object", + }); + assert.throws( + () => checkScopeCatalogPackage({ repoRoot, packageRoot }), + /unexpected package file: connectors\/extra\/schemas\/extra\.json/, + ); +}); + +test("conservative mechanical rules cover every major and minor contract category", () => { + const majorCases = [ + { + name: "pair removed", + mutateCurrent: (root) => mutateCatalog(root, (catalog) => catalog.scopes.pop()), + }, + { + name: "catalog-schema bytes changed", + mutateCurrent: (root) => + writeJson(join(root, "schemas", "scope-catalog.schema.json"), { + type: "object", + required: ["scopes"], + }), + }, + { + name: "Desktop connector removed", + preparePrevious: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop.connectors.push({ + id: "alpha-backup-playwright", + status: "experimental", + }); + }), + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop.connectors.pop(); + }), + }, + { + name: "Web support removed", + preparePrevious: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.web = { status: "supported" }; + }), + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.web = { status: "blocked" }; + }), + }, + { + name: "maturity decreases", + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].maturity = "experimental"; + }), + }, + { + name: "limit metadata changes", + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop.connectors[0].limits = [ + { + type: "maxItems", + value: 10, + unit: "items", + description: "At most ten items.", + }, + ]; + }), + }, + ]; + for (const fixture of majorCases) { + assert.equal(compareFixtureMutation(fixture).impact, "major", fixture.name); + } + + const minorCases = [ + { + name: "pair added", + mutateCurrent: (root) => { + writeJson(join(root, "connectors", "alpha", "schemas", "alpha.posts.json"), { + scope: "alpha.posts", + type: "array", + }); + mutateCatalog(root, (catalog) => { + catalog.scopes.push({ + ...structuredClone(catalog.scopes[0]), + scopeId: "alpha.posts", + description: "Alpha posts.", + schema: { path: "connectors/alpha/schemas/alpha.posts.json" }, + }); + }); + }, + }, + { + name: "connector added", + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop.connectors.push({ + id: "alpha-backup-playwright", + status: "experimental", + }); + }), + }, + { + name: "Desktop becomes supported with limits", + preparePrevious: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop = { + status: "unsupported", + connectors: [], + }; + }), + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop = { + status: "supported", + limits: [ + { + type: "maxItems", + value: 10, + unit: "items", + description: "At most ten items.", + }, + ], + connectors: [{ id: "alpha-playwright", status: "beta" }], + }; + }), + }, + { + name: "Web becomes supported", + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.web = { + status: "supported", + limits: [ + { + type: "maxItems", + value: 10, + unit: "items", + description: "At most ten items.", + }, + ], + }; + }), + }, + { + name: "maturity increases", + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].maturity = "stable"; + }), + }, + ]; + for (const fixture of minorCases) { + assert.equal(compareFixtureMutation(fixture).impact, "minor", fixture.name); + } + + const blockerEvidence = compareFixtureMutation({ + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.web = { + status: "blocked", + blocker: { id: "evidence-1", description: "Capture live evidence." }, + }; + }), + }); + assert.equal(blockerEvidence.impact, "patch"); +}); + +test("reordering equivalent Desktop and Web limits leaves the contract unchanged", () => { + const reordered = compareFixtureMutation({ + preparePrevious: (root) => + mutateCatalog(root, (catalog) => { + const limits = [ + { + type: "maxItems", + value: 10, + unit: "items", + description: "At most ten items.", + }, + { + type: "timeWindow", + value: 30, + unit: "days", + description: "The last thirty days.", + }, + ]; + catalog.scopes[0].fulfillment.desktop.connectors[0].limits = limits; + catalog.scopes[0].fulfillment.web = { + status: "supported", + limits: structuredClone(limits), + }; + }), + mutateCurrent: (root) => + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop.connectors[0].limits.reverse(); + catalog.scopes[0].fulfillment.web.limits.reverse(); + }), + }); + assert.equal(reordered.impact, "none"); + assert.deepEqual(reordered.changes, []); + assert.equal( + reordered.currentContractFingerprint, + reordered.previousContractFingerprint, + ); +}); + +test("contract fingerprints are identical across locale settings", () => { + const root = makeContractFixture(); + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop.connectors = [ + { id: "alpha.I", status: "beta" }, + { id: "alpha.i", status: "beta" }, + ]; + }); + + assert.equal( + readContractFingerprintInLocale(root, "en_US.UTF-8"), + readContractFingerprintInLocale(root, "tr_TR.UTF-8"), + ); +}); + +test("duplicate Desktop connector IDs are rejected deterministically", () => { + const root = makeContractFixture(); + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop.connectors = [ + { + id: "alpha-playwright", + status: "beta", + limits: [{ type: "maxItems", value: 10, unit: "items" }], + }, + { + id: "alpha-playwright", + status: "stable", + limits: [{ type: "maxItems", value: 20, unit: "items" }], + }, + ]; + }); + + function rejectionMessage() { + try { + readContractSnapshot(root); + } catch (error) { + assert.ok(error instanceof Error); + return error.message; + } + assert.fail("Expected duplicate Desktop connector IDs to be rejected"); + } + + const firstMessage = rejectionMessage(); + mutateCatalog(root, (catalog) => { + catalog.scopes[0].fulfillment.desktop.connectors.reverse(); + }); + assert.equal(rejectionMessage(), firstMessage); + assert.equal( + firstMessage, + 'Duplicate Desktop connector ID for catalog pair ["alpha","alpha.profile"]: alpha-playwright', + ); +}); + +test("later builds bump from the published package and keep a cumulative changelog", () => { + const previousRepoRoot = makeContractFixture(); + const previousPackageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-previous-")); + cpSync( + join(repoRoot, "packages", "scope-catalog", "package.json"), + join(previousPackageRoot, "package.json"), + ); + cpSync( + join(repoRoot, "packages", "scope-catalog", "README.md"), + join(previousPackageRoot, "README.md"), + ); + buildScopeCatalogPackage({ + repoRoot: previousRepoRoot, + packageRoot: previousPackageRoot, + }); + + const currentRepoRoot = cloneFixture(previousRepoRoot); + mutateCatalog(currentRepoRoot, (catalog) => { + catalog.scopes[0].description = "A clearer compatible description."; + }); + const currentPackageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-current-")); + cpSync( + join(repoRoot, "packages", "scope-catalog", "package.json"), + join(currentPackageRoot, "package.json"), + ); + cpSync( + join(repoRoot, "packages", "scope-catalog", "README.md"), + join(currentPackageRoot, "README.md"), + ); + const release = buildScopeCatalogPackage({ + repoRoot: currentRepoRoot, + packageRoot: currentPackageRoot, + previousPackageRoot, + }); + const changelog = readFileSync(join(currentPackageRoot, "CHANGELOG.md"), "utf8"); + assert.equal(release.previousVersion, "1.0.0"); + assert.equal(release.currentVersion, "1.0.1"); + assert.equal(release.impact, "patch"); + assert.ok(changelog.indexOf("All notable") < changelog.indexOf("## 1.0.1")); + assert.ok(changelog.indexOf("## 1.0.1") < changelog.indexOf("## 1.0.0")); + assert.equal(changelog.match(/^# Changelog$/gm)?.length, 1); +}); + +test("later fulfillment changes without limits round-trip through release.json", () => { + const previousRepoRoot = makeContractFixture(); + const previousPackageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-previous-")); + cpSync( + join(repoRoot, "packages", "scope-catalog", "package.json"), + join(previousPackageRoot, "package.json"), + ); + cpSync( + join(repoRoot, "packages", "scope-catalog", "README.md"), + join(previousPackageRoot, "README.md"), + ); + buildScopeCatalogPackage({ + repoRoot: previousRepoRoot, + packageRoot: previousPackageRoot, + }); + + const currentRepoRoot = cloneFixture(previousRepoRoot); + mutateCatalog(currentRepoRoot, (catalog) => { + catalog.scopes[0].fulfillment.desktop.connectors.push({ + id: "alpha-backup-playwright", + status: "experimental", + }); + catalog.scopes[0].fulfillment.web = { status: "supported" }; + }); + const currentPackageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-current-")); + cpSync( + join(repoRoot, "packages", "scope-catalog", "package.json"), + join(currentPackageRoot, "package.json"), + ); + cpSync( + join(repoRoot, "packages", "scope-catalog", "README.md"), + join(currentPackageRoot, "README.md"), + ); + buildScopeCatalogPackage({ + repoRoot: currentRepoRoot, + packageRoot: currentPackageRoot, + previousPackageRoot, + }); + + assert.doesNotThrow(() => + checkScopeCatalogPackage({ + repoRoot: currentRepoRoot, + packageRoot: currentPackageRoot, + previousPackageRoot, + }), + ); +}); + +test("publication authorization prevents initial push publication and permits later releases", () => { + const initialRelease = { + currentVersion: "1.0.0", + previousVersion: null, + impact: "minor", + }; + assert.deepEqual( + decideScopeCatalogPublication({ + eventName: "push", + packageExists: false, + initialConfirmed: false, + release: initialRelease, + }), + { + shouldPublish: false, + authentication: "none", + reason: + "Initial package does not exist; push and unconfirmed dispatch runs validate and pack but cannot publish.", + }, + ); + assert.deepEqual( + decideScopeCatalogPublication({ + eventName: "workflow_dispatch", + packageExists: false, + initialConfirmed: false, + release: initialRelease, + }), + { + shouldPublish: false, + authentication: "none", + reason: + "Initial package does not exist; push and unconfirmed dispatch runs validate and pack but cannot publish.", + }, + ); + assert.deepEqual( + decideScopeCatalogPublication({ + eventName: "workflow_dispatch", + packageExists: false, + initialConfirmed: true, + release: initialRelease, + }), + { + shouldPublish: true, + authentication: "bootstrap-token", + reason: "Initial 1.0.0 publication explicitly confirmed by Callum.", + }, + ); + assert.deepEqual( + decideScopeCatalogPublication({ + eventName: "push", + packageExists: true, + initialConfirmed: false, + release: { currentVersion: "1.0.1", previousVersion: "1.0.0", impact: "patch" }, + }), + { + shouldPublish: true, + authentication: "oidc-trusted-publishing", + reason: "Published predecessor 1.0.0 exists; release impact is patch.", + }, + ); + assert.equal( + decideScopeCatalogPublication({ + eventName: "push", + packageExists: true, + initialConfirmed: false, + release: { currentVersion: "1.0.0", previousVersion: "1.0.0", impact: "none" }, + }).shouldPublish, + false, + ); + assert.throws( + () => + decideScopeCatalogPublication({ + eventName: "workflow_dispatch", + packageExists: false, + initialConfirmed: true, + release: { currentVersion: "2.0.0", previousVersion: null, impact: "major" }, + }), + /Initial publication must be 1\.0\.0/, + ); + + const workflow = readFileSync( + join(repoRoot, ".github", "workflows", "publish-scope-catalog.yml"), + "utf8", + ); + assert.match(workflow, /workflow_dispatch:/); + assert.match(workflow, /confirmInitialPublish:/); + assert.match(workflow, /decideScopeCatalogPublication/); + assert.match(workflow, /node-version: "24\.4\.0"/); + assert.match(workflow, /npm install --global npm@11\.5\.1/); + assert.match(workflow, /Authentication: \\`\$authentication\\`/); + assert.match(workflow, /delete the NPM_TOKEN GitHub secret/); + assert.match(workflow, /npm trusted publishing must already be configured/); + assert.match(workflow, /npm publish .*--access public --provenance/); + assert.equal(workflow.match(/npm publish /g)?.length, 2); + assert.doesNotMatch(workflow, /consumer-update-prs|unity-surfaces|vana-data-app-starter/); +}); + +test("every publication requires the checked-out SHA to remain current main", () => { + const workflow = readFileSync( + join(repoRoot, ".github", "workflows", "publish-scope-catalog.yml"), + "utf8", + ); + function readPublishStep(name) { + const marker = `\n - name: ${name}`; + const start = workflow.indexOf(marker); + assert.notEqual(start, -1, `workflow must contain ${name}`); + const next = workflow.indexOf("\n - name:", start + marker.length); + return workflow.slice(start, next === -1 ? undefined : next); + } + + function readPublishScript(step) { + const runMarker = " run: |\n"; + const runStart = step.indexOf(runMarker); + assert.notEqual(runStart, -1, "publication freshness guard must run with publish"); + return step + .slice(runStart + runMarker.length) + .replace(/^ {10}/gm, "") + .replace("${{ steps.pack.outputs.tarball }}", "scope-catalog.tgz"); + } + + const initialStep = readPublishStep("Publish initial package with bootstrap token"); + const laterStep = readPublishStep("Publish later package with trusted publishing"); + const publishScripts = [readPublishScript(initialStep), readPublishScript(laterStep)]; + + function runPublishGate({ publishScript, checkedOutSha, currentMainSha }) { + const root = mkdtempSync(join(tmpdir(), "scope-catalog-publication-gate-")); + const npmCallsPath = join(root, "npm-calls"); + const summaryPath = join(root, "summary"); + writeFileSync(npmCallsPath, ""); + writeFileSync(summaryPath, ""); + const gitStub = `git() { + if [ "$*" != "ls-remote --exit-code origin refs/heads/main" ]; then + echo "unexpected git arguments: $*" >&2 + return 96 + fi + printf "%s\\trefs/heads/main\\n" "$CURRENT_MAIN_SHA" + }`; + const npmStub = 'npm() { printf "%s\\n" "$*" >> "$NPM_CALLS"; }'; + const result = spawnSync( + "bash", + ["-c", `${gitStub}\n${npmStub}\n${publishScript}`], + { + encoding: "utf8", + env: { + ...process.env, + CHECKED_OUT_SHA: checkedOutSha, + CURRENT_MAIN_SHA: currentMainSha, + GITHUB_STEP_SUMMARY: summaryPath, + NPM_CALLS: npmCallsPath, + }, + }, + ); + assert.equal(result.status, 0, result.stderr); + return { + npmCalls: readFileSync(npmCallsPath, "utf8"), + summary: readFileSync(summaryPath, "utf8"), + }; + } + + const oldSha = "1".repeat(40); + const currentSha = "2".repeat(40); + for (const publishScript of publishScripts) { + const stale = runPublishGate({ + publishScript, + checkedOutSha: oldSha, + currentMainSha: currentSha, + }); + assert.equal(stale.npmCalls, ""); + assert.match(stale.summary, /publication skipped/i); + assert.match(stale.summary, new RegExp(oldSha)); + assert.match(stale.summary, new RegExp(currentSha)); + + const current = runPublishGate({ + publishScript, + checkedOutSha: currentSha, + currentMainSha: currentSha, + }); + assert.equal( + current.npmCalls, + "publish scope-catalog.tgz --access public --provenance\n", + ); + assert.equal(current.summary, ""); + } + + assert.match( + initialStep, + /authentication == 'bootstrap-token'/, + ); + assert.match(initialStep, /github\.event_name == 'workflow_dispatch'/); + assert.match(initialStep, /inputs\.confirmInitialPublish == true/); + assert.match(initialStep, /NODE_AUTH_TOKEN: \$\{\{ secrets\.NPM_TOKEN \}\}/); + assert.match(laterStep, /authentication == 'oidc-trusted-publishing'/); + assert.doesNotMatch(laterStep, /NODE_AUTH_TOKEN|NPM_TOKEN/); + for (const step of [initialStep, laterStep]) { + assert.match(step, /CHECKED_OUT_SHA: \$\{\{ github\.sha \}\}/); + assert.doesNotMatch(step, /EVENT_NAME/); + } + assert.equal(workflow.match(/NODE_AUTH_TOKEN/g)?.length, 1); + assert.match(workflow, /concurrency:\n group: publish-scope-catalog\n cancel-in-progress: false/); +}); From d8ce04cf6191ee33b69fd03ddf3148f269c80984 Mon Sep 17 00:00:00 2001 From: callumflack Date: Mon, 13 Jul 2026 20:03:09 +1000 Subject: [PATCH 2/2] Stop tracking generated scope catalog output --- packages/scope-catalog/.gitignore | 7 + packages/scope-catalog/CHANGELOG.md | 11 - .../amazon/schemas/amazon.orders.json | 42 - .../amazon/schemas/amazon.profile.json | 16 - .../schemas/claude.conversations.json | 225 --- .../anthropic/schemas/claude.projects.json | 92 -- .../apple/schemas/icloud_notes.folders.json | 27 - .../apple/schemas/icloud_notes.notes.json | 35 - .../doordash/schemas/doordash.orders.json | 75 - .../github/schemas/github.contributions.json | 62 - .../github/schemas/github.events.json | 38 - .../github/schemas/github.history.json | 70 - .../github/schemas/github.profile.json | 67 - .../github/schemas/github.repositories.json | 36 - .../github/schemas/github.starred.json | 30 - .../google/schemas/youtube.history.json | 32 - .../google/schemas/youtube.likes.json | 31 - .../google/schemas/youtube.playlistItems.json | 44 - .../google/schemas/youtube.playlists.json | 32 - .../google/schemas/youtube.profile.json | 26 - .../google/schemas/youtube.subscriptions.json | 34 - .../google/schemas/youtube.watchLater.json | 31 - .../connectors/heb/schemas/heb.nutrition.json | 78 - .../connectors/heb/schemas/heb.orders.json | 46 - .../connectors/heb/schemas/heb.profile.json | 26 - .../schemas/linkedin.connections.json | 28 - .../linkedin/schemas/linkedin.education.json | 29 - .../linkedin/schemas/linkedin.experience.json | 29 - .../linkedin/schemas/linkedin.languages.json | 26 - .../linkedin/schemas/linkedin.profile.json | 21 - .../linkedin/schemas/linkedin.skills.json | 26 - .../meta/schemas/instagram.ads.json | 47 - .../meta/schemas/instagram.following.json | 31 - .../meta/schemas/instagram.posts.json | 41 - .../meta/schemas/instagram.profile.json | 25 - .../openai/schemas/chatgpt.conversations.json | 46 - .../openai/schemas/chatgpt.memories.json | 30 - .../oura/schemas/oura.activity.json | 49 - .../oura/schemas/oura.readiness.json | 43 - .../connectors/oura/schemas/oura.sleep.json | 69 - .../shopify/schemas/shop.orders.json | 37 - .../spotify/schemas/spotify.playlists.json | 62 - .../spotify/schemas/spotify.profile.json | 23 - .../spotify/schemas/spotify.savedTracks.json | 60 - .../uber/schemas/uber.receipts.json | 34 - .../connectors/uber/schemas/uber.trips.json | 35 - .../valve/schemas/steam.friends.json | 20 - .../connectors/valve/schemas/steam.games.json | 42 - .../valve/schemas/steam.profile.json | 24 - .../schemas/wholefoods.nutrition.json | 44 - .../wholefoods/schemas/wholefoods.orders.json | 46 - .../schemas/wholefoods.profile.json | 16 - .../{package.json => package.template.json} | 1 - packages/scope-catalog/release.json | 212 --- .../schemas/scope-catalog.schema.json | 211 --- packages/scope-catalog/scope-catalog.json | 1287 ----------------- scripts/build-scope-catalog-package.mjs | 11 +- scripts/check-scope-catalog-package.mjs | 7 +- scripts/scope-catalog-package.test.mjs | 22 +- 59 files changed, 33 insertions(+), 3914 deletions(-) create mode 100644 packages/scope-catalog/.gitignore delete mode 100644 packages/scope-catalog/CHANGELOG.md delete mode 100644 packages/scope-catalog/connectors/amazon/schemas/amazon.orders.json delete mode 100644 packages/scope-catalog/connectors/amazon/schemas/amazon.profile.json delete mode 100644 packages/scope-catalog/connectors/anthropic/schemas/claude.conversations.json delete mode 100644 packages/scope-catalog/connectors/anthropic/schemas/claude.projects.json delete mode 100644 packages/scope-catalog/connectors/apple/schemas/icloud_notes.folders.json delete mode 100644 packages/scope-catalog/connectors/apple/schemas/icloud_notes.notes.json delete mode 100644 packages/scope-catalog/connectors/doordash/schemas/doordash.orders.json delete mode 100644 packages/scope-catalog/connectors/github/schemas/github.contributions.json delete mode 100644 packages/scope-catalog/connectors/github/schemas/github.events.json delete mode 100644 packages/scope-catalog/connectors/github/schemas/github.history.json delete mode 100644 packages/scope-catalog/connectors/github/schemas/github.profile.json delete mode 100644 packages/scope-catalog/connectors/github/schemas/github.repositories.json delete mode 100644 packages/scope-catalog/connectors/github/schemas/github.starred.json delete mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.history.json delete mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.likes.json delete mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.playlistItems.json delete mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.playlists.json delete mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.profile.json delete mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.subscriptions.json delete mode 100644 packages/scope-catalog/connectors/google/schemas/youtube.watchLater.json delete mode 100644 packages/scope-catalog/connectors/heb/schemas/heb.nutrition.json delete mode 100644 packages/scope-catalog/connectors/heb/schemas/heb.orders.json delete mode 100644 packages/scope-catalog/connectors/heb/schemas/heb.profile.json delete mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.connections.json delete mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.education.json delete mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.experience.json delete mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.languages.json delete mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.profile.json delete mode 100644 packages/scope-catalog/connectors/linkedin/schemas/linkedin.skills.json delete mode 100644 packages/scope-catalog/connectors/meta/schemas/instagram.ads.json delete mode 100644 packages/scope-catalog/connectors/meta/schemas/instagram.following.json delete mode 100644 packages/scope-catalog/connectors/meta/schemas/instagram.posts.json delete mode 100644 packages/scope-catalog/connectors/meta/schemas/instagram.profile.json delete mode 100644 packages/scope-catalog/connectors/openai/schemas/chatgpt.conversations.json delete mode 100644 packages/scope-catalog/connectors/openai/schemas/chatgpt.memories.json delete mode 100644 packages/scope-catalog/connectors/oura/schemas/oura.activity.json delete mode 100644 packages/scope-catalog/connectors/oura/schemas/oura.readiness.json delete mode 100644 packages/scope-catalog/connectors/oura/schemas/oura.sleep.json delete mode 100644 packages/scope-catalog/connectors/shopify/schemas/shop.orders.json delete mode 100644 packages/scope-catalog/connectors/spotify/schemas/spotify.playlists.json delete mode 100644 packages/scope-catalog/connectors/spotify/schemas/spotify.profile.json delete mode 100644 packages/scope-catalog/connectors/spotify/schemas/spotify.savedTracks.json delete mode 100644 packages/scope-catalog/connectors/uber/schemas/uber.receipts.json delete mode 100644 packages/scope-catalog/connectors/uber/schemas/uber.trips.json delete mode 100644 packages/scope-catalog/connectors/valve/schemas/steam.friends.json delete mode 100644 packages/scope-catalog/connectors/valve/schemas/steam.games.json delete mode 100644 packages/scope-catalog/connectors/valve/schemas/steam.profile.json delete mode 100644 packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.nutrition.json delete mode 100644 packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.orders.json delete mode 100644 packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.profile.json rename packages/scope-catalog/{package.json => package.template.json} (97%) delete mode 100644 packages/scope-catalog/release.json delete mode 100644 packages/scope-catalog/schemas/scope-catalog.schema.json delete mode 100644 packages/scope-catalog/scope-catalog.json diff --git a/packages/scope-catalog/.gitignore b/packages/scope-catalog/.gitignore new file mode 100644 index 0000000..efec0a1 --- /dev/null +++ b/packages/scope-catalog/.gitignore @@ -0,0 +1,7 @@ +# Generated by `npm run scope-catalog-package:build`. +/CHANGELOG.md +/connectors/ +/package.json +/release.json +/schemas/ +/scope-catalog.json diff --git a/packages/scope-catalog/CHANGELOG.md b/packages/scope-catalog/CHANGELOG.md deleted file mode 100644 index bb451e3..0000000 --- a/packages/scope-catalog/CHANGELOG.md +++ /dev/null @@ -1,11 +0,0 @@ -# Changelog - -All notable public scope-catalog contract changes are recorded here. - -## 1.0.0 - -- Impact: minor -- Contract fingerprint: `sha256:0c1ab8a19b236cd2b1d1a6ae19a2acee53519812d1fd7b4e443cdf5f7755fb09` -- Added pairs: `amazon/amazon.orders`, `amazon/amazon.profile`, `chatgpt/chatgpt.conversations`, `chatgpt/chatgpt.memories`, `claude/claude.conversations`, `claude/claude.projects`, `doordash/doordash.orders`, `github/github.contributions`, `github/github.events`, `github/github.history`, `github/github.profile`, `github/github.repositories`, `github/github.starred`, `heb/heb.nutrition`, `heb/heb.orders`, `heb/heb.profile`, `icloud_notes/icloud_notes.folders`, `icloud_notes/icloud_notes.notes`, `instagram/instagram.ads`, `instagram/instagram.following`, `instagram/instagram.posts`, `instagram/instagram.profile`, `linkedin/linkedin.connections`, `linkedin/linkedin.education`, `linkedin/linkedin.experience`, `linkedin/linkedin.languages`, `linkedin/linkedin.profile`, `linkedin/linkedin.skills`, `oura/oura.activity`, `oura/oura.readiness`, `oura/oura.sleep`, `shop/shop.orders`, `spotify/spotify.playlists`, `spotify/spotify.profile`, `spotify/spotify.savedTracks`, `steam/steam.friends`, `steam/steam.games`, `steam/steam.profile`, `uber/uber.receipts`, `uber/uber.trips`, `wholefoods/wholefoods.nutrition`, `wholefoods/wholefoods.orders`, `wholefoods/wholefoods.profile`, `youtube/youtube.history`, `youtube/youtube.likes`, `youtube/youtube.playlistItems`, `youtube/youtube.playlists`, `youtube/youtube.profile`, `youtube/youtube.subscriptions`, `youtube/youtube.watchLater` -- Removed pairs: None -- Changed pairs: 0 diff --git a/packages/scope-catalog/connectors/amazon/schemas/amazon.orders.json b/packages/scope-catalog/connectors/amazon/schemas/amazon.orders.json deleted file mode 100644 index 19aca0e..0000000 --- a/packages/scope-catalog/connectors/amazon/schemas/amazon.orders.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "Amazon Orders", - "version": "1.0.0", - "scope": "amazon.orders", - "dialect": "json", - "description": "Amazon order history including items, prices, dates, and delivery status", - "schema": { - "type": "object", - "properties": { - "orders": { - "type": "array", - "items": { - "type": "object", - "properties": { - "orderId": { "type": "string" }, - "orderDate": { "type": "string" }, - "orderTotal": { "type": "string" }, - "deliveryStatus": { "type": "string" }, - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "url": { "type": "string" }, - "price": { "type": "string" } - }, - "required": ["name"], - "additionalProperties": false - } - } - }, - "required": ["orderId", "items"], - "additionalProperties": false - } - }, - "total": { "type": "number" } - }, - "required": ["orders", "total"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/amazon/schemas/amazon.profile.json b/packages/scope-catalog/connectors/amazon/schemas/amazon.profile.json deleted file mode 100644 index 333ddbc..0000000 --- a/packages/scope-catalog/connectors/amazon/schemas/amazon.profile.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "Amazon Profile", - "version": "1.0.0", - "scope": "amazon.profile", - "dialect": "json", - "description": "Amazon account profile information including name and Prime membership status", - "schema": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "isPrime": { "type": "boolean" } - }, - "required": ["name"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/anthropic/schemas/claude.conversations.json b/packages/scope-catalog/connectors/anthropic/schemas/claude.conversations.json deleted file mode 100644 index 130fd23..0000000 --- a/packages/scope-catalog/connectors/anthropic/schemas/claude.conversations.json +++ /dev/null @@ -1,225 +0,0 @@ -{ - "name": "Claude Conversations", - "version": "2.0.0", - "scope": "claude.conversations", - "dialect": "json", - "description": "Claude conversations including chat ids, titles, URLs, and full thread messages when the authenticated conversation API is available.", - "schema": { - "type": "object", - "properties": { - "profile": { - "type": "object", - "properties": { - "name": { - "type": [ - "string", - "null" - ], - "description": "Display name shown in the Claude user menu." - }, - "plan": { - "type": [ - "string", - "null" - ], - "description": "Current Claude plan label shown in the user menu." - } - }, - "required": [ - "name", - "plan" - ], - "additionalProperties": false - }, - "organizationId": { - "type": [ - "string", - "null" - ], - "description": "Active Claude organization id used for authenticated API requests." - }, - "conversations": { - "type": "array", - "description": "Chats collected from Claude, enriched with full thread data when possible.", - "items": { - "type": "object", - "properties": { - "id": { - "type": [ - "string", - "null" - ], - "description": "Chat identifier parsed from the sidebar route when available." - }, - "title": { - "type": "string", - "description": "Conversation title shown in the Claude sidebar." - }, - "href": { - "type": "string", - "description": "Relative Claude route for the conversation." - }, - "createdAt": { - "type": [ - "string", - "null" - ], - "description": "Conversation creation timestamp if Claude returned one." - }, - "updatedAt": { - "type": [ - "string", - "null" - ], - "description": "Conversation update timestamp if Claude returned one." - }, - "starred": { - "type": [ - "boolean", - "null" - ], - "description": "Whether Claude marked the conversation as starred, when available." - }, - "projectId": { - "type": [ - "string", - "null" - ], - "description": "Associated Claude project id, when present." - }, - "messageCount": { - "type": [ - "number", - "null" - ], - "description": "Number of messages collected for the conversation." - }, - "messages": { - "type": "array", - "description": "Thread messages collected from Claude's conversation API.", - "items": { - "type": "object", - "properties": { - "id": { - "type": [ - "string", - "null" - ], - "description": "Claude message id." - }, - "sender": { - "type": [ - "string", - "null" - ], - "description": "Message sender role, such as human or assistant." - }, - "parentId": { - "type": [ - "string", - "null" - ], - "description": "Parent message id in the conversation tree." - }, - "createdAt": { - "type": [ - "string", - "null" - ], - "description": "Message creation timestamp if available." - }, - "updatedAt": { - "type": [ - "string", - "null" - ], - "description": "Message update timestamp if available." - }, - "content": { - "type": "string", - "description": "Flattened text content extracted from the Claude message payload." - }, - "rawContent": { - "description": "Original Claude message content payload.", - "type": [ - "array", - "object", - "string", - "null" - ] - }, - "attachments": { - "type": "array", - "description": "Message attachments returned by Claude, if any.", - "items": { - "type": [ - "object", - "string" - ] - } - } - }, - "required": [ - "id", - "sender", - "parentId", - "createdAt", - "updatedAt", - "content", - "attachments" - ], - "additionalProperties": false - } - }, - "fetchError": { - "type": [ - "string", - "null" - ], - "description": "Error captured when Claude conversation detail could not be fetched." - } - }, - "required": [ - "id", - "title", - "href", - "createdAt", - "updatedAt", - "starred", - "messageCount", - "messages" - ], - "additionalProperties": false - } - }, - "total": { - "type": "number", - "description": "Number of conversations exported." - }, - "messageTotal": { - "type": "number", - "description": "Total number of messages exported across all conversations." - }, - "source": { - "type": "string", - "description": "How the data was collected for this export." - }, - "apiError": { - "type": [ - "string", - "null" - ], - "description": "Top-level API error message when Claude conversation APIs were unavailable." - } - }, - "required": [ - "profile", - "organizationId", - "conversations", - "total", - "messageTotal", - "source" - ], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/anthropic/schemas/claude.projects.json b/packages/scope-catalog/connectors/anthropic/schemas/claude.projects.json deleted file mode 100644 index 8a632d9..0000000 --- a/packages/scope-catalog/connectors/anthropic/schemas/claude.projects.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "name": "Claude Projects", - "version": "2.0.0", - "scope": "claude.projects", - "dialect": "json", - "description": "Claude projects including project ids, titles, labels, relative URLs, and project detail when the authenticated project API is available.", - "schema": { - "type": "object", - "properties": { - "profile": { - "type": "object", - "properties": { - "name": { - "type": ["string", "null"], - "description": "Display name shown in the Claude user menu." - }, - "plan": { - "type": ["string", "null"], - "description": "Current Claude plan label shown in the user menu." - } - }, - "required": ["name", "plan"], - "additionalProperties": false - }, - "organizationId": { - "type": ["string", "null"], - "description": "Active Claude organization id used for authenticated API requests." - }, - "projects": { - "type": "array", - "description": "Projects collected from Claude, enriched with project detail when possible.", - "items": { - "type": "object", - "properties": { - "id": { - "type": ["string", "null"], - "description": "Project identifier parsed from the sidebar route when available." - }, - "title": { - "type": "string", - "description": "Project title shown in the Claude sidebar." - }, - "href": { - "type": "string", - "description": "Relative Claude route for the project." - }, - "label": { - "type": ["string", "null"], - "description": "Accessible label for the project entry, if present." - }, - "createdAt": { - "type": ["string", "null"], - "description": "Project creation timestamp if Claude returned one." - }, - "updatedAt": { - "type": ["string", "null"], - "description": "Project update timestamp if Claude returned one." - }, - "archived": { - "type": ["boolean", "null"], - "description": "Whether the project appears archived." - }, - "detail": { - "description": "Raw Claude project detail payload when fetched successfully.", - "type": ["object", "array", "null"] - }, - "fetchError": { - "type": ["string", "null"], - "description": "Error captured when Claude project detail could not be fetched." - } - }, - "required": ["id", "title", "href", "label", "createdAt", "updatedAt", "archived"], - "additionalProperties": false - } - }, - "total": { - "type": "number", - "description": "Number of projects exported." - }, - "source": { - "type": "string", - "description": "How the data was collected for this export." - }, - "apiError": { - "type": ["string", "null"], - "description": "Top-level API error message when Claude project APIs were unavailable." - } - }, - "required": ["profile", "organizationId", "projects", "total", "source"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/apple/schemas/icloud_notes.folders.json b/packages/scope-catalog/connectors/apple/schemas/icloud_notes.folders.json deleted file mode 100644 index 643611a..0000000 --- a/packages/scope-catalog/connectors/apple/schemas/icloud_notes.folders.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "iCloud Notes Folders", - "version": "1.2.0", - "scope": "icloud_notes.folders", - "dialect": "json", - "description": "Folder structure used to organize iCloud Notes. Field shape reflects the data the CG-in-prod iCloud Notes script emits: one object per folder with its CloudKit recordName and display title.", - "schema": { - "type": "object", - "properties": { - "folders": { - "type": "array", - "items": { - "type": "object", - "properties": { - "recordName": { "type": "string" }, - "title": { "type": "string" } - }, - "required": ["recordName", "title"], - "additionalProperties": true - } - }, - "total": { "type": "number" } - }, - "required": ["folders"], - "additionalProperties": true - } -} diff --git a/packages/scope-catalog/connectors/apple/schemas/icloud_notes.notes.json b/packages/scope-catalog/connectors/apple/schemas/icloud_notes.notes.json deleted file mode 100644 index 9ca2cb1..0000000 --- a/packages/scope-catalog/connectors/apple/schemas/icloud_notes.notes.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "iCloud Notes", - "version": "1.2.0", - "scope": "icloud_notes.notes", - "dialect": "json", - "description": "Notes exported from iCloud. Field shape reflects the data the CG-in-prod iCloud Notes script emits: one object per note with recordName, title, snippet, folder, pin state, created/modified dates, attachment flag, and extracted text content.", - "schema": { - "type": "object", - "properties": { - "notes": { - "type": "array", - "items": { - "type": "object", - "properties": { - "recordName": { "type": "string" }, - "title": { "type": ["string", "null"] }, - "snippet": { "type": ["string", "null"] }, - "folder": { "type": ["string", "null"] }, - "isPinned": { "type": "boolean" }, - "createdDate": { "type": ["string", "null"], "format": "date-time" }, - "modifiedDate": { "type": ["string", "null"], "format": "date-time" }, - "hasAttachments": { "type": "boolean" }, - "textContent": { "type": ["string", "null"] } - }, - "required": ["recordName", "title"], - "additionalProperties": true - } - }, - "total": { "type": "number" }, - "userName": { "type": ["string", "null"] } - }, - "required": ["notes"], - "additionalProperties": true - } -} diff --git a/packages/scope-catalog/connectors/doordash/schemas/doordash.orders.json b/packages/scope-catalog/connectors/doordash/schemas/doordash.orders.json deleted file mode 100644 index 831ef27..0000000 --- a/packages/scope-catalog/connectors/doordash/schemas/doordash.orders.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "DoorDash Order History", - "version": "1.0.0", - "scope": "doordash.orders", - "dialect": "json", - "description": "DoorDash order history including restaurant names, items ordered with prices, dates, totals, delivery addresses, and delivery status", - "schema": { - "type": "object", - "properties": { - "orders": { - "type": "array", - "description": "List of DoorDash orders", - "items": { - "type": "object", - "properties": { - "orderId": { - "type": "string", - "description": "Unique identifier for the order (UUID)" - }, - "restaurant": { - "type": "string", - "description": "Name of the restaurant or store" - }, - "date": { - "type": "string", - "format": "date-time", - "description": "When the order was placed (ISO 8601)" - }, - "total": { - "type": "string", - "description": "Total amount charged for the order" - }, - "itemCount": { - "type": "string", - "description": "Number of items in the order" - }, - "items": { - "type": "array", - "description": "Individual items in the order", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the item" - }, - "quantity": { - "type": "number", - "description": "Quantity ordered" - }, - "price": { - "type": "string", - "description": "Price per item" - } - }, - "additionalProperties": true - } - }, - "status": { - "type": "string", - "description": "Delivery status (e.g., Delivered, Cancelled, Refunded)" - }, - "deliveryAddress": { - "type": "string", - "description": "Delivery address for the order" - } - }, - "additionalProperties": true - } - } - }, - "required": ["orders"], - "additionalProperties": true - } -} diff --git a/packages/scope-catalog/connectors/github/schemas/github.contributions.json b/packages/scope-catalog/connectors/github/schemas/github.contributions.json deleted file mode 100644 index 361b46d..0000000 --- a/packages/scope-catalog/connectors/github/schemas/github.contributions.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "GitHub Contributions", - "version": "1.0.0", - "scope": "github.contributions", - "dialect": "json", - "description": "GitHub contribution graph (daily commit counts for the last year) plus aggregate streak and month totals.", - "schema": { - "type": "object", - "properties": { - "totalContributionsLastYear": { "type": ["number", "null"] }, - "yearTotals": { - "type": "array", - "items": { - "type": "object", - "properties": { - "year": { "type": "number" }, - "total": { "type": "number" } - }, - "required": ["year", "total"], - "additionalProperties": false - } - }, - "days": { - "type": "array", - "items": { - "type": "object", - "properties": { - "date": { "type": "string" }, - "count": { "type": "number" }, - "level": { "type": ["number", "null"] } - }, - "required": ["date", "count"], - "additionalProperties": false - } - }, - "monthlyTotals": { - "type": "array", - "items": { - "type": "object", - "properties": { - "month": { "type": "string" }, - "count": { "type": "number" } - }, - "required": ["month", "count"], - "additionalProperties": false - } - }, - "topDay": { - "type": ["object", "null"], - "properties": { - "date": { "type": "string" }, - "count": { "type": "number" } - }, - "required": ["date", "count"], - "additionalProperties": false - }, - "fetchedAt": { "type": "string" } - }, - "required": ["days", "fetchedAt"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/github/schemas/github.events.json b/packages/scope-catalog/connectors/github/schemas/github.events.json deleted file mode 100644 index 6b2fd91..0000000 --- a/packages/scope-catalog/connectors/github/schemas/github.events.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "GitHub Activity Events", - "version": "1.0.0", - "scope": "github.events", - "dialect": "json", - "description": "Recent public activity (pushes, pull requests, issues, comments, branches, releases, stars, forks) across every repository the user has touched — including organization-owned repos invisible to github.repositories.", - "schema": { - "type": "object", - "properties": { - "events": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "type": { "type": "string" }, - "createdAt": { "type": "string" }, - "repo": { "type": "string" }, - "repoUrl": { "type": "string" }, - "action": { "type": ["string", "null"] }, - "title": { "type": ["string", "null"] }, - "body": { "type": ["string", "null"] }, - "url": { "type": ["string", "null"] }, - "branch": { "type": ["string", "null"] }, - "commits": { "type": ["number", "null"] }, - "isPublic": { "type": "boolean" } - }, - "required": ["id", "type", "createdAt", "repo", "isPublic"], - "additionalProperties": false - } - }, - "fetchedAt": { "type": "string" }, - "windowDescription": { "type": "string" } - }, - "required": ["events", "fetchedAt"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/github/schemas/github.history.json b/packages/scope-catalog/connectors/github/schemas/github.history.json deleted file mode 100644 index 0789635..0000000 --- a/packages/scope-catalog/connectors/github/schemas/github.history.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "name": "GitHub Authored History", - "version": "1.0.0", - "scope": "github.history", - "dialect": "json", - "description": "Full lifetime of pull requests and issues authored by the user, fetched via the GitHub Search API. Covers any repository the user has authored in (including organizations and forks) — far broader than the 90-day Events window. Up to 1000 items per type per query.", - "schema": { - "type": "object", - "properties": { - "pullRequests": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "type": { "type": "string" }, - "number": { "type": ["number", "null"] }, - "title": { "type": ["string", "null"] }, - "body": { "type": ["string", "null"] }, - "state": { "type": ["string", "null"] }, - "createdAt": { "type": ["string", "null"] }, - "updatedAt": { "type": ["string", "null"] }, - "closedAt": { "type": ["string", "null"] }, - "mergedAt": { "type": ["string", "null"] }, - "url": { "type": ["string", "null"] }, - "repo": { "type": "string" }, - "repoUrl": { "type": ["string", "null"] }, - "labels": { "type": "array", "items": { "type": "string" } }, - "comments": { "type": "number" }, - "reactionsTotal": { "type": "number" }, - "isDraft": { "type": "boolean" } - }, - "required": ["id", "type", "repo"], - "additionalProperties": false - } - }, - "issues": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "type": { "type": "string" }, - "number": { "type": ["number", "null"] }, - "title": { "type": ["string", "null"] }, - "body": { "type": ["string", "null"] }, - "state": { "type": ["string", "null"] }, - "createdAt": { "type": ["string", "null"] }, - "updatedAt": { "type": ["string", "null"] }, - "closedAt": { "type": ["string", "null"] }, - "mergedAt": { "type": ["string", "null"] }, - "url": { "type": ["string", "null"] }, - "repo": { "type": "string" }, - "repoUrl": { "type": ["string", "null"] }, - "labels": { "type": "array", "items": { "type": "string" } }, - "comments": { "type": "number" }, - "reactionsTotal": { "type": "number" }, - "isDraft": { "type": "boolean" } - }, - "required": ["id", "type", "repo"], - "additionalProperties": false - } - }, - "fetchedAt": { "type": "string" }, - "windowDescription": { "type": "string" } - }, - "required": ["pullRequests", "issues", "fetchedAt"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/github/schemas/github.profile.json b/packages/scope-catalog/connectors/github/schemas/github.profile.json deleted file mode 100644 index f784250..0000000 --- a/packages/scope-catalog/connectors/github/schemas/github.profile.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "GitHub Profile", - "version": "1.1.0", - "scope": "github.profile", - "dialect": "json", - "description": "GitHub user profile information, including pinned repositories, organization memberships, and achievement badges", - "schema": { - "type": "object", - "properties": { - "username": { "type": "string" }, - "fullName": { "type": "string" }, - "bio": { "type": "string" }, - "company": { "type": "string" }, - "location": { "type": "string" }, - "website": { "type": "string" }, - "avatarUrl": { "type": "string" }, - "followers": { "type": "number" }, - "following": { "type": "number" }, - "repositoryCount": { "type": "number" }, - "profileUrl": { "type": "string" }, - "pinnedRepositories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fullName": { "type": "string" }, - "url": { "type": ["string", "null"] }, - "description": { "type": "string" }, - "language": { "type": ["string", "null"] }, - "stars": { "type": "number" } - }, - "required": ["fullName"], - "additionalProperties": false - } - }, - "organizations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "login": { "type": "string" }, - "label": { "type": "string" }, - "url": { "type": "string" }, - "avatarUrl": { "type": ["string", "null"] } - }, - "required": ["login"], - "additionalProperties": false - } - }, - "achievements": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "iconUrl": { "type": ["string", "null"] } - }, - "required": ["name"], - "additionalProperties": false - } - }, - "contributionsLastYear": { "type": ["number", "null"] } - }, - "required": ["username", "profileUrl"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/github/schemas/github.repositories.json b/packages/scope-catalog/connectors/github/schemas/github.repositories.json deleted file mode 100644 index 9e80ca4..0000000 --- a/packages/scope-catalog/connectors/github/schemas/github.repositories.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "GitHub Repositories", - "version": "1.0.0", - "scope": "github.repositories", - "dialect": "json", - "description": "GitHub repositories visible in the user's repositories tab", - "schema": { - "type": "object", - "properties": { - "repositories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "url": { "type": "string" }, - "description": { "type": "string" }, - "language": { "type": "string" }, - "stars": { "type": "number" }, - "forks": { "type": "number" }, - "visibility": { "type": "string" }, - "topics": { - "type": "array", - "items": { "type": "string" } - }, - "updatedAt": { "type": ["string", "null"] } - }, - "required": ["name", "url"], - "additionalProperties": false - } - } - }, - "required": ["repositories"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/github/schemas/github.starred.json b/packages/scope-catalog/connectors/github/schemas/github.starred.json deleted file mode 100644 index edc061b..0000000 --- a/packages/scope-catalog/connectors/github/schemas/github.starred.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "GitHub Starred Repositories", - "version": "1.0.0", - "scope": "github.starred", - "dialect": "json", - "description": "GitHub repositories starred by the user", - "schema": { - "type": "object", - "properties": { - "starred": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fullName": { "type": "string" }, - "url": { "type": "string" }, - "description": { "type": "string" }, - "language": { "type": "string" }, - "stars": { "type": "number" }, - "updatedAt": { "type": ["string", "null"] } - }, - "required": ["fullName", "url"], - "additionalProperties": false - } - } - }, - "required": ["starred"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.history.json b/packages/scope-catalog/connectors/google/schemas/youtube.history.json deleted file mode 100644 index fbd1087..0000000 --- a/packages/scope-catalog/connectors/google/schemas/youtube.history.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "YouTube Watch History (Recent)", - "version": "1.0.0", - "scope": "youtube.history", - "dialect": "json", - "description": "Most recent watch history entries (top 50) collected from the YouTube History page.", - "schema": { - "type": "object", - "properties": { - "timeWindow": { "type": "string" }, - "history": { - "type": "array", - "items": { - "type": "object", - "properties": { - "watchedAtText": { "type": ["string", "null"], "description": "Section date header e.g. Today, Yesterday, Jan 23 2026" }, - "videoId": { "type": ["string", "null"] }, - "videoUrl": { "type": "string" }, - "videoTitle": { "type": ["string", "null"] }, - "channelTitle": { "type": ["string", "null"] }, - "views": { "type": ["string", "null"], "description": "Raw view count text e.g. '97k views'" }, - "description": { "type": ["string", "null"], "description": "Short video description snippet shown in history" } - }, - "required": ["videoUrl"], - "additionalProperties": false - } - } - }, - "required": ["timeWindow", "history"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.likes.json b/packages/scope-catalog/connectors/google/schemas/youtube.likes.json deleted file mode 100644 index 43fc8e8..0000000 --- a/packages/scope-catalog/connectors/google/schemas/youtube.likes.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "YouTube Liked Videos", - "version": "1.0.0", - "scope": "youtube.likes", - "dialect": "json", - "description": "Videos liked by the user (Liked videos).", - "schema": { - "type": "object", - "properties": { - "likedVideos": { - "type": "array", - "items": { - "type": "object", - "properties": { - "videoId": { "type": ["string", "null"] }, - "videoUrl": { "type": "string" }, - "videoTitle": { "type": "string" }, - "channelTitle": { "type": ["string", "null"] }, - "channelUrl": { "type": ["string", "null"] }, - "durationText": { "type": ["string", "null"] }, - "thumbnailUrl": { "type": ["string", "null"] } - }, - "required": ["videoUrl", "videoTitle"], - "additionalProperties": false - } - } - }, - "required": ["likedVideos"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.playlistItems.json b/packages/scope-catalog/connectors/google/schemas/youtube.playlistItems.json deleted file mode 100644 index 8bfd5c6..0000000 --- a/packages/scope-catalog/connectors/google/schemas/youtube.playlistItems.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "YouTube Playlist Items", - "version": "1.0.0", - "scope": "youtube.playlistItems", - "dialect": "json", - "description": "Videos inside user playlists, including video titles and URLs.", - "schema": { - "type": "object", - "properties": { - "playlists": { - "type": "array", - "items": { - "type": "object", - "properties": { - "playlistId": { "type": "string" }, - "playlistTitle": { "type": ["string", "null"] }, - "playlistUrl": { "type": ["string", "null"] }, - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "videoId": { "type": ["string", "null"] }, - "videoUrl": { "type": "string" }, - "videoTitle": { "type": "string" }, - "channelTitle": { "type": ["string", "null"] }, - "channelUrl": { "type": ["string", "null"] }, - "durationText": { "type": ["string", "null"] }, - "thumbnailUrl": { "type": ["string", "null"] } - }, - "required": ["videoUrl", "videoTitle"], - "additionalProperties": false - } - } - }, - "required": ["playlistId", "items"], - "additionalProperties": false - } - } - }, - "required": ["playlists"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.playlists.json b/packages/scope-catalog/connectors/google/schemas/youtube.playlists.json deleted file mode 100644 index 04c2fff..0000000 --- a/packages/scope-catalog/connectors/google/schemas/youtube.playlists.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "YouTube Playlists", - "version": "1.0.0", - "scope": "youtube.playlists", - "dialect": "json", - "description": "User-created playlists (excludes Liked Videos and Watch Later).", - "schema": { - "type": "object", - "properties": { - "playlists": { - "type": "array", - "items": { - "type": "object", - "properties": { - "playlistId": { "type": "string" }, - "url": { "type": "string" }, - "title": { "type": ["string", "null"] }, - "owner": { "type": ["string", "null"], "description": "Display name of playlist owner" }, - "ownerUrl": { "type": ["string", "null"], "description": "Channel URL of owner" }, - "privacy": { "type": ["string", "null"], "enum": ["Public", "Private", "Unlisted", null] }, - "videoCount": { "type": ["number", "null"] }, - "views": { "type": ["number", "null"], "description": "0 for 'No views'" } - }, - "required": ["playlistId", "url"], - "additionalProperties": false - } - } - }, - "required": ["playlists"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.profile.json b/packages/scope-catalog/connectors/google/schemas/youtube.profile.json deleted file mode 100644 index b52fbb0..0000000 --- a/packages/scope-catalog/connectors/google/schemas/youtube.profile.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "YouTube Profile", - "version": "1.0.0", - "scope": "youtube.profile", - "dialect": "json", - "description": "Basic YouTube profile information including email, channel URL, handle, and joined date.", - "schema": { - "type": "object", - "properties": { - "email": { "type": ["string", "null"] }, - "channelUrl": { "type": ["string", "null"] }, - "handle": { "type": ["string", "null"] }, - "joinedDate": { "type": ["string", "null"] }, - "channelTitle": { "type": ["string", "null"] }, - "channelId": { "type": ["string", "null"] }, - "avatarUrl": { "type": ["string", "null"] }, - "description": { "type": ["string", "null"] }, - "country": { "type": ["string", "null"] }, - "subscriberCount": { "type": ["number", "null"] }, - "viewCount": { "type": ["number", "null"] }, - "videoCount": { "type": ["number", "null"] } - }, - "required": [], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.subscriptions.json b/packages/scope-catalog/connectors/google/schemas/youtube.subscriptions.json deleted file mode 100644 index ad3200b..0000000 --- a/packages/scope-catalog/connectors/google/schemas/youtube.subscriptions.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "YouTube Subscriptions", - "version": "1.0.0", - "scope": "youtube.subscriptions", - "dialect": "json", - "description": "Channels the user is subscribed to.", - "schema": { - "type": "object", - "properties": { - "subscriptions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "channelTitle": { "type": "string" }, - "channelUrl": { "type": "string" }, - "handle": { "type": ["string", "null"] }, - "channelId": { "type": ["string", "null"] }, - "avatarUrl": { "type": ["string", "null"] }, - "subscriberCountText": { "type": ["string", "null"], "description": "Raw text e.g. '5.3m subscribers'" }, - "subscriberCount": { "type": ["number", "null"], "description": "Parsed integer subscriber count" }, - "description": { "type": ["string", "null"] }, - "isVerified": { "type": "boolean" }, - "isBellNotification": { "type": "boolean", "description": "True when 'All notifications' bell is active" } - }, - "required": ["channelTitle", "channelUrl"], - "additionalProperties": false - } - } - }, - "required": ["subscriptions"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/google/schemas/youtube.watchLater.json b/packages/scope-catalog/connectors/google/schemas/youtube.watchLater.json deleted file mode 100644 index 81d7255..0000000 --- a/packages/scope-catalog/connectors/google/schemas/youtube.watchLater.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "YouTube Watch Later", - "version": "1.0.0", - "scope": "youtube.watchLater", - "dialect": "json", - "description": "Videos saved to Watch Later.", - "schema": { - "type": "object", - "properties": { - "watchLater": { - "type": "array", - "items": { - "type": "object", - "properties": { - "videoId": { "type": ["string", "null"] }, - "videoUrl": { "type": "string" }, - "videoTitle": { "type": "string" }, - "channelTitle": { "type": ["string", "null"] }, - "channelUrl": { "type": ["string", "null"] }, - "durationText": { "type": ["string", "null"] }, - "thumbnailUrl": { "type": ["string", "null"] } - }, - "required": ["videoUrl", "videoTitle"], - "additionalProperties": false - } - } - }, - "required": ["watchLater"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/heb/schemas/heb.nutrition.json b/packages/scope-catalog/connectors/heb/schemas/heb.nutrition.json deleted file mode 100644 index 403aa4f..0000000 --- a/packages/scope-catalog/connectors/heb/schemas/heb.nutrition.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "name": "H-E-B Nutrition", - "version": "1.0.0", - "scope": "heb.nutrition", - "dialect": "json", - "description": "Nutrition facts per product ordered from H-E-B, including macros, micronutrients, ingredients, and allergens", - "schema": { - "type": "object", - "properties": { - "items": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "source": { "type": "string", "enum": ["heb_product_page", "usda_fdc", "not_found", "error", "blocked"] }, - "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, - "calories": { "type": ["number", "null"] }, - "protein_g": { "type": ["number", "null"] }, - "carbs_g": { "type": ["number", "null"] }, - "fat_g": { "type": ["number", "null"] }, - "sodium_mg": { "type": ["number", "null"] }, - "fiber_g": { "type": ["number", "null"] }, - "sugar_g": { "type": ["number", "null"] }, - "saturated_fat_g": { "type": ["number", "null"] }, - "trans_fat_g": { "type": ["number", "null"] }, - "cholesterol_mg": { "type": ["number", "null"] }, - "added_sugar_g": { "type": ["number", "null"] }, - "calcium_mg": { "type": ["number", "null"] }, - "iron_mg": { "type": ["number", "null"] }, - "potassium_mg": { "type": ["number", "null"] }, - "vitamin_d_mcg": { "type": ["number", "null"] }, - "servingSize": { "type": ["string", "null"] }, - "servingsPerContainer": { "type": ["string", "null"] }, - "upc": { "type": ["string", "null"] }, - "ingredients": { "type": ["string", "null"] }, - "allergens": { "type": ["string", "null"] }, - "category": { - "oneOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } }, - { "type": "null" } - ] - }, - "highlights": { - "type": ["array", "null"], - "items": { "type": "string" } - }, - "images": { - "oneOf": [ - { "type": "string" }, - { - "type": "object", - "properties": { - "full": { "type": "string" }, - "thumbnail": { "type": "string" } - } - }, - { "type": "null" } - ] - } - }, - "required": ["name", "source"] - } - }, - "coverage": { - "type": "object", - "properties": { - "total": { "type": "number" }, - "found": { "type": "number" }, - "foundUSDA": { "type": "number" }, - "percentCovered": { "type": "number" } - } - } - }, - "required": ["items", "coverage"] - } -} diff --git a/packages/scope-catalog/connectors/heb/schemas/heb.orders.json b/packages/scope-catalog/connectors/heb/schemas/heb.orders.json deleted file mode 100644 index b5f2502..0000000 --- a/packages/scope-catalog/connectors/heb/schemas/heb.orders.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "H-E-B Orders", - "version": "1.0.0", - "scope": "heb.orders", - "dialect": "json", - "description": "H-E-B curbside and delivery order history with item details", - "schema": { - "type": "object", - "properties": { - "orders": { - "type": "array", - "items": { - "type": "object", - "properties": { - "orderId": { "type": "string" }, - "orderUrl": { "type": "string" }, - "orderDate": { "type": ["string", "null"] }, - "total": { "type": ["number", "null"] }, - "itemCount": { "type": ["number", "null"] }, - "status": { "type": ["string", "null"] }, - "address": { "type": ["string", "null"] }, - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "productId": { "type": "string" }, - "productUrl": { "type": ["string", "null"] }, - "imageUrl": { "type": ["string", "null"] }, - "quantity": { "type": ["string", "null"] }, - "price": { "type": ["number", "null"] } - }, - "required": ["name", "productId"] - } - } - }, - "required": ["orderId", "items"] - } - }, - "totalOrders": { "type": "number" }, - "totalItems": { "type": "number" } - }, - "required": ["orders", "totalOrders", "totalItems"] - } -} diff --git a/packages/scope-catalog/connectors/heb/schemas/heb.profile.json b/packages/scope-catalog/connectors/heb/schemas/heb.profile.json deleted file mode 100644 index 11de11b..0000000 --- a/packages/scope-catalog/connectors/heb/schemas/heb.profile.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "H-E-B Profile", - "version": "1.0.0", - "scope": "heb.profile", - "dialect": "json", - "description": "H-E-B account profile including name, email, phone, and delivery addresses", - "schema": { - "type": "object", - "properties": { - "name": { "type": ["string", "null"] }, - "email": { "type": ["string", "null"] }, - "phone": { "type": ["string", "null"] }, - "deliveryAddresses": { - "type": "array", - "items": { - "type": "object", - "properties": { - "address": { "type": "string" }, - "label": { "type": ["string", "null"] }, - "isPrimary": { "type": "boolean" } - } - } - } - } - } -} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.connections.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.connections.json deleted file mode 100644 index 9ab5ad4..0000000 --- a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.connections.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "LinkedIn Connections", - "version": "1.0.0", - "scope": "linkedin.connections", - "dialect": "json", - "description": "LinkedIn connections with names, headlines, profile URLs, and date connected", - "schema": { - "type": "object", - "properties": { - "connections": { - "type": "array", - "items": { - "type": "object", - "properties": { - "fullName": { "type": "string" }, - "headline": { "type": "string" }, - "profileUrl": { "type": "string" }, - "dateConnected": { "type": "string" } - }, - "required": ["fullName", "headline", "profileUrl", "dateConnected"], - "additionalProperties": false - } - } - }, - "required": ["connections"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.education.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.education.json deleted file mode 100644 index ca5b76b..0000000 --- a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.education.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "LinkedIn Education", - "version": "1.0.0", - "scope": "linkedin.education", - "dialect": "json", - "description": "LinkedIn education history including schools, degrees, years, grades, and logos", - "schema": { - "type": "object", - "properties": { - "education": { - "type": "array", - "items": { - "type": "object", - "properties": { - "schoolName": { "type": "string" }, - "degree": { "type": "string" }, - "years": { "type": "string" }, - "grade": { "type": "string" }, - "logoUrl": { "type": "string" } - }, - "required": ["schoolName", "degree", "years", "grade", "logoUrl"], - "additionalProperties": false - } - } - }, - "required": ["education"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.experience.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.experience.json deleted file mode 100644 index 4ec0bf6..0000000 --- a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.experience.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "LinkedIn Experience", - "version": "1.0.0", - "scope": "linkedin.experience", - "dialect": "json", - "description": "LinkedIn work experience including job titles, companies, dates, locations, and descriptions", - "schema": { - "type": "object", - "properties": { - "experiences": { - "type": "array", - "items": { - "type": "object", - "properties": { - "jobTitle": { "type": "string" }, - "companyName": { "type": "string" }, - "dates": { "type": "string" }, - "location": { "type": "string" }, - "description": { "type": "string" } - }, - "required": ["jobTitle", "companyName", "dates", "location", "description"], - "additionalProperties": false - } - } - }, - "required": ["experiences"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.languages.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.languages.json deleted file mode 100644 index 8003db8..0000000 --- a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.languages.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "LinkedIn Languages", - "version": "1.0.0", - "scope": "linkedin.languages", - "dialect": "json", - "description": "LinkedIn languages with proficiency levels", - "schema": { - "type": "object", - "properties": { - "languages": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "proficiency": { "type": "string" } - }, - "required": ["name", "proficiency"], - "additionalProperties": false - } - } - }, - "required": ["languages"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.profile.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.profile.json deleted file mode 100644 index 8bbf790..0000000 --- a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.profile.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "LinkedIn Profile", - "version": "1.0.0", - "scope": "linkedin.profile", - "dialect": "json", - "description": "LinkedIn profile including name, headline, location, about, connections count, and profile picture", - "schema": { - "type": "object", - "properties": { - "profileUrl": { "type": "string" }, - "fullName": { "type": "string" }, - "headline": { "type": "string" }, - "location": { "type": "string" }, - "connections": { "type": "string" }, - "profilePictureUrl": { "type": "string" }, - "about": { "type": "string" } - }, - "required": ["profileUrl", "fullName", "headline", "location", "connections", "profilePictureUrl", "about"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.skills.json b/packages/scope-catalog/connectors/linkedin/schemas/linkedin.skills.json deleted file mode 100644 index a48de00..0000000 --- a/packages/scope-catalog/connectors/linkedin/schemas/linkedin.skills.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "LinkedIn Skills", - "version": "1.0.0", - "scope": "linkedin.skills", - "dialect": "json", - "description": "LinkedIn skills with endorsement counts", - "schema": { - "type": "object", - "properties": { - "skills": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "endorsements": { "type": "string" } - }, - "required": ["name", "endorsements"], - "additionalProperties": false - } - } - }, - "required": ["skills"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/meta/schemas/instagram.ads.json b/packages/scope-catalog/connectors/meta/schemas/instagram.ads.json deleted file mode 100644 index 9b0838e..0000000 --- a/packages/scope-catalog/connectors/meta/schemas/instagram.ads.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "Instagram Ad Interests", - "version": "1.0.0", - "scope": "instagram.ads", - "dialect": "json", - "description": "Advertisers the user has seen ads from, ad topic interests, and targeting categories based on their Instagram activity", - "schema": { - "type": "object", - "properties": { - "advertisers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" } - }, - "required": ["name"], - "additionalProperties": false - } - }, - "ad_topics": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" } - }, - "required": ["name"], - "additionalProperties": false - } - }, - "categories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "description": { "type": ["string", "null"] } - }, - "required": ["name"] - } - } - }, - "required": ["advertisers", "ad_topics"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/meta/schemas/instagram.following.json b/packages/scope-catalog/connectors/meta/schemas/instagram.following.json deleted file mode 100644 index ad7a39d..0000000 --- a/packages/scope-catalog/connectors/meta/schemas/instagram.following.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "Instagram Following", - "version": "1.0.0", - "scope": "instagram.following", - "dialect": "json", - "description": "The list of Instagram accounts the user follows, as returned by the Instagram friendships/following endpoint.", - "schema": { - "type": "object", - "properties": { - "accounts": { - "type": "array", - "items": { - "type": "object", - "properties": { - "username": { "type": "string" }, - "full_name": { "type": "string" }, - "pk": { "type": "string" }, - "is_private": { "type": "boolean" }, - "is_verified": { "type": "boolean" }, - "profile_pic_url": { "type": ["string", "null"] } - }, - "required": ["username"], - "additionalProperties": false - } - }, - "total": { "type": "number" } - }, - "required": ["accounts"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/meta/schemas/instagram.posts.json b/packages/scope-catalog/connectors/meta/schemas/instagram.posts.json deleted file mode 100644 index 6b28a92..0000000 --- a/packages/scope-catalog/connectors/meta/schemas/instagram.posts.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "Instagram Posts", - "version": "2.0.0", - "scope": "instagram.posts", - "dialect": "json", - "description": "User's Instagram posts including images, captions, and like engagement data", - "schema": { - "type": "object", - "properties": { - "posts": { - "type": "array", - "items": { - "type": "object", - "properties": { - "img_url": { "type": "string" }, - "caption": { "type": "string" }, - "num_of_likes": { "type": "number" }, - "taken_at": { "type": "string" }, - "who_liked": { - "type": "array", - "items": { - "type": "object", - "properties": { - "profile_pic_url": { "type": "string" }, - "pk": { "type": "string" }, - "username": { "type": "string" }, - "id": { "type": "string" } - }, - "additionalProperties": false - } - } - }, - "required": ["img_url", "caption", "num_of_likes"], - "additionalProperties": false - } - } - }, - "required": ["posts"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/meta/schemas/instagram.profile.json b/packages/scope-catalog/connectors/meta/schemas/instagram.profile.json deleted file mode 100644 index 274bdff..0000000 --- a/packages/scope-catalog/connectors/meta/schemas/instagram.profile.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "Instagram Profile", - "version": "2.0.0", - "scope": "instagram.profile", - "dialect": "json", - "description": "Basic Instagram profile information including username, bio, and follower counts", - "schema": { - "type": "object", - "properties": { - "username": { "type": "string" }, - "full_name": { "type": "string" }, - "bio": { "type": "string" }, - "profile_pic_url": { "type": "string" }, - "external_url": { "type": "string" }, - "follower_count": { "type": "number" }, - "following_count": { "type": "number" }, - "media_count": { "type": "number" }, - "is_private": { "type": "boolean" }, - "is_verified": { "type": "boolean" }, - "is_business": { "type": "boolean" } - }, - "required": ["username", "full_name"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/openai/schemas/chatgpt.conversations.json b/packages/scope-catalog/connectors/openai/schemas/chatgpt.conversations.json deleted file mode 100644 index 2c8bb33..0000000 --- a/packages/scope-catalog/connectors/openai/schemas/chatgpt.conversations.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "ChatGPT Conversations", - "version": "2.0.0", - "scope": "chatgpt.conversations", - "dialect": "json", - "description": "Conversation history from ChatGPT including full message threads with user and assistant messages", - "schema": { - "type": "object", - "properties": { - "conversations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "create_time": { "type": "string" }, - "update_time": { "type": "string" }, - "message_count": { "type": "number" }, - "messages": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "role": { "type": "string" }, - "content": { "type": "string" }, - "content_type": { "type": "string" }, - "create_time": { "type": ["string", "null"] }, - "model": { "type": ["string", "null"] } - }, - "required": ["id", "role", "content"], - "additionalProperties": false - } - } - }, - "required": ["id", "title", "create_time", "update_time", "message_count", "messages"], - "additionalProperties": false - } - }, - "total": { "type": "number" } - }, - "required": ["conversations", "total"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/openai/schemas/chatgpt.memories.json b/packages/scope-catalog/connectors/openai/schemas/chatgpt.memories.json deleted file mode 100644 index 76bca75..0000000 --- a/packages/scope-catalog/connectors/openai/schemas/chatgpt.memories.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "ChatGPT Memories", - "version": "2.0.0", - "scope": "chatgpt.memories", - "dialect": "json", - "description": "Saved memories from ChatGPT including user preferences and context the model remembers", - "schema": { - "type": "object", - "properties": { - "memories": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "content": { "type": "string" }, - "created_at": { "type": "string" }, - "updated_at": { "type": "string" }, - "type": { "type": "string" } - }, - "required": ["id", "content", "created_at"], - "additionalProperties": false - } - }, - "total": { "type": "number" } - }, - "required": ["memories", "total"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/oura/schemas/oura.activity.json b/packages/scope-catalog/connectors/oura/schemas/oura.activity.json deleted file mode 100644 index b3fddd2..0000000 --- a/packages/scope-catalog/connectors/oura/schemas/oura.activity.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "Oura Activity", - "version": "1.0.0", - "scope": "oura.activity", - "dialect": "json", - "description": "Daily activity data from Oura Ring including activity scores, step counts, calorie expenditure, and time spent at different activity levels.", - "schema": { - "type": "object", - "properties": { - "days": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "day": { "type": "string", "format": "date", "description": "Date in YYYY-MM-DD format" }, - "score": { "type": ["integer", "null"], "minimum": 0, "maximum": 100, "description": "Overall activity score (0-100)" }, - "timestamp": { "type": "string", "format": "date-time" }, - "activeCalories": { "type": ["integer", "null"], "description": "Calories burned through activity" }, - "totalCalories": { "type": ["integer", "null"], "description": "Total calories burned including BMR" }, - "steps": { "type": ["integer", "null"], "description": "Total step count" }, - "equivalentWalkingDistance": { "type": ["integer", "null"], "description": "Equivalent walking distance in meters" }, - "highActivityTime": { "type": ["integer", "null"], "description": "Time in high activity in seconds" }, - "mediumActivityTime": { "type": ["integer", "null"], "description": "Time in medium activity in seconds" }, - "lowActivityTime": { "type": ["integer", "null"], "description": "Time in low activity in seconds" }, - "sedentaryTime": { "type": ["integer", "null"], "description": "Sedentary time in seconds" }, - "restingTime": { "type": ["integer", "null"], "description": "Resting time in seconds" }, - "inactivityAlerts": { "type": ["integer", "null"], "description": "Number of inactivity alerts received" }, - "contributors": { - "type": "object", - "properties": { - "meet_daily_targets": { "type": ["integer", "null"], "description": "Meeting daily targets score (0-100)" }, - "move_every_hour": { "type": ["integer", "null"], "description": "Hourly movement score (0-100)" }, - "recovery_time": { "type": ["integer", "null"], "description": "Recovery time score (0-100)" }, - "stay_active": { "type": ["integer", "null"], "description": "Stay active score (0-100)" }, - "training_frequency": { "type": ["integer", "null"], "description": "Training frequency score (0-100)" }, - "training_volume": { "type": ["integer", "null"], "description": "Training volume score (0-100)" } - }, - "additionalProperties": true - } - }, - "required": ["day", "score"] - } - } - }, - "required": ["days"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/oura/schemas/oura.readiness.json b/packages/scope-catalog/connectors/oura/schemas/oura.readiness.json deleted file mode 100644 index 64ce099..0000000 --- a/packages/scope-catalog/connectors/oura/schemas/oura.readiness.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "Oura Readiness", - "version": "1.0.0", - "scope": "oura.readiness", - "dialect": "json", - "description": "Daily readiness scores from Oura Ring, including overall score and contributing factors like HRV balance, resting heart rate, recovery index, and body temperature.", - "schema": { - "type": "object", - "properties": { - "days": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "day": { "type": "string", "format": "date", "description": "Date in YYYY-MM-DD format" }, - "score": { "type": ["integer", "null"], "minimum": 0, "maximum": 100, "description": "Overall readiness score (0-100)" }, - "timestamp": { "type": "string", "format": "date-time" }, - "temperatureDeviation": { "type": ["number", "null"], "description": "Body temperature deviation from baseline in degrees Celsius" }, - "temperatureTrendDeviation": { "type": ["number", "null"], "description": "Temperature trend deviation from baseline" }, - "contributors": { - "type": "object", - "properties": { - "activity_balance": { "type": ["integer", "null"], "description": "Activity balance contributor score (0-100)" }, - "body_temperature": { "type": ["integer", "null"], "description": "Body temperature contributor score (0-100)" }, - "hrv_balance": { "type": ["integer", "null"], "description": "HRV balance contributor score (0-100)" }, - "previous_day_activity": { "type": ["integer", "null"], "description": "Previous day activity contributor score (0-100)" }, - "previous_night": { "type": ["integer", "null"], "description": "Previous night sleep contributor score (0-100)" }, - "recovery_index": { "type": ["integer", "null"], "description": "Recovery index contributor score (0-100)" }, - "resting_heart_rate": { "type": ["integer", "null"], "description": "Resting heart rate contributor score (0-100)" }, - "sleep_balance": { "type": ["integer", "null"], "description": "Sleep balance contributor score (0-100)" } - }, - "additionalProperties": true - } - }, - "required": ["day", "score"] - } - } - }, - "required": ["days"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/oura/schemas/oura.sleep.json b/packages/scope-catalog/connectors/oura/schemas/oura.sleep.json deleted file mode 100644 index e8ae730..0000000 --- a/packages/scope-catalog/connectors/oura/schemas/oura.sleep.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "Oura Sleep", - "version": "1.0.0", - "scope": "oura.sleep", - "dialect": "json", - "description": "Sleep data from Oura Ring including daily sleep scores with contributor breakdowns and detailed sleep period data with durations, stages, heart rate, and HRV.", - "schema": { - "type": "object", - "properties": { - "dailyScores": { - "type": "array", - "description": "Daily sleep score summaries", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "day": { "type": "string", "format": "date", "description": "Date in YYYY-MM-DD format" }, - "score": { "type": ["integer", "null"], "minimum": 0, "maximum": 100, "description": "Overall sleep score (0-100)" }, - "timestamp": { "type": "string", "format": "date-time" }, - "contributors": { - "type": "object", - "properties": { - "deep_sleep": { "type": ["integer", "null"], "description": "Deep sleep contributor score (0-100)" }, - "efficiency": { "type": ["integer", "null"], "description": "Sleep efficiency contributor score (0-100)" }, - "latency": { "type": ["integer", "null"], "description": "Sleep latency contributor score (0-100)" }, - "rem_sleep": { "type": ["integer", "null"], "description": "REM sleep contributor score (0-100)" }, - "restfulness": { "type": ["integer", "null"], "description": "Restfulness contributor score (0-100)" }, - "timing": { "type": ["integer", "null"], "description": "Sleep timing contributor score (0-100)" }, - "total_sleep": { "type": ["integer", "null"], "description": "Total sleep contributor score (0-100)" } - }, - "additionalProperties": true - } - }, - "required": ["day", "score"] - } - }, - "sleepPeriods": { - "type": "array", - "description": "Detailed sleep period records", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "day": { "type": "string", "format": "date", "description": "Date in YYYY-MM-DD format" }, - "type": { "type": "string", "enum": ["long_sleep", "short_sleep", "rest"], "description": "Type of sleep period" }, - "bedtimeStart": { "type": ["string", "null"], "format": "date-time", "description": "Bedtime start in ISO 8601" }, - "bedtimeEnd": { "type": ["string", "null"], "format": "date-time", "description": "Bedtime end in ISO 8601" }, - "totalSleepDuration": { "type": ["integer", "null"], "description": "Total sleep duration in seconds" }, - "timeInBed": { "type": ["integer", "null"], "description": "Total time in bed in seconds" }, - "deepSleepDuration": { "type": ["integer", "null"], "description": "Deep sleep duration in seconds" }, - "lightSleepDuration": { "type": ["integer", "null"], "description": "Light sleep duration in seconds" }, - "remSleepDuration": { "type": ["integer", "null"], "description": "REM sleep duration in seconds" }, - "awakeTime": { "type": ["integer", "null"], "description": "Awake time during sleep in seconds" }, - "efficiency": { "type": ["integer", "null"], "description": "Sleep efficiency percentage" }, - "latency": { "type": ["integer", "null"], "description": "Sleep onset latency in seconds" }, - "averageHeartRate": { "type": ["number", "null"], "description": "Average heart rate during sleep in BPM" }, - "averageHrv": { "type": ["integer", "null"], "description": "Average heart rate variability during sleep in ms" }, - "lowestHeartRate": { "type": ["integer", "null"], "description": "Lowest heart rate during sleep in BPM" }, - "averageBreath": { "type": ["number", "null"], "description": "Average breathing rate during sleep in breaths/min" }, - "restlessPeriods": { "type": ["integer", "null"], "description": "Number of restless periods during sleep" } - }, - "required": ["day"] - } - } - }, - "required": ["dailyScores", "sleepPeriods"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/shopify/schemas/shop.orders.json b/packages/scope-catalog/connectors/shopify/schemas/shop.orders.json deleted file mode 100644 index 4cf512f..0000000 --- a/packages/scope-catalog/connectors/shopify/schemas/shop.orders.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "Shop Order History", - "version": "1.0.0", - "scope": "shop.orders", - "dialect": "json", - "description": "Order history from the Shop app (Shopify) including merchant names, item counts, totals, and delivery status", - "schema": { - "type": "object", - "properties": { - "orders": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "orderNumber": { "type": "string" }, - "placedAt": { "type": "string", "format": "date-time" }, - "merchantName": { "type": "string" }, - "total": { "type": "number" }, - "currency": { "type": "string" }, - "status": { "type": "string" }, - "itemCount": { "type": "number" }, - "lineItemTitles": { - "type": "array", - "items": { "type": "string" } - }, - "detailUrl": { "type": "string" } - }, - "required": ["id"], - "additionalProperties": false - } - } - }, - "required": ["orders"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/spotify/schemas/spotify.playlists.json b/packages/scope-catalog/connectors/spotify/schemas/spotify.playlists.json deleted file mode 100644 index 7335d80..0000000 --- a/packages/scope-catalog/connectors/spotify/schemas/spotify.playlists.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "Spotify Playlists", - "version": "1.0.0", - "scope": "spotify.playlists", - "dialect": "json", - "description": "User's Spotify playlists including track listings with artist and album details", - "schema": { - "type": "object", - "properties": { - "playlists": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "description": { "type": "string" }, - "owner": { "type": "string" }, - "uri": { "type": "string" }, - "followers": { "type": "number" }, - "images": { - "type": "array", - "items": { "type": "string" } - }, - "tracks_total": { "type": "number" }, - "tracks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "added_at": { "type": "string" }, - "added_by": { "type": "string" }, - "name": { "type": "string" }, - "artists": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" } - }, - "required": ["name"], - "additionalProperties": false - } - }, - "album": { "type": "string" }, - "duration_ms": { "type": "number" }, - "uri": { "type": "string" } - }, - "required": ["name", "artists"], - "additionalProperties": false - } - } - }, - "required": ["name", "tracks"], - "additionalProperties": false - } - }, - "total": { "type": "number" } - }, - "required": ["playlists", "total"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/spotify/schemas/spotify.profile.json b/packages/scope-catalog/connectors/spotify/schemas/spotify.profile.json deleted file mode 100644 index 2397278..0000000 --- a/packages/scope-catalog/connectors/spotify/schemas/spotify.profile.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "Spotify Profile", - "version": "1.0.0", - "scope": "spotify.profile", - "dialect": "json", - "description": "Basic Spotify profile information including display name, followers, and following counts", - "schema": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "display_name": { "type": "string" }, - "uri": { "type": "string" }, - "followers": { "type": "number" }, - "following": { "type": "number" }, - "images": { - "type": "array", - "items": { "type": "string" } - } - }, - "required": ["id", "display_name"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/spotify/schemas/spotify.savedTracks.json b/packages/scope-catalog/connectors/spotify/schemas/spotify.savedTracks.json deleted file mode 100644 index 70d3623..0000000 --- a/packages/scope-catalog/connectors/spotify/schemas/spotify.savedTracks.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "Spotify Saved Tracks", - "version": "1.0.0", - "scope": "spotify.savedTracks", - "dialect": "json", - "description": "User's saved (liked) tracks from Spotify including artist, album, and track details", - "schema": { - "type": "object", - "properties": { - "savedTracks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "added_at": { "type": "string" }, - "name": { "type": "string" }, - "artists": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" } - }, - "required": ["name"], - "additionalProperties": false - } - }, - "album": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "artists": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" } - }, - "required": ["name"], - "additionalProperties": false - } - } - }, - "required": ["name"], - "additionalProperties": false - }, - "duration_ms": { "type": "number" }, - "uri": { "type": "string" }, - "explicit": { "type": "boolean" } - }, - "required": ["name", "artists"], - "additionalProperties": false - } - }, - "total": { "type": "number" } - }, - "required": ["savedTracks", "total"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/uber/schemas/uber.receipts.json b/packages/scope-catalog/connectors/uber/schemas/uber.receipts.json deleted file mode 100644 index d31cc72..0000000 --- a/packages/scope-catalog/connectors/uber/schemas/uber.receipts.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "Uber Receipts", - "version": "1.0.0", - "scope": "uber.receipts", - "dialect": "json", - "description": "Detailed fare breakdowns and receipt information for each Uber trip", - "schema": { - "type": "object", - "properties": { - "receipts": { - "type": "array", - "items": { - "type": "object", - "properties": { - "tripId": { "type": "string" }, - "fare": { "type": "string" }, - "currencyCode": { "type": "string" }, - "distance": { "type": "string" }, - "distanceLabel": { "type": "string" }, - "duration": { "type": "string" }, - "durationLabel": { "type": "string" }, - "vehicleType": { "type": "string" }, - "surgeMultiplier": { "type": "string" }, - "fareBreakdown": { "type": "string" } - }, - "required": ["tripId"], - "additionalProperties": false - } - } - }, - "required": ["receipts"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/uber/schemas/uber.trips.json b/packages/scope-catalog/connectors/uber/schemas/uber.trips.json deleted file mode 100644 index 6474672..0000000 --- a/packages/scope-catalog/connectors/uber/schemas/uber.trips.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "Uber Trip History", - "version": "1.0.0", - "scope": "uber.trips", - "dialect": "json", - "description": "Complete history of Uber rides including pickup/dropoff locations, dates, fares, and vehicle types", - "schema": { - "type": "object", - "properties": { - "trips": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "status": { "type": "string" }, - "requestTime": { "type": "string" }, - "dropoffTime": { "type": "string" }, - "pickupAddress": { "type": "string" }, - "dropoffAddress": { "type": "string" }, - "fare": { "type": "string" }, - "currencyCode": { "type": "string" }, - "vehicleType": { "type": "string" }, - "city": { "type": "string" }, - "isSurge": { "type": "boolean" } - }, - "required": ["id"], - "additionalProperties": false - } - } - }, - "required": ["trips"], - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/connectors/valve/schemas/steam.friends.json b/packages/scope-catalog/connectors/valve/schemas/steam.friends.json deleted file mode 100644 index 0dbcba2..0000000 --- a/packages/scope-catalog/connectors/valve/schemas/steam.friends.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "Steam Friends", - "scope": "steam.friends", - "description": "Steam friend list with persona names, avatars, and friendship dates", - "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "steamId": { "type": "string", "description": "Friend's 64-bit Steam ID" }, - "personaName": { "type": ["string", "null"], "description": "Friend's display name" }, - "avatarUrl": { "type": ["string", "null"], "format": "uri", "description": "URL to the friend's avatar image" }, - "profileUrl": { "type": ["string", "null"], "format": "uri", "description": "URL to the friend's Steam Community profile" }, - "friendSince": { "type": ["string", "null"], "format": "date-time", "description": "When the friendship was established" }, - "relationship": { "type": "string", "description": "Relationship type (usually 'friend')" } - }, - "required": ["steamId"] - } - } -} diff --git a/packages/scope-catalog/connectors/valve/schemas/steam.games.json b/packages/scope-catalog/connectors/valve/schemas/steam.games.json deleted file mode 100644 index 05d064d..0000000 --- a/packages/scope-catalog/connectors/valve/schemas/steam.games.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "Steam Games", - "scope": "steam.games", - "description": "Owned games with playtime statistics and recently played games", - "schema": { - "type": "object", - "properties": { - "owned": { - "type": "array", - "description": "All games owned by the user, sorted by playtime descending", - "items": { - "type": "object", - "properties": { - "appId": { "type": "integer", "description": "Steam application ID" }, - "name": { "type": "string", "description": "Game title" }, - "playtimeMinutes": { "type": "integer", "description": "Total playtime in minutes" }, - "playtimeHours": { "type": "number", "description": "Total playtime in hours (rounded to 1 decimal)" }, - "playtimeTwoWeeksMinutes": { "type": "integer", "description": "Playtime in the last two weeks in minutes" }, - "iconUrl": { "type": ["string", "null"], "format": "uri", "description": "URL to the game's icon image" }, - "lastPlayed": { "type": ["string", "null"], "format": "date-time", "description": "When the game was last played" } - }, - "required": ["appId", "name", "playtimeMinutes"] - } - }, - "recentlyPlayed": { - "type": "array", - "description": "Games played in the last two weeks", - "items": { - "type": "object", - "properties": { - "appId": { "type": "integer", "description": "Steam application ID" }, - "name": { "type": "string", "description": "Game title" }, - "playtimeTwoWeeksMinutes": { "type": "integer", "description": "Playtime in last two weeks in minutes" }, - "playtimeForeverMinutes": { "type": "integer", "description": "Total playtime in minutes" } - }, - "required": ["appId", "name"] - } - } - }, - "required": ["owned", "recentlyPlayed"] - } -} diff --git a/packages/scope-catalog/connectors/valve/schemas/steam.profile.json b/packages/scope-catalog/connectors/valve/schemas/steam.profile.json deleted file mode 100644 index fc901e6..0000000 --- a/packages/scope-catalog/connectors/valve/schemas/steam.profile.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "Steam Profile", - "scope": "steam.profile", - "description": "Steam user profile including persona name, avatar, level, location, and account metadata", - "schema": { - "type": "object", - "properties": { - "steamId": { "type": "string", "description": "64-bit Steam ID" }, - "personaName": { "type": "string", "description": "Display name on Steam" }, - "profileUrl": { "type": "string", "format": "uri", "description": "URL to the user's Steam Community profile" }, - "avatarUrl": { "type": "string", "format": "uri", "description": "URL to the user's full-size avatar image" }, - "realName": { "type": ["string", "null"], "description": "Real name if set by the user" }, - "country": { "type": ["string", "null"], "description": "ISO 3166-1 alpha-2 country code" }, - "state": { "type": ["string", "null"], "description": "State/region code" }, - "cityId": { "type": ["integer", "null"], "description": "Steam internal city identifier" }, - "steamLevel": { "type": ["integer", "null"], "description": "Steam profile level" }, - "accountCreated": { "type": ["string", "null"], "format": "date-time", "description": "When the Steam account was created" }, - "lastLogoff": { "type": ["string", "null"], "format": "date-time", "description": "Last time the user was seen online" }, - "personaState": { "type": "integer", "description": "Online status (0=offline, 1=online, 2=busy, 3=away, 4=snooze, 5=looking to trade, 6=looking to play)" }, - "communityVisibilityState": { "type": "integer", "description": "Profile visibility (1=private, 3=public)" } - }, - "required": ["steamId", "personaName", "profileUrl"] - } -} diff --git a/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.nutrition.json b/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.nutrition.json deleted file mode 100644 index 7614ed6..0000000 --- a/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.nutrition.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "Whole Foods Nutrition", - "version": "1.0.0", - "scope": "wholefoods.nutrition", - "dialect": "json", - "definitionUrl": "https://raw.githubusercontent.com/vana-com/data-connectors/main/connectors/wholefoods/schemas/wholefoods.nutrition.json", - "description": "Nutrition facts per unique product ordered from Whole Foods Market, aligned to Schema.org NutritionInformation", - "schema": { - "type": "object", - "properties": { - "items": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "source": { "type": "string", "enum": ["wholefoods_product_page", "wholefoods_structured_data", "amazon_product_page", "usda_fdc", "not_found", "error", "blocked"] }, - "confidence": { "type": "string", "enum": ["high", "medium", "low"] }, - "calories": { "type": ["number", "null"] }, - "protein_g": { "type": ["number", "null"] }, - "carbs_g": { "type": ["number", "null"] }, - "fat_g": { "type": ["number", "null"] }, - "sodium_mg": { "type": ["number", "null"] }, - "fiber_g": { "type": ["number", "null"] }, - "sugar_g": { "type": ["number", "null"] }, - "servingSize": { "type": ["string", "null"] }, - "servingsPerContainer": { "type": ["string", "null"] } - }, - "required": ["name", "source"] - } - }, - "coverage": { - "type": "object", - "properties": { - "total": { "type": "number" }, - "found": { "type": "number" }, - "foundUSDA": { "type": "number" }, - "percentCovered": { "type": "number" } - } - } - }, - "required": ["items", "coverage"] - } -} diff --git a/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.orders.json b/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.orders.json deleted file mode 100644 index 26bbd8f..0000000 --- a/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.orders.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "Whole Foods Orders", - "version": "1.0.0", - "scope": "wholefoods.orders", - "dialect": "json", - "definitionUrl": "https://raw.githubusercontent.com/vana-com/data-connectors/main/connectors/wholefoods/schemas/wholefoods.orders.json", - "description": "Whole Foods Market delivery and pickup order history with item details", - "schema": { - "type": "object", - "properties": { - "orders": { - "type": "array", - "items": { - "type": "object", - "properties": { - "orderId": { "type": "string" }, - "orderUrl": { "type": "string" }, - "orderDate": { "type": ["string", "null"] }, - "total": { "type": ["number", "null"] }, - "itemCount": { "type": ["number", "null"] }, - "status": { "type": ["string", "null"] }, - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "productId": { "type": "string" }, - "productUrl": { "type": "string" }, - "imageUrl": { "type": "string" }, - "quantity": { "type": ["string", "null"] }, - "price": { "type": ["number", "null"] } - }, - "required": ["name", "productId"] - } - } - }, - "required": ["orderId", "items"] - } - }, - "totalOrders": { "type": "number" }, - "totalItems": { "type": "number" } - }, - "required": ["orders", "totalOrders", "totalItems"] - } -} diff --git a/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.profile.json b/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.profile.json deleted file mode 100644 index 9db460c..0000000 --- a/packages/scope-catalog/connectors/wholefoods/schemas/wholefoods.profile.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "Whole Foods Profile", - "version": "1.0.0", - "scope": "wholefoods.profile", - "dialect": "json", - "definitionUrl": "https://raw.githubusercontent.com/vana-com/data-connectors/main/connectors/wholefoods/schemas/wholefoods.profile.json", - "description": "Amazon account information associated with Whole Foods Market orders", - "schema": { - "type": "object", - "properties": { - "name": { "type": ["string", "null"] }, - "email": { "type": ["string", "null"] } - }, - "additionalProperties": false - } -} diff --git a/packages/scope-catalog/package.json b/packages/scope-catalog/package.template.json similarity index 97% rename from packages/scope-catalog/package.json rename to packages/scope-catalog/package.template.json index c69c246..799f43f 100644 --- a/packages/scope-catalog/package.json +++ b/packages/scope-catalog/package.template.json @@ -1,6 +1,5 @@ { "name": "@opendatalabs/scope-catalog", - "version": "1.0.0", "description": "Versioned public Vana source and scope catalog", "type": "module", "repository": { diff --git a/packages/scope-catalog/release.json b/packages/scope-catalog/release.json deleted file mode 100644 index 6d6a5a2..0000000 --- a/packages/scope-catalog/release.json +++ /dev/null @@ -1,212 +0,0 @@ -{ - "schemaVersion": "1.0.0", - "currentVersion": "1.0.0", - "previousVersion": null, - "currentContractFingerprint": "sha256:0c1ab8a19b236cd2b1d1a6ae19a2acee53519812d1fd7b4e443cdf5f7755fb09", - "previousContractFingerprint": null, - "added": [ - [ - "amazon", - "amazon.orders" - ], - [ - "amazon", - "amazon.profile" - ], - [ - "chatgpt", - "chatgpt.conversations" - ], - [ - "chatgpt", - "chatgpt.memories" - ], - [ - "claude", - "claude.conversations" - ], - [ - "claude", - "claude.projects" - ], - [ - "doordash", - "doordash.orders" - ], - [ - "github", - "github.contributions" - ], - [ - "github", - "github.events" - ], - [ - "github", - "github.history" - ], - [ - "github", - "github.profile" - ], - [ - "github", - "github.repositories" - ], - [ - "github", - "github.starred" - ], - [ - "heb", - "heb.nutrition" - ], - [ - "heb", - "heb.orders" - ], - [ - "heb", - "heb.profile" - ], - [ - "icloud_notes", - "icloud_notes.folders" - ], - [ - "icloud_notes", - "icloud_notes.notes" - ], - [ - "instagram", - "instagram.ads" - ], - [ - "instagram", - "instagram.following" - ], - [ - "instagram", - "instagram.posts" - ], - [ - "instagram", - "instagram.profile" - ], - [ - "linkedin", - "linkedin.connections" - ], - [ - "linkedin", - "linkedin.education" - ], - [ - "linkedin", - "linkedin.experience" - ], - [ - "linkedin", - "linkedin.languages" - ], - [ - "linkedin", - "linkedin.profile" - ], - [ - "linkedin", - "linkedin.skills" - ], - [ - "oura", - "oura.activity" - ], - [ - "oura", - "oura.readiness" - ], - [ - "oura", - "oura.sleep" - ], - [ - "shop", - "shop.orders" - ], - [ - "spotify", - "spotify.playlists" - ], - [ - "spotify", - "spotify.profile" - ], - [ - "spotify", - "spotify.savedTracks" - ], - [ - "steam", - "steam.friends" - ], - [ - "steam", - "steam.games" - ], - [ - "steam", - "steam.profile" - ], - [ - "uber", - "uber.receipts" - ], - [ - "uber", - "uber.trips" - ], - [ - "wholefoods", - "wholefoods.nutrition" - ], - [ - "wholefoods", - "wholefoods.orders" - ], - [ - "wholefoods", - "wholefoods.profile" - ], - [ - "youtube", - "youtube.history" - ], - [ - "youtube", - "youtube.likes" - ], - [ - "youtube", - "youtube.playlistItems" - ], - [ - "youtube", - "youtube.playlists" - ], - [ - "youtube", - "youtube.profile" - ], - [ - "youtube", - "youtube.subscriptions" - ], - [ - "youtube", - "youtube.watchLater" - ] - ], - "removed": [], - "changes": [], - "impact": "minor" -} diff --git a/packages/scope-catalog/schemas/scope-catalog.schema.json b/packages/scope-catalog/schemas/scope-catalog.schema.json deleted file mode 100644 index fbb282b..0000000 --- a/packages/scope-catalog/schemas/scope-catalog.schema.json +++ /dev/null @@ -1,211 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:vana:data-connectors:scope-catalog:1.0.0", - "title": "Vana public source and scope catalog", - "type": "object", - "required": ["catalogSchema", "distribution", "catalogVersion", "generatedBy", "generatedFrom", "scopes"], - "properties": { - "catalogSchema": { - "type": "object", - "required": ["path", "releaseAsset"], - "properties": { - "path": { "const": "schemas/scope-catalog.schema.json" }, - "releaseAsset": { "const": "scope-catalog.schema.json" } - }, - "additionalProperties": false - }, - "catalogVersion": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" }, - "distribution": { - "type": "object", - "required": ["repository"], - "properties": { - "repository": { "const": "https://github.com/vana-com/data-connectors" }, - "sourceCommit": { "type": "string", "pattern": "^[0-9a-f]{40}$" }, - "releaseTag": { "type": "string", "pattern": "^connectors-[0-9a-f]{12}$" } - }, - "dependentRequired": { - "sourceCommit": ["releaseTag"], - "releaseTag": ["sourceCommit"] - }, - "additionalProperties": false - }, - "generatedBy": { "const": "scripts/generate-scope-catalog.mjs" }, - "generatedFrom": { - "type": "object", - "required": ["publishability", "manifests", "webCapabilities"], - "properties": { - "publishability": { - "type": "object", - "required": ["path", "manifestSelector"], - "properties": { - "path": { "const": "registry.json" }, - "manifestSelector": { "const": "connectors[].files.metadata" } - }, - "additionalProperties": false - }, - "manifests": { - "type": "array", - "items": { "type": "string", "pattern": "^connectors/.+-playwright\\.json$" }, - "uniqueItems": true - }, - "webCapabilities": { "const": "scopes/web-capabilities.json" } - }, - "additionalProperties": false - }, - "scopes": { - "type": "array", - "items": { "$ref": "#/$defs/scope" } - } - }, - "$defs": { - "connector": { - "type": "object", - "required": ["id", "status"], - "properties": { - "id": { "type": "string", "minLength": 1 }, - "status": { "type": "string", "enum": ["stable", "beta", "experimental"] }, - "limits": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#/$defs/limit" } - } - }, - "additionalProperties": false - }, - "limit": { - "type": "object", - "required": ["type", "value", "unit", "description"], - "properties": { - "type": { "type": "string", "enum": ["maxItems", "timeWindow"] }, - "value": { "type": "integer", "minimum": 1 }, - "unit": { "type": "string", "minLength": 1 }, - "description": { "type": "string", "minLength": 1 } - }, - "additionalProperties": false - }, - "blocker": { - "type": "object", - "required": ["id", "description", "requiredCapture"], - "properties": { - "id": { "type": "string", "minLength": 1 }, - "description": { "type": "string", "minLength": 1 }, - "requiredCapture": { - "type": "array", - "minItems": 1, - "items": { "type": "string", "minLength": 1 } - } - }, - "additionalProperties": false - }, - "scope": { - "type": "object", - "required": ["sourceId", "scopeId", "description", "schema", "maturity", "fulfillment"], - "properties": { - "sourceId": { "type": "string", "pattern": "^[a-z0-9_-]+$" }, - "scopeId": { "type": "string", "pattern": "^[a-z0-9_-]+\\.[A-Za-z0-9_.-]+$" }, - "description": { "type": "string", "minLength": 1 }, - "schema": { - "type": "object", - "required": ["path"], - "properties": { - "path": { "type": "string", "pattern": "^connectors/.+/schemas/.+\\.json$" }, - "url": { "type": "string", "pattern": "^https://raw\\.githubusercontent\\.com/vana-com/data-connectors/[0-9a-f]{40}/connectors/.+/schemas/.+\\.json$" } - }, - "additionalProperties": false - }, - "maturity": { "type": "string", "enum": ["stable", "beta", "experimental"] }, - "fulfillment": { - "type": "object", - "required": ["desktop", "web"], - "properties": { - "desktop": { - "type": "object", - "required": ["status", "connectors"], - "properties": { - "status": { "const": "supported" }, - "connectors": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#/$defs/connector" }, - "uniqueItems": true - } - }, - "additionalProperties": false - }, - "web": { - "type": "object", - "required": ["status"], - "properties": { - "status": { "type": "string", "enum": ["supported", "unsupported", "blocked"] }, - "limits": { - "type": "array", - "minItems": 1, - "items": { "$ref": "#/$defs/limit" } - }, - "blocker": { "$ref": "#/$defs/blocker" } - }, - "allOf": [ - { - "if": { "properties": { "status": { "const": "blocked" } }, "required": ["status"] }, - "then": { - "properties": { "blocker": { "$ref": "#/$defs/blocker" } }, - "required": ["blocker"] - }, - "else": { "not": { "required": ["blocker"] } } - }, - { - "if": { "properties": { "status": { "const": "supported" } }, "required": ["status"] }, - "else": { - "not": { - "properties": { "limits": { "type": "array" } }, - "required": ["limits"] - } - } - } - ], - "additionalProperties": false - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - } - }, - "allOf": [ - { - "if": { - "properties": { - "distribution": { - "type": "object", - "properties": { - "sourceCommit": { "type": "string" } - }, - "required": ["sourceCommit"] - } - }, - "required": ["distribution"] - }, - "then": { - "properties": { - "scopes": { - "type": "array", - "items": { - "type": "object", - "properties": { - "schema": { - "type": "object", - "properties": { - "url": { "type": "string" } - }, - "required": ["url"] - } - } - } - } - } - } - } - ], - "additionalProperties": false -} diff --git a/packages/scope-catalog/scope-catalog.json b/packages/scope-catalog/scope-catalog.json deleted file mode 100644 index 49b5657..0000000 --- a/packages/scope-catalog/scope-catalog.json +++ /dev/null @@ -1,1287 +0,0 @@ -{ - "catalogSchema": { - "path": "schemas/scope-catalog.schema.json", - "releaseAsset": "scope-catalog.schema.json" - }, - "distribution": { - "repository": "https://github.com/vana-com/data-connectors" - }, - "catalogVersion": "1.0.0", - "generatedBy": "scripts/generate-scope-catalog.mjs", - "generatedFrom": { - "publishability": { - "path": "registry.json", - "manifestSelector": "connectors[].files.metadata" - }, - "manifests": [ - "connectors/amazon/amazon-playwright.json", - "connectors/anthropic/claude-export-playwright.json", - "connectors/apple/icloud-notes-playwright.json", - "connectors/doordash/doordash-playwright.json", - "connectors/github/github-playwright.json", - "connectors/google/youtube-playwright.json", - "connectors/heb/heb-playwright.json", - "connectors/linkedin/linkedin-playwright.json", - "connectors/meta/instagram-ads-playwright.json", - "connectors/meta/instagram-playwright.json", - "connectors/openai/chatgpt-playwright.json", - "connectors/oura/oura-playwright.json", - "connectors/shopify/shop-playwright.json", - "connectors/spotify/spotify-playwright.json", - "connectors/uber/uber-playwright.json", - "connectors/valve/steam-playwright.json", - "connectors/wholefoods/wholefoods-playwright.json" - ], - "webCapabilities": "scopes/web-capabilities.json" - }, - "scopes": [ - { - "sourceId": "amazon", - "scopeId": "amazon.orders", - "description": "Order history including items, prices, dates, and delivery status", - "schema": { - "path": "connectors/amazon/schemas/amazon.orders.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "amazon-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "amazon", - "scopeId": "amazon.profile", - "description": "Account name and Prime membership status", - "schema": { - "path": "connectors/amazon/schemas/amazon.profile.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "amazon-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "chatgpt", - "scopeId": "chatgpt.conversations", - "description": "All conversation history including messages with ChatGPT", - "schema": { - "path": "connectors/openai/schemas/chatgpt.conversations.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "chatgpt-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "chatgpt", - "scopeId": "chatgpt.memories", - "description": "Saved memories that ChatGPT uses to personalize responses", - "schema": { - "path": "connectors/openai/schemas/chatgpt.memories.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "chatgpt-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "claude", - "scopeId": "claude.conversations", - "description": "All Claude conversations with full message threads, from Anthropic's official data export.", - "schema": { - "path": "connectors/anthropic/schemas/claude.conversations.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "claude-export-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "claude", - "scopeId": "claude.projects", - "description": "Claude projects and their detail, from Anthropic's official data export.", - "schema": { - "path": "connectors/anthropic/schemas/claude.projects.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "claude-export-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "doordash", - "scopeId": "doordash.orders", - "description": "Complete order history with restaurant names, items ordered, dates, totals, and delivery status", - "schema": { - "path": "connectors/doordash/schemas/doordash.orders.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "doordash-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "github", - "scopeId": "github.contributions", - "description": "Daily contribution counts for the last 4 years (per-year scrape, not just rolling 12 months), monthly totals, per-year totals, and your top day", - "schema": { - "path": "connectors/github/schemas/github.contributions.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "github-playwright", - "status": "stable", - "limits": [ - { - "type": "timeWindow", - "value": 4, - "unit": "years", - "description": "The Desktop connector collects the four most recent calendar years." - } - ] - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "github", - "scopeId": "github.events", - "description": "Recent public activity (pushes, pull requests, issues, comments, branches, releases) across every repository you have touched, including organization-owned repos", - "schema": { - "path": "connectors/github/schemas/github.events.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "github-playwright", - "status": "stable", - "limits": [ - { - "type": "maxItems", - "value": 300, - "unit": "events", - "description": "The Desktop connector returns at most 300 public events." - }, - { - "type": "timeWindow", - "value": 90, - "unit": "days", - "description": "The GitHub public-events API covers at most the previous 90 days." - } - ] - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "github", - "scopeId": "github.history", - "description": "Pull requests and issues you have authored across public repositories via the GitHub Search API, including title, body, dates, repository, labels, and state.", - "schema": { - "path": "connectors/github/schemas/github.history.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "github-playwright", - "status": "stable", - "limits": [ - { - "type": "maxItems", - "value": 1000, - "unit": "items per type", - "description": "The GitHub Search API returns at most 1,000 pull requests and 1,000 issues per query." - } - ] - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "github", - "scopeId": "github.profile", - "description": "Account profile information such as name, bio, follower counts, pinned repositories, organization memberships, and achievement badges", - "schema": { - "path": "connectors/github/schemas/github.profile.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "github-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "supported" - } - } - }, - { - "sourceId": "github", - "scopeId": "github.repositories", - "description": "Your repository list with metadata like language, stars, and update time", - "schema": { - "path": "connectors/github/schemas/github.repositories.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "github-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "github", - "scopeId": "github.starred", - "description": "Repositories you have starred on GitHub", - "schema": { - "path": "connectors/github/schemas/github.starred.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "github-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "heb", - "scopeId": "heb.nutrition", - "description": "Nutrition facts (calories, macros, sodium, fiber, vitamins) for each product ordered. Aligned to Schema.org NutritionInformation.", - "schema": { - "path": "connectors/heb/schemas/heb.nutrition.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "heb-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "heb", - "scopeId": "heb.orders", - "description": "Curbside and delivery orders with item names, quantities, prices, and order dates", - "schema": { - "path": "connectors/heb/schemas/heb.orders.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "heb-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "heb", - "scopeId": "heb.profile", - "description": "Your name, email, phone number, and saved delivery addresses", - "schema": { - "path": "connectors/heb/schemas/heb.profile.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "heb-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "icloud_notes", - "scopeId": "icloud_notes.folders", - "description": "Folder structure for organizing notes", - "schema": { - "path": "connectors/apple/schemas/icloud_notes.folders.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "icloud-notes-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "icloud_notes", - "scopeId": "icloud_notes.notes", - "description": "Note content, titles, created/modified timestamps, and folder assignment", - "schema": { - "path": "connectors/apple/schemas/icloud_notes.notes.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "icloud-notes-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "instagram", - "scopeId": "instagram.ads", - "description": "Advertisers the user has seen ads from and ad topic interests based on their Instagram activity", - "schema": { - "path": "connectors/meta/schemas/instagram.ads.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "instagram-playwright", - "status": "stable" - }, - { - "id": "instagram-ads-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "instagram", - "scopeId": "instagram.following", - "description": "The list of Instagram accounts you follow", - "schema": { - "path": "connectors/meta/schemas/instagram.following.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "instagram-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "instagram", - "scopeId": "instagram.posts", - "description": "Published posts from your feed", - "schema": { - "path": "connectors/meta/schemas/instagram.posts.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "instagram-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "supported", - "limits": [ - { - "type": "maxItems", - "value": 150, - "unit": "posts", - "description": "The Web path returns at most the 150 most recent posts." - } - ] - } - } - }, - { - "sourceId": "instagram", - "scopeId": "instagram.profile", - "description": "Profile information including bio and follower counts", - "schema": { - "path": "connectors/meta/schemas/instagram.profile.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "instagram-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "supported" - } - } - }, - { - "sourceId": "linkedin", - "scopeId": "linkedin.connections", - "description": "Your LinkedIn connections with names, headlines, profile URLs, and date connected", - "schema": { - "path": "connectors/linkedin/schemas/linkedin.connections.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "linkedin-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "blocked", - "blocker": { - "id": "linkedin-live-output", - "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", - "requiredCapture": [ - "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", - "The resulting Personal Server scope inventory for the same run and user after sync." - ] - } - } - } - }, - { - "sourceId": "linkedin", - "scopeId": "linkedin.education", - "description": "Your education history including schools, degrees, years, and grades", - "schema": { - "path": "connectors/linkedin/schemas/linkedin.education.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "linkedin-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "blocked", - "blocker": { - "id": "linkedin-live-output", - "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", - "requiredCapture": [ - "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", - "The resulting Personal Server scope inventory for the same run and user after sync." - ] - } - } - } - }, - { - "sourceId": "linkedin", - "scopeId": "linkedin.experience", - "description": "Your work experience including job titles, companies, dates, locations, and descriptions", - "schema": { - "path": "connectors/linkedin/schemas/linkedin.experience.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "linkedin-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "blocked", - "blocker": { - "id": "linkedin-live-output", - "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", - "requiredCapture": [ - "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", - "The resulting Personal Server scope inventory for the same run and user after sync." - ] - } - } - } - }, - { - "sourceId": "linkedin", - "scopeId": "linkedin.languages", - "description": "Your languages and proficiency levels", - "schema": { - "path": "connectors/linkedin/schemas/linkedin.languages.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "linkedin-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "blocked", - "blocker": { - "id": "linkedin-live-output", - "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", - "requiredCapture": [ - "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", - "The resulting Personal Server scope inventory for the same run and user after sync." - ] - } - } - } - }, - { - "sourceId": "linkedin", - "scopeId": "linkedin.profile", - "description": "Your LinkedIn profile including name, headline, location, about, and profile picture", - "schema": { - "path": "connectors/linkedin/schemas/linkedin.profile.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "linkedin-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "blocked", - "blocker": { - "id": "linkedin-live-output", - "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", - "requiredCapture": [ - "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", - "The resulting Personal Server scope inventory for the same run and user after sync." - ] - } - } - } - }, - { - "sourceId": "linkedin", - "scopeId": "linkedin.skills", - "description": "Your skills and endorsement counts", - "schema": { - "path": "connectors/linkedin/schemas/linkedin.skills.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "linkedin-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "blocked", - "blocker": { - "id": "linkedin-live-output", - "description": "LinkedIn Web scope capability is not classified without live end-to-end evidence.", - "requiredCapture": [ - "A captured successful LinkedIn Data Pipe result showing the exact returned scope-key set.", - "The resulting Personal Server scope inventory for the same run and user after sync." - ] - } - } - } - }, - { - "sourceId": "oura", - "scopeId": "oura.activity", - "description": "Daily activity scores, step counts, calorie burn, and activity level breakdowns", - "schema": { - "path": "connectors/oura/schemas/oura.activity.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "oura-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "oura", - "scopeId": "oura.readiness", - "description": "Daily readiness scores and contributing factors like HRV balance, resting heart rate, recovery, and body temperature", - "schema": { - "path": "connectors/oura/schemas/oura.readiness.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "oura-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "oura", - "scopeId": "oura.sleep", - "description": "Daily sleep scores with contributor breakdowns and detailed sleep period data including duration, stages, heart rate, and HRV", - "schema": { - "path": "connectors/oura/schemas/oura.sleep.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "oura-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "shop", - "scopeId": "shop.orders", - "description": "Complete order history from the Shop app including merchants, items, totals, and delivery status", - "schema": { - "path": "connectors/shopify/schemas/shop.orders.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "shop-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "spotify", - "scopeId": "spotify.playlists", - "description": "Playlists and their tracks", - "schema": { - "path": "connectors/spotify/schemas/spotify.playlists.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "spotify-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "spotify", - "scopeId": "spotify.profile", - "description": "Profile information", - "schema": { - "path": "connectors/spotify/schemas/spotify.profile.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "spotify-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "supported" - } - } - }, - { - "sourceId": "spotify", - "scopeId": "spotify.savedTracks", - "description": "Saved/liked tracks in your library", - "schema": { - "path": "connectors/spotify/schemas/spotify.savedTracks.json" - }, - "maturity": "stable", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "spotify-playwright", - "status": "stable" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "steam", - "scopeId": "steam.friends", - "description": "Friend list with persona names, avatars, and friendship dates", - "schema": { - "path": "connectors/valve/schemas/steam.friends.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "steam-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "steam", - "scopeId": "steam.games", - "description": "Owned games with playtime statistics, plus recently played games", - "schema": { - "path": "connectors/valve/schemas/steam.games.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "steam-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "steam", - "scopeId": "steam.profile", - "description": "Steam profile including persona name, avatar, level, country, and account age", - "schema": { - "path": "connectors/valve/schemas/steam.profile.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "steam-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "uber", - "scopeId": "uber.receipts", - "description": "Fare breakdowns and receipt details for each trip", - "schema": { - "path": "connectors/uber/schemas/uber.receipts.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "uber-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "uber", - "scopeId": "uber.trips", - "description": "Complete history of your Uber rides including pickup/dropoff locations, dates, and driver info", - "schema": { - "path": "connectors/uber/schemas/uber.trips.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "uber-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "wholefoods", - "scopeId": "wholefoods.nutrition", - "description": "Nutrition facts (calories, macros, sodium, fiber, vitamins) for each product ordered. Aligned to Schema.org NutritionInformation.", - "schema": { - "path": "connectors/wholefoods/schemas/wholefoods.nutrition.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "wholefoods-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "wholefoods", - "scopeId": "wholefoods.orders", - "description": "Whole Foods delivery and pickup orders with item names, quantities, prices, and order dates", - "schema": { - "path": "connectors/wholefoods/schemas/wholefoods.orders.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "wholefoods-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "wholefoods", - "scopeId": "wholefoods.profile", - "description": "Your Amazon account name and email associated with Whole Foods orders", - "schema": { - "path": "connectors/wholefoods/schemas/wholefoods.profile.json" - }, - "maturity": "experimental", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "wholefoods-playwright", - "status": "experimental" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "youtube", - "scopeId": "youtube.history", - "description": "Raw watch history entries for the top 50 most recent items", - "schema": { - "path": "connectors/google/schemas/youtube.history.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "youtube-playwright", - "status": "beta", - "limits": [ - { - "type": "maxItems", - "value": 50, - "unit": "items", - "description": "The Desktop connector returns at most the 50 most recent watch history items." - } - ] - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "youtube", - "scopeId": "youtube.likes", - "description": "Videos you have liked", - "schema": { - "path": "connectors/google/schemas/youtube.likes.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "youtube-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "youtube", - "scopeId": "youtube.playlistItems", - "description": "Videos inside your playlists, including titles and URLs", - "schema": { - "path": "connectors/google/schemas/youtube.playlistItems.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "youtube-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "youtube", - "scopeId": "youtube.playlists", - "description": "Playlists visible in your YouTube Library", - "schema": { - "path": "connectors/google/schemas/youtube.playlists.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "youtube-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "youtube", - "scopeId": "youtube.profile", - "description": "Email, channel URL, handle, and joined date (plus optional channel fields like title, avatar, and stats)", - "schema": { - "path": "connectors/google/schemas/youtube.profile.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "youtube-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "supported" - } - } - }, - { - "sourceId": "youtube", - "scopeId": "youtube.subscriptions", - "description": "Channels you are subscribed to", - "schema": { - "path": "connectors/google/schemas/youtube.subscriptions.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "youtube-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - }, - { - "sourceId": "youtube", - "scopeId": "youtube.watchLater", - "description": "Videos saved to Watch Later", - "schema": { - "path": "connectors/google/schemas/youtube.watchLater.json" - }, - "maturity": "beta", - "fulfillment": { - "desktop": { - "status": "supported", - "connectors": [ - { - "id": "youtube-playwright", - "status": "beta" - } - ] - }, - "web": { - "status": "unsupported" - } - } - } - ] -} diff --git a/scripts/build-scope-catalog-package.mjs b/scripts/build-scope-catalog-package.mjs index 155ae94..a6794cf 100644 --- a/scripts/build-scope-catalog-package.mjs +++ b/scripts/build-scope-catalog-package.mjs @@ -72,12 +72,13 @@ export function buildScopeCatalogPackage({ packageRoot = defaultPackageRoot, previousPackageRoot = null, } = {}) { + const packageTemplatePath = join(packageRoot, "package.template.json"); const packageJsonPath = join(packageRoot, "package.json"); const readmePath = join(packageRoot, "README.md"); - if (!existsSync(packageJsonPath) || !existsSync(readmePath)) { - throw new Error("Package root must contain authored package.json and README.md"); + if (!existsSync(packageTemplatePath) || !existsSync(readmePath)) { + throw new Error("Package root must contain authored package.template.json and README.md"); } - const packageJson = readJson(packageJsonPath); + const packageJson = readJson(packageTemplatePath); if (packageJson.name !== "@opendatalabs/scope-catalog") { throw new Error("Package name must remain @opendatalabs/scope-catalog"); } @@ -89,6 +90,7 @@ export function buildScopeCatalogPackage({ for (const path of [ "CHANGELOG.md", "connectors", + "package.json", "release.json", "schemas", "scope-catalog.json", @@ -96,7 +98,8 @@ export function buildScopeCatalogPackage({ rmSync(join(packageRoot, path), { force: true, recursive: true }); } - writeJson(packageJsonPath, { ...packageJson, version: release.currentVersion }); + const { name, ...packageMetadata } = packageJson; + writeJson(packageJsonPath, { name, version: release.currentVersion, ...packageMetadata }); copyFileSync(join(repoRoot, "scope-catalog.json"), join(packageRoot, "scope-catalog.json")); mkdirSync(join(packageRoot, "schemas"), { recursive: true }); copyFileSync( diff --git a/scripts/check-scope-catalog-package.mjs b/scripts/check-scope-catalog-package.mjs index 57c155f..cb00b12 100644 --- a/scripts/check-scope-catalog-package.mjs +++ b/scripts/check-scope-catalog-package.mjs @@ -36,6 +36,7 @@ const requiredFiles = [ "schemas", "scope-catalog.json", ]; +const sourceOnlyFiles = new Set([".gitignore", "package.template.json"]); function readJson(path) { return JSON.parse(readFileSync(path, "utf8")); @@ -44,6 +45,7 @@ function readJson(path) { function listFiles(root, directory = root) { return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { const path = join(directory, entry.name); + if (sourceOnlyFiles.has(relative(root, path))) return []; return entry.isDirectory() ? listFiles(root, path) : [relative(root, path)]; }); } @@ -111,7 +113,10 @@ export function checkScopeCatalogPackage({ } const expectedRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-check-")); - cpSync(join(packageRoot, "package.json"), join(expectedRoot, "package.json")); + cpSync( + join(packageRoot, "package.template.json"), + join(expectedRoot, "package.template.json"), + ); cpSync(join(packageRoot, "README.md"), join(expectedRoot, "README.md")); buildScopeCatalogPackage({ repoRoot, diff --git a/scripts/scope-catalog-package.test.mjs b/scripts/scope-catalog-package.test.mjs index 90ce500..c53c6d1 100644 --- a/scripts/scope-catalog-package.test.mjs +++ b/scripts/scope-catalog-package.test.mjs @@ -189,8 +189,12 @@ test("initial, unchanged, major, minor and patch contracts select deterministic test("package build preserves package-relative paths and check rejects extra payload schemas", () => { const packageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-output-")); - cpSync(join(repoRoot, "packages", "scope-catalog", "package.json"), join(packageRoot, "package.json")); + cpSync( + join(repoRoot, "packages", "scope-catalog", "package.template.json"), + join(packageRoot, "package.template.json"), + ); cpSync(join(repoRoot, "packages", "scope-catalog", "README.md"), join(packageRoot, "README.md")); + cpSync(join(repoRoot, "packages", "scope-catalog", ".gitignore"), join(packageRoot, ".gitignore")); buildScopeCatalogPackage({ repoRoot, packageRoot }); const catalog = readJson(join(packageRoot, "scope-catalog.json")); @@ -471,8 +475,8 @@ test("later builds bump from the published package and keep a cumulative changel const previousRepoRoot = makeContractFixture(); const previousPackageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-previous-")); cpSync( - join(repoRoot, "packages", "scope-catalog", "package.json"), - join(previousPackageRoot, "package.json"), + join(repoRoot, "packages", "scope-catalog", "package.template.json"), + join(previousPackageRoot, "package.template.json"), ); cpSync( join(repoRoot, "packages", "scope-catalog", "README.md"), @@ -489,8 +493,8 @@ test("later builds bump from the published package and keep a cumulative changel }); const currentPackageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-current-")); cpSync( - join(repoRoot, "packages", "scope-catalog", "package.json"), - join(currentPackageRoot, "package.json"), + join(repoRoot, "packages", "scope-catalog", "package.template.json"), + join(currentPackageRoot, "package.template.json"), ); cpSync( join(repoRoot, "packages", "scope-catalog", "README.md"), @@ -514,8 +518,8 @@ test("later fulfillment changes without limits round-trip through release.json", const previousRepoRoot = makeContractFixture(); const previousPackageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-previous-")); cpSync( - join(repoRoot, "packages", "scope-catalog", "package.json"), - join(previousPackageRoot, "package.json"), + join(repoRoot, "packages", "scope-catalog", "package.template.json"), + join(previousPackageRoot, "package.template.json"), ); cpSync( join(repoRoot, "packages", "scope-catalog", "README.md"), @@ -536,8 +540,8 @@ test("later fulfillment changes without limits round-trip through release.json", }); const currentPackageRoot = mkdtempSync(join(tmpdir(), "scope-catalog-package-current-")); cpSync( - join(repoRoot, "packages", "scope-catalog", "package.json"), - join(currentPackageRoot, "package.json"), + join(repoRoot, "packages", "scope-catalog", "package.template.json"), + join(currentPackageRoot, "package.template.json"), ); cpSync( join(repoRoot, "packages", "scope-catalog", "README.md"),