{
  "connector": {
    "key": "acme-projects-minimal",
    "kind": "http",
    "name": "Acme Projects (minimal)",
    "sdk": ">=2",
    "version": 1
  },
  "files": {
    "CHANGELOG.md": "# Changelog\n\n## 2026-09-27\n\n- First version: users, synced.\n",
    "README.md": "# Acme Projects (sync only)\n\nSyncs Acme Projects users.\n",
    "handlers/connection/testConnection.ts": "import type { Handler } from \"../../types.gen.ts\";\nimport { ConnectorSdkError } from \"@owlie/connectors/sdk/v2\";\n\n/** Reads one user: proves the subdomain, the token and permission to read users. */\nconst testConnection: Handler<\"connection.testConnection\"> = async (_input, ctx) => {\n  try {\n    await ctx.http.get(\"/users\", { ...ctx.options, query: { limit: 1 } });\n    return \"connected\";\n  } catch (error) {\n    throw new ConnectorSdkError(error, {\n      code: \"CONFIGURATION_ERROR\",\n      message: \"Acme Projects connection test failed\",\n      customerMessage: \"Acme Projects could not verify the subdomain and API token.\",\n      handledAt: \"connector.invocation-context\",\n    });\n  }\n};\n\nexport default testConnection;\n",
    "handlers/user/fetchAll.ts": "import type { Handler, UserRecord } from \"../../types.gen.ts\";\n\nconst fetchAll: Handler<\"user.fetchAll\"> = async (options, ctx) => {\n  const page = await ctx.paginate<UserRecord>({ path: \"/users\", options });\n  for (const record of page.records) {\n    ctx.validate.resourceSchema(\"user\", record, { mode: \"warn\", operation: \"fetchAll\", subject: \"user record\" });\n  }\n  return page;\n};\n\nexport default fetchAll;\n",
    "handlers/user/fetchOne.ts": "import type { Handler, UserRecord } from \"../../types.gen.ts\";\nimport { isNotFound } from \"@owlie/connectors/sdk/v2\";\nimport { resolveUserId } from \"../../lib/lookups.ts\";\n\nconst fetchOne: Handler<\"user.fetchOne\"> = async (identifiers, ctx) => {\n  try {\n    const id = await resolveUserId(ctx, identifiers);\n    const response = await ctx.http.get<UserRecord>(`/users/${encodeURIComponent(id)}`, ctx.options);\n    return {\n      record: response.data,\n      metadata: { lifecycleState: response.data.status === \"deactivated\" ? \"DISABLED\" : \"ACTIVE\" },\n    };\n  } catch (error) {\n    if (isNotFound(error)) return { record: null };\n    throw error;\n  }\n};\n\nexport default fetchOne;\n",
    "lib/lookups.ts": "import type { Context } from \"../types.gen.ts\";\n\n/** The user's Acme id: taken as given when present, else looked up by email. A miss throws NOT_FOUND. */\nexport async function resolveUserId(ctx: Context, identifiers: { id?: string; email?: string }): Promise<string> {\n  if (identifiers.id) return identifiers.id;\n  if (!identifiers.email) throw ctx.errors.invalidInput(\"An Acme Projects user needs an id or an email\");\n  const response = await ctx.http.get<{ data: { id: string }[] }>(\"/users\", {\n    ...ctx.options,\n    query: { email: identifiers.email, limit: 1 },\n  });\n  const user = response.data.data[0];\n  if (!user) throw ctx.errors.notFound(\"User\", `No Acme Projects user has the email ${identifiers.email}`);\n  return user.id;\n}\n"
  },
  "format": 1,
  "manifest": {
    "key": "acme-projects-minimal",
    "version": 1,
    "name": "Acme Projects (minimal)",
    "description": "Acme Projects users, synced.",
    "icon": "@acmeprojects.example",
    "kind": "http",
    "provides": ["sync"],
    "pagination_type": "cursor",
    "config": {
      "schema": {
        "type": "object",
        "required": ["subdomain"],
        "properties": {
          "subdomain": {
            "type": "string",
            "minLength": 1,
            "pattern": "^[a-z0-9-]+$",
            "title": "Subdomain",
            "description": "Your Acme Projects subdomain, for example acme in acme.acmeprojects.example.",
            "x-suffix": ".acmeprojects.example"
          }
        },
        "additionalProperties": false
      }
    },
    "auth": [
      {
        "key": "api-token",
        "title": "API token",
        "description": "An Acme Projects admin API token.",
        "config": {
          "schema": {
            "type": "object",
            "required": ["api_token"],
            "properties": {
              "api_token": {
                "type": "string",
                "minLength": 1,
                "title": "API token",
                "format": "password",
                "x-sensitive": true
              }
            },
            "additionalProperties": false
          }
        },
        "apply": {
          "header": {
            "Authorization": {
              "expr": "'Bearer ' + config.api_token"
            }
          },
          "base_url": {
            "expr": "'https://' + config.subdomain + '.acmeprojects.example/api/v2'"
          }
        }
      }
    ],
    "egress": {
      "manual": ["acmeprojects.example"]
    },
    "entities": {
      "user": {
        "name": "User",
        "description": "An Acme Projects user. The account entity.",
        "is_account": true,
        "identifier_paths": ["id", "email"],
        "sync_support": {
          "supports_incremental": false,
          "supports_deleted": false
        },
        "schema": {
          "type": "object",
          "properties": {
            "id": {
              "type": "string",
              "title": "User ID",
              "readOnly": true,
              "x-identifier": true,
              "x-provider-stable-id": true
            },
            "email": {
              "type": "string",
              "format": "email",
              "title": "Email",
              "x-identifier": true
            },
            "first_name": {
              "type": "string",
              "title": "First name"
            },
            "last_name": {
              "type": "string",
              "title": "Last name"
            },
            "status": {
              "type": "string",
              "enum": ["active", "deactivated"],
              "title": "Status",
              "readOnly": true
            },
            "created_at": {
              "type": "string",
              "format": "date-time",
              "title": "Created",
              "readOnly": true
            }
          }
        },
        "sync_profile": {
          "target": "RESOURCE",
          "matchingRules": [
            {
              "identityField": "email",
              "externalExpression": "email"
            }
          ],
          "is_active": "status != 'deactivated'"
        }
      }
    },
    "grant_kinds": []
  },
  "provenance": {
    "source": "Owlie documentation example"
  }
}
