@hypercerts-org/sdk-core 0.10.0-beta.4 → 0.10.0-beta.5

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/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { NodeSavedSession, NodeSavedState, OAuthSession } from '@atproto/oauth-client-node';
2
2
  import { z } from 'zod';
3
- import { EventEmitter } from 'eventemitter3';
4
- import { OrgHypercertsClaimEvidence, OrgHypercertsClaimActivity, OrgHypercertsClaimCollection, ComAtprotoRepoStrongRef, OrgHypercertsClaimRights, OrgHypercertsClaimContribution, OrgHypercertsClaimMeasurement, OrgHypercertsClaimEvaluation, OrgHypercertsClaimProject, AppCertifiedLocation, AppCertifiedBadgeAward, AppCertifiedBadgeDefinition, AppCertifiedBadgeResponse, OrgHypercertsFundingReceipt, OrgHypercertsDefs } from '@hypercerts-org/lexicon';
5
- export { AppCertifiedBadgeAward, AppCertifiedBadgeDefinition, AppCertifiedBadgeResponse, AppCertifiedDefs, AppCertifiedLocation, ComAtprotoRepoStrongRef, HYPERCERTS_LEXICON_DOC, HYPERCERTS_LEXICON_JSON, HYPERCERTS_NSIDS, HYPERCERTS_NSIDS_BY_TYPE, HYPERCERTS_SCHEMAS, HYPERCERTS_SCHEMA_DICT, OrgHypercertsClaimActivity, OrgHypercertsClaimCollection, OrgHypercertsClaimContribution, OrgHypercertsClaimEvaluation, OrgHypercertsClaimEvidence, OrgHypercertsClaimMeasurement, OrgHypercertsClaimProject, OrgHypercertsClaimRights, OrgHypercertsDefs, OrgHypercertsFundingReceipt, lexicons, validate } from '@hypercerts-org/lexicon';
6
- import { Agent } from '@atproto/api';
7
- import { LexiconDoc } from '@atproto/lexicon';
3
+ import { LexiconDoc as LexiconDoc$1, Lexicons } from '@atproto/lexicon';
8
4
  export { BlobRef, JsonBlobRef } from '@atproto/lexicon';
5
+ import { Agent } from '@atproto/api';
6
+ import { EventEmitter } from 'eventemitter3';
7
+ import { OrgHypercertsClaimActivity, OrgHypercertsClaimCollection, ComAtprotoRepoStrongRef, OrgHypercertsClaimRights, OrgHypercertsClaimContributionDetails, OrgHypercertsClaimContributorInformation, OrgHypercertsClaimMeasurement, OrgHypercertsClaimEvaluation, OrgHypercertsHelperWorkScopeTag, AppCertifiedLocation, AppCertifiedBadgeAward, AppCertifiedBadgeDefinition, AppCertifiedBadgeResponse, OrgHypercertsFundingReceipt, OrgHypercertsClaimEvidence, OrgHypercertsDefs } from '@hypercerts-org/lexicon';
8
+ export { AppCertifiedBadgeAward, AppCertifiedBadgeDefinition, AppCertifiedBadgeResponse, AppCertifiedDefs, AppCertifiedLocation, ComAtprotoRepoStrongRef, HYPERCERTS_LEXICON_DOC, HYPERCERTS_LEXICON_JSON, HYPERCERTS_NSIDS, HYPERCERTS_NSIDS_BY_TYPE, HYPERCERTS_SCHEMAS, HYPERCERTS_SCHEMA_DICT, OrgHypercertsClaimActivity, OrgHypercertsClaimCollection, OrgHypercertsClaimContributionDetails, OrgHypercertsClaimContributorInformation, OrgHypercertsClaimEvaluation, OrgHypercertsClaimEvidence, OrgHypercertsClaimMeasurement, OrgHypercertsClaimRights, OrgHypercertsDefs, OrgHypercertsFundingReceipt, OrgHypercertsHelperWorkScopeTag, lexicons, validate } from '@hypercerts-org/lexicon';
9
9
 
10
10
  /**
11
11
  * Storage interface for persisting OAuth sessions.
@@ -737,6 +737,236 @@ declare const CollaboratorSchema: z.ZodObject<{
737
737
  */
738
738
  type Collaborator = z.infer<typeof CollaboratorSchema>;
739
739
 
740
+ /**
741
+ * LexiconRegistry - Manages custom lexicon registration and validation.
742
+ *
743
+ * This module provides a registry for AT Protocol lexicon schemas,
744
+ * allowing developers to register custom lexicons and validate records
745
+ * against registered schemas.
746
+ *
747
+ * @packageDocumentation
748
+ */
749
+
750
+ /**
751
+ * Validation result from lexicon validation.
752
+ */
753
+ interface ValidationResult {
754
+ /**
755
+ * Whether the record is valid according to the lexicon.
756
+ */
757
+ valid: boolean;
758
+ /**
759
+ * Error message if validation failed.
760
+ */
761
+ error?: string;
762
+ }
763
+ /**
764
+ * Registry for managing AT Protocol lexicon schemas.
765
+ *
766
+ * The LexiconRegistry allows developers to:
767
+ * - Register custom lexicon definitions
768
+ * - Validate records against registered schemas
769
+ * - Query registered lexicons
770
+ * - Add lexicons to AT Protocol agents
771
+ *
772
+ * @example Basic usage
773
+ * ```typescript
774
+ * const registry = new LexiconRegistry();
775
+ *
776
+ * // Register a custom lexicon
777
+ * registry.register({
778
+ * lexicon: 1,
779
+ * id: "org.myapp.customRecord",
780
+ * defs: {
781
+ * main: {
782
+ * type: "record",
783
+ * key: "tid",
784
+ * record: {
785
+ * type: "object",
786
+ * required: ["$type", "title"],
787
+ * properties: {
788
+ * "$type": { type: "string", const: "org.myapp.customRecord" },
789
+ * title: { type: "string" }
790
+ * }
791
+ * }
792
+ * }
793
+ * }
794
+ * });
795
+ *
796
+ * // Validate a record
797
+ * const result = registry.validate("org.myapp.customRecord", {
798
+ * $type: "org.myapp.customRecord",
799
+ * title: "My Record"
800
+ * });
801
+ *
802
+ * if (!result.valid) {
803
+ * console.error(result.error);
804
+ * }
805
+ * ```
806
+ */
807
+ declare class LexiconRegistry {
808
+ private lexicons;
809
+ private registeredIds;
810
+ /**
811
+ * Creates a new LexiconRegistry instance.
812
+ *
813
+ * @param initialLexicons - Optional array of lexicons to register on initialization
814
+ */
815
+ constructor(initialLexicons?: LexiconDoc$1[]);
816
+ /**
817
+ * Registers a single lexicon definition.
818
+ *
819
+ * @param lexicon - The lexicon document to register
820
+ * @throws {Error} If the lexicon is invalid or already registered
821
+ *
822
+ * @example
823
+ * ```typescript
824
+ * registry.register({
825
+ * lexicon: 1,
826
+ * id: "org.myapp.customRecord",
827
+ * defs: { ... }
828
+ * });
829
+ * ```
830
+ */
831
+ register(lexicon: LexiconDoc$1): void;
832
+ /**
833
+ * Registers multiple lexicon definitions at once.
834
+ *
835
+ * @param lexicons - Array of lexicon documents to register
836
+ * @throws {Error} If any lexicon is invalid or already registered
837
+ *
838
+ * @example
839
+ * ```typescript
840
+ * registry.registerMany([lexicon1, lexicon2, lexicon3]);
841
+ * ```
842
+ */
843
+ registerMany(lexicons: LexiconDoc$1[]): void;
844
+ /**
845
+ * Registers a lexicon from a JSON object.
846
+ *
847
+ * This is a convenience method for registering lexicons loaded from JSON files.
848
+ *
849
+ * @param lexiconJson - The lexicon as a plain JavaScript object
850
+ * @throws {ValidationError} If the lexicon is not a valid object
851
+ * @throws {Error} If the lexicon is invalid or already registered
852
+ *
853
+ * @example
854
+ * ```typescript
855
+ * import customLexicon from "./custom-lexicon.json";
856
+ * registry.registerFromJSON(customLexicon);
857
+ * ```
858
+ */
859
+ registerFromJSON(lexiconJson: unknown): void;
860
+ /**
861
+ * Unregisters a lexicon by its NSID.
862
+ *
863
+ * @param nsid - The NSID of the lexicon to unregister
864
+ * @returns True if the lexicon was unregistered, false if it wasn't registered
865
+ *
866
+ * @example
867
+ * ```typescript
868
+ * registry.unregister("org.myapp.customRecord");
869
+ * ```
870
+ */
871
+ unregister(nsid: string): boolean;
872
+ /**
873
+ * Checks if a lexicon is registered.
874
+ *
875
+ * @param nsid - The NSID to check
876
+ * @returns True if the lexicon is registered
877
+ *
878
+ * @example
879
+ * ```typescript
880
+ * if (registry.isRegistered("org.myapp.customRecord")) {
881
+ * // Lexicon is available
882
+ * }
883
+ * ```
884
+ */
885
+ isRegistered(nsid: string): boolean;
886
+ /**
887
+ * Gets a lexicon definition by its NSID.
888
+ *
889
+ * @param nsid - The NSID of the lexicon to retrieve
890
+ * @returns The lexicon document, or undefined if not found
891
+ *
892
+ * @example
893
+ * ```typescript
894
+ * const lexicon = registry.get("org.myapp.customRecord");
895
+ * if (lexicon) {
896
+ * console.log(lexicon.defs);
897
+ * }
898
+ * ```
899
+ */
900
+ get(nsid: string): LexiconDoc$1 | undefined;
901
+ /**
902
+ * Gets all registered lexicon NSIDs.
903
+ *
904
+ * @returns Array of registered NSIDs
905
+ *
906
+ * @example
907
+ * ```typescript
908
+ * const registered = registry.getAll();
909
+ * console.log(`Registered lexicons: ${registered.join(", ")}`);
910
+ * ```
911
+ */
912
+ getAll(): string[];
913
+ /**
914
+ * Validates a record against a registered lexicon.
915
+ *
916
+ * @param nsid - The collection NSID to validate against
917
+ * @param record - The record data to validate
918
+ * @returns Validation result with success status and optional error message
919
+ *
920
+ * @example
921
+ * ```typescript
922
+ * const result = registry.validate("org.myapp.customRecord", {
923
+ * $type: "org.myapp.customRecord",
924
+ * title: "My Record"
925
+ * });
926
+ *
927
+ * if (!result.valid) {
928
+ * console.error(`Validation failed: ${result.error}`);
929
+ * }
930
+ * ```
931
+ */
932
+ validate(nsid: string, record: unknown): ValidationResult;
933
+ /**
934
+ * Adds all registered lexicons to an AT Protocol Agent.
935
+ *
936
+ * This method is currently a no-op as the AT Protocol Agent
937
+ * doesn't provide a public API for adding lexicons at runtime.
938
+ * Lexicons must be registered with the server.
939
+ *
940
+ * This method is kept for future compatibility if the API
941
+ * adds support for client-side lexicon registration.
942
+ *
943
+ * @param _agent - The AT Protocol Agent (currently unused)
944
+ *
945
+ * @example
946
+ * ```typescript
947
+ * const agent = new Agent(session);
948
+ * registry.addToAgent(agent);
949
+ * // Reserved for future use
950
+ * ```
951
+ */
952
+ addToAgent(_agent: Agent): void;
953
+ /**
954
+ * Gets the underlying Lexicons instance.
955
+ *
956
+ * This provides direct access to the AT Protocol Lexicons object
957
+ * for advanced use cases.
958
+ *
959
+ * @returns The internal Lexicons instance
960
+ *
961
+ * @example
962
+ * ```typescript
963
+ * const lexicons = registry.getLexicons();
964
+ * // Use lexicons directly for advanced operations
965
+ * ```
966
+ */
967
+ getLexicons(): Lexicons;
968
+ }
969
+
740
970
  /**
741
971
  * Repository types - Shared types for repository operations
742
972
  * @packageDocumentation
@@ -887,7 +1117,7 @@ interface ProgressStep {
887
1117
  * All hypercert-related lexicons for registration with AT Protocol Agent.
888
1118
  * This array contains all lexicon documents from the published package.
889
1119
  */
890
- declare const HYPERCERT_LEXICONS: LexiconDoc[];
1120
+ declare const HYPERCERT_LEXICONS: LexiconDoc$1[];
891
1121
  /**
892
1122
  * Collection NSIDs (Namespaced Identifiers) for hypercert records.
893
1123
  *
@@ -908,9 +1138,15 @@ declare const HYPERCERT_COLLECTIONS: {
908
1138
  */
909
1139
  readonly LOCATION: "app.certified.location";
910
1140
  /**
911
- * Contribution record collection.
1141
+ * Contribution details record collection.
1142
+ * For storing details about a specific contribution (role, description, timeframe).
1143
+ */
1144
+ readonly CONTRIBUTION_DETAILS: "org.hypercerts.claim.contributionDetails";
1145
+ /**
1146
+ * Contributor information record collection.
1147
+ * For storing contributor profile information (identifier, displayName, image).
912
1148
  */
913
- readonly CONTRIBUTION: "org.hypercerts.claim.contribution";
1149
+ readonly CONTRIBUTOR_INFORMATION: "org.hypercerts.claim.contributorInformation";
914
1150
  /**
915
1151
  * Measurement record collection.
916
1152
  */
