@xyz17711/url-extract 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,88 @@
1
- # Temporary Holding Version
1
+ # @xyz17711/url-extract
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![Publish](https://github.com/17711-services/clients/actions/workflows/publish-node.yml/badge.svg)](https://github.com/17711-services/clients/actions/workflows/publish-node.yml)
4
+ [![npm](https://img.shields.io/npm/v/@xyz17711/url-extract)](https://www.npmjs.com/package/@xyz17711/url-extract)
5
+ [![License](https://img.shields.io/npm/l/@xyz17711/url-extract)](https://github.com/17711-services/clients/blob/main/LICENSE)
6
+
7
+ Typed TypeScript client for **url-extract-service**, part of the
8
+ [17711.xyz](https://api.17711.xyz) microservice fleet -- pay-per-call APIs settled in USDC via
9
+ [x402](https://x402.org), listed on [x402scan](https://www.x402scan.com/server/f1c7b972-3405-4b75-8b4f-d1bfbd6305ff).
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install @xyz17711/url-extract
15
+ ```
16
+
17
+ ## Methods
18
+
19
+ | Method | Description |
20
+ | --- | --- |
21
+ | `getCompanyProfile` | [Deprecated - use company_profile_get_profile] Company profile from a domain or a name as valid JSON ($0.009, x402) |
22
+ | `getStructuredData` | URL extract with a question: ask any web page a question and get structured data as JSON that matches your schema ($0.02, x402) |
23
+
24
+ ## Quickstart
25
+
26
+ ```typescript
27
+ import { Client } from "@xyz17711/url-extract";
28
+
29
+ const client = new Client("https://api.17711.xyz/registry/url-extract-service");
30
+ // see the Methods table above for every available call and its request/response type
31
+ ```
32
+
33
+ ## Paying past the free quota
34
+
35
+ Every gated tool allows a small number of free calls per day; beyond that it returns a 402
36
+ challenge. Without a wallet configured, this client throws `PaymentRequiredError` with the price,
37
+ network, and payee address attached:
38
+
39
+ ```typescript
40
+ import { Client, PaymentRequiredError } from "@xyz17711/url-extract";
41
+
42
+ const client = new Client("https://api.17711.xyz/registry/url-extract-service");
43
+ try {
44
+ await client.getCompanyProfile(/* ... */);
45
+ } catch (e) {
46
+ if (e instanceof PaymentRequiredError) {
47
+ console.log(`needs ${e.priceUsdc} USDC on ${e.network}, payable to ${e.payTo}`);
48
+ }
49
+ }
50
+ ```
51
+
52
+ To pay automatically, configure a wallet on the client -- the private key should come from your
53
+ own environment/secrets manager, never a literal string in source code:
54
+
55
+ ```typescript
56
+ import { Client } from "@xyz17711/url-extract";
57
+
58
+ const client = new Client("https://api.17711.xyz/registry/url-extract-service", {
59
+ x402PrivateKey: process.env.X402_PRIVATE_KEY,
60
+ x402ExpectedNetwork: "eip155:8453", // Base mainnet; use eip155:84532 for Base Sepolia testnet
61
+ x402MaxPaymentUsdc: 0.01, // refuse any single call above this
62
+ x402MaxTotalSpendUsdc: 1.0, // refuse once this WALLET's lifetime spend would exceed it
63
+ });
64
+ ```
65
+
66
+ **Never commit a private key.** Both spend caps are required together with the key -- a wallet
67
+ with real funds and no explicit caps refuses to construct at all (`WalletConfigError`), on
68
+ purpose. The cumulative cap is tracked per wallet address, shared by every `Client` you construct
69
+ with that same key in this process.
70
+
71
+ ## LangChain.js
72
+
73
+ ```typescript
74
+ import { Client } from "@xyz17711/url-extract";
75
+ import { UrlExtractToolkit } from "@xyz17711/url-extract/langchain";
76
+
77
+ const client = new Client("https://api.17711.xyz/registry/url-extract-service", { /* ...wallet options... */ });
78
+ const tools = new UrlExtractToolkit(client).getTools();
79
+ ```
80
+
81
+ Requires the optional `@langchain/core`+`zod` peer dependencies (`npm install @langchain/core
82
+ zod`) -- importing the base package above never requires them; only `@xyz17711/url-extract/langchain`
83
+ does.
84
+
85
+ ## License
86
+
87
+ MIT -- see [`LICENSE`](../../LICENSE), shared by every language's client library in the
88
+ `clients` repo this package lives in.
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Typed HTTP client and request/response interfaces for url-extract-service.
3
+ */
4
+ import { Client as BaseClient, type ClientOptions } from "@xyz17711/core";
5
+ export interface DomainInfo {
6
+ /** Years since registration, one decimal. */
7
+ domain_age_years?: number | null;
8
+ /** Mail platform deduced from the MX records (`google-workspace`, `microsoft-365`, ...). */
9
+ email_provider?: string | null;
10
+ /** Expiration date, `YYYY-MM-DD`. */
11
+ expires_at?: string | null;
12
+ /** Sending services declared in the SPF record (`sendgrid`, `mailchimp`, ...). */
13
+ mail_services: string[];
14
+ nameservers: string[];
15
+ /** Registration date, `YYYY-MM-DD`. */
16
+ registered_at?: string | null;
17
+ /** The registrable domain the lookups were made for. */
18
+ registrable_domain: string;
19
+ /** The registrant, only when it is an organization published in RDAP. */
20
+ registrant_org?: string | null;
21
+ registrar?: string | null;
22
+ /** RDAP status flags (e.g. `client transfer prohibited`), at most 4. */
23
+ statuses: string[];
24
+ }
25
+ export interface GetCompanyProfileResponse {
26
+ /** Every automatic correction applied to the model's answer. */
27
+ applied_fixes: unknown[];
28
+ /** The host that was profiled, lowercased, without scheme or path. */
29
+ domain: string;
30
+ /** Public registration and DNS facts about the domain: registrar, registration and expiry dates, age, name servers, public registrant organization, mail platform and sending services. Fields that could not be looked up are absent or empty. */
31
+ domain_info: DomainInfo;
32
+ /** Language of the profile's free-text values. */
33
+ output_language: string;
34
+ /** The pages that were actually read to build the profile. */
35
+ pages_read: string[];
36
+ /** Number of model passes used (2 only when the first answer was incomplete). */
37
+ passes: number;
38
+ /** The profile: `name`, `description`, `offering`, `target_customers`, `pricing_summary`, `headquarters`, `founded`, `contact` (`emails`, `phones`) and `social` (`linkedin`, `twitter`, `github`, `facebook`, `instagram`, `youtube`). A value the pages do not state is `null`. */
39
+ profile: unknown;
40
+ /** Every schema violation that could not be corrected. */
41
+ remaining_issues: unknown[];
42
+ /** `true` when the website was found from `company_name`. */
43
+ resolved_from_name: boolean;
44
+ /** Language of the website (ISO 639-1 code). */
45
+ source_language: string;
46
+ /** E-mail addresses and social links the model produced that do NOT appear in the pages read; they were removed from `profile` so nothing in it is invented. */
47
+ unverified_removed: string[];
48
+ /** Whether the profile satisfies the profile schema after automatic correction. */
49
+ valid?: boolean | null;
50
+ }
51
+ export interface GetCompanyProfileRequest {
52
+ /** The company's name, when you do not know its website (e.g. `Mistral AI`): the official site is looked up first. `domain` wins when both are given. */
53
+ company_name?: string | null;
54
+ /** The company's website: a domain such as `stripe.com` or a full URL (`https://stripe.com/`). Give this or `company_name`. */
55
+ domain?: string | null;
56
+ /** Language of the free-text values of the answer (`en` by default; `fr`, `de`, `es`, `pt-BR`...). The pages may be in any language; the JSON keys are always English. */
57
+ language?: string | null;
58
+ }
59
+ export interface GetStructuredDataResponse {
60
+ /** How old this answer is, in seconds (0 for a fresh read). */
61
+ age_seconds: number;
62
+ /** Every automatic correction applied to the model's answer, in order. */
63
+ applied_fixes: unknown[];
64
+ /** The structured answer (an object or an array), corrected against `schema` when one was given. */
65
+ data: unknown;
66
+ /** The URL actually read, after redirects. */
67
+ final_url: string;
68
+ /** `true` when this answer was served from a stored result rather than computed now. */
69
+ from_cache: boolean;
70
+ /** `true` when the page text came from a stored copy (fresh enough for `max_age_seconds`). */
71
+ page_from_cache: boolean;
72
+ /** `true` when the page was longer than the amount of text the answer is based on. */
73
+ page_truncated: boolean;
74
+ /** Every schema violation that could not be corrected. */
75
+ remaining_issues: unknown[];
76
+ /** When the page was read to build this answer (UTC). */
77
+ retrieved_at: string;
78
+ /** `true` when the page could not be refreshed and an older stored copy was used. */
79
+ stale_page: boolean;
80
+ /** The page title, when one could be extracted. */
81
+ title?: string | null;
82
+ /** The URL that was requested. */
83
+ url: string;
84
+ /** Whether `data` satisfies `schema` after correction; absent when no schema was given. */
85
+ valid?: boolean | null;
86
+ }
87
+ export interface GetStructuredDataRequest {
88
+ /** The oldest answer you accept, in seconds. Omit it for the default (an identical question about the same page up to 1 hour old); `0` forces a fresh read of the page and a fresh answer. The response always says how old it is. */
89
+ max_age_seconds?: number | null;
90
+ /** What to extract or answer, in plain language, e.g. "list the pricing plans with their name and monthly price in USD". */
91
+ question: string;
92
+ /** Optional JSON Schema the answer must satisfy. When given, the answer is validated against it and automatically corrected where a safe fix exists (type coercion, missing defaults, out-of-range numbers, unknown properties); anything that cannot be fixed is reported in `remaining_issues`. Omitted = a free-form JSON answer, returned as-is. */
93
+ schema?: unknown;
94
+ /** Address of the web page to read (`http` or `https`). */
95
+ url: string;
96
+ }
97
+ /** Typed client for url-extract-service, e.g. `client.getCompanyProfile(...)`. */
98
+ export declare class Client extends BaseClient {
99
+ /** [Deprecated - use company_profile_get_profile] Company profile from a domain or a name as valid JSON ($0.009, x402) */
100
+ getCompanyProfile(request: GetCompanyProfileRequest): Promise<GetCompanyProfileResponse>;
101
+ /** URL extract with a question: ask any web page a question and get structured data as JSON that matches your schema ($0.02, x402) */
102
+ getStructuredData(request: GetStructuredDataRequest): Promise<GetStructuredDataResponse>;
103
+ }
104
+ export { ClientOptions };
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Typed HTTP client and request/response interfaces for url-extract-service.
3
+ */
4
+ import { Client as BaseClient } from "@xyz17711/core";
5
+ /** Typed client for url-extract-service, e.g. `client.getCompanyProfile(...)`. */
6
+ export class Client extends BaseClient {
7
+ /** [Deprecated - use company_profile_get_profile] Company profile from a domain or a name as valid JSON ($0.009, x402) */
8
+ async getCompanyProfile(request) {
9
+ return this.post("/v1/url-extract/get_company_profile", request);
10
+ }
11
+ /** URL extract with a question: ask any web page a question and get structured data as JSON that matches your schema ($0.02, x402) */
12
+ async getStructuredData(request) {
13
+ return this.post("/v1/url-extract/get_structured_data", request);
14
+ }
15
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * LangChain.js tools for url-extract-service, grouped in one Toolkit -- one tool per operation, each just an async function (JS has no separate sync form to generate). Requires the `@langchain/core`+`zod` peer dependencies declared in this package's own package.json -- imported from `url-extract/langchain`, never from the package root, so importing the base client never requires them installed.
3
+ */
4
+ import { z } from "zod";
5
+ import { Client } from "./index.js";
6
+ export declare class UrlExtractToolkit {
7
+ private client;
8
+ constructor(client: Client);
9
+ getTools(): (import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
10
+ company_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
11
+ domain: z.ZodOptional<z.ZodNullable<z.ZodString>>;
12
+ language: z.ZodOptional<z.ZodNullable<z.ZodString>>;
13
+ }, z.core.$strip>, {
14
+ company_name?: string | null | undefined;
15
+ domain?: string | null | undefined;
16
+ language?: string | null | undefined;
17
+ }, {
18
+ company_name?: string | null | undefined;
19
+ domain?: string | null | undefined;
20
+ language?: string | null | undefined;
21
+ }, import("./index.js").GetCompanyProfileResponse, unknown, "getCompanyProfile"> | import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
22
+ max_age_seconds: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
23
+ question: z.ZodString;
24
+ schema: z.ZodOptional<z.ZodUnknown>;
25
+ url: z.ZodString;
26
+ }, z.core.$strip>, {
27
+ question: string;
28
+ url: string;
29
+ max_age_seconds?: number | null | undefined;
30
+ schema?: unknown;
31
+ }, {
32
+ question: string;
33
+ url: string;
34
+ max_age_seconds?: number | null | undefined;
35
+ schema?: unknown;
36
+ }, import("./index.js").GetStructuredDataResponse, unknown, "getStructuredData">)[];
37
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * LangChain.js tools for url-extract-service, grouped in one Toolkit -- one tool per operation, each just an async function (JS has no separate sync form to generate). Requires the `@langchain/core`+`zod` peer dependencies declared in this package's own package.json -- imported from `url-extract/langchain`, never from the package root, so importing the base client never requires them installed.
3
+ */
4
+ import { tool } from "@langchain/core/tools";
5
+ import { z } from "zod";
6
+ export class UrlExtractToolkit {
7
+ constructor(client) {
8
+ this.client = client;
9
+ }
10
+ getTools() {
11
+ return [
12
+ tool(async (input) => this.client.getCompanyProfile(input), {
13
+ name: "getCompanyProfile",
14
+ description: "[Deprecated - use company_profile_get_profile] Company profile from a domain or a name as valid JSON ($0.009, x402)",
15
+ schema: z.object({ company_name: z.string().nullable().optional(), domain: z.string().nullable().optional(), language: z.string().nullable().optional() }),
16
+ }),
17
+ tool(async (input) => this.client.getStructuredData(input), {
18
+ name: "getStructuredData",
19
+ description: "URL extract with a question: ask any web page a question and get structured data as JSON that matches your schema ($0.02, x402)",
20
+ schema: z.object({ max_age_seconds: z.number().nullable().optional(), question: z.string(), schema: z.unknown().optional(), url: z.string() }),
21
+ }),
22
+ ];
23
+ }
24
+ }
package/package.json CHANGED
@@ -1,6 +1,70 @@
1
1
  {
2
2
  "name": "@xyz17711/url-extract",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "Typed TypeScript client for the 17711.xyz Url Extract API: pay-per-call, settled in USDC via x402.",
5
+ "license": "MIT",
6
+ "author": "17711 Services",
7
+ "homepage": "https://api.17711.xyz",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/17711-services/clients.git",
11
+ "directory": "node/packages/url-extract"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/17711-services/clients/issues"
15
+ },
16
+ "keywords": [
17
+ "x402",
18
+ "usdc",
19
+ "api-client",
20
+ "pay-per-call",
21
+ "ai-agents",
22
+ "mcp",
23
+ "langchain",
24
+ "url-extract"
25
+ ],
26
+ "files": [
27
+ "dist",
28
+ "README.md"
29
+ ],
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "type": "module",
34
+ "main": "dist/index.js",
35
+ "types": "dist/index.d.ts",
36
+ "exports": {
37
+ ".": {
38
+ "types": "./dist/index.d.ts",
39
+ "default": "./dist/index.js"
40
+ },
41
+ "./langchain": {
42
+ "types": "./dist/langchain.d.ts",
43
+ "default": "./dist/langchain.js"
44
+ }
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -p .",
48
+ "test": "npm run build && node --test test/*.test.mjs"
49
+ },
50
+ "dependencies": {
51
+ "@xyz17711/core": "^0.1.0"
52
+ },
53
+ "peerDependencies": {
54
+ "@langchain/core": ">=0.3",
55
+ "zod": "^3 || ^4"
56
+ },
57
+ "peerDependenciesMeta": {
58
+ "@langchain/core": {
59
+ "optional": true
60
+ },
61
+ "zod": {
62
+ "optional": true
63
+ }
64
+ },
65
+ "devDependencies": {
66
+ "typescript": "^5",
67
+ "@langchain/core": "^1.2",
68
+ "zod": "^4"
69
+ }
70
+ }