@tmturtle/http-client 1.0.0

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 ADDED
@@ -0,0 +1,36 @@
1
+ # Trademark Turtle HTTP Client
2
+
3
+ Typed access to Trademark Turtle search, exact trademark identities, listing
4
+ text matching, reports, account context, and service status.
5
+
6
+ ## Install
7
+
8
+ ```sh
9
+ bun add @tmturtle/http-client
10
+ ```
11
+
12
+ ## Use
13
+
14
+ ```ts
15
+ import { createTmturtleClient } from "@tmturtle/http-client";
16
+
17
+ const client = createTmturtleClient({
18
+ apiKey: process.env.TMTURTLE_API_KEY!,
19
+ baseUrl: "https://tmturtle.merchbase.co",
20
+ });
21
+
22
+ const results = await client.trademarks.search.query({
23
+ match: "both",
24
+ mode: "multi",
25
+ query: "turtle club",
26
+ status: "live",
27
+ });
28
+
29
+ const trademark = await client.trademarks.get.query({
30
+ serialNumber: "60146682",
31
+ });
32
+ ```
33
+
34
+ The package exports `TmturtleClient`, `TmturtleRouterInputs`, and
35
+ `TmturtleRouterOutputs`. See the [HTTP API reference](https://github.com/merchbaseco/tmturtle/blob/main/docs/reference/http-api.md)
36
+ for authorization, procedure, pagination, and error contracts.
@@ -0,0 +1,532 @@
1
+ import { CreateTRPCClient } from "@trpc/client";
2
+ import { inferRouterInputs, inferRouterOutputs } from "@trpc/server";
3
+ //#region ../../apps/server/src/ingestion/mark-types.d.ts
4
+ declare const markVersions: {
5
+ readonly authorityPolicy: "uspto-authority-v1";
6
+ readonly normalization: "uspto-normalization-v1";
7
+ readonly projection: "uspto-projection-v2";
8
+ readonly sourceProfile: "uspto-application-xml-v2.0-v1";
9
+ };
10
+ type MarkVersions = Omit<typeof markVersions, "projection"> & {
11
+ projection: string;
12
+ };
13
+ interface SourceContributor {
14
+ artifactVersionSha256: string;
15
+ claimPath: string;
16
+ group: "mark-presentation";
17
+ physicalRecordIndex: number;
18
+ product: string;
19
+ }
20
+ type MarkType = "design" | "other" | "text" | "typeset";
21
+ interface MarkClass {
22
+ internationalCode: string | null;
23
+ statusCode: string | null;
24
+ statusDate: string | null;
25
+ }
26
+ interface MarkGoodsServices {
27
+ text: string | null;
28
+ typeCode: string | null;
29
+ }
30
+ interface MarkOwner {
31
+ entryNumber: string | null;
32
+ partyName: string | null;
33
+ partyType: string | null;
34
+ }
35
+ interface MarkStatusEvent {
36
+ code: string | null;
37
+ date: string | null;
38
+ description: string | null;
39
+ number: string | null;
40
+ type: string | null;
41
+ }
42
+ interface ProjectedMark {
43
+ classes: MarkClass[];
44
+ contributors: SourceContributor[];
45
+ goodsServices: MarkGoodsServices[];
46
+ kind: "resolved";
47
+ mark: {
48
+ filingDate: string | null;
49
+ markDrawingCode: string | null;
50
+ registrationDate: string | null;
51
+ registrationNumber: string | null;
52
+ serialNumber: string;
53
+ sourceTransactionDate: string | null;
54
+ statusCode: string | null;
55
+ statusDate: string | null;
56
+ wordMark: string | null;
57
+ };
58
+ owners: MarkOwner[];
59
+ statusEvents: MarkStatusEvent[];
60
+ versions: MarkVersions;
61
+ }
62
+ //#endregion
63
+ //#region ../../apps/server/src/api/contracts.d.ts
64
+ declare const legalDisclaimer = "Trademark data is informational, not legal advice. Verify critical decisions with the USPTO or qualified counsel.";
65
+ interface AuthenticatedAccount {
66
+ accountId: string;
67
+ credential: {
68
+ type: "api-key";
69
+ keyId: string;
70
+ suffix: string;
71
+ } | {
72
+ type: "clerk";
73
+ };
74
+ }
75
+ interface PublicApiKey {
76
+ createdAt: string;
77
+ id: string;
78
+ lastUsedAt: string | null;
79
+ name: string;
80
+ status: "active" | "revoked";
81
+ suffix: string;
82
+ }
83
+ interface AccountService {
84
+ createApiKey: (name: string) => Promise<{
85
+ key: PublicApiKey;
86
+ token: string;
87
+ }>;
88
+ listApiKeys: () => Promise<PublicApiKey[]>;
89
+ revokeApiKey: (id: string) => Promise<PublicApiKey | null>;
90
+ }
91
+ type MarkDetail = Omit<ProjectedMark, "contributors" | "kind" | "mark" | "versions"> & {
92
+ legalDisclaimer: typeof legalDisclaimer;
93
+ mark: ProjectedMark["mark"] & {
94
+ status: "dead" | "live" | "unknown";
95
+ };
96
+ provenance: {
97
+ contributors: SourceContributor[];
98
+ versions: ProjectedMark["versions"];
99
+ };
100
+ type: MarkType;
101
+ };
102
+ interface SearchInputBase {
103
+ expectedDataVersion?: string;
104
+ limit: 25;
105
+ offset: number;
106
+ query: string;
107
+ registered: "all" | "yes" | "no";
108
+ sort: "relevance" | "newest-activity" | "oldest-activity";
109
+ status: "all" | "live" | "dead";
110
+ type: "all" | "design" | "typeset" | "text" | "other";
111
+ }
112
+ type SearchInput = SearchInputBase & ({
113
+ match: "exact" | "partial" | "both";
114
+ mode: "multi";
115
+ } | {
116
+ match?: never;
117
+ mode: "split";
118
+ } | {
119
+ match?: never;
120
+ mode: "wildcard";
121
+ });
122
+ interface MarkSummary {
123
+ goodsServicesExcerpt: string | null;
124
+ internationalClasses: string[];
125
+ owner: string | null;
126
+ registrationNumber: string | null;
127
+ serialNumber: string;
128
+ sourceTransactionDate: string | null;
129
+ status: "live" | "dead" | "unknown";
130
+ statusDate: string | null;
131
+ type: MarkType;
132
+ wordMark: string;
133
+ }
134
+ interface MarkPage {
135
+ items: MarkSummary[];
136
+ limit: 25;
137
+ meta: {
138
+ dataVersion: string;
139
+ };
140
+ offset: number;
141
+ total: number;
142
+ }
143
+ interface SearchPage extends Omit<MarkPage, "items"> {
144
+ items: Array<MarkSummary & {
145
+ match: "exact" | "partial";
146
+ }>;
147
+ liveMatchCounts: {
148
+ exact: number;
149
+ partial: number;
150
+ };
151
+ }
152
+ interface LatestInput {
153
+ expectedDataVersion?: string;
154
+ limit: 25;
155
+ offset: number;
156
+ }
157
+ interface MatchTextInput {
158
+ text: string;
159
+ type: "all" | "design" | "typeset" | "text" | "other";
160
+ }
161
+ interface MatchTextResult {
162
+ matches: Array<{
163
+ end: number;
164
+ mark: MarkSummary;
165
+ start: number;
166
+ }>;
167
+ meta: MarkPage["meta"];
168
+ }
169
+ interface MarksService {
170
+ getByRegistrationNumber: (registrationNumber: string) => Promise<MarkDetail | null>;
171
+ getBySerialNumber: (serialNumber: string) => Promise<MarkDetail | null>;
172
+ latest: (input: LatestInput) => Promise<MarkPage>;
173
+ matchText: (input: MatchTextInput) => Promise<MatchTextResult>;
174
+ search: (input: SearchInput) => Promise<SearchPage>;
175
+ }
176
+ interface ReportInput {
177
+ event: "filed" | "published-for-opposition" | "registered";
178
+ expectedDataVersion?: string;
179
+ expectedFrom?: string;
180
+ expectedTo?: string;
181
+ limit: 25;
182
+ offset: number;
183
+ registered: "all" | "yes" | "no";
184
+ sort: "newest-activity" | "oldest-activity";
185
+ status: "all" | "live" | "dead";
186
+ type: "all" | "design" | "typeset" | "text" | "other";
187
+ window?: "previous-week";
188
+ }
189
+ interface ReportPage extends MarkPage {
190
+ from: string | null;
191
+ items: Omit<SearchPage["items"][number], "match">[];
192
+ to: string | null;
193
+ }
194
+ interface ReportsService {
195
+ run: (input: ReportInput) => Promise<ReportPage>;
196
+ }
197
+ interface SyncStatus {
198
+ activeState: "applying" | "discovering" | "downloading" | "failed" | "idle";
199
+ dataVersion: number;
200
+ failedCount: number;
201
+ lastSuccessfulUpdateAt: string | null;
202
+ latestProcessedDate: string | null;
203
+ pendingCount: number;
204
+ }
205
+ interface SyncService {
206
+ status: () => Promise<SyncStatus>;
207
+ }
208
+ interface BoundedPage<T> {
209
+ items: T[];
210
+ limit: number;
211
+ offset: number;
212
+ total: number;
213
+ }
214
+ interface OperatorArtifact {
215
+ applicationCompletedAt: string | null;
216
+ applicationState: "applying" | "complete" | "needs_attention" | "pending";
217
+ appliedRecordCount: number;
218
+ artifactId: string;
219
+ bytes: number | null;
220
+ currentError: string | null;
221
+ downloadedAt: string | null;
222
+ downloadResponseState: {
223
+ contentLength?: string;
224
+ contentType?: string;
225
+ etag?: string;
226
+ observedAt?: string;
227
+ providerRequestCount?: number;
228
+ rateLimitReset?: string;
229
+ requestId?: string;
230
+ retryAfter?: string;
231
+ retryAfterSeconds?: number;
232
+ retryNotBefore?: string;
233
+ status: number;
234
+ } | null;
235
+ downloadState: "blocked" | "downloaded" | "downloading" | "pending";
236
+ filename: string;
237
+ parserVersion: string | null;
238
+ physicalRecordCount: number;
239
+ processingDisposition: "covered" | "deferred" | "required";
240
+ product: "TRTDXFAP" | "TRTYRAP";
241
+ projectedMarkCount: number;
242
+ sha256: string | null;
243
+ sourceFromDate: string;
244
+ sourceToDate: string;
245
+ storageState: "cleaned-up" | "not-downloaded" | "retained";
246
+ unresolvedRecordCount: number;
247
+ updatedAt: string;
248
+ }
249
+ interface OperatorPageInput {
250
+ limit: number;
251
+ offset: number;
252
+ }
253
+ interface PublicSourceStatus {
254
+ catalog: {
255
+ liveMarkCount: number;
256
+ registeredMarkCount: number;
257
+ totalMarkCount: number;
258
+ };
259
+ source: {
260
+ currentArtifact: {
261
+ filename: string;
262
+ state: "applying" | "discovering" | "downloading";
263
+ } | null;
264
+ lastActivityAt: string | null;
265
+ latestProcessedDate: string | null;
266
+ processingActivity: Array<{
267
+ count: number;
268
+ date: string;
269
+ }>;
270
+ };
271
+ }
272
+ interface OperatorSyncStatus extends PublicSourceStatus {
273
+ attention: {
274
+ items: Array<{
275
+ artifactId: string;
276
+ filename: string;
277
+ httpStatus: number | null;
278
+ message: string | null;
279
+ providerRequestCount: number | null;
280
+ retryNotBefore: string | null;
281
+ stage: "application" | "download" | "worker";
282
+ updatedAt: string;
283
+ }>;
284
+ total: number;
285
+ };
286
+ }
287
+ interface OperatorSyncService {
288
+ artifacts: (input: OperatorPageInput) => Promise<BoundedPage<OperatorArtifact>>;
289
+ publicStatus: () => Promise<PublicSourceStatus>;
290
+ status: () => Promise<OperatorSyncStatus>;
291
+ }
292
+ //#endregion
293
+ //#region ../../apps/server/src/api/router.d.ts
294
+ interface AppContext {
295
+ account: AccountService;
296
+ auth: AuthenticatedAccount;
297
+ marks: MarksService;
298
+ operator: boolean;
299
+ operatorSync: OperatorSyncService;
300
+ reports: ReportsService;
301
+ sync: SyncService;
302
+ }
303
+ declare const authenticatedClientRouter: import("@trpc/server").TRPCBuiltRouter<{
304
+ ctx: AppContext;
305
+ meta: object;
306
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
307
+ transformer: false;
308
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
309
+ account: import("@trpc/server").TRPCBuiltRouter<{
310
+ ctx: AppContext;
311
+ meta: object;
312
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
313
+ transformer: false;
314
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
315
+ "api-keys": import("@trpc/server").TRPCBuiltRouter<{
316
+ ctx: AppContext;
317
+ meta: object;
318
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
319
+ transformer: false;
320
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
321
+ create: import("@trpc/server").TRPCMutationProcedure<{
322
+ input: {
323
+ name: string;
324
+ };
325
+ output: {
326
+ key: PublicApiKey;
327
+ token: string;
328
+ };
329
+ meta: object;
330
+ }>;
331
+ list: import("@trpc/server").TRPCQueryProcedure<{
332
+ input: void;
333
+ output: PublicApiKey[];
334
+ meta: object;
335
+ }>;
336
+ revoke: import("@trpc/server").TRPCMutationProcedure<{
337
+ input: {
338
+ id: string;
339
+ };
340
+ output: PublicApiKey;
341
+ meta: object;
342
+ }>;
343
+ }>>;
344
+ me: import("@trpc/server").TRPCQueryProcedure<{
345
+ input: void;
346
+ output: AuthenticatedAccount;
347
+ meta: object;
348
+ }>;
349
+ }>>;
350
+ marks: import("@trpc/server").TRPCBuiltRouter<{
351
+ ctx: AppContext;
352
+ meta: object;
353
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
354
+ transformer: false;
355
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
356
+ get: import("@trpc/server").TRPCQueryProcedure<{
357
+ input: {
358
+ serialNumber: string;
359
+ };
360
+ output: MarkDetail;
361
+ meta: object;
362
+ }>;
363
+ "get-by-registration": import("@trpc/server").TRPCQueryProcedure<{
364
+ input: {
365
+ registrationNumber: string;
366
+ };
367
+ output: MarkDetail;
368
+ meta: object;
369
+ }>;
370
+ latest: import("@trpc/server").TRPCQueryProcedure<{
371
+ input: {
372
+ expectedDataVersion?: string | undefined;
373
+ limit?: 25 | undefined;
374
+ offset?: number | undefined;
375
+ };
376
+ output: MarkPage;
377
+ meta: object;
378
+ }>;
379
+ "match-text": import("@trpc/server").TRPCQueryProcedure<{
380
+ input: {
381
+ text: string;
382
+ type?: "all" | "design" | "other" | "text" | "typeset" | undefined;
383
+ };
384
+ output: MatchTextResult;
385
+ meta: object;
386
+ }>;
387
+ search: import("@trpc/server").TRPCQueryProcedure<{
388
+ input: {
389
+ expectedDataVersion?: string | undefined;
390
+ limit?: 25 | undefined;
391
+ offset?: number | undefined;
392
+ query: string;
393
+ registered?: "all" | "no" | "yes" | undefined;
394
+ sort?: "newest-activity" | "oldest-activity" | "relevance" | undefined;
395
+ status?: "all" | "dead" | "live" | undefined;
396
+ type?: "all" | "design" | "other" | "text" | "typeset" | undefined;
397
+ match?: "both" | "exact" | "partial" | undefined;
398
+ mode: "multi";
399
+ } | {
400
+ expectedDataVersion?: string | undefined;
401
+ limit?: 25 | undefined;
402
+ offset?: number | undefined;
403
+ query: string;
404
+ registered?: "all" | "no" | "yes" | undefined;
405
+ sort?: "newest-activity" | "oldest-activity" | "relevance" | undefined;
406
+ status?: "all" | "dead" | "live" | undefined;
407
+ type?: "all" | "design" | "other" | "text" | "typeset" | undefined;
408
+ match?: undefined;
409
+ mode: "split";
410
+ } | {
411
+ expectedDataVersion?: string | undefined;
412
+ limit?: 25 | undefined;
413
+ offset?: number | undefined;
414
+ query: string;
415
+ registered?: "all" | "no" | "yes" | undefined;
416
+ sort?: "newest-activity" | "oldest-activity" | "relevance" | undefined;
417
+ status?: "all" | "dead" | "live" | undefined;
418
+ type?: "all" | "design" | "other" | "text" | "typeset" | undefined;
419
+ match?: undefined;
420
+ mode: "wildcard";
421
+ };
422
+ output: SearchPage;
423
+ meta: object;
424
+ }>;
425
+ }>>;
426
+ reports: import("@trpc/server").TRPCBuiltRouter<{
427
+ ctx: AppContext;
428
+ meta: object;
429
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
430
+ transformer: false;
431
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
432
+ run: import("@trpc/server").TRPCQueryProcedure<{
433
+ input: {
434
+ expectedDataVersion?: string | undefined;
435
+ limit?: 25 | undefined;
436
+ offset?: number | undefined;
437
+ registered?: "all" | "no" | "yes" | undefined;
438
+ sort?: "newest-activity" | "oldest-activity" | undefined;
439
+ status?: "all" | "dead" | "live" | undefined;
440
+ type?: "all" | "design" | "other" | "text" | "typeset" | undefined;
441
+ expectedFrom?: string | undefined;
442
+ expectedTo?: string | undefined;
443
+ event: "filed";
444
+ window: "previous-week";
445
+ } | {
446
+ expectedDataVersion?: string | undefined;
447
+ limit?: 25 | undefined;
448
+ offset?: number | undefined;
449
+ registered?: "all" | "no" | "yes" | undefined;
450
+ sort?: "newest-activity" | "oldest-activity" | undefined;
451
+ status?: "all" | "dead" | "live" | undefined;
452
+ type?: "all" | "design" | "other" | "text" | "typeset" | undefined;
453
+ expectedFrom?: string | undefined;
454
+ expectedTo?: string | undefined;
455
+ event: "registered";
456
+ window: "previous-week";
457
+ } | {
458
+ expectedDataVersion?: string | undefined;
459
+ limit?: 25 | undefined;
460
+ offset?: number | undefined;
461
+ registered?: "all" | "no" | "yes" | undefined;
462
+ sort?: "newest-activity" | "oldest-activity" | undefined;
463
+ status?: "all" | "dead" | "live" | undefined;
464
+ type?: "all" | "design" | "other" | "text" | "typeset" | undefined;
465
+ event: "published-for-opposition";
466
+ };
467
+ output: ReportPage;
468
+ meta: object;
469
+ }>;
470
+ }>>;
471
+ sync: import("@trpc/server").TRPCBuiltRouter<{
472
+ ctx: AppContext;
473
+ meta: object;
474
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
475
+ transformer: false;
476
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
477
+ status: import("@trpc/server").TRPCQueryProcedure<{
478
+ input: void;
479
+ output: SyncStatus;
480
+ meta: object;
481
+ }>;
482
+ }>>;
483
+ }>>;
484
+ type AuthenticatedClientRouter = typeof authenticatedClientRouter;
485
+ //#endregion
486
+ //#region src/index.d.ts
487
+ type InternalClient = CreateTRPCClient<AuthenticatedClientRouter>;
488
+ type InternalInputs = inferRouterInputs<AuthenticatedClientRouter>;
489
+ type InternalOutputs = inferRouterOutputs<AuthenticatedClientRouter>;
490
+ interface TmturtleClient {
491
+ account: InternalClient["account"];
492
+ reports: InternalClient["reports"];
493
+ status: InternalClient["sync"]["status"];
494
+ trademarks: {
495
+ get: InternalClient["marks"]["get"];
496
+ getByRegistration: InternalClient["marks"]["get-by-registration"];
497
+ latest: InternalClient["marks"]["latest"];
498
+ matchText: InternalClient["marks"]["match-text"];
499
+ search: InternalClient["marks"]["search"];
500
+ };
501
+ }
502
+ interface TmturtleRouterInputs {
503
+ account: InternalInputs["account"];
504
+ reports: InternalInputs["reports"];
505
+ status: InternalInputs["sync"]["status"];
506
+ trademarks: {
507
+ get: InternalInputs["marks"]["get"];
508
+ getByRegistration: InternalInputs["marks"]["get-by-registration"];
509
+ latest: InternalInputs["marks"]["latest"];
510
+ matchText: InternalInputs["marks"]["match-text"];
511
+ search: InternalInputs["marks"]["search"];
512
+ };
513
+ }
514
+ interface TmturtleRouterOutputs {
515
+ account: InternalOutputs["account"];
516
+ reports: InternalOutputs["reports"];
517
+ status: InternalOutputs["sync"]["status"];
518
+ trademarks: {
519
+ get: InternalOutputs["marks"]["get"];
520
+ getByRegistration: InternalOutputs["marks"]["get-by-registration"];
521
+ latest: InternalOutputs["marks"]["latest"];
522
+ matchText: InternalOutputs["marks"]["match-text"];
523
+ search: InternalOutputs["marks"]["search"];
524
+ };
525
+ }
526
+ interface TmturtleClientOptions {
527
+ apiKey: string;
528
+ baseUrl: string;
529
+ }
530
+ declare function createTmturtleClient({ apiKey, baseUrl }: TmturtleClientOptions): TmturtleClient;
531
+ //#endregion
532
+ export { TmturtleClient, TmturtleClientOptions, TmturtleRouterInputs, TmturtleRouterOutputs, createTmturtleClient };
package/dist/index.mjs ADDED
@@ -0,0 +1,22 @@
1
+ import { createTRPCClient, httpLink } from "@trpc/client";
2
+ //#region src/index.ts
3
+ function createTmturtleClient({ apiKey, baseUrl }) {
4
+ const client = createTRPCClient({ links: [httpLink({
5
+ headers: { authorization: `Bearer ${apiKey}` },
6
+ url: new URL("/api/trpc", baseUrl).toString()
7
+ })] });
8
+ return {
9
+ account: client.account,
10
+ reports: client.reports,
11
+ status: client.sync.status,
12
+ trademarks: {
13
+ get: client.marks.get,
14
+ getByRegistration: client.marks["get-by-registration"],
15
+ latest: client.marks.latest,
16
+ matchText: client.marks["match-text"],
17
+ search: client.marks.search
18
+ }
19
+ };
20
+ }
21
+ //#endregion
22
+ export { createTmturtleClient };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@tmturtle/http-client",
3
+ "version": "1.0.0",
4
+ "description": "Typed HTTP client for the Trademark Turtle API",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/merchbaseco/tmturtle.git",
8
+ "directory": "packages/http-client"
9
+ },
10
+ "homepage": "https://github.com/merchbaseco/tmturtle#readme",
11
+ "bugs": "https://github.com/merchbaseco/tmturtle/issues",
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "type": "module",
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.mts",
22
+ "import": "./dist/index.mjs"
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "tsdown src/index.ts --format esm --dts --clean",
27
+ "prepack": "bun run build"
28
+ },
29
+ "dependencies": {
30
+ "@trpc/client": "11.18.0",
31
+ "@trpc/server": "11.18.0"
32
+ },
33
+ "devDependencies": {
34
+ "tsdown": "0.22.8"
35
+ }
36
+ }