@@ -925,12 +1161,9 @@ declare const HYPERCERT_COLLECTIONS: {
925
1161
  readonly EVIDENCE: "org.hypercerts.claim.evidence";
926
1162
  /**
927
1163
  * Collection record collection (groups of hypercerts).
1164
+ * Projects are now collections with type='project'.
928
1165
  */
929
1166
  readonly COLLECTION: "org.hypercerts.claim.collection";
930
- /**
931
- * Project record collection.
932
- */
933
- readonly PROJECT: "org.hypercerts.claim.project";
934
1167
  /**
935
1168
  * Badge award record collection.
936
1169
  */
@@ -947,6 +1180,11 @@ declare const HYPERCERT_COLLECTIONS: {
947
1180
  * Funding receipt record collection.
948
1181
  */
949
1182
  readonly FUNDING_RECEIPT: "org.hypercerts.funding.receipt";
1183
+ /**
1184
+ * Work scope tag record collection.
1185
+ * For defining reusable work scope atoms.
1186
+ */
1187
+ readonly WORK_SCOPE_TAG: "org.hypercerts.helper.workScopeTag";
950
1188
  };
951
1189
 
952
1190
  /**
@@ -960,13 +1198,18 @@ declare const HYPERCERT_COLLECTIONS: {
960
1198
  type StrongRef = ComAtprotoRepoStrongRef.Main;
961
1199
  type HypercertClaim = OrgHypercertsClaimActivity.Main;
962
1200
  type HypercertRights = OrgHypercertsClaimRights.Main;
963
- type HypercertContribution = OrgHypercertsClaimContribution.Main;
1201
+ type HypercertContributionDetails = OrgHypercertsClaimContributionDetails.Main;
1202
+ type HypercertContributorInformation = OrgHypercertsClaimContributorInformation.Main;
1203
+ /** Contributor entry in an activity - can be inline or reference external records */
1204
+ type HypercertContributor = OrgHypercertsClaimActivity.Contributor;
964
1205
  type HypercertMeasurement = OrgHypercertsClaimMeasurement.Main;
965
1206
  type HypercertEvaluation = OrgHypercertsClaimEvaluation.Main;
966
1207
  type HypercertEvidence = OrgHypercertsClaimEvidence.Main;
967
1208
  type HypercertCollection = OrgHypercertsClaimCollection.Main;
968
- type HypercertCollectionClaimItem = OrgHypercertsClaimActivity.ActivityWeight;
969
- type HypercertProject = OrgHypercertsClaimProject.Main;
1209
+ /** Collection item with optional weight */
1210
+ type HypercertCollectionItem = OrgHypercertsClaimCollection.Item;
1211
+ /** Work scope tag for creating reusable scope atoms */
1212
+ type HypercertWorkScopeTag = OrgHypercertsHelperWorkScopeTag.Main;
970
1213
  type HypercertLocation = AppCertifiedLocation.Main;
971
1214
  type BadgeAward = AppCertifiedBadgeAward.Main;
972
1215
  type BadgeDefinition = AppCertifiedBadgeDefinition.Main;
@@ -1002,6 +1245,58 @@ interface HypercertWithMetadata {
1002
1245
  cid: string;
1003
1246
  record: HypercertClaim;
1004
1247
  }
1248
+ /**
1249
+ * Project type - a HypercertCollection with type='project'.
1250
+ */
1251
+ interface HypercertProject extends HypercertCollection {
1252
+ type: "project";
1253
+ }
1254
+ /**
1255
+ * HypercertProject with AT Protocol metadata.
1256
+ */
1257
+ interface HypercertProjectWithMetadata {
1258
+ uri: string;
1259
+ cid: string;
1260
+ record: HypercertProject;
1261
+ }
1262
+ /**
1263
+ * Parameters for creating a project.
1264
+ */
1265
+ interface CreateProjectParams {
1266
+ title: string;
1267
+ shortDescription: string;
1268
+ description?: unknown;
1269
+ avatar?: Blob;
1270
+ banner?: Blob;
1271
+ activities?: Array<{
1272
+ uri: string;
1273
+ cid: string;
1274
+ weight: string;
1275
+ }>;
1276
+ location?: {
1277
+ uri: string;
1278
+ cid: string;
1279
+ };
1280
+ }
1281
+ /**
1282
+ * Parameters for updating a project.
1283
+ */
1284
+ interface UpdateProjectParams {
1285
+ title?: string;
1286
+ shortDescription?: string;
1287
+ description?: unknown;
1288
+ avatar?: Blob;
1289
+ banner?: Blob;
1290
+ activities?: Array<{
1291
+ uri: string;
1292
+ cid: string;
1293
+ weight: string;
1294
+ }>;
1295
+ location?: {
1296
+ uri: string;
1297
+ cid: string;
1298
+ };
1299
+ }
1005
1300
 
1006
1301
  /**
1007
1302
  * Parameters for creating a new hypercert.
@@ -1083,14 +1378,12 @@ interface CreateHypercertParams {
1083
1378
  description: string;
1084
1379
  /**
1085
1380
  * Scope of work or impact area.
1086
- * Logical scope of the work using label-based conditions. All labels in `withinAllOf` must apply; at least one label in `withinAnyOf` must apply if provided; no label in `withinNoneOf` may apply.
1381
+ * Logical scope of the work using label-based conditions.
1087
1382
  *
1088
- * @example "Climate Action", "Education", "Healthcare"
1383
+ * @example WorkScopeAll with atom references
1089
1384
  */
1090
- workScope?: {
1091
- withinAllOf?: string[];
1092
- withinAnyOf?: string[];
1093
- withinNoneOf?: string[];
1385
+ workScope?: OrgHypercertsDefs.WorkScopeAll | OrgHypercertsDefs.WorkScopeAny | OrgHypercertsDefs.WorkScopeNot | OrgHypercertsDefs.WorkScopeAtom | {
1386
+ $type: string;
1094
1387
  };
1095
1388
  /**
1096
1389
  * Start date of the work period.
@@ -1142,34 +1435,7 @@ interface CreateHypercertParams {
1142
1435
  /**
1143
1436
  * Optional geographic location of the impact.
1144
1437
  */
1145
- location?: {
1146
- /**
1147
- * Location value/address.
1148
- *
1149
- * @example "San Francisco, CA, USA"
1150
- */
1151
- value: string;
1152
- /**
1153
- * Human-readable location name.
1154
- *
1155
- * @example "SF Bay Area"
1156
- */
1157
- name?: string;
1158
- /**
1159
- * Description of the location scope.
1160
- */
1161
- description?: string;
1162
- /**
1163
- * Spatial Reference System identifier (required if location is provided).
1164
- *
1165
- * @example "EPSG:4326" for WGS84
1166
- */
1167
- srs: string;
1168
- /**
1169
- * GeoJSON file as a Blob for precise boundaries.
1170
- */
1171
- geojson?: Blob;
1172
- };
1438
+ location?: AttachLocationParams;
1173
1439
  /**
1174
1440
  * Optional list of contributions to the impact.
1175
1441
  *
@@ -1194,7 +1460,7 @@ interface CreateHypercertParams {
1194
1460
  /**
1195
1461
  * Optional evidence supporting the impact claim.
1196
1462
  */
1197
- evidence?: HypercertEvidence[];
1463
+ evidence?: Array<Omit<CreateHypercertEvidenceParams, "subjectUri">>;
1198
1464
  /**
1199
1465
  * Optional callback for progress updates during creation.
1200
1466
  *
@@ -1219,6 +1485,88 @@ interface CreateOrganizationParams {
1219
1485
  */
1220
1486
  description?: string;
1221
1487
  }
1488
+ /**
1489
+ * Input params for creating Hypercert evidence.
1490
+ *
1491
+ * Based on `org.hypercerts.claim.evidence` but:
1492
+ * - removes: $type, createdAt, subject, content
1493
+ * - adds: subjectUri, content (string | Blob)
1494
+ */
1495
+ interface CreateHypercertEvidenceParams {
1496
+ /**
1497
+ * URI for the subject this evidence is attached to.
1498
+ */
1499
+ subjectUri: string;
1500
+ /**
1501
+ * Evidence content.
1502
+ * - string: should be a URI.
1503
+ * - Blob: binary payload (e.g. image/pdf)
1504
+ */
1505
+ content: string | Blob;
1506
+ /**
1507
+ * Title to describe the nature of the evidence.
1508
+ */
1509
+ title: string;
1510
+ /**
1511
+ * Short description explaining what this evidence shows.
1512
+ */
1513
+ shortDescription?: string;
1514
+ /**
1515
+ * Longer description describing the evidence in more detail.
1516
+ */
1517
+ description?: string;
1518
+ /**
1519
+ * How this evidence relates to the subject.
1520
+ */
1521
+ relationType?: "supports" | "challenges" | "clarifies" | (string & {});
1522
+ /**
1523
+ * Any additional custom fields supported by the record.
1524
+ */
1525
+ [k: string]: unknown;
1526
+ }
1527
+ /**
1528
+ * Parameters for attaching a location to a hypercert.
1529
+ *
1530
+ * @example Using a string location
1531
+ * ```typescript
1532
+ * const params: AttachLocationParams = {
1533
+ * lpVersion: "1.0.0",
1534
+ * srs: "EPSG:4326",
1535
+ * locationType: "coordinate-decimal",
1536
+ * location: "https://locationuri.com",
1537
+ * name: "San Francisco",
1538
+ * description: "Project location in SF Bay Area",
1539
+ * };
1540
+ * ```
1541
+ *
1542
+ * @example Using a GeoJSON Blob
1543
+ * ```typescript
1544
+ * const geojsonBlob = new Blob(
1545
+ * [JSON.stringify({ type: "Point", coordinates: [-122.4194, 37.7749] })],
1546
+ * { type: "application/geo+json" }
1547
+ * );
1548
+ * const params: AttachLocationParams = {
1549
+ * lpVersion: "1.0.0",
1550
+ * srs: "EPSG:4326",
1551
+ * locationType: "geojson-point",
1552
+ * location: geojsonBlob,
1553
+ * };
1554
+ * ```
1555
+ */
1556
+ interface AttachLocationParams {
1557
+ /** The version of the Location Protocol */
1558
+ lpVersion: string;
1559
+ /** The Spatial Reference System URI (e.g., http://www.opengis.net/def/crs/OGC/1.3/CRS84) that defines the coordinate system. */
1560
+ srs: string;
1561
+ /** An identifier for the format of the location data (e.g., coordinate-decimal, geojson-point) */
1562
+ locationType: "coordinate-decimal" | "geojson-point" | (string & {});
1563
+ /** Location data as either a URL string or a GeoJSON Blob */
1564
+ location: string | Blob;
1565
+ /** Optional name for this location */
1566
+ name?: string;
1567
+ /** Optional description for this location */
1568
+ description?: string;
1569
+ }
1222
1570
  /**
1223
1571
  * Result of creating a hypercert.
1224
1572
  *
@@ -1249,6 +1597,10 @@ interface CreateHypercertResult {
1249
1597
  * AT-URIs of contribution records, if contributions were provided.
1250
1598
  */
1251
1599
  contributionUris?: string[];
1600
+ /**
1601
+ * AT-URIs of evidence records, if evidence was provided.
1602
+ */
1603
+ evidenceUris?: string[];
1252
1604
  }
1253
1605
  /**
1254
1606
  * Low-level record operations for AT Protocol CRUD.
@@ -1563,6 +1915,26 @@ interface HypercertEvents {
1563
1915
  uri: string;
1564
1916
  cid: string;
1565
1917
  };
1918
+ /**
1919
+ * Emitted when a project is created.
1920
+ */
1921
+ projectCreated: {
1922
+ uri: string;
1923
+ cid: string;
1924
+ };
1925
+ /**
1926
+ * Emitted when a project is updated.
1927
+ */
1928
+ projectUpdated: {
1929
+ uri: string;
1930
+ cid: string;
1931
+ };
1932
+ /**
1933
+ * Emitted when a project is deleted.
1934
+ */
1935
+ projectDeleted: {
1936
+ uri: string;
1937
+ };
1566
1938
  }
1567
1939
  /**
1568
1940
  * High-level hypercert operations.
@@ -1664,21 +2036,14 @@ interface HypercertOperations extends EventEmitter<HypercertEvents> {
1664
2036
  * @param location.geojson - Optional GeoJSON blob for precise boundaries
1665
2037
  * @returns Promise resolving to location record result
1666
2038
  */
1667
- attachLocation(uri: string, location: {
1668
- value: string;
1669
- name?: string;
1670
- description?: string;
1671
- srs: string;
1672
- geojson?: Blob;
1673
- }): Promise<CreateResult>;
2039
+ attachLocation(uri: string, location: AttachLocationParams): Promise<CreateResult>;
1674
2040
  /**
1675
2041
  * Adds evidence to an existing hypercert.
1676
2042
  *
1677
- * @param uri - AT-URI of the hypercert
1678
- * @param evidence - Array of evidence items to add
2043
+ * @param evidence - Evidence item to add
1679
2044
  * @returns Promise resolving to update result
1680
2045
  */
1681
- addEvidence(uri: string, evidence: HypercertEvidence[]): Promise<UpdateResult>;
2046
+ addEvidence(evidence: CreateHypercertEvidenceParams): Promise<UpdateResult>;
1682
2047
  /**
1683
2048
  * Creates a contribution record.
1684
2049
  *
@@ -1730,7 +2095,7 @@ interface HypercertOperations extends EventEmitter<HypercertEvents> {
1730
2095
  weight: string;
1731
2096
  }>;
1732
2097
  shortDescription?: string;
1733
- coverPhoto?: Blob;
2098
+ banner?: Blob;
1734
2099
  }): Promise<CreateResult>;
1735
2100
  /**
1736
2101
  * Gets a collection by URI.
@@ -1754,34 +2119,104 @@ interface HypercertOperations extends EventEmitter<HypercertEvents> {
1754
2119
  cid: string;
1755
2120
  record: HypercertCollection;
1756
2121
  }>>;
1757
- }
1758
- /**
1759
- * Collaborator operations for SDS access control.
1760
- *
1761
- * **SDS Only**: These operations are only available on Shared Data Servers.
1762
- *
1763
- * @example
1764
- * ```typescript
1765
- * // Grant access
1766
- * await repo.collaborators.grant({
1767
- * userDid: "did:plc:new-user",
1768
- * role: "editor",
1769
- * });
1770
- *
1771
- * // List collaborators
1772
- * const collaborators = await repo.collaborators.list();
1773
- *
1774
- * // Check access
1775
- * const hasAccess = await repo.collaborators.hasAccess("did:plc:someone");
1776
- * const role = await repo.collaborators.getRole("did:plc:someone");
1777
- *
1778
- * // Get current user permissions
1779
- * const permissions = await repo.collaborators.getPermissions();
1780
- * if (permissions.admin) {
1781
- * // Can manage collaborators
1782
- * }
1783
- *
1784
- * // Transfer ownership
2122
+ /**
2123
+ * Creates a project.
2124
+ *
2125
+ * @param params - Project parameters
2126
+ * @returns Promise resolving to project record result
2127
+ */
2128
+ createProject(params: {
2129
+ title: string;
2130
+ shortDescription: string;
2131
+ description?: unknown;
2132
+ avatar?: Blob;
2133
+ banner?: Blob;
2134
+ activities?: Array<{
2135
+ uri: string;
2136
+ cid: string;
2137
+ weight: string;
2138
+ }>;
2139
+ }): Promise<CreateResult>;
2140
+ /**
2141
+ * Gets a project by URI.
2142
+ *
2143
+ * Projects are collections with type='project'.
2144
+ *
2145
+ * @param uri - AT-URI of the project
2146
+ * @returns Promise resolving to project data (as collection)
2147
+ */
2148
+ getProject(uri: string): Promise<{
2149
+ uri: string;
2150
+ cid: string;
2151
+ record: HypercertCollection;
2152
+ }>;
2153
+ /**
2154
+ * Lists projects with pagination.
2155
+ *
2156
+ * Projects are collections with type='project'.
2157
+ *
2158
+ * @param params - Optional pagination parameters
2159
+ * @returns Promise resolving to paginated list
2160
+ */
2161
+ listProjects(params?: ListParams): Promise<PaginatedList<{
2162
+ uri: string;
2163
+ cid: string;
2164
+ record: HypercertCollection;
2165
+ }>>;
2166
+ /**
2167
+ * Updates a project.
2168
+ *
2169
+ * @param uri - AT-URI of the project
2170
+ * @param updates - Fields to update
2171
+ * @returns Promise resolving to update result
2172
+ */
2173
+ updateProject(uri: string, updates: {
2174
+ title?: string;
2175
+ shortDescription?: string;
2176
+ description?: unknown;
2177
+ avatar?: Blob | null;
2178
+ banner?: Blob | null;
2179
+ activities?: Array<{
2180
+ uri: string;
2181
+ cid: string;
2182
+ weight: string;
2183
+ }>;
2184
+ }): Promise<UpdateResult>;
2185
+ /**
2186
+ * Deletes a project.
2187
+ *
2188
+ * @param uri - AT-URI of the project
2189
+ * @returns Promise resolving when deleted
2190
+ */
2191
+ deleteProject(uri: string): Promise<void>;
2192
+ }
2193
+ /**
2194
+ * Collaborator operations for SDS access control.
2195
+ *
2196
+ * **SDS Only**: These operations are only available on Shared Data Servers.
2197
+ *
2198
+ * @example
2199
+ * ```typescript
2200
+ * // Grant access
2201
+ * await repo.collaborators.grant({
2202
+ * userDid: "did:plc:new-user",
2203
+ * role: "editor",
2204
+ * });
2205
+ *
2206
+ * // List collaborators
2207
+ * const collaborators = await repo.collaborators.list();
2208
+ *
2209
+ * // Check access
2210
+ * const hasAccess = await repo.collaborators.hasAccess("did:plc:someone");
2211
+ * const role = await repo.collaborators.getRole("did:plc:someone");
2212
+ *
2213
+ * // Get current user permissions
2214
+ * const permissions = await repo.collaborators.getPermissions();
2215
+ * if (permissions.admin) {
2216
+ * // Can manage collaborators
2217
+ * }
2218
+ *
2219
+ * // Transfer ownership
1785
2220
  * await repo.collaborators.transferOwnership({
1786
2221
  * newOwnerDid: "did:plc:new-owner",
1787
2222
  * });
@@ -2008,6 +2443,7 @@ declare class Repository {
2008
2443
  private logger?;
2009
2444
  private agent;
2010
2445
  private _isSDS;
2446
+ private lexiconRegistry;
2011
2447
  private _records?;
2012
2448
  private _blobs?;
2013
2449
  private _profile?;
@@ -2022,6 +2458,7 @@ declare class Repository {
2022
2458
  * @param repoDid - DID of the repository to operate on
2023
2459
  * @param isSDS - Whether this is a Shared Data Server
2024
2460
  * @param logger - Optional logger for debugging
2461
+ * @param lexiconRegistry - Registry for custom lexicon management
2025
2462
  *
2026
2463
  * @remarks
2027
2464
  * This constructor is typically not called directly. Use
@@ -2029,7 +2466,7 @@ declare class Repository {
2029
2466
  *
2030
2467
  * @internal
2031
2468
  */
2032
- constructor(session: Session, serverUrl: string, repoDid: string, isSDS: boolean, logger?: LoggerInterface);
2469
+ constructor(session: Session, serverUrl: string, repoDid: string, isSDS: boolean, logger?: LoggerInterface, lexiconRegistry?: LexiconRegistry);
2033
2470
  /**
2034
2471
  * The DID (Decentralized Identifier) of this repository.
2035
2472
  *
@@ -2093,6 +2530,50 @@ declare class Repository {
2093
2530
  * ```
2094
2531
  */
2095
2532
  repo(did: string): Repository;
2533
+ /**
2534
+ * Gets the LexiconRegistry instance for managing custom lexicons.
2535
+ *
2536
+ * The registry is shared across all operations in this repository and
2537
+ * enables validation of custom record types.
2538
+ *
2539
+ * @returns The {@link LexiconRegistry} instance
2540
+ *
2541
+ * @example
2542
+ * ```typescript
2543
+ * // Access the registry
2544
+ * const registry = repo.getLexiconRegistry();
2545
+ *
2546
+ * // Register a custom lexicon
2547
+ * registry.register({
2548
+ * lexicon: 1,
2549
+ * id: "org.myapp.evaluation",
2550
+ * defs: {
2551
+ * main: {
2552
+ * type: "record",
2553
+ * key: "tid",
2554
+ * record: {
2555
+ * type: "object",
2556
+ * required: ["$type", "score"],
2557
+ * properties: {
2558
+ * "$type": { type: "string", const: "org.myapp.evaluation" },
2559
+ * score: { type: "integer", minimum: 0, maximum: 100 }
2560
+ * }
2561
+ * }
2562
+ * }
2563
+ * }
2564
+ * });
2565
+ *
2566
+ * // Now create records using the custom lexicon
2567
+ * await repo.records.create({
2568
+ * collection: "org.myapp.evaluation",
2569
+ * record: {
2570
+ * $type: "org.myapp.evaluation",
2571
+ * score: 85
2572
+ * }
2573
+ * });
2574
+ * ```
2575
+ */
2576
+ getLexiconRegistry(): LexiconRegistry;
2096
2577
  /**
2097
2578
  * Low-level record operations for CRUD on any AT Protocol record type.
2098
2579
  *
@@ -2269,22 +2750,28 @@ declare class Repository {
2269
2750
  * Zod schema for OAuth configuration validation.
2270
2751
  *
2271
2752
  * @remarks
2272
- * All URLs must be valid and use HTTPS in production. The `jwkPrivate` field
2273
- * should contain the private key in JWK (JSON Web Key) format as a string.
2753
+ * All URLs must be valid and use HTTPS in production. For local development,
2754
+ * HTTP loopback URLs (localhost, 127.0.0.1, [::1]) are allowed.
2755
+ * The `jwkPrivate` field should contain the private key in JWK (JSON Web Key) format as a string.
2274
2756
  */
2275
2757
  declare const OAuthConfigSchema: z.ZodObject<{
2276
2758
  /**
2277
2759
  * URL to the OAuth client metadata JSON document.
2278
2760
  * This document describes your application to the authorization server.
2279
2761
  *
2762
+ * For local development, you can use `http://localhost/` as a loopback client.
2763
+ *
2280
2764
  * @see https://atproto.com/specs/oauth#client-metadata
2281
2765
  */
2282
- clientId: z.ZodString;
2766
+ clientId: z.ZodEffects<z.ZodString, string, string>;
2283
2767
  /**
2284
2768
  * URL where users are redirected after authentication.
2285
2769
  * Must match one of the redirect URIs in your client metadata.
2770
+ *
2771
+ * For local development, you can use HTTP loopback URLs like
2772
+ * `http://127.0.0.1:3000/callback` or `http://localhost:3000/callback`.
2286
2773
  */
2287
- redirectUri: z.ZodString;
2774
+ redirectUri: z.ZodEffects<z.ZodString, string, string>;
2288
2775
  /**
2289
2776
  * OAuth scopes to request, space-separated.
2290
2777
  *
@@ -2318,8 +2805,11 @@ declare const OAuthConfigSchema: z.ZodObject<{
2318
2805
  /**
2319
2806
  * URL to your public JWKS (JSON Web Key Set) endpoint.
2320
2807
  * Used by the authorization server to verify your client's signatures.
2808
+ *
2809
+ * For local development, you can serve JWKS from a loopback URL like
2810
+ * `http://127.0.0.1:3000/.well-known/jwks.json`.
2321
2811
  */
2322
- jwksUri: z.ZodString;
2812
+ jwksUri: z.ZodEffects<z.ZodString, string, string>;
2323
2813
  /**
2324
2814
  * Private JWK (JSON Web Key) as a JSON string.
2325
2815
  * Used for signing DPoP proofs and client assertions.
@@ -2329,40 +2819,78 @@ declare const OAuthConfigSchema: z.ZodObject<{
2329
2819
  * Typically loaded from environment variables or a secrets manager.
2330
2820
  */
2331
2821
  jwkPrivate: z.ZodString;
2822
+ /**
2823
+ * Enable development mode features (optional).
2824
+ *
2825
+ * When true, suppresses warnings about using HTTP loopback URLs.
2826
+ * Should be set to true for local development to reduce console noise.
2827
+ *
2828
+ * @default false
2829
+ *
2830
+ * @example
2831
+ * ```typescript
2832
+ * oauth: {
2833
+ * clientId: "http://localhost/",
2834
+ * redirectUri: "http://127.0.0.1:3000/callback",
2835
+ * // ... other config
2836
+ * developmentMode: true, // Suppress loopback warnings
2837
+ * }
2838
+ * ```
2839
+ */
2840
+ developmentMode: z.ZodOptional<z.ZodBoolean>;
2332
2841
  }, "strip", z.ZodTypeAny, {
2333
2842
  clientId: string;
2334
2843
  redirectUri: string;
2335
2844
  scope: string;
2336
2845
  jwksUri: string;
2337
2846
  jwkPrivate: string;
2847
+ developmentMode?: boolean | undefined;
2338
2848
  }, {
2339
2849
  clientId: string;
2340
2850
  redirectUri: string;
2341
2851
  scope: string;
2342
2852
  jwksUri: string;
2343
2853
  jwkPrivate: string;
2854
+ developmentMode?: boolean | undefined;
2344
2855
  }>;
2345
2856
  /**
2346
2857
  * Zod schema for server URL configuration.
2347
2858
  *
2348
2859
  * @remarks
2349
2860
  * At least one server (PDS or SDS) should be configured for the SDK to be useful.
2861
+ * For local development, HTTP loopback URLs are allowed.
2350
2862
  */
2351
2863
  declare const ServerConfigSchema: z.ZodObject<{
2352
2864
  /**
2353
2865
  * Personal Data Server URL - the user's own AT Protocol server.
2354
2866
  * This is the primary server for user data operations.
2355
2867
  *
2356
- * @example "https://bsky.social"
2868
+ * @example Production
2869
+ * ```typescript
2870
+ * pds: "https://bsky.social"
2871
+ * ```
2872
+ *
2873
+ * @example Local development
2874
+ * ```typescript
2875
+ * pds: "http://localhost:2583"
2876
+ * ```
2357
2877
  */
2358
- pds: z.ZodOptional<z.ZodString>;
2878
+ pds: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
2359
2879
  /**
2360
2880
  * Shared Data Server URL - for collaborative data storage.
2361
2881
  * Required for collaborator and organization operations.
2362
2882
  *
2363
- * @example "https://sds.hypercerts.org"
2883
+ * @example Production
2884
+ * ```typescript
2885
+ * sds: "https://sds.hypercerts.org"
2886
+ * ```
2887
+ *
2888
+ * @example Local development
2889
+ * ```typescript
2890
+ * sds: "http://127.0.0.1:2584"
2891
+ * ```
2364
2892
  */
2365
- sds: z.ZodOptional<z.ZodString>;
2893
+ sds: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
2366
2894
  }, "strip", z.ZodTypeAny, {
2367
2895
  pds?: string | undefined;
2368
2896
  sds?: string | undefined;
@@ -2408,14 +2936,19 @@ declare const ATProtoSDKConfigSchema: z.ZodObject<{
2408
2936
  * URL to the OAuth client metadata JSON document.
2409
2937
  * This document describes your application to the authorization server.
2410
2938
  *
2939
+ * For local development, you can use `http://localhost/` as a loopback client.
2940
+ *
2411
2941
  * @see https://atproto.com/specs/oauth#client-metadata
2412
2942
  */
2413
- clientId: z.ZodString;
2943
+ clientId: z.ZodEffects<z.ZodString, string, string>;
2414
2944
  /**
2415
2945
  * URL where users are redirected after authentication.
2416
2946
  * Must match one of the redirect URIs in your client metadata.
2947
+ *
2948
+ * For local development, you can use HTTP loopback URLs like
2949
+ * `http://127.0.0.1:3000/callback` or `http://localhost:3000/callback`.
2417
2950
  */
2418
- redirectUri: z.ZodString;
2951
+ redirectUri: z.ZodEffects<z.ZodString, string, string>;
2419
2952
  /**
2420
2953
  * OAuth scopes to request, space-separated.
2421
2954
  *
@@ -2449,8 +2982,11 @@ declare const ATProtoSDKConfigSchema: z.ZodObject<{
2449
2982
  /**
2450
2983
  * URL to your public JWKS (JSON Web Key Set) endpoint.
2451
2984
  * Used by the authorization server to verify your client's signatures.
2985
+ *
2986
+ * For local development, you can serve JWKS from a loopback URL like
2987
+ * `http://127.0.0.1:3000/.well-known/jwks.json`.
2452
2988
  */
2453
- jwksUri: z.ZodString;
2989
+ jwksUri: z.ZodEffects<z.ZodString, string, string>;
2454
2990
  /**
2455
2991
  * Private JWK (JSON Web Key) as a JSON string.
2456
2992
  * Used for signing DPoP proofs and client assertions.
@@ -2460,34 +2996,71 @@ declare const ATProtoSDKConfigSchema: z.ZodObject<{
2460
2996
  * Typically loaded from environment variables or a secrets manager.
2461
2997
  */
2462
2998
  jwkPrivate: z.ZodString;
2999
+ /**
3000
+ * Enable development mode features (optional).
3001
+ *
3002
+ * When true, suppresses warnings about using HTTP loopback URLs.
3003
+ * Should be set to true for local development to reduce console noise.
3004
+ *
3005
+ * @default false
3006
+ *
3007
+ * @example
3008
+ * ```typescript
3009
+ * oauth: {
3010
+ * clientId: "http://localhost/",
3011
+ * redirectUri: "http://127.0.0.1:3000/callback",
3012
+ * // ... other config
3013
+ * developmentMode: true, // Suppress loopback warnings
3014
+ * }
3015
+ * ```
3016
+ */
3017
+ developmentMode: z.ZodOptional<z.ZodBoolean>;
2463
3018
  }, "strip", z.ZodTypeAny, {
2464
3019
  clientId: string;
2465
3020
  redirectUri: string;
2466
3021
  scope: string;
2467
3022
  jwksUri: string;
2468
3023
  jwkPrivate: string;
3024
+ developmentMode?: boolean | undefined;
2469
3025
  }, {
2470
3026
  clientId: string;
2471
3027
  redirectUri: string;
2472
3028
  scope: string;
2473
3029
  jwksUri: string;
2474
3030
  jwkPrivate: string;
3031
+ developmentMode?: boolean | undefined;
2475
3032
  }>;
2476
3033
  servers: z.ZodOptional<z.ZodObject<{
2477
3034
  /**
2478
3035
  * Personal Data Server URL - the user's own AT Protocol server.
2479
3036
  * This is the primary server for user data operations.
2480
3037
  *
2481
- * @example "https://bsky.social"
3038
+ * @example Production
3039
+ * ```typescript
3040
+ * pds: "https://bsky.social"
3041
+ * ```
3042
+ *
3043
+ * @example Local development
3044
+ * ```typescript
3045
+ * pds: "http://localhost:2583"
3046
+ * ```
2482
3047
  */
2483
- pds: z.ZodOptional<z.ZodString>;
3048
+ pds: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
2484
3049
  /**
2485
3050
  * Shared Data Server URL - for collaborative data storage.
2486
3051
  * Required for collaborator and organization operations.
2487
3052
  *
2488
- * @example "https://sds.hypercerts.org"
3053
+ * @example Production
3054
+ * ```typescript
3055
+ * sds: "https://sds.hypercerts.org"
3056
+ * ```
3057
+ *
3058
+ * @example Local development
3059
+ * ```typescript
3060
+ * sds: "http://127.0.0.1:2584"
3061
+ * ```
2489
3062
  */
2490
- sds: z.ZodOptional<z.ZodString>;
3063
+ sds: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
2491
3064
  }, "strip", z.ZodTypeAny, {
2492
3065
  pds?: string | undefined;
2493
3066
  sds?: string | undefined;
@@ -2520,6 +3093,7 @@ declare const ATProtoSDKConfigSchema: z.ZodObject<{
2520
3093
  scope: string;
2521
3094
  jwksUri: string;
2522
3095
  jwkPrivate: string;
3096
+ developmentMode?: boolean | undefined;
2523
3097
  };
2524
3098
  servers?: {
2525
3099
  pds?: string | undefined;
@@ -2536,6 +3110,7 @@ declare const ATProtoSDKConfigSchema: z.ZodObject<{
2536
3110
  scope: string;
2537
3111
  jwksUri: string;
2538
3112
  jwkPrivate: string;
3113
+ developmentMode?: boolean | undefined;
2539
3114
  };
2540
3115
  servers?: {
2541
3116
  pds?: string | undefined;
@@ -2784,6 +3359,7 @@ declare class ATProtoSDK {
2784
3359
  private oauthClient;
2785
3360
  private config;
2786
3361
  private logger?;
3362
+ private lexiconRegistry;
2787
3363
  /**
2788
3364
  * Creates a new ATProto SDK instance.
2789
3365
  *
@@ -3003,6 +3579,32 @@ declare class ATProtoSDK {
3003
3579
  * ```
3004
3580
  */
3005
3581
  repository(session: Session, options?: RepositoryOptions): Repository;
3582
+ /**
3583
+ * Gets the LexiconRegistry instance for managing custom lexicons.
3584
+ *
3585
+ * The registry allows you to register custom lexicon schemas and validate
3586
+ * records against them. All registered lexicons will be automatically
3587
+ * validated during record creation operations.
3588
+ *
3589
+ * @returns The {@link LexiconRegistry} instance
3590
+ *
3591
+ * @example
3592
+ * ```typescript
3593
+ * // Register a custom lexicon
3594
+ * const registry = sdk.getLexiconRegistry();
3595
+ * registry.register({
3596
+ * lexicon: 1,
3597
+ * id: "org.myapp.customRecord",
3598
+ * defs: { ... }
3599
+ * });
3600
+ *
3601
+ * // Check if lexicon is registered
3602
+ * if (registry.isRegistered("org.myapp.customRecord")) {
3603
+ * console.log("Custom lexicon is available");
3604
+ * }
3605
+ * ```
3606
+ */
3607
+ getLexiconRegistry(): LexiconRegistry;
3006
3608
  /**
3007
3609
  * The configured PDS (Personal Data Server) URL.
3008
3610
  *
@@ -3017,87 +3619,1169 @@ declare class ATProtoSDK {
3017
3619
  get sdsUrl(): string | undefined;
3018
3620
  }
3019
3621
  /**
3020
- * Factory function to create an ATProto SDK instance.
3622
+ * Factory function to create an ATProto SDK instance.
3623
+ *
3624
+ * This is a convenience function equivalent to `new ATProtoSDK(config)`.
3625
+ *
3626
+ * @param config - SDK configuration
3627
+ * @returns A new {@link ATProtoSDK} instance
3628
+ *
3629
+ * @example
3630
+ * ```typescript
3631
+ * import { createATProtoSDK } from "@hypercerts-org/sdk";
3632
+ *
3633
+ * const sdk = createATProtoSDK({
3634
+ * oauth: { ... },
3635
+ * servers: { pds: "https://bsky.social" },
3636
+ * });
3637
+ * ```
3638
+ */
3639
+ declare function createATProtoSDK(config: ATProtoSDKConfig): ATProtoSDK;
3640
+
3641
+ /**
3642
+ * ConfigurableAgent - Agent with configurable service URL routing.
3643
+ *
3644
+ * This module provides an Agent extension that allows routing requests to
3645
+ * a specific server URL, overriding the default URL from the OAuth session.
3646
+ *
3647
+ * @packageDocumentation
3648
+ */
3649
+
3650
+ /**
3651
+ * Agent subclass that routes requests to a configurable service URL.
3652
+ *
3653
+ * The standard Agent uses the service URL embedded in the OAuth session's
3654
+ * fetch handler. This class allows overriding that URL to route requests
3655
+ * to different servers (e.g., PDS vs SDS, or multiple SDS instances).
3656
+ *
3657
+ * @remarks
3658
+ * This is particularly useful for:
3659
+ * - Routing to a Shared Data Server (SDS) while authenticated via PDS
3660
+ * - Supporting multiple SDS instances for different organizations
3661
+ * - Testing against different server environments
3662
+ *
3663
+ * @example Basic usage
3664
+ * ```typescript
3665
+ * const session = await sdk.authorize("user.bsky.social");
3666
+ *
3667
+ * // Create agent routing to SDS instead of session's default PDS
3668
+ * const sdsAgent = new ConfigurableAgent(session, "https://sds.hypercerts.org");
3669
+ *
3670
+ * // All requests will now go to the SDS
3671
+ * await sdsAgent.com.atproto.repo.createRecord({...});
3672
+ * ```
3673
+ *
3674
+ * @example Multiple SDS instances
3675
+ * ```typescript
3676
+ * // Route to organization A's SDS
3677
+ * const orgAAgent = new ConfigurableAgent(session, "https://sds-org-a.example.com");
3678
+ *
3679
+ * // Route to organization B's SDS
3680
+ * const orgBAgent = new ConfigurableAgent(session, "https://sds-org-b.example.com");
3681
+ * ```
3682
+ */
3683
+ declare class ConfigurableAgent extends Agent {
3684
+ private customServiceUrl;
3685
+ /**
3686
+ * Creates a ConfigurableAgent that routes to a specific service URL.
3687
+ *
3688
+ * @param session - OAuth session for authentication
3689
+ * @param serviceUrl - Base URL of the server to route requests to
3690
+ *
3691
+ * @remarks
3692
+ * The agent wraps the session's fetch handler to intercept requests and
3693
+ * prepend the custom service URL instead of using the session's default.
3694
+ */
3695
+ constructor(session: Session, serviceUrl: string);
3696
+ /**
3697
+ * Gets the service URL this agent routes to.
3698
+ *
3699
+ * @returns The base URL of the configured service
3700
+ */
3701
+ getServiceUrl(): string;
3702
+ }
3703
+
3704
+ /**
3705
+ * BaseOperations - Abstract base class for custom lexicon operations.
3706
+ *
3707
+ * This module provides a foundation for building domain-specific operation
3708
+ * classes that work with custom lexicons. It handles validation, record
3709
+ * creation, and provides utilities for working with AT Protocol records.
3710
+ *
3711
+ * @packageDocumentation
3712
+ */
3713
+
3714
+ /**
3715
+ * Abstract base class for creating custom lexicon operation classes.
3716
+ *
3717
+ * Extend this class to build domain-specific operations for your custom
3718
+ * lexicons. The base class provides:
3719
+ *
3720
+ * - Automatic validation against registered lexicon schemas
3721
+ * - Helper methods for creating and updating records
3722
+ * - Utilities for building strongRefs and AT-URIs
3723
+ * - Error handling and logging support
3724
+ *
3725
+ * @typeParam TParams - Type of parameters accepted by the create() method
3726
+ * @typeParam TResult - Type of result returned by the create() method
3727
+ *
3728
+ * @remarks
3729
+ * This class is designed to be extended by developers creating custom
3730
+ * operation classes for their own lexicons. It follows the same patterns
3731
+ * as the built-in hypercert operations.
3732
+ *
3733
+ * @example Basic usage
3734
+ * ```typescript
3735
+ * import { BaseOperations } from "@hypercerts-org/sdk-core";
3736
+ *
3737
+ * interface EvaluationParams {
3738
+ * subjectUri: string;
3739
+ * subjectCid: string;
3740
+ * score: number;
3741
+ * methodology?: string;
3742
+ * }
3743
+ *
3744
+ * interface EvaluationResult {
3745
+ * uri: string;
3746
+ * cid: string;
3747
+ * record: MyEvaluation;
3748
+ * }
3749
+ *
3750
+ * class EvaluationOperations extends BaseOperations<EvaluationParams, EvaluationResult> {
3751
+ * async create(params: EvaluationParams): Promise<EvaluationResult> {
3752
+ * const record = {
3753
+ * $type: "org.myapp.evaluation",
3754
+ * subject: this.createStrongRef(params.subjectUri, params.subjectCid),
3755
+ * score: params.score,
3756
+ * methodology: params.methodology,
3757
+ * createdAt: new Date().toISOString(),
3758
+ * };
3759
+ *
3760
+ * const { uri, cid } = await this.validateAndCreate("org.myapp.evaluation", record);
3761
+ * return { uri, cid, record };
3762
+ * }
3763
+ * }
3764
+ * ```
3765
+ *
3766
+ * @example With validation and error handling
3767
+ * ```typescript
3768
+ * class ProjectOperations extends BaseOperations<CreateProjectParams, ProjectResult> {
3769
+ * async create(params: CreateProjectParams): Promise<ProjectResult> {
3770
+ * // Validate input parameters
3771
+ * if (!params.title || params.title.trim().length === 0) {
3772
+ * throw new ValidationError("Project title cannot be empty");
3773
+ * }
3774
+ *
3775
+ * const record = {
3776
+ * $type: "org.myapp.project",
3777
+ * title: params.title,
3778
+ * description: params.description,
3779
+ * createdAt: new Date().toISOString(),
3780
+ * };
3781
+ *
3782
+ * try {
3783
+ * const { uri, cid } = await this.validateAndCreate("org.myapp.project", record);
3784
+ * this.logger?.info(`Created project: ${uri}`);
3785
+ * return { uri, cid, record };
3786
+ * } catch (error) {
3787
+ * this.logger?.error(`Failed to create project: ${error}`);
3788
+ * throw error;
3789
+ * }
3790
+ * }
3791
+ * }
3792
+ * ```
3793
+ */
3794
+ declare abstract class BaseOperations<TParams = unknown, TResult = unknown> {
3795
+ protected agent: Agent;
3796
+ protected repoDid: string;
3797
+ protected lexiconRegistry: LexiconRegistry;
3798
+ protected logger?: LoggerInterface | undefined;
3799
+ /**
3800
+ * Creates a new BaseOperations instance.
3801
+ *
3802
+ * @param agent - AT Protocol Agent for making API calls
3803
+ * @param repoDid - DID of the repository to operate on
3804
+ * @param lexiconRegistry - Registry for validating records against lexicon schemas
3805
+ * @param logger - Optional logger for debugging and monitoring
3806
+ *
3807
+ * @internal
3808
+ */
3809
+ constructor(agent: Agent, repoDid: string, lexiconRegistry: LexiconRegistry, logger?: LoggerInterface | undefined);
3810
+ /**
3811
+ * Validates a record against its lexicon schema and creates it in the repository.
3812
+ *
3813
+ * This method performs the following steps:
3814
+ * 1. Validates the record against the registered lexicon schema
3815
+ * 2. Throws ValidationError if validation fails
3816
+ * 3. Creates the record using the AT Protocol Agent
3817
+ * 4. Returns the created record's URI and CID
3818
+ *
3819
+ * @param collection - NSID of the collection (e.g., "org.myapp.customRecord")
3820
+ * @param record - Record data conforming to the collection's lexicon schema
3821
+ * @param rkey - Optional record key. If not provided, a TID is auto-generated
3822
+ * @returns Promise resolving to the created record's URI and CID
3823
+ * @throws {@link ValidationError} if the record doesn't conform to the lexicon schema
3824
+ * @throws {@link NetworkError} if the API request fails
3825
+ *
3826
+ * @example
3827
+ * ```typescript
3828
+ * const record = {
3829
+ * $type: "org.myapp.evaluation",
3830
+ * subject: { uri: "at://...", cid: "bafyrei..." },
3831
+ * score: 85,
3832
+ * createdAt: new Date().toISOString(),
3833
+ * };
3834
+ *
3835
+ * const { uri, cid } = await this.validateAndCreate("org.myapp.evaluation", record);
3836
+ * ```
3837
+ */
3838
+ protected validateAndCreate(collection: string, record: unknown, rkey?: string): Promise<CreateResult>;
3839
+ /**
3840
+ * Validates a record against its lexicon schema and updates it in the repository.
3841
+ *
3842
+ * This method performs the following steps:
3843
+ * 1. Validates the record against the registered lexicon schema
3844
+ * 2. Throws ValidationError if validation fails
3845
+ * 3. Updates the record using the AT Protocol Agent
3846
+ * 4. Returns the updated record's URI and new CID
3847
+ *
3848
+ * @param collection - NSID of the collection
3849
+ * @param rkey - Record key (the last segment of the AT-URI)
3850
+ * @param record - New record data (completely replaces existing record)
3851
+ * @returns Promise resolving to the updated record's URI and new CID
3852
+ * @throws {@link ValidationError} if the record doesn't conform to the lexicon schema
3853
+ * @throws {@link NetworkError} if the API request fails
3854
+ *
3855
+ * @remarks
3856
+ * This is a full replacement operation, not a partial update.
3857
+ *
3858
+ * @example
3859
+ * ```typescript
3860
+ * const updatedRecord = {
3861
+ * $type: "org.myapp.evaluation",
3862
+ * subject: { uri: "at://...", cid: "bafyrei..." },
3863
+ * score: 90, // Updated score
3864
+ * createdAt: existingRecord.createdAt,
3865
+ * };
3866
+ *
3867
+ * const { uri, cid } = await this.validateAndUpdate(
3868
+ * "org.myapp.evaluation",
3869
+ * "abc123",
3870
+ * updatedRecord
3871
+ * );
3872
+ * ```
3873
+ */
3874
+ protected validateAndUpdate(collection: string, rkey: string, record: unknown): Promise<UpdateResult>;
3875
+ /**
3876
+ * Creates a strongRef object from a URI and CID.
3877
+ *
3878
+ * StrongRefs are used in AT Protocol to reference specific versions
3879
+ * of records. They ensure that references point to an exact record
3880
+ * version, not just the latest version.
3881
+ *
3882
+ * @param uri - AT-URI of the record (e.g., "at://did:plc:abc/collection/rkey")
3883
+ * @param cid - Content Identifier (CID) of the record
3884
+ * @returns StrongRef object with uri and cid properties
3885
+ *
3886
+ * @example
3887
+ * ```typescript
3888
+ * const hypercertRef = this.createStrongRef(
3889
+ * "at://did:plc:abc123/org.hypercerts.claim.activity/xyz789",
3890
+ * "bafyreiabc123..."
3891
+ * );
3892
+ *
3893
+ * const evaluation = {
3894
+ * $type: "org.myapp.evaluation",
3895
+ * subject: hypercertRef, // Reference to specific hypercert version
3896
+ * score: 85,
3897
+ * createdAt: new Date().toISOString(),
3898
+ * };
3899
+ * ```
3900
+ */
3901
+ protected createStrongRef(uri: string, cid: string): StrongRef;
3902
+ /**
3903
+ * Creates a strongRef from a CreateResult or UpdateResult.
3904
+ *
3905
+ * This is a convenience method for creating strongRefs from the
3906
+ * results of create or update operations.
3907
+ *
3908
+ * @param result - Result from a create or update operation
3909
+ * @returns StrongRef object with uri and cid properties
3910
+ *
3911
+ * @example
3912
+ * ```typescript
3913
+ * // Create a project
3914
+ * const projectResult = await this.validateAndCreate("org.myapp.project", projectRecord);
3915
+ *
3916
+ * // Create a task that references the project
3917
+ * const taskRecord = {
3918
+ * $type: "org.myapp.task",
3919
+ * project: this.createStrongRefFromResult(projectResult),
3920
+ * title: "Implement feature",
3921
+ * createdAt: new Date().toISOString(),
3922
+ * };
3923
+ * ```
3924
+ */
3925
+ protected createStrongRefFromResult(result: CreateResult | UpdateResult): StrongRef;
3926
+ /**
3927
+ * Parses an AT-URI to extract its components.
3928
+ *
3929
+ * AT-URIs follow the format: `at://{did}/{collection}/{rkey}`
3930
+ *
3931
+ * @param uri - AT-URI to parse
3932
+ * @returns Object containing did, collection, and rkey
3933
+ * @throws Error if the URI format is invalid
3934
+ *
3935
+ * @example
3936
+ * ```typescript
3937
+ * const { did, collection, rkey } = this.parseAtUri(
3938
+ * "at://did:plc:abc123/org.hypercerts.claim.activity/xyz789"
3939
+ * );
3940
+ * // did: "did:plc:abc123"
3941
+ * // collection: "org.hypercerts.claim.activity"
3942
+ * // rkey: "xyz789"
3943
+ * ```
3944
+ */
3945
+ protected parseAtUri(uri: string): {
3946
+ did: string;
3947
+ collection: string;
3948
+ rkey: string;
3949
+ };
3950
+ /**
3951
+ * Builds an AT-URI from its components.
3952
+ *
3953
+ * @param did - DID of the repository
3954
+ * @param collection - NSID of the collection
3955
+ * @param rkey - Record key (typically a TID)
3956
+ * @returns Complete AT-URI string
3957
+ *
3958
+ * @example
3959
+ * ```typescript
3960
+ * const uri = this.buildAtUri(
3961
+ * "did:plc:abc123",
3962
+ * "org.myapp.evaluation",
3963
+ * "xyz789"
3964
+ * );
3965
+ * // Returns: "at://did:plc:abc123/org.myapp.evaluation/xyz789"
3966
+ * ```
3967
+ */
3968
+ protected buildAtUri(did: string, collection: string, rkey: string): string;
3969
+ /**
3970
+ * Abstract create method that must be implemented by subclasses.
3971
+ *
3972
+ * Implement this method to define how your custom records are created.
3973
+ * Use the helper methods like `validateAndCreate()`, `createStrongRef()`,
3974
+ * etc. to build your implementation.
3975
+ *
3976
+ * @param params - Parameters for creating the record
3977
+ * @returns Promise resolving to the creation result
3978
+ *
3979
+ * @example
3980
+ * ```typescript
3981
+ * async create(params: EvaluationParams): Promise<EvaluationResult> {
3982
+ * const record = {
3983
+ * $type: "org.myapp.evaluation",
3984
+ * subject: this.createStrongRef(params.subjectUri, params.subjectCid),
3985
+ * score: params.score,
3986
+ * methodology: params.methodology,
3987
+ * createdAt: new Date().toISOString(),
3988
+ * };
3989
+ *
3990
+ * const { uri, cid } = await this.validateAndCreate("org.myapp.evaluation", record);
3991
+ * return { uri, cid, record };
3992
+ * }
3993
+ * ```
3994
+ */
3995
+ abstract create(params: TParams): Promise<TResult>;
3996
+ }
3997
+
3998
+ /**
3999
+ * Lexicon Development Utilities - AT-URI and StrongRef Helpers
4000
+ *
4001
+ * This module provides utilities for working with AT Protocol URIs and strongRefs
4002
+ * when building custom lexicons. These tools help developers create type-safe
4003
+ * references between records.
4004
+ *
4005
+ * @packageDocumentation
4006
+ */
4007
+
4008
+ /**
4009
+ * Components of an AT-URI (AT Protocol Uniform Resource Identifier).
4010
+ *
4011
+ * AT-URIs follow the format: `at://{did}/{collection}/{rkey}`
4012
+ * where:
4013
+ * - `did`: The DID of the repository owner (e.g., "did:plc:abc123")
4014
+ * - `collection`: The NSID of the record type (e.g., "org.hypercerts.claim.activity")
4015
+ * - `rkey`: The record key, either a TID or custom key (e.g., "3km2vj4kfqp2a")
4016
+ */
4017
+ interface AtUriComponents {
4018
+ /** Repository owner's DID */
4019
+ did: string;
4020
+ /** Collection NSID (lexicon identifier) */
4021
+ collection: string;
4022
+ /** Record key (TID or custom string) */
4023
+ rkey: string;
4024
+ }
4025
+ /**
4026
+ * Parse an AT-URI into its component parts.
4027
+ *
4028
+ * Extracts the DID, collection NSID, and record key from an AT-URI string.
4029
+ * AT-URIs follow the format: `at://{did}/{collection}/{rkey}`
4030
+ *
4031
+ * @param uri - The AT-URI to parse
4032
+ * @returns The components of the URI
4033
+ * @throws {Error} If the URI format is invalid
4034
+ *
4035
+ * @example
4036
+ * ```typescript
4037
+ * const components = parseAtUri("at://did:plc:abc123/org.hypercerts.claim.activity/3km2vj4kfqp2a");
4038
+ * console.log(components);
4039
+ * // {
4040
+ * // did: "did:plc:abc123",
4041
+ * // collection: "org.hypercerts.claim.activity",
4042
+ * // rkey: "3km2vj4kfqp2a"
4043
+ * // }
4044
+ * ```
4045
+ */
4046
+ declare function parseAtUri(uri: string): AtUriComponents;
4047
+ /**
4048
+ * Build an AT-URI from its component parts.
4049
+ *
4050
+ * Constructs a valid AT-URI string from a DID, collection NSID, and record key.
4051
+ * The resulting URI follows the format: `at://{did}/{collection}/{rkey}`
4052
+ *
4053
+ * @param did - The repository owner's DID
4054
+ * @param collection - The collection NSID (lexicon identifier)
4055
+ * @param rkey - The record key (TID or custom string)
4056
+ * @returns The complete AT-URI
4057
+ *
4058
+ * @example
4059
+ * ```typescript
4060
+ * const uri = buildAtUri(
4061
+ * "did:plc:abc123",
4062
+ * "org.hypercerts.claim.activity",
4063
+ * "3km2vj4kfqp2a"
4064
+ * );
4065
+ * console.log(uri); // "at://did:plc:abc123/org.hypercerts.claim.activity/3km2vj4kfqp2a"
4066
+ * ```
4067
+ */
4068
+ declare function buildAtUri(did: string, collection: string, rkey: string): string;
4069
+ /**
4070
+ * Extract the record key (TID or custom key) from an AT-URI.
4071
+ *
4072
+ * Returns the last component of the AT-URI, which is the record key.
4073
+ * This is equivalent to `parseAtUri(uri).rkey` but more efficient.
4074
+ *
4075
+ * @param uri - The AT-URI to extract from
4076
+ * @returns The record key (TID or custom string)
4077
+ * @throws {Error} If the URI format is invalid
4078
+ *
4079
+ * @example
4080
+ * ```typescript
4081
+ * const rkey = extractRkeyFromUri("at://did:plc:abc123/org.hypercerts.claim.activity/3km2vj4kfqp2a");
4082
+ * console.log(rkey); // "3km2vj4kfqp2a"
4083
+ * ```
4084
+ */
4085
+ declare function extractRkeyFromUri(uri: string): string;
4086
+ /**
4087
+ * Check if a string is a valid AT-URI format.
4088
+ *
4089
+ * Validates that the string follows the AT-URI format without throwing errors.
4090
+ * This is useful for input validation before parsing.
4091
+ *
4092
+ * @param uri - The string to validate
4093
+ * @returns True if the string is a valid AT-URI, false otherwise
4094
+ *
4095
+ * @example
4096
+ * ```typescript
4097
+ * if (isValidAtUri(userInput)) {
4098
+ * const components = parseAtUri(userInput);
4099
+ * // ... use components
4100
+ * } else {
4101
+ * console.error("Invalid AT-URI");
4102
+ * }
4103
+ * ```
4104
+ */
4105
+ declare function isValidAtUri(uri: string): boolean;
4106
+ /**
4107
+ * Create a strongRef from a URI and CID.
4108
+ *
4109
+ * StrongRefs are the canonical way to reference specific versions of records
4110
+ * in AT Protocol. They combine an AT-URI (which identifies the record) with
4111
+ * a CID (which identifies the specific version).
4112
+ *
4113
+ * @param uri - The AT-URI of the record
4114
+ * @param cid - The CID (Content Identifier) of the record version
4115
+ * @returns A strongRef object
4116
+ *
4117
+ * @example
4118
+ * ```typescript
4119
+ * const ref = createStrongRef(
4120
+ * "at://did:plc:abc123/org.hypercerts.claim.activity/3km2vj4kfqp2a",
4121
+ * "bafyreiabc123..."
4122
+ * );
4123
+ * console.log(ref);
4124
+ * // {
4125
+ * // uri: "at://did:plc:abc123/org.hypercerts.claim.activity/3km2vj4kfqp2a",
4126
+ * // cid: "bafyreiabc123..."
4127
+ * // }
4128
+ * ```
4129
+ */
4130
+ declare function createStrongRef(uri: string, cid: string): StrongRef;
4131
+ /**
4132
+ * Create a strongRef from a CreateResult or UpdateResult.
4133
+ *
4134
+ * This is a convenience function that extracts the URI and CID from
4135
+ * the result of a record creation or update operation.
4136
+ *
4137
+ * @param result - The result from creating or updating a record
4138
+ * @returns A strongRef object
4139
+ *
4140
+ * @example
4141
+ * ```typescript
4142
+ * const hypercert = await repo.hypercerts.create({
4143
+ * title: "Climate Research",
4144
+ * // ... other params
4145
+ * });
4146
+ *
4147
+ * const ref = createStrongRefFromResult(hypercert);
4148
+ * // Now use ref in another record to reference this hypercert
4149
+ * ```
4150
+ */
4151
+ declare function createStrongRefFromResult(result: CreateResult | UpdateResult): StrongRef;
4152
+ /**
4153
+ * Validate that an object is a valid strongRef.
4154
+ *
4155
+ * Checks that the object has the required `uri` and `cid` properties
4156
+ * and that they are non-empty strings.
4157
+ *
4158
+ * @param ref - The object to validate
4159
+ * @returns True if the object is a valid strongRef, false otherwise
4160
+ *
4161
+ * @example
4162
+ * ```typescript
4163
+ * const maybeRef = { uri: "at://...", cid: "bafyrei..." };
4164
+ * if (validateStrongRef(maybeRef)) {
4165
+ * // Safe to use as strongRef
4166
+ * record.subject = maybeRef;
4167
+ * }
4168
+ * ```
4169
+ */
4170
+ declare function validateStrongRef(ref: unknown): ref is StrongRef;
4171
+ /**
4172
+ * Type guard to check if a value is a strongRef.
4173
+ *
4174
+ * This is an alias for `validateStrongRef` that provides better semantics
4175
+ * for type narrowing in TypeScript.
4176
+ *
4177
+ * @param value - The value to check
4178
+ * @returns True if the value is a strongRef, false otherwise
4179
+ *
4180
+ * @example
4181
+ * ```typescript
4182
+ * function processReference(ref: unknown) {
4183
+ * if (isStrongRef(ref)) {
4184
+ * // TypeScript knows ref is StrongRef here
4185
+ * console.log(ref.uri);
4186
+ * }
4187
+ * }
4188
+ * ```
4189
+ */
4190
+ declare function isStrongRef(value: unknown): value is StrongRef;
4191
+
4192
+ /**
4193
+ * Lexicon Builder Utilities
4194
+ *
4195
+ * This module provides utilities for constructing lexicon JSON schemas programmatically.
4196
+ * These builders help developers create valid AT Protocol lexicons with proper structure
4197
+ * and type-safe field definitions.
4198
+ *
4199
+ * @packageDocumentation
4200
+ */
4201
+ /**
4202
+ * Lexicon field type definitions.
4203
+ */
4204
+ type LexiconFieldType = "string" | "integer" | "boolean" | "number" | "datetime" | "blob" | "ref" | "array" | "object" | "unknown";
4205
+ /**
4206
+ * Base lexicon field definition.
4207
+ */
4208
+ interface LexiconFieldBase {
4209
+ type: LexiconFieldType;
4210
+ description?: string;
4211
+ }
4212
+ /**
4213
+ * String field definition.
4214
+ */
4215
+ interface LexiconStringField extends LexiconFieldBase {
4216
+ type: "string";
4217
+ format?: "datetime" | "uri" | "at-uri" | "did" | "handle" | "at-identifier" | "nsid" | "cid";
4218
+ minLength?: number;
4219
+ maxLength?: number;
4220
+ minGraphemes?: number;
4221
+ maxGraphemes?: number;
4222
+ enum?: string[];
4223
+ const?: string;
4224
+ default?: string;
4225
+ }
4226
+ /**
4227
+ * Integer field definition.
4228
+ */
4229
+ interface LexiconIntegerField extends LexiconFieldBase {
4230
+ type: "integer";
4231
+ minimum?: number;
4232
+ maximum?: number;
4233
+ enum?: number[];
4234
+ const?: number;
4235
+ default?: number;
4236
+ }
4237
+ /**
4238
+ * Number field definition.
4239
+ */
4240
+ interface LexiconNumberField extends LexiconFieldBase {
4241
+ type: "number";
4242
+ minimum?: number;
4243
+ maximum?: number;
4244
+ enum?: number[];
4245
+ const?: number;
4246
+ default?: number;
4247
+ }
4248
+ /**
4249
+ * Boolean field definition.
4250
+ */
4251
+ interface LexiconBooleanField extends LexiconFieldBase {
4252
+ type: "boolean";
4253
+ const?: boolean;
4254
+ default?: boolean;
4255
+ }
4256
+ /**
4257
+ * Reference field definition (for strongRefs).
4258
+ */
4259
+ interface LexiconRefField extends LexiconFieldBase {
4260
+ type: "ref";
4261
+ ref: string;
4262
+ }
4263
+ /**
4264
+ * Array field definition.
4265
+ */
4266
+ interface LexiconArrayField extends LexiconFieldBase {
4267
+ type: "array";
4268
+ items: LexiconField;
4269
+ minLength?: number;
4270
+ maxLength?: number;
4271
+ }
4272
+ /**
4273
+ * Object field definition.
4274
+ */
4275
+ interface LexiconObjectField extends LexiconFieldBase {
4276
+ type: "object";
4277
+ properties?: Record<string, LexiconField>;
4278
+ required?: string[];
4279
+ }
4280
+ /**
4281
+ * Blob field definition.
4282
+ */
4283
+ interface LexiconBlobField extends LexiconFieldBase {
4284
+ type: "blob";
4285
+ accept?: string[];
4286
+ maxSize?: number;
4287
+ }
4288
+ /**
4289
+ * Unknown field definition (accepts any type).
4290
+ */
4291
+ interface LexiconUnknownField extends LexiconFieldBase {
4292
+ type: "unknown";
4293
+ }
4294
+ /**
4295
+ * Union of all lexicon field types.
4296
+ */
4297
+ type LexiconField = LexiconStringField | LexiconIntegerField | LexiconNumberField | LexiconBooleanField | LexiconRefField | LexiconArrayField | LexiconObjectField | LexiconBlobField | LexiconUnknownField;
4298
+ /**
4299
+ * Record definition for a lexicon.
3021
4300
  *
3022
- * This is a convenience function equivalent to `new ATProtoSDK(config)`.
4301
+ * Key types:
4302
+ * - "tid" (default): Server-generated timestamp-based ID
4303
+ * - "any": Client can specify any valid rkey
4304
+ */
4305
+ interface LexiconRecordDef {
4306
+ type: "record";
4307
+ key?: "tid" | "any";
4308
+ record: {
4309
+ type: "object";
4310
+ required: string[];
4311
+ properties: Record<string, LexiconField>;
4312
+ };
4313
+ }
4314
+ /**
4315
+ * Main lexicon document structure.
4316
+ */
4317
+ interface LexiconDoc {
4318
+ lexicon: 1;
4319
+ id: string;
4320
+ defs: {
4321
+ main: LexiconRecordDef;
4322
+ [key: string]: unknown;
4323
+ };
4324
+ }
4325
+ /**
4326
+ * Create a string field definition.
3023
4327
  *
3024
- * @param config - SDK configuration
3025
- * @returns A new {@link ATProtoSDK} instance
4328
+ * @param options - String field options
4329
+ * @returns A lexicon string field definition
3026
4330
  *
3027
4331
  * @example
3028
4332
  * ```typescript
3029
- * import { createATProtoSDK } from "@hypercerts-org/sdk";
4333
+ * const titleField = createStringField({
4334
+ * description: "Title of the item",
4335
+ * minLength: 1,
4336
+ * maxLength: 200,
4337
+ * });
4338
+ * ```
4339
+ */
4340
+ declare function createStringField(options?: Omit<LexiconStringField, "type">): LexiconStringField;
4341
+ /**
4342
+ * Create an integer field definition.
3030
4343
  *
3031
- * const sdk = createATProtoSDK({
3032
- * oauth: { ... },
3033
- * servers: { pds: "https://bsky.social" },
4344
+ * @param options - Integer field options
4345
+ * @returns A lexicon integer field definition
4346
+ *
4347
+ * @example
4348
+ * ```typescript
4349
+ * const scoreField = createIntegerField({
4350
+ * description: "Score from 0 to 100",
4351
+ * minimum: 0,
4352
+ * maximum: 100,
3034
4353
  * });
3035
4354
  * ```
3036
4355
  */
3037
- declare function createATProtoSDK(config: ATProtoSDKConfig): ATProtoSDK;
4356
+ declare function createIntegerField(options?: Omit<LexiconIntegerField, "type">): LexiconIntegerField;
4357
+ /**
4358
+ * Create a number field definition.
4359
+ *
4360
+ * @param options - Number field options
4361
+ * @returns A lexicon number field definition
4362
+ *
4363
+ * @example
4364
+ * ```typescript
4365
+ * const weightField = createNumberField({
4366
+ * description: "Weight as decimal",
4367
+ * minimum: 0,
4368
+ * maximum: 1,
4369
+ * });
4370
+ * ```
4371
+ */
4372
+ declare function createNumberField(options?: Omit<LexiconNumberField, "type">): LexiconNumberField;
4373
+ /**
4374
+ * Create a boolean field definition.
4375
+ *
4376
+ * @param options - Boolean field options
4377
+ * @returns A lexicon boolean field definition
4378
+ *
4379
+ * @example
4380
+ * ```typescript
4381
+ * const verifiedField = createBooleanField({
4382
+ * description: "Whether the item is verified",
4383
+ * default: false,
4384
+ * });
4385
+ * ```
4386
+ */
4387
+ declare function createBooleanField(options?: Omit<LexiconBooleanField, "type">): LexiconBooleanField;
4388
+ /**
4389
+ * Create a strongRef field definition.
4390
+ *
4391
+ * StrongRefs are the standard way to reference other records in AT Protocol.
4392
+ * They contain both the AT-URI and CID of the referenced record.
4393
+ *
4394
+ * @param options - Reference field options
4395
+ * @returns A lexicon reference field definition
4396
+ *
4397
+ * @example
4398
+ * ```typescript
4399
+ * const subjectField = createStrongRefField({
4400
+ * description: "The hypercert being evaluated",
4401
+ * });
4402
+ * ```
4403
+ */
4404
+ declare function createStrongRefField(options?: Omit<LexiconRefField, "type" | "ref"> & {
4405
+ ref?: string;
4406
+ }): LexiconRefField;
4407
+ /**
4408
+ * Create an array field definition.
4409
+ *
4410
+ * @param itemType - The type of items in the array
4411
+ * @param options - Array field options
4412
+ * @returns A lexicon array field definition
4413
+ *
4414
+ * @example
4415
+ * ```typescript
4416
+ * const tagsField = createArrayField(
4417
+ * createStringField({ maxLength: 50 }),
4418
+ * {
4419
+ * description: "List of tags",
4420
+ * minLength: 1,
4421
+ * maxLength: 10,
4422
+ * }
4423
+ * );
4424
+ * ```
4425
+ */
4426
+ declare function createArrayField(itemType: LexiconField, options?: Omit<LexiconArrayField, "type" | "items">): LexiconArrayField;
4427
+ /**
4428
+ * Create an object field definition.
4429
+ *
4430
+ * @param options - Object field options
4431
+ * @returns A lexicon object field definition
4432
+ *
4433
+ * @example
4434
+ * ```typescript
4435
+ * const metadataField = createObjectField({
4436
+ * description: "Additional metadata",
4437
+ * properties: {
4438
+ * author: createStringField(),
4439
+ * version: createIntegerField(),
4440
+ * },
4441
+ * required: ["author"],
4442
+ * });
4443
+ * ```
4444
+ */
4445
+ declare function createObjectField(options?: Omit<LexiconObjectField, "type">): LexiconObjectField;
4446
+ /**
4447
+ * Create a blob field definition.
4448
+ *
4449
+ * @param options - Blob field options
4450
+ * @returns A lexicon blob field definition
4451
+ *
4452
+ * @example
4453
+ * ```typescript
4454
+ * const imageField = createBlobField({
4455
+ * description: "Profile image",
4456
+ * accept: ["image/png", "image/jpeg"],
4457
+ * maxSize: 1000000, // 1MB
4458
+ * });
4459
+ * ```
4460
+ */
4461
+ declare function createBlobField(options?: Omit<LexiconBlobField, "type">): LexiconBlobField;
4462
+ /**
4463
+ * Create a datetime string field.
4464
+ *
4465
+ * This is a convenience function for creating string fields with datetime format.
4466
+ *
4467
+ * @param options - String field options
4468
+ * @returns A lexicon string field with datetime format
4469
+ *
4470
+ * @example
4471
+ * ```typescript
4472
+ * const createdAtField = createDatetimeField({
4473
+ * description: "When the record was created",
4474
+ * });
4475
+ * ```
4476
+ */
4477
+ declare function createDatetimeField(options?: Omit<LexiconStringField, "type" | "format">): LexiconStringField;
4478
+ /**
4479
+ * Create a record definition.
4480
+ *
4481
+ * This defines the structure of records in your lexicon.
4482
+ *
4483
+ * @param properties - The record's properties (fields)
4484
+ * @param required - Array of required field names
4485
+ * @param keyType - The type of record key ("tid" for server-generated, "any" for custom)
4486
+ * @returns A lexicon record definition
4487
+ *
4488
+ * @example
4489
+ * ```typescript
4490
+ * const recordDef = createRecordDef(
4491
+ * {
4492
+ * $type: createStringField({ const: "org.myapp.evaluation" }),
4493
+ * subject: createStrongRefField({ description: "The evaluated item" }),
4494
+ * score: createIntegerField({ minimum: 0, maximum: 100 }),
4495
+ * createdAt: createDatetimeField(),
4496
+ * },
4497
+ * ["$type", "subject", "score", "createdAt"],
4498
+ * "tid"
4499
+ * );
4500
+ * ```
4501
+ */
4502
+ declare function createRecordDef(properties: Record<string, LexiconField>, required: string[], keyType?: "tid" | "any"): LexiconRecordDef;
4503
+ /**
4504
+ * Create a complete lexicon document.
4505
+ *
4506
+ * This creates a full lexicon JSON structure that can be registered with the SDK.
4507
+ *
4508
+ * @param nsid - The NSID (Namespaced Identifier) for this lexicon
4509
+ * @param properties - The record's properties (fields)
4510
+ * @param required - Array of required field names
4511
+ * @param keyType - The type of record key ("tid" for server-generated, "any" for custom)
4512
+ * @returns A complete lexicon document
4513
+ *
4514
+ * @example
4515
+ * ```typescript
4516
+ * const lexicon = createLexiconDoc(
4517
+ * "org.myapp.evaluation",
4518
+ * {
4519
+ * $type: createStringField({ const: "org.myapp.evaluation" }),
4520
+ * subject: createStrongRefField({ description: "The evaluated item" }),
4521
+ * score: createIntegerField({ minimum: 0, maximum: 100 }),
4522
+ * methodology: createStringField({ maxLength: 500 }),
4523
+ * createdAt: createDatetimeField(),
4524
+ * },
4525
+ * ["$type", "subject", "score", "createdAt"],
4526
+ * "tid"
4527
+ * );
4528
+ *
4529
+ * // Register with SDK
4530
+ * sdk.getLexiconRegistry().registerFromJSON(lexicon);
4531
+ * ```
4532
+ */
4533
+ declare function createLexiconDoc(nsid: string, properties: Record<string, LexiconField>, required: string[], keyType?: "tid" | "any"): LexiconDoc;
4534
+ /**
4535
+ * Validate a lexicon document structure.
4536
+ *
4537
+ * Performs basic validation to ensure the lexicon follows AT Protocol conventions.
4538
+ * This does NOT perform full JSON schema validation.
4539
+ *
4540
+ * @param lexicon - The lexicon document to validate
4541
+ * @returns True if valid, false otherwise
4542
+ *
4543
+ * @example
4544
+ * ```typescript
4545
+ * const lexicon = createLexiconDoc(...);
4546
+ * if (validateLexiconStructure(lexicon)) {
4547
+ * sdk.getLexiconRegistry().registerFromJSON(lexicon);
4548
+ * } else {
4549
+ * console.error("Invalid lexicon structure");
4550
+ * }
4551
+ * ```
4552
+ */
4553
+ declare function validateLexiconStructure(lexicon: unknown): lexicon is LexiconDoc;
3038
4554
 
3039
4555
  /**
3040
- * ConfigurableAgent - Agent with configurable service URL routing.
4556
+ * Sidecar Pattern Utilities
3041
4557
  *
3042
- * This module provides an Agent extension that allows routing requests to
3043
- * a specific server URL, overriding the default URL from the OAuth session.
4558
+ * This module provides utilities for implementing the AT Protocol "sidecar pattern"
4559
+ * where additional records are created that reference a main record via StrongRef.
4560
+ *
4561
+ * ## The Sidecar Pattern
4562
+ *
4563
+ * In AT Protocol, the sidecar pattern uses **unidirectional references**:
4564
+ * - Sidecar records contain a StrongRef (uri + cid) pointing to the main record
4565
+ * - Main records do NOT maintain back-references to sidecars
4566
+ * - Sidecars are discovered by querying records that reference the main record
4567
+ * - Optionally, sidecars can use the same rkey as the main record (in different collections)
4568
+ *
4569
+ * ## Example Use Cases
4570
+ *
4571
+ * - Evaluations that reference hypercerts
4572
+ * - Comments that reference posts
4573
+ * - Metadata records that reference primary entities
4574
+ *
4575
+ * @see https://atproto.com/specs/record-key
4576
+ * @see https://atproto.com/specs/data-model
3044
4577
  *
3045
4578
  * @packageDocumentation
3046
4579
  */
3047
4580
 
3048
4581
  /**
3049
- * Agent subclass that routes requests to a configurable service URL.
4582
+ * Parameters for creating a sidecar record.
4583
+ */
4584
+ interface SidecarRecordParams {
4585
+ /** The collection NSID for the sidecar record */
4586
+ collection: string;
4587
+ /** The record data */
4588
+ record: Record<string, unknown>;
4589
+ /** Optional custom rkey */
4590
+ rkey?: string;
4591
+ }
4592
+ /**
4593
+ * Result from creating a sidecar record.
4594
+ */
4595
+ interface SidecarResult {
4596
+ /** The main record that was referenced */
4597
+ mainRecord: CreateResult;
4598
+ /** The sidecar record that was created */
4599
+ sidecarRecord: CreateResult;
4600
+ }
4601
+ /**
4602
+ * Parameters for attaching a sidecar to an existing record.
4603
+ */
4604
+ interface AttachSidecarParams {
4605
+ /** The main record to reference */
4606
+ mainRecord: {
4607
+ uri: string;
4608
+ cid: string;
4609
+ };
4610
+ /** The sidecar record to create */
4611
+ sidecar: SidecarRecordParams;
4612
+ }
4613
+ /**
4614
+ * Result from creating multiple sidecars.
4615
+ */
4616
+ interface MultiSidecarResult {
4617
+ /** The main record that was created */
4618
+ main: CreateResult;
4619
+ /** The sidecar records that were created */
4620
+ sidecars: CreateResult[];
4621
+ }
4622
+ /**
4623
+ * Parameters for creating a main record with multiple sidecars.
4624
+ */
4625
+ interface CreateWithSidecarsParams {
4626
+ /** The main record to create */
4627
+ main: SidecarRecordParams;
4628
+ /** The sidecar records to create (can reference the main record via placeholder) */
4629
+ sidecars: SidecarRecordParams[];
4630
+ }
4631
+ /**
4632
+ * Create a sidecar record that references an existing record.
3050
4633
  *
3051
- * The standard Agent uses the service URL embedded in the OAuth session's
3052
- * fetch handler. This class allows overriding that URL to route requests
3053
- * to different servers (e.g., PDS vs SDS, or multiple SDS instances).
4634
+ * This is a low-level utility that creates a single sidecar record. The sidecar
4635
+ * record should include a strongRef field that points to the main record.
3054
4636
  *
3055
- * @remarks
3056
- * This is particularly useful for:
3057
- * - Routing to a Shared Data Server (SDS) while authenticated via PDS
3058
- * - Supporting multiple SDS instances for different organizations
3059
- * - Testing against different server environments
4637
+ * @param repo - The repository instance
4638
+ * @param collection - The collection NSID for the sidecar
4639
+ * @param record - The sidecar record data (should include a strongRef to the main record)
4640
+ * @param options - Optional creation options
4641
+ * @returns The created sidecar record
3060
4642
  *
3061
- * @example Basic usage
4643
+ * @example
3062
4644
  * ```typescript
3063
- * const session = await sdk.authorize("user.bsky.social");
4645
+ * const hypercert = await repo.hypercerts.create({...});
4646
+ *
4647
+ * const evaluation = await createSidecarRecord(
4648
+ * repo,
4649
+ * "org.myapp.evaluation",
4650
+ * {
4651
+ * $type: "org.myapp.evaluation",
4652
+ * subject: { uri: hypercert.hypercertUri, cid: hypercert.hypercertCid },
4653
+ * score: 85,
4654
+ * createdAt: new Date().toISOString(),
4655
+ * }
4656
+ * );
4657
+ * ```
4658
+ */
4659
+ declare function createSidecarRecord(repo: Repository, collection: string, record: Record<string, unknown>, options?: {
4660
+ rkey?: string;
4661
+ }): Promise<CreateResult>;
4662
+ /**
4663
+ * Attach a sidecar record to an existing main record.
3064
4664
  *
3065
- * // Create agent routing to SDS instead of session's default PDS
3066
- * const sdsAgent = new ConfigurableAgent(session, "https://sds.hypercerts.org");
4665
+ * This creates a new record that references an existing record via strongRef.
4666
+ * It's a higher-level convenience function that wraps `createSidecarRecord`.
3067
4667
  *
3068
- * // All requests will now go to the SDS
3069
- * await sdsAgent.com.atproto.repo.createRecord({...});
4668
+ * @param repo - The repository instance
4669
+ * @param params - Parameters including the main record reference and sidecar definition
4670
+ * @returns Both the main record reference and the created sidecar
4671
+ *
4672
+ * @example
4673
+ * ```typescript
4674
+ * const hypercert = await repo.hypercerts.create({...});
4675
+ *
4676
+ * const result = await attachSidecar(repo, {
4677
+ * mainRecord: {
4678
+ * uri: hypercert.hypercertUri,
4679
+ * cid: hypercert.hypercertCid,
4680
+ * },
4681
+ * sidecar: {
4682
+ * collection: "org.myapp.evaluation",
4683
+ * record: {
4684
+ * $type: "org.myapp.evaluation",
4685
+ * subject: { uri: hypercert.hypercertUri, cid: hypercert.hypercertCid },
4686
+ * score: 85,
4687
+ * createdAt: new Date().toISOString(),
4688
+ * },
4689
+ * },
4690
+ * });
3070
4691
  * ```
4692
+ */
4693
+ declare function attachSidecar(repo: Repository, params: AttachSidecarParams): Promise<SidecarResult>;
4694
+ /**
4695
+ * Create a main record and multiple sidecar records in sequence.
3071
4696
  *
3072
- * @example Multiple SDS instances
4697
+ * This orchestrates the creation of a main record followed by one or more
4698
+ * sidecar records that reference it. This is useful for workflows like:
4699
+ * - Creating a project with multiple hypercert claims
4700
+ * - Creating a hypercert with evidence and evaluation records
4701
+ *
4702
+ * @param repo - The repository instance
4703
+ * @param params - Parameters including the main record and sidecar definitions
4704
+ * @returns The main record and all created sidecar records
4705
+ *
4706
+ * @example
3073
4707
  * ```typescript
3074
- * // Route to organization A's SDS
3075
- * const orgAAgent = new ConfigurableAgent(session, "https://sds-org-a.example.com");
4708
+ * const result = await createWithSidecars(repo, {
4709
+ * main: {
4710
+ * collection: "org.hypercerts.project",
4711
+ * record: {
4712
+ * $type: "org.hypercerts.project",
4713
+ * title: "Climate Initiative 2024",
4714
+ * description: "Our climate work",
4715
+ * createdAt: new Date().toISOString(),
4716
+ * },
4717
+ * },
4718
+ * sidecars: [
4719
+ * {
4720
+ * collection: "org.hypercerts.claim.activity",
4721
+ * record: {
4722
+ * $type: "org.hypercerts.claim.activity",
4723
+ * title: "Tree Planting",
4724
+ * // ... other hypercert fields
4725
+ * // Note: If you need to reference the main record, you must wait
4726
+ * // for result.main and then call batchCreateSidecars separately
4727
+ * },
4728
+ * },
4729
+ * {
4730
+ * collection: "org.hypercerts.claim.activity",
4731
+ * record: {
4732
+ * $type: "org.hypercerts.claim.activity",
4733
+ * title: "Carbon Measurement",
4734
+ * // ... other hypercert fields
4735
+ * },
4736
+ * },
4737
+ * ],
4738
+ * });
3076
4739
  *
3077
- * // Route to organization B's SDS
3078
- * const orgBAgent = new ConfigurableAgent(session, "https://sds-org-b.example.com");
4740
+ * console.log(result.main.uri); // Main project record
4741
+ * console.log(result.sidecars.length); // 2 hypercert sidecars
3079
4742
  * ```
3080
4743
  */
3081
- declare class ConfigurableAgent extends Agent {
3082
- private customServiceUrl;
3083
- /**
3084
- * Creates a ConfigurableAgent that routes to a specific service URL.
3085
- *
3086
- * @param session - OAuth session for authentication
3087
- * @param serviceUrl - Base URL of the server to route requests to
3088
- *
3089
- * @remarks
3090
- * The agent wraps the session's fetch handler to intercept requests and
3091
- * prepend the custom service URL instead of using the session's default.
3092
- */
3093
- constructor(session: Session, serviceUrl: string);
3094
- /**
3095
- * Gets the service URL this agent routes to.
3096
- *
3097
- * @returns The base URL of the configured service
3098
- */
3099
- getServiceUrl(): string;
3100
- }
4744
+ declare function createWithSidecars(repo: Repository, params: CreateWithSidecarsParams): Promise<MultiSidecarResult>;
4745
+ /**
4746
+ * Batch create multiple sidecar records.
4747
+ *
4748
+ * This is useful when you want to add multiple related records
4749
+ * efficiently. The sidecar records should already contain any necessary
4750
+ * references to the main record in their data.
4751
+ *
4752
+ * @param repo - The repository instance
4753
+ * @param sidecars - Array of sidecar definitions (records should include references)
4754
+ * @returns Array of created sidecar records
4755
+ *
4756
+ * @example
4757
+ * ```typescript
4758
+ * const hypercert = await repo.hypercerts.create({...});
4759
+ * const mainRef = { uri: hypercert.hypercertUri, cid: hypercert.hypercertCid };
4760
+ *
4761
+ * const evaluations = await batchCreateSidecars(repo, [
4762
+ * {
4763
+ * collection: "org.myapp.evaluation",
4764
+ * record: {
4765
+ * $type: "org.myapp.evaluation",
4766
+ * subject: mainRef, // Reference already included
4767
+ * score: 85,
4768
+ * methodology: "Peer review",
4769
+ * createdAt: new Date().toISOString(),
4770
+ * },
4771
+ * },
4772
+ * {
4773
+ * collection: "org.myapp.comment",
4774
+ * record: {
4775
+ * $type: "org.myapp.comment",
4776
+ * subject: mainRef, // Reference already included
4777
+ * text: "Great work!",
4778
+ * createdAt: new Date().toISOString(),
4779
+ * },
4780
+ * },
4781
+ * ]);
4782
+ * ```
4783
+ */
4784
+ declare function batchCreateSidecars(repo: Repository, sidecars: SidecarRecordParams[]): Promise<CreateResult[]>;
3101
4785
 
3102
4786
  /**
3103
4787
  * Base error class for all SDK errors.
@@ -3671,12 +5355,29 @@ type IdentityAttr = z.infer<typeof IdentityAttrSchema>;
3671
5355
  /**
3672
5356
  * Zod schema for MIME type patterns.
3673
5357
  *
3674
- * Validates MIME type strings like "image/*" or "video/mp4".
5358
+ * Validates MIME type strings used in blob permissions.
5359
+ * Supports standard MIME types and wildcard patterns per ATProto spec.
5360
+ *
5361
+ * **References:**
5362
+ * - ATProto Permission Spec: https://atproto.com/specs/permission (blob resource)
5363
+ * - RFC 2045 (MIME): https://www.rfc-editor.org/rfc/rfc2045 (token definition)
5364
+ * - IANA Media Types: https://www.iana.org/assignments/media-types/
5365
+ *
5366
+ * **Implementation:**
5367
+ * This is a "good enough" validation that allows common real-world MIME types:
5368
+ * - Type: letters, digits (e.g., "3gpp")
5369
+ * - Subtype: letters, digits, hyphens, plus signs, dots, underscores, wildcards
5370
+ * - Examples: "image/png", "application/vnd.api+json", "video/*", "clue_info+xml"
5371
+ *
5372
+ * Note: We use a simplified regex rather than full RFC 2045 token validation
5373
+ * for practicality. Zod v4 has native MIME support (z.file().mime()) but would
5374
+ * require a larger migration effort.
3675
5375
  *
3676
5376
  * @example
3677
5377
  * ```typescript
3678
- * MimeTypeSchema.parse('image/*'); // Valid
3679
- * MimeTypeSchema.parse('video/mp4'); // Valid
5378
+ * MimeTypeSchema.parse('image/*'); // Valid - wildcard
5379
+ * MimeTypeSchema.parse('video/mp4'); // Valid - standard
5380
+ * MimeTypeSchema.parse('application/vnd.api+json'); // Valid - with dots/plus
3680
5381
  * MimeTypeSchema.parse('invalid'); // Throws ZodError
3681
5382
  * ```
3682
5383
  */
@@ -3687,6 +5388,12 @@ declare const MimeTypeSchema: z.ZodString;
3687
5388
  * NSIDs are reverse-DNS style identifiers used throughout ATProto
3688
5389
  * (e.g., "app.bsky.feed.post" or "com.example.myrecord").
3689
5390
  *
5391
+ * Official ATProto NSID spec requires:
5392
+ * - Each segment must be 1-63 characters
5393
+ * - Authority segments (all but last) can contain hyphens, but not at boundaries
5394
+ * - Name segment (last) must start with a letter and contain only alphanumerics
5395
+ * - Hyphens only allowed in authority segments, not in the name segment
5396
+ *
3690
5397
  * @see https://atproto.com/specs/nsid
3691
5398
  *
3692
5399
  * @example
@@ -4521,20 +6228,44 @@ declare function parseScope(scope: string): string[];
4521
6228
  /**
4522
6229
  * Check if a scope string contains a specific permission.
4523
6230
  *
4524
- * This function performs exact string matching. For more advanced
4525
- * permission checking (e.g., wildcard matching), you'll need to
4526
- * implement custom logic.
6231
+ * Implements permission matching per ATProto OAuth spec with support for
6232
+ * exact matching and limited wildcard patterns.
6233
+ *
6234
+ * **References:**
6235
+ * - ATProto Permission Spec: https://atproto.com/specs/permission
6236
+ * - ATProto OAuth Spec: https://atproto.com/specs/oauth
6237
+ *
6238
+ * **Supported wildcards (per spec):**
6239
+ * - `repo:*` - Matches any repository collection (e.g., `repo:app.bsky.feed.post`)
6240
+ * - `rpc:*` - Matches any RPC lexicon (but aud cannot also be wildcard)
6241
+ * - `blob:image/*` - MIME type wildcards (e.g., matches `blob:image/png`, `blob:image/jpeg`)
6242
+ * - `blob:` + wildcard MIME - Matches any MIME type (using `*` + `/` + `*` pattern)
6243
+ * - `identity:*` - Full control of DID document and handle (spec allows `*` as attr value)
6244
+ *
6245
+ * **NOT supported (per spec):**
6246
+ * - `account:*` - Account attr does not support wildcards (only `email` and `repo` allowed)
6247
+ * - `include:*` - Include NSID does not support wildcards
6248
+ * - Partial wildcards like `com.example.*` are not supported
4527
6249
  *
4528
6250
  * @param scope - Space-separated scope string
4529
6251
  * @param permission - The permission to check for
4530
6252
  * @returns True if the scope contains the permission
4531
6253
  *
4532
- * @example
6254
+ * @example Exact matching
4533
6255
  * ```typescript
4534
- * const scope = "account:email?action=read repo:app.bsky.feed.post";
4535
- * hasPermission(scope, "account:email?action=read"); // true
6256
+ * const scope = "account:email repo:app.bsky.feed.post";
6257
+ * hasPermission(scope, "account:email"); // true
4536
6258
  * hasPermission(scope, "account:repo"); // false
4537
6259
  * ```
6260
+ *
6261
+ * @example Wildcard matching
6262
+ * ```typescript
6263
+ * const scope = "repo:* blob:image/* identity:*";
6264
+ * hasPermission(scope, "repo:app.bsky.feed.post"); // true
6265
+ * hasPermission(scope, "blob:image/png"); // true
6266
+ * hasPermission(scope, "blob:video/mp4"); // false
6267
+ * hasPermission(scope, "identity:handle"); // true
6268
+ * ```
4538
6269
  */
4539
6270
  declare function hasPermission(scope: string, permission: string): boolean;
4540
6271
  /**
@@ -4618,5 +6349,5 @@ declare function validateScope(scope: string): {
4618
6349
  invalidPermissions: string[];
4619
6350
  };
4620
6351
 
4621
- export { ATPROTO_SCOPE, ATProtoSDK, ATProtoSDKConfigSchema, ATProtoSDKError, AccountActionSchema, AccountAttrSchema, AccountPermissionSchema, AuthenticationError, BlobPermissionSchema, CollaboratorPermissionsSchema, CollaboratorSchema, ConfigurableAgent, HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS, IdentityAttrSchema, IdentityPermissionSchema, InMemorySessionStore, InMemoryStateStore, IncludePermissionSchema, MimeTypeSchema, NetworkError, NsidSchema, OAuthConfigSchema, OrganizationSchema, PermissionBuilder, PermissionSchema, RepoActionSchema, RepoPermissionSchema, Repository, RpcPermissionSchema, SDSRequiredError, ScopePresets, ServerConfigSchema, SessionExpiredError, TRANSITION_SCOPES, TimeoutConfigSchema, TransitionScopeSchema, ValidationError, buildScope, createATProtoSDK, hasAllPermissions, hasAnyPermission, hasPermission, mergeScopes, parseScope, removePermissions, validateScope };
4622
- export type { ATProtoSDKConfig, AccountAction, AccountAttr, AccountPermissionInput, AuthorizeOptions, BadgeAward, BadgeDefinition, BadgeResponse, BlobOperations, BlobPermissionInput, CacheInterface, Collaborator, CollaboratorOperations, CollaboratorPermissions, CreateHypercertParams, CreateHypercertResult, CreateResult, DID, FundingReceipt, HypercertClaim, HypercertCollection, HypercertCollectionClaimItem, HypercertContribution, HypercertEvaluation, HypercertEvents, HypercertEvidence, HypercertImage, HypercertImageRecord, HypercertLocation, HypercertMeasurement, HypercertOperations, HypercertProject, HypercertRights, HypercertWithMetadata, IdentityAttr, IdentityPermissionInput, IncludePermissionInput, ListParams, LoggerInterface, Organization, OrganizationInfo, OrganizationOperations, PaginatedList, Permission, PermissionInput, ProfileOperations, ProgressStep, RecordOperations, RepoAction, RepoPermissionInput, RepositoryAccessGrant, RepositoryOptions, RepositoryRole, RpcPermissionInput, Session, SessionStore, StateStore, StrongRef, TransitionScope, UpdateResult };
6352
+ export { ATPROTO_SCOPE, ATProtoSDK, ATProtoSDKConfigSchema, ATProtoSDKError, AccountActionSchema, AccountAttrSchema, AccountPermissionSchema, AuthenticationError, BaseOperations, BlobPermissionSchema, CollaboratorPermissionsSchema, CollaboratorSchema, ConfigurableAgent, HYPERCERT_COLLECTIONS, HYPERCERT_LEXICONS, IdentityAttrSchema, IdentityPermissionSchema, InMemorySessionStore, InMemoryStateStore, IncludePermissionSchema, LexiconRegistry, MimeTypeSchema, NetworkError, NsidSchema, OAuthConfigSchema, OrganizationSchema, PermissionBuilder, PermissionSchema, RepoActionSchema, RepoPermissionSchema, Repository, RpcPermissionSchema, SDSRequiredError, ScopePresets, ServerConfigSchema, SessionExpiredError, TRANSITION_SCOPES, TimeoutConfigSchema, TransitionScopeSchema, ValidationError, attachSidecar, batchCreateSidecars, buildAtUri, buildScope, createATProtoSDK, createArrayField, createBlobField, createBooleanField, createDatetimeField, createIntegerField, createLexiconDoc, createNumberField, createObjectField, createRecordDef, createSidecarRecord, createStringField, createStrongRef, createStrongRefField, createStrongRefFromResult, createWithSidecars, extractRkeyFromUri, hasAllPermissions, hasAnyPermission, hasPermission, isStrongRef, isValidAtUri, mergeScopes, parseAtUri, parseScope, removePermissions, validateLexiconStructure, validateScope, validateStrongRef };
6353
+ export type { ATProtoSDKConfig, AccountAction, AccountAttr, AccountPermissionInput, AtUriComponents, AttachLocationParams, AttachSidecarParams, AuthorizeOptions, BadgeAward, BadgeDefinition, BadgeResponse, BlobOperations, BlobPermissionInput, CacheInterface, Collaborator, CollaboratorOperations, CollaboratorPermissions, CreateHypercertEvidenceParams, CreateHypercertParams, CreateHypercertResult, CreateOrganizationParams, CreateProjectParams, CreateResult, CreateWithSidecarsParams, DID, FundingReceipt, HypercertClaim, HypercertCollection, HypercertCollectionItem, HypercertContributionDetails, HypercertContributor, HypercertContributorInformation, HypercertEvaluation, HypercertEvents, HypercertEvidence, HypercertImage, HypercertImageRecord, HypercertLocation, HypercertMeasurement, HypercertOperations, HypercertProject, HypercertProjectWithMetadata, HypercertRights, HypercertWithMetadata, HypercertWorkScopeTag, IdentityAttr, IdentityPermissionInput, IncludePermissionInput, LexiconArrayField, LexiconBlobField, LexiconBooleanField, LexiconDoc, LexiconField, LexiconFieldType, LexiconIntegerField, LexiconNumberField, LexiconObjectField, LexiconRecordDef, LexiconRefField, LexiconStringField, LexiconUnknownField, ListParams, LoggerInterface, MultiSidecarResult, Organization, OrganizationInfo, OrganizationOperations, PaginatedList, Permission, PermissionInput, ProfileOperations, ProgressStep, RecordOperations, RepoAction, RepoPermissionInput, RepositoryAccessGrant, RepositoryOptions, RepositoryRole, RpcPermissionInput, Session, SessionStore, SidecarRecordParams, SidecarResult, StateStore, StrongRef, TransitionScope, UpdateProjectParams, UpdateResult, ValidationResult };