@atproto/syntax 0.4.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @atproto/syntax
2
2
 
3
+ ## 0.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [`67eb0c1`](https://github.com/bluesky-social/atproto/commit/67eb0c19ac415e762e221b2ccda9f0bcf7b3dd6f) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Improve efficiency of `AtUri` `did` getter and typing of `hostname` property
8
+
9
+ ## 0.5.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#4689](https://github.com/bluesky-social/atproto/pull/4689) [`f7c2610`](https://github.com/bluesky-social/atproto/commit/f7c26103a6d4e24e5bedbb6fd908be140420e0dd) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Remove global `Date.toISOString()` overload and replace with more accurate, less permissive, `AtprotoDate` interface. This change prevent using any `Date` instance to generate a `DatetimeString`, since some JS dates can actually not be safely stringified to a `DatetimeString`.
14
+
15
+ ### Patch Changes
16
+
17
+ - [#4689](https://github.com/bluesky-social/atproto/pull/4689) [`f7c2610`](https://github.com/bluesky-social/atproto/commit/f7c26103a6d4e24e5bedbb6fd908be140420e0dd) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add type safe accessors to read and write `AtUri`'s `did`, `collection` and `rkey` properties
18
+
19
+ - [#4689](https://github.com/bluesky-social/atproto/pull/4689) [`f7c2610`](https://github.com/bluesky-social/atproto/commit/f7c26103a6d4e24e5bedbb6fd908be140420e0dd) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Test `ensureValidDatetime`, `isValidDatetime` and `normalizeDatetime` individually, for expected failures.
20
+
21
+ - [#4689](https://github.com/bluesky-social/atproto/pull/4689) [`f7c2610`](https://github.com/bluesky-social/atproto/commit/f7c26103a6d4e24e5bedbb6fd908be140420e0dd) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Allow calling `DatetimeString` validation utilities with `unknown` values (instead of only `string`)
22
+
23
+ - [#4689](https://github.com/bluesky-social/atproto/pull/4689) [`f7c2610`](https://github.com/bluesky-social/atproto/commit/f7c26103a6d4e24e5bedbb6fd908be140420e0dd) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Preserve input type when normalizing a valid `HandleString`
24
+
25
+ - [#4688](https://github.com/bluesky-social/atproto/pull/4688) [`52834ab`](https://github.com/bluesky-social/atproto/commit/52834aba182da8df3611fd9dff924e6c6a3973a7) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Minor optimization in regex based NSID string validation
26
+
27
+ - [#4689](https://github.com/bluesky-social/atproto/pull/4689) [`f7c2610`](https://github.com/bluesky-social/atproto/commit/f7c26103a6d4e24e5bedbb6fd908be140420e0dd) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Improve type strictness of `NSID`'s `authority` and `toString()` properties
28
+
3
29
  ## 0.4.3
4
30
 
5
31
  ### Patch Changes
@@ -1,6 +1,53 @@
1
1
  import { DidString } from './did.js';
2
2
  import { HandleString } from './handle.js';
3
+ /**
4
+ * An "at-identifier" string - either a {@link DidString} or a {@link HandleString}
5
+ *
6
+ * @example `"did:plc:1234..."`, `"did:web:example.com"` or `"alice.bsky.social"`
7
+ */
3
8
  export type AtIdentifierString = DidString | HandleString;
4
- export declare function ensureValidAtIdentifier(input: string): asserts input is AtIdentifierString;
5
- export declare function isValidAtIdentifier<I extends string>(input: I): input is I & AtIdentifierString;
9
+ /**
10
+ * Discriminates {@link HandleString} from a valid {@link AtIdentifierString}.
11
+ *
12
+ * @return `true` if the identifier is a handle, `false` otherwise
13
+ */
14
+ export declare function isHandleIdentifier(id: AtIdentifierString): id is HandleString;
15
+ /**
16
+ * Discriminates {@link DidString} from a valid {@link AtIdentifierString}.
17
+ *
18
+ * @return `true` if the identifier is a DID, `false` otherwise
19
+ */
20
+ export declare function isDidIdentifier(id: AtIdentifierString): id is DidString;
21
+ /**
22
+ * Validates that a string is a valid {@link AtIdentifierString} format string,
23
+ * throwing an error if it is not.
24
+ *
25
+ * @throws InvalidHandleError if the input string does not meet the atproto 'datetime' format requirements.
26
+ * @see {@link AtIdentifierString}
27
+ */
28
+ export declare function assertAtIdentifierString<I>(input: I): asserts input is I & AtIdentifierString;
29
+ /**
30
+ * Casts a string to a {@link AtIdentifierString} if it is a valid at-identifier
31
+ * string, throwing an error if it is not.
32
+ *
33
+ * @throws InvalidHandleError if the input string does not meet the atproto 'at-identifier' format requirements.
34
+ * @see {@link AtIdentifierString}
35
+ */
36
+ export declare function asAtIdentifierString<I>(input: I): I & AtIdentifierString;
37
+ /**
38
+ * Type guard that checks if a value is a valid AT identifier (DID or handle).
39
+ *
40
+ * @param value - The value to check
41
+ * @returns `true` if the value is a valid AT identifier
42
+ * @see {@link AtIdentifierString}
43
+ */
44
+ export declare function isAtIdentifierString<I>(input: I): input is I & AtIdentifierString;
45
+ /**
46
+ * Returns the input if it is a valid {@link AtIdentifierString} format string, or
47
+ * `undefined` if it is not.
48
+ *
49
+ * @see {@link AtIdentifierString}
50
+ */
51
+ export declare function ifAtIdentifierString<I>(input: I): undefined | (I & AtIdentifierString);
52
+ export { assertAtIdentifierString as ensureValidAtIdentifier, isAtIdentifierString as isValidAtIdentifier, };
6
53
  //# sourceMappingURL=at-identifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"at-identifier.d.ts","sourceRoot":"","sources":["../src/at-identifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmC,MAAM,UAAU,CAAA;AACrE,OAAO,EACL,YAAY,EAIb,MAAM,aAAa,CAAA;AAEpB,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,YAAY,CAAA;AAEzD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,KAAK,IAAI,kBAAkB,CAUrC;AAED,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAClD,KAAK,EAAE,CAAC,GACP,KAAK,IAAI,CAAC,GAAG,kBAAkB,CAMjC"}
1
+ {"version":3,"file":"at-identifier.d.ts","sourceRoot":"","sources":["../src/at-identifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmC,MAAM,UAAU,CAAA;AACrE,OAAO,EACL,YAAY,EAIb,MAAM,aAAa,CAAA;AAEpB;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,YAAY,CAAA;AAEzD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,kBAAkB,GAAG,EAAE,IAAI,YAAY,CAE7E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,kBAAkB,GAAG,EAAE,IAAI,SAAS,CAEvE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,KAAK,EAAE,CAAC,GACP,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,kBAAkB,CAYzC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAGxE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,KAAK,EAAE,CAAC,GACP,KAAK,IAAI,CAAC,GAAG,kBAAkB,CAQjC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,KAAK,EAAE,CAAC,GACP,SAAS,GAAG,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAEtC;AAGD,OAAO,EACL,wBAAwB,IAAI,uBAAuB,EACnD,oBAAoB,IAAI,mBAAmB,GAC5C,CAAA"}
@@ -1,12 +1,44 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ensureValidAtIdentifier = ensureValidAtIdentifier;
4
- exports.isValidAtIdentifier = isValidAtIdentifier;
3
+ exports.isHandleIdentifier = isHandleIdentifier;
4
+ exports.isDidIdentifier = isDidIdentifier;
5
+ exports.assertAtIdentifierString = assertAtIdentifierString;
6
+ exports.ensureValidAtIdentifier = assertAtIdentifierString;
7
+ exports.asAtIdentifierString = asAtIdentifierString;
8
+ exports.isAtIdentifierString = isAtIdentifierString;
9
+ exports.isValidAtIdentifier = isAtIdentifierString;
10
+ exports.ifAtIdentifierString = ifAtIdentifierString;
5
11
  const did_js_1 = require("./did.js");
6
12
  const handle_js_1 = require("./handle.js");
7
- function ensureValidAtIdentifier(input) {
13
+ /**
14
+ * Discriminates {@link HandleString} from a valid {@link AtIdentifierString}.
15
+ *
16
+ * @return `true` if the identifier is a handle, `false` otherwise
17
+ */
18
+ function isHandleIdentifier(id) {
19
+ return !isDidIdentifier(id);
20
+ }
21
+ /**
22
+ * Discriminates {@link DidString} from a valid {@link AtIdentifierString}.
23
+ *
24
+ * @return `true` if the identifier is a DID, `false` otherwise
25
+ */
26
+ function isDidIdentifier(id) {
27
+ return id.startsWith('did:');
28
+ }
29
+ /**
30
+ * Validates that a string is a valid {@link AtIdentifierString} format string,
31
+ * throwing an error if it is not.
32
+ *
33
+ * @throws InvalidHandleError if the input string does not meet the atproto 'datetime' format requirements.
34
+ * @see {@link AtIdentifierString}
35
+ */
36
+ function assertAtIdentifierString(input) {
8
37
  try {
9
- if (input.startsWith('did:')) {
38
+ if (!input || typeof input !== 'string') {
39
+ throw new TypeError('Identifier must be a non-empty string');
40
+ }
41
+ else if (input.startsWith('did:')) {
10
42
  (0, did_js_1.ensureValidDidRegex)(input);
11
43
  }
12
44
  else {
@@ -17,12 +49,42 @@ function ensureValidAtIdentifier(input) {
17
49
  throw new handle_js_1.InvalidHandleError('Invalid DID or handle', { cause });
18
50
  }
19
51
  }
20
- function isValidAtIdentifier(input) {
21
- if (input.startsWith('did:')) {
52
+ /**
53
+ * Casts a string to a {@link AtIdentifierString} if it is a valid at-identifier
54
+ * string, throwing an error if it is not.
55
+ *
56
+ * @throws InvalidHandleError if the input string does not meet the atproto 'at-identifier' format requirements.
57
+ * @see {@link AtIdentifierString}
58
+ */
59
+ function asAtIdentifierString(input) {
60
+ assertAtIdentifierString(input);
61
+ return input;
62
+ }
63
+ /**
64
+ * Type guard that checks if a value is a valid AT identifier (DID or handle).
65
+ *
66
+ * @param value - The value to check
67
+ * @returns `true` if the value is a valid AT identifier
68
+ * @see {@link AtIdentifierString}
69
+ */
70
+ function isAtIdentifierString(input) {
71
+ if (!input || typeof input !== 'string') {
72
+ return false;
73
+ }
74
+ else if (input.startsWith('did:')) {
22
75
  return (0, did_js_1.isValidDid)(input);
23
76
  }
24
77
  else {
25
78
  return (0, handle_js_1.isValidHandle)(input);
26
79
  }
27
80
  }
81
+ /**
82
+ * Returns the input if it is a valid {@link AtIdentifierString} format string, or
83
+ * `undefined` if it is not.
84
+ *
85
+ * @see {@link AtIdentifierString}
86
+ */
87
+ function ifAtIdentifierString(input) {
88
+ return isAtIdentifierString(input) ? input : undefined;
89
+ }
28
90
  //# sourceMappingURL=at-identifier.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"at-identifier.js","sourceRoot":"","sources":["../src/at-identifier.ts"],"names":[],"mappings":";;AAUA,0DAYC;AAED,kDAQC;AAhCD,qCAAqE;AACrE,2CAKoB;AAIpB,SAAgB,uBAAuB,CACrC,KAAa;IAEb,IAAI,CAAC;QACH,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,IAAA,4BAAmB,EAAC,KAAK,CAAC,CAAA;QAC5B,CAAC;aAAM,CAAC;YACN,IAAA,kCAAsB,EAAC,KAAK,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,8BAAkB,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IAClE,CAAC;AACH,CAAC;AAED,SAAgB,mBAAmB,CACjC,KAAQ;IAER,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAA,mBAAU,EAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;SAAM,CAAC;QACN,OAAO,IAAA,yBAAa,EAAC,KAAK,CAAC,CAAA;IAC7B,CAAC;AACH,CAAC","sourcesContent":["import { DidString, ensureValidDidRegex, isValidDid } from './did.js'\nimport {\n HandleString,\n InvalidHandleError,\n ensureValidHandleRegex,\n isValidHandle,\n} from './handle.js'\n\nexport type AtIdentifierString = DidString | HandleString\n\nexport function ensureValidAtIdentifier(\n input: string,\n): asserts input is AtIdentifierString {\n try {\n if (input.startsWith('did:')) {\n ensureValidDidRegex(input)\n } else {\n ensureValidHandleRegex(input)\n }\n } catch (cause) {\n throw new InvalidHandleError('Invalid DID or handle', { cause })\n }\n}\n\nexport function isValidAtIdentifier<I extends string>(\n input: I,\n): input is I & AtIdentifierString {\n if (input.startsWith('did:')) {\n return isValidDid(input)\n } else {\n return isValidHandle(input)\n }\n}\n"]}
1
+ {"version":3,"file":"at-identifier.js","sourceRoot":"","sources":["../src/at-identifier.ts"],"names":[],"mappings":";;AAoBA,gDAEC;AAOD,0CAEC;AASD,4DAcC;AA+C6B,2DAAuB;AAtCrD,oDAGC;AASD,oDAUC;AAiByB,mDAAmB;AAT7C,oDAIC;AAjGD,qCAAqE;AACrE,2CAKoB;AASpB;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,EAAsB;IACvD,OAAO,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;AAC7B,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAAC,EAAsB;IACpD,OAAO,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;AAC9B,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,wBAAwB,CACtC,KAAQ;IAER,IAAI,CAAC;QACH,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAA;QAC9D,CAAC;aAAM,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,IAAA,4BAAmB,EAAC,KAAK,CAAC,CAAA;QAC5B,CAAC;aAAM,CAAC;YACN,IAAA,kCAAsB,EAAC,KAAK,CAAC,CAAA;QAC/B,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,8BAAkB,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAA;IAClE,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAI,KAAQ;IAC9C,wBAAwB,CAAC,KAAK,CAAC,CAAA;IAC/B,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAClC,KAAQ;IAER,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,KAAK,CAAA;IACd,CAAC;SAAM,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACpC,OAAO,IAAA,mBAAU,EAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;SAAM,CAAC;QACN,OAAO,IAAA,yBAAa,EAAC,KAAK,CAAC,CAAA;IAC7B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,oBAAoB,CAClC,KAAQ;IAER,OAAO,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AACxD,CAAC","sourcesContent":["import { DidString, ensureValidDidRegex, isValidDid } from './did.js'\nimport {\n HandleString,\n InvalidHandleError,\n ensureValidHandleRegex,\n isValidHandle,\n} from './handle.js'\n\n/**\n * An \"at-identifier\" string - either a {@link DidString} or a {@link HandleString}\n *\n * @example `\"did:plc:1234...\"`, `\"did:web:example.com\"` or `\"alice.bsky.social\"`\n */\nexport type AtIdentifierString = DidString | HandleString\n\n/**\n * Discriminates {@link HandleString} from a valid {@link AtIdentifierString}.\n *\n * @return `true` if the identifier is a handle, `false` otherwise\n */\nexport function isHandleIdentifier(id: AtIdentifierString): id is HandleString {\n return !isDidIdentifier(id)\n}\n\n/**\n * Discriminates {@link DidString} from a valid {@link AtIdentifierString}.\n *\n * @return `true` if the identifier is a DID, `false` otherwise\n */\nexport function isDidIdentifier(id: AtIdentifierString): id is DidString {\n return id.startsWith('did:')\n}\n\n/**\n * Validates that a string is a valid {@link AtIdentifierString} format string,\n * throwing an error if it is not.\n *\n * @throws InvalidHandleError if the input string does not meet the atproto 'datetime' format requirements.\n * @see {@link AtIdentifierString}\n */\nexport function assertAtIdentifierString<I>(\n input: I,\n): asserts input is I & AtIdentifierString {\n try {\n if (!input || typeof input !== 'string') {\n throw new TypeError('Identifier must be a non-empty string')\n } else if (input.startsWith('did:')) {\n ensureValidDidRegex(input)\n } else {\n ensureValidHandleRegex(input)\n }\n } catch (cause) {\n throw new InvalidHandleError('Invalid DID or handle', { cause })\n }\n}\n\n/**\n * Casts a string to a {@link AtIdentifierString} if it is a valid at-identifier\n * string, throwing an error if it is not.\n *\n * @throws InvalidHandleError if the input string does not meet the atproto 'at-identifier' format requirements.\n * @see {@link AtIdentifierString}\n */\nexport function asAtIdentifierString<I>(input: I): I & AtIdentifierString {\n assertAtIdentifierString(input)\n return input\n}\n\n/**\n * Type guard that checks if a value is a valid AT identifier (DID or handle).\n *\n * @param value - The value to check\n * @returns `true` if the value is a valid AT identifier\n * @see {@link AtIdentifierString}\n */\nexport function isAtIdentifierString<I>(\n input: I,\n): input is I & AtIdentifierString {\n if (!input || typeof input !== 'string') {\n return false\n } else if (input.startsWith('did:')) {\n return isValidDid(input)\n } else {\n return isValidHandle(input)\n }\n}\n\n/**\n * Returns the input if it is a valid {@link AtIdentifierString} format string, or\n * `undefined` if it is not.\n *\n * @see {@link AtIdentifierString}\n */\nexport function ifAtIdentifierString<I>(\n input: I,\n): undefined | (I & AtIdentifierString) {\n return isAtIdentifierString(input) ? input : undefined\n}\n\n// Legacy exports (should we deprecate these ?)\nexport {\n assertAtIdentifierString as ensureValidAtIdentifier,\n isAtIdentifierString as isValidAtIdentifier,\n}\n"]}
package/dist/aturi.d.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { AtIdentifierString } from './at-identifier.js';
2
2
  import { AtUriString } from './aturi_validation.js';
3
+ import { DidString } from './did.js';
4
+ import { NsidString } from './nsid.js';
5
+ import { RecordKeyString } from './recordkey.js';
3
6
  export * from './aturi_validation.js';
7
+ export type { AtIdentifierString, AtUriString, DidString, NsidString, RecordKeyString, };
4
8
  export declare const ATP_URI_REGEX: RegExp;
5
9
  export declare class AtUri {
6
10
  hash: string;
@@ -11,14 +15,19 @@ export declare class AtUri {
11
15
  static make(handleOrDid: string, collection?: string, rkey?: string): AtUri;
12
16
  get protocol(): string;
13
17
  get origin(): `at://did:${string}:${string}` | `at://${string}.${string}`;
14
- get hostname(): string;
18
+ get did(): DidString;
19
+ get hostname(): AtIdentifierString;
15
20
  set hostname(v: string);
16
21
  get search(): string;
17
22
  set search(v: string);
18
23
  get collection(): string;
24
+ get collectionSafe(): NsidString;
19
25
  set collection(v: string);
26
+ unsafelySetCollection(v: string): void;
20
27
  get rkey(): string;
28
+ get rkeySafe(): RecordKeyString;
21
29
  set rkey(v: string);
30
+ unsafelySetRkey(v: string): void;
22
31
  get href(): AtUriString;
23
32
  toString(): AtUriString;
24
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"aturi.d.ts","sourceRoot":"","sources":["../src/aturi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAA2B,MAAM,oBAAoB,CAAA;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAGnD,cAAc,uBAAuB,CAAA;AAErC,eAAO,MAAM,aAAa,QAEyE,CAAA;AAInG,qBAAa,KAAK;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,kBAAkB,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,eAAe,CAAA;gBAEjB,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK;IAgB9C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAOnE,IAAI,QAAQ,WAEX;IAED,IAAI,MAAM,gEAET;IAED,IAAI,QAAQ,IAII,MAAM,CAFrB;IAED,IAAI,QAAQ,CAAC,CAAC,EAAE,MAAM,EAGrB;IAED,IAAI,MAAM,IAII,MAAM,CAFnB;IAED,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,EAEnB;IAED,IAAI,UAAU,IAII,MAAM,CAFvB;IAED,IAAI,UAAU,CAAC,CAAC,EAAE,MAAM,EAKvB;IAED,IAAI,IAAI,IAII,MAAM,CAFjB;IAED,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,EAKjB;IAED,IAAI,IAAI,gBAEP;IAED,QAAQ,IAAI,WAAW;CAexB"}
1
+ {"version":3,"file":"aturi.d.ts","sourceRoot":"","sources":["../src/aturi.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAGnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAmB,MAAM,UAAU,CAAA;AACrD,OAAO,EAAE,UAAU,EAAmB,MAAM,WAAW,CAAA;AACvD,OAAO,EAAE,eAAe,EAAwB,MAAM,gBAAgB,CAAA;AAEtE,cAAc,uBAAuB,CAAA;AAGrC,YAAY,EACV,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,UAAU,EACV,eAAe,GAChB,CAAA;AAED,eAAO,MAAM,aAAa,QAEyE,CAAA;AAInG,qBAAa,KAAK;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,kBAAkB,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,eAAe,CAAA;gBAEjB,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,KAAK;IAgB9C,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;IAOnE,IAAI,QAAQ,WAEX;IAED,IAAI,MAAM,gEAET;IAED,IAAI,GAAG,IAAI,SAAS,CAInB;IAED,IAAI,QAAQ,IAAI,kBAAkB,CAEjC;IAED,IAAI,QAAQ,CAAC,CAAC,EAAE,MAAM,EAGrB;IAED,IAAI,MAAM,IAII,MAAM,CAFnB;IAED,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,EAEnB;IAED,IAAI,UAAU,IAUI,MAAM,CARvB;IAED,IAAI,cAAc,IAAI,UAAU,CAI/B;IAED,IAAI,UAAU,CAAC,CAAC,EAAE,MAAM,EAGvB;IAED,qBAAqB,CAAC,CAAC,EAAE,MAAM;IAM/B,IAAI,IAAI,IAUI,MAAM,CARjB;IAED,IAAI,QAAQ,IAAI,eAAe,CAI9B;IAED,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,EAGjB;IAED,eAAe,CAAC,CAAC,EAAE,MAAM;IAOzB,IAAI,IAAI,gBAEP;IAED,QAAQ,IAAI,WAAW;CAexB"}
package/dist/aturi.js CHANGED
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AtUri = exports.ATP_URI_REGEX = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const at_identifier_js_1 = require("./at-identifier.js");
6
+ const did_js_1 = require("./did.js");
6
7
  const nsid_js_1 = require("./nsid.js");
8
+ const recordkey_js_1 = require("./recordkey.js");
7
9
  tslib_1.__exportStar(require("./aturi_validation.js"), exports);
8
10
  exports.ATP_URI_REGEX =
9
11
  // proto- --did-------------- --name---------------- --path---- --query-- --hash--
@@ -41,6 +43,12 @@ class AtUri {
41
43
  get origin() {
42
44
  return `at://${this.host}`;
43
45
  }
46
+ get did() {
47
+ const { host } = this;
48
+ if ((0, at_identifier_js_1.isDidIdentifier)(host))
49
+ return host;
50
+ throw new did_js_1.InvalidDidError(`AtUri "${this}" does not have a DID hostname`);
51
+ }
44
52
  get hostname() {
45
53
  return this.host;
46
54
  }
@@ -57,8 +65,16 @@ class AtUri {
57
65
  get collection() {
58
66
  return this.pathname.split('/').filter(Boolean)[0] || '';
59
67
  }
68
+ get collectionSafe() {
69
+ const { collection } = this;
70
+ (0, nsid_js_1.ensureValidNsid)(collection);
71
+ return collection;
72
+ }
60
73
  set collection(v) {
61
74
  (0, nsid_js_1.ensureValidNsid)(v);
75
+ this.unsafelySetCollection(v);
76
+ }
77
+ unsafelySetCollection(v) {
62
78
  const parts = this.pathname.split('/').filter(Boolean);
63
79
  parts[0] = v;
64
80
  this.pathname = parts.join('/');
@@ -66,7 +82,16 @@ class AtUri {
66
82
  get rkey() {
67
83
  return this.pathname.split('/').filter(Boolean)[1] || '';
68
84
  }
85
+ get rkeySafe() {
86
+ const { rkey } = this;
87
+ (0, recordkey_js_1.ensureValidRecordKey)(rkey);
88
+ return rkey;
89
+ }
69
90
  set rkey(v) {
91
+ (0, recordkey_js_1.ensureValidRecordKey)(v);
92
+ this.unsafelySetRkey(v);
93
+ }
94
+ unsafelySetRkey(v) {
70
95
  const parts = this.pathname.split('/').filter(Boolean);
71
96
  parts[0] ||= 'undefined';
72
97
  parts[1] = v;
package/dist/aturi.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"aturi.js","sourceRoot":"","sources":["../src/aturi.ts"],"names":[],"mappings":"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","sourcesContent":["import { AtIdentifierString, ensureValidAtIdentifier } from './at-identifier.js'\nimport { AtUriString } from './aturi_validation.js'\nimport { ensureValidNsid } from './nsid.js'\n\nexport * from './aturi_validation.js'\n\nexport const ATP_URI_REGEX =\n // proto- --did-------------- --name---------------- --path---- --query-- --hash--\n /^(at:\\/\\/)?((?:did:[a-z0-9:%-]+)|(?:[a-z0-9][a-z0-9.:-]*))(\\/[^?#\\s]*)?(\\?[^#\\s]+)?(#[^\\s]+)?$/i\n// --path----- --query-- --hash--\nconst RELATIVE_REGEX = /^(\\/[^?#\\s]*)?(\\?[^#\\s]+)?(#[^\\s]+)?$/i\n\nexport class AtUri {\n hash: string\n host: AtIdentifierString\n pathname: string\n searchParams: URLSearchParams\n\n constructor(uri: string, base?: string | AtUri) {\n const parsed =\n base !== undefined\n ? typeof base === 'string'\n ? Object.assign(parse(base), parseRelative(uri))\n : Object.assign({ host: base.host }, parseRelative(uri))\n : parse(uri)\n\n ensureValidAtIdentifier(parsed.host)\n\n this.hash = parsed.hash ?? ''\n this.host = parsed.host\n this.pathname = parsed.pathname ?? ''\n this.searchParams = parsed.searchParams\n }\n\n static make(handleOrDid: string, collection?: string, rkey?: string) {\n let str = handleOrDid\n if (collection) str += '/' + collection\n if (rkey) str += '/' + rkey\n return new AtUri(str)\n }\n\n get protocol() {\n return 'at:'\n }\n\n get origin() {\n return `at://${this.host}` as const\n }\n\n get hostname() {\n return this.host\n }\n\n set hostname(v: string) {\n ensureValidAtIdentifier(v)\n this.host = v\n }\n\n get search() {\n return this.searchParams.toString()\n }\n\n set search(v: string) {\n this.searchParams = new URLSearchParams(v)\n }\n\n get collection() {\n return this.pathname.split('/').filter(Boolean)[0] || ''\n }\n\n set collection(v: string) {\n ensureValidNsid(v)\n const parts = this.pathname.split('/').filter(Boolean)\n parts[0] = v\n this.pathname = parts.join('/')\n }\n\n get rkey() {\n return this.pathname.split('/').filter(Boolean)[1] || ''\n }\n\n set rkey(v: string) {\n const parts = this.pathname.split('/').filter(Boolean)\n parts[0] ||= 'undefined'\n parts[1] = v\n this.pathname = parts.join('/')\n }\n\n get href() {\n return this.toString()\n }\n\n toString(): AtUriString {\n let path = this.pathname || '/'\n if (!path.startsWith('/')) {\n path = `/${path}`\n }\n let qs = ''\n if (this.searchParams.size) {\n qs = `?${this.searchParams.toString()}`\n }\n let hash = this.hash\n if (hash && !hash.startsWith('#')) {\n hash = `#${hash}`\n }\n return `at://${this.host}${path}${qs}${hash}` as AtUriString\n }\n}\n\nfunction parse(str: string) {\n const match = str.match(ATP_URI_REGEX) as null | {\n 0: string\n 1: string | undefined // proto\n 2: string // host\n 3: string | undefined // path\n 4: string | undefined // query\n 5: string | undefined // hash\n }\n\n if (!match) {\n throw new Error(`Invalid AT uri: ${str}`)\n }\n\n return {\n host: match[2],\n hash: match[5],\n pathname: match[3],\n searchParams: new URLSearchParams(match[4]),\n }\n}\n\nfunction parseRelative(str: string) {\n const match = str.match(RELATIVE_REGEX) as null | {\n 0: string\n 1: string | undefined // path\n 2: string | undefined // query\n 3: string | undefined // hash\n }\n\n if (!match) {\n throw new Error(`Invalid path: ${str}`)\n }\n\n return {\n hash: match[3],\n pathname: match[1],\n searchParams: new URLSearchParams(match[2]),\n }\n}\n"]}
1
+ {"version":3,"file":"aturi.js","sourceRoot":"","sources":["../src/aturi.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AtIdentifierString,\n ensureValidAtIdentifier,\n isDidIdentifier,\n} from './at-identifier.js'\nimport { AtUriString } from './aturi_validation.js'\nimport { DidString, InvalidDidError } from './did.js'\nimport { NsidString, ensureValidNsid } from './nsid.js'\nimport { RecordKeyString, ensureValidRecordKey } from './recordkey.js'\n\nexport * from './aturi_validation.js'\n\n// Re-export types used in public interface\nexport type {\n AtIdentifierString,\n AtUriString,\n DidString,\n NsidString,\n RecordKeyString,\n}\n\nexport const ATP_URI_REGEX =\n // proto- --did-------------- --name---------------- --path---- --query-- --hash--\n /^(at:\\/\\/)?((?:did:[a-z0-9:%-]+)|(?:[a-z0-9][a-z0-9.:-]*))(\\/[^?#\\s]*)?(\\?[^#\\s]+)?(#[^\\s]+)?$/i\n// --path----- --query-- --hash--\nconst RELATIVE_REGEX = /^(\\/[^?#\\s]*)?(\\?[^#\\s]+)?(#[^\\s]+)?$/i\n\nexport class AtUri {\n hash: string\n host: AtIdentifierString\n pathname: string\n searchParams: URLSearchParams\n\n constructor(uri: string, base?: string | AtUri) {\n const parsed =\n base !== undefined\n ? typeof base === 'string'\n ? Object.assign(parse(base), parseRelative(uri))\n : Object.assign({ host: base.host }, parseRelative(uri))\n : parse(uri)\n\n ensureValidAtIdentifier(parsed.host)\n\n this.hash = parsed.hash ?? ''\n this.host = parsed.host\n this.pathname = parsed.pathname ?? ''\n this.searchParams = parsed.searchParams\n }\n\n static make(handleOrDid: string, collection?: string, rkey?: string) {\n let str = handleOrDid\n if (collection) str += '/' + collection\n if (rkey) str += '/' + rkey\n return new AtUri(str)\n }\n\n get protocol() {\n return 'at:'\n }\n\n get origin() {\n return `at://${this.host}` as const\n }\n\n get did(): DidString {\n const { host } = this\n if (isDidIdentifier(host)) return host\n throw new InvalidDidError(`AtUri \"${this}\" does not have a DID hostname`)\n }\n\n get hostname(): AtIdentifierString {\n return this.host\n }\n\n set hostname(v: string) {\n ensureValidAtIdentifier(v)\n this.host = v\n }\n\n get search() {\n return this.searchParams.toString()\n }\n\n set search(v: string) {\n this.searchParams = new URLSearchParams(v)\n }\n\n get collection() {\n return this.pathname.split('/').filter(Boolean)[0] || ''\n }\n\n get collectionSafe(): NsidString {\n const { collection } = this\n ensureValidNsid(collection)\n return collection\n }\n\n set collection(v: string) {\n ensureValidNsid(v)\n this.unsafelySetCollection(v)\n }\n\n unsafelySetCollection(v: string) {\n const parts = this.pathname.split('/').filter(Boolean)\n parts[0] = v\n this.pathname = parts.join('/')\n }\n\n get rkey() {\n return this.pathname.split('/').filter(Boolean)[1] || ''\n }\n\n get rkeySafe(): RecordKeyString {\n const { rkey } = this\n ensureValidRecordKey(rkey)\n return rkey\n }\n\n set rkey(v: string) {\n ensureValidRecordKey(v)\n this.unsafelySetRkey(v)\n }\n\n unsafelySetRkey(v: string) {\n const parts = this.pathname.split('/').filter(Boolean)\n parts[0] ||= 'undefined'\n parts[1] = v\n this.pathname = parts.join('/')\n }\n\n get href() {\n return this.toString()\n }\n\n toString(): AtUriString {\n let path = this.pathname || '/'\n if (!path.startsWith('/')) {\n path = `/${path}`\n }\n let qs = ''\n if (this.searchParams.size) {\n qs = `?${this.searchParams.toString()}`\n }\n let hash = this.hash\n if (hash && !hash.startsWith('#')) {\n hash = `#${hash}`\n }\n return `at://${this.host}${path}${qs}${hash}` as AtUriString\n }\n}\n\nfunction parse(str: string) {\n const match = str.match(ATP_URI_REGEX) as null | {\n 0: string\n 1: string | undefined // proto\n 2: string // host\n 3: string | undefined // path\n 4: string | undefined // query\n 5: string | undefined // hash\n }\n\n if (!match) {\n throw new Error(`Invalid AT uri: ${str}`)\n }\n\n return {\n host: match[2],\n hash: match[5],\n pathname: match[3],\n searchParams: new URLSearchParams(match[4]),\n }\n}\n\nfunction parseRelative(str: string) {\n const match = str.match(RELATIVE_REGEX) as null | {\n 0: string\n 1: string | undefined // path\n 2: string | undefined // query\n 3: string | undefined // hash\n }\n\n if (!match) {\n throw new Error(`Invalid path: ${str}`)\n }\n\n return {\n hash: match[3],\n pathname: match[1],\n searchParams: new URLSearchParams(match[2]),\n }\n}\n"]}
@@ -1,14 +1,131 @@
1
- /** An ISO 8601 formatted datetime string (YYYY-MM-DDTHH:mm:ss.sssZ) */
2
- export type DatetimeString = `${string}-${string}-${string}T${string}:${string}:${string}${'Z' | `+${string}` | `-${string}`}`;
3
- declare global {
4
- interface Date {
5
- toISOString(): `${string}-${string}-${string}T${string}:${string}:${string}Z`;
6
- }
7
- }
8
- export declare function ensureValidDatetime<I extends string>(input: I): asserts input is I & DatetimeString;
9
- export declare function isValidDatetime<I extends string>(input: I): input is I & DatetimeString;
10
- export declare function normalizeDatetime(dtStr: string): DatetimeString;
11
- export declare const normalizeDatetimeAlways: (dtStr: string) => DatetimeString;
1
+ /**
2
+ * Indicates a date or string is not a valid representation of a datetime
3
+ * according to the atproto
4
+ * {@link https://atproto.com/specs/lexicon#datetime specification}.
5
+ */
12
6
  export declare class InvalidDatetimeError extends Error {
13
7
  }
8
+ /**
9
+ * A subset of {@link DatetimeString} that represent valid datetime strings with
10
+ * the format: `YYYY-MM-DDTHH:mm:ss.sssZ`, as returned by `Date.toISOString()
11
+ * for dates between the years 0000 and 9999.
12
+ *
13
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString}
14
+ */
15
+ export type ISODatetimeString = `${string}-${string}-${string}T${string}:${string}:${string}.${string}Z`;
16
+ /**
17
+ * Represents a {@link Date} that can be safely stringified into a valid atproto
18
+ * {@link DatetimeString} using the {@link Date.toISOString toISOString()}
19
+ * method.
20
+ */
21
+ export interface AtprotoDate extends Date {
22
+ toISOString(): ISODatetimeString;
23
+ }
24
+ /**
25
+ * @see {@link AtprotoDate}
26
+ */
27
+ export declare function assertAtprotoDate(date: Date): asserts date is AtprotoDate;
28
+ /**
29
+ * @see {@link AtprotoDate}
30
+ */
31
+ export declare function asAtprotoDate(date: Date): AtprotoDate;
32
+ /**
33
+ * @see {@link AtprotoDate}
34
+ */
35
+ export declare function isAtprotoDate(date: Date): date is AtprotoDate;
36
+ /**
37
+ * @see {@link AtprotoDate}
38
+ */
39
+ export declare function ifAtprotoDate(date: Date): AtprotoDate | undefined;
40
+ /**
41
+ * Datetime strings in atproto data structures and API calls should meet the
42
+ * {@link https://ijmacd.github.io/rfc3339-iso8601/ intersecting} requirements
43
+ * of the RFC 3339, ISO 8601, and WHATWG HTML datetime standards.
44
+ *
45
+ * @note This literal template type is not accurate enough to ensure that a
46
+ * string is a valid atproto datetime. The {@link DatetimeString} validation
47
+ * functions ({@link assertDatetimeString}, {@link isDatetimeString}, etc)
48
+ * should be used to validate that a string meets the atproto datetime
49
+ * requirements, and the {@link toDatetimeString} function should be used to
50
+ * convert a {@link Date} object into a valid {@link DatetimeString} string.
51
+ *
52
+ * @example "2024-01-15T12:30:00Z"
53
+ * @example "2024-01-15T12:30:00.000Z"
54
+ * @example "2024-01-15T12:30:00+00:00"
55
+ * @example "2024-01-15T11:30:00-01:00"
56
+ * @see {@link https://atproto.com/specs/lexicon#datetime atproto Lexicon datetime format}
57
+ * @see {@link https://www.rfc-editor.org/rfc/rfc3339 RFC 3339}
58
+ * @see {@link https://www.iso.org/iso-8601-date-and-time-format.html ISO 8601}
59
+ */
60
+ export type DatetimeString = `${string}-${string}-${string}T${string}:${string}:${string}Z` | `${string}-${string}-${string}T${string}:${string}:${string}${'+' | '-'}${string}:${string}`;
61
+ /**
62
+ * Validates that a string is a valid {@link DatetimeString} format string,
63
+ * throwing an error if it is not.
64
+ *
65
+ * @throws InvalidDatetimeError if the input string does not meet the atproto 'datetime' format requirements.
66
+ * @see {@link DatetimeString}
67
+ */
68
+ export declare function assertDatetimeString<I>(input: I): asserts input is I & DatetimeString;
69
+ /**
70
+ * Casts a string to a {@link DatetimeString} if it is a valid datetime format
71
+ * string, throwing an error if it is not.
72
+ *
73
+ * @throws InvalidDatetimeError if the input string does not meet the atproto 'datetime' format requirements.
74
+ * @see {@link DatetimeString}
75
+ */
76
+ export declare function asDatetimeString<I>(input: I): I & DatetimeString;
77
+ /**
78
+ * Checks if a string is a valid {@link DatetimeString} format string.
79
+ *
80
+ * @see {@link DatetimeString}
81
+ */
82
+ export declare function isDatetimeString<I>(input: I): input is I & DatetimeString;
83
+ /**
84
+ * Returns the input if it is a valid {@link DatetimeString} format string, or
85
+ * `undefined` if it is not.
86
+ *
87
+ * @see {@link DatetimeString}
88
+ */
89
+ export declare function ifDatetimeString<I>(input: I): undefined | (I & DatetimeString);
90
+ /**
91
+ * Returns the current date and time as a {@link DatetimeString}.
92
+ *
93
+ * @see {@link DatetimeString}
94
+ */
95
+ export declare function currentDatetimeString(): DatetimeString;
96
+ /**
97
+ * Converts any {@link Date} into a {@link DatetimeString} if possible, throwing
98
+ * an error if the date is not a valid atproto datetime.
99
+ *
100
+ * This is short-hand for `asAtprotoDate(date).toISOString()`.
101
+ *
102
+ * @throws InvalidDatetimeError if the input date is not a valid atproto datetime (eg, it is too far in the future or past, or it normalizes to a negative year).
103
+ * @see {@link DatetimeString}
104
+ */
105
+ export declare function toDatetimeString(date: Date): DatetimeString;
106
+ /**
107
+ * Takes a flexible datetime string and normalizes its representation.
108
+ *
109
+ * This function will work with any valid value that can be parsed as a date. It
110
+ * *additionally* is more flexible about accepting datetimes that are missing
111
+ * timezone information, and normalizing them to a valid atproto datetime.
112
+ *
113
+ * One use-case is a consistent, sortable string. Another is to work with older
114
+ * invalid createdAt datetimes.
115
+ *
116
+ * @returns ISODatetimeString - a valid atproto datetime with millisecond precision (3 sub-second digits) and UTC timezone with trailing 'Z' syntax.
117
+ * @throws InvalidDatetimeError - if the input string could not be parsed as a datetime, even with permissive parsing.
118
+ */
119
+ export declare function normalizeDatetime(dtStr: string): ISODatetimeString;
120
+ /**
121
+ * Variant of {@link normalizeDatetime} which always returns a valid datetime
122
+ * string.
123
+ *
124
+ * If a {@link InvalidDatetimeError} is encountered, returns the UNIX epoch time
125
+ * as a UTC datetime (`1970-01-01T00:00:00.000Z`).
126
+ *
127
+ * @see {@link normalizeDatetime}
128
+ */
129
+ export declare function normalizeDatetimeAlways(dtStr: string): ISODatetimeString;
130
+ export { assertDatetimeString as ensureValidDatetime, isDatetimeString as isValidDatetime, };
14
131
  //# sourceMappingURL=datetime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"datetime.d.ts","sourceRoot":"","sources":["../src/datetime.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,MAAM,cAAc,GACxB,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,GAAG,GAAG,GAAG,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,EAAE,CAAA;AAGnG,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,IAAI;QACZ,WAAW,IAAI,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,GAAG,CAAA;KAC9E;CACF;AAKD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAClD,KAAK,EAAE,CAAC,GACP,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,cAAc,CA4BrC;AAID,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAC9C,KAAK,EAAE,CAAC,GACP,KAAK,IAAI,CAAC,GAAG,cAAc,CAQ7B;AAYD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAkC/D;AAMD,eAAO,MAAM,uBAAuB,GAAI,OAAO,MAAM,KAAG,cASvD,CAAA;AAID,qBAAa,oBAAqB,SAAQ,KAAK;CAAG"}
1
+ {"version":3,"file":"datetime.d.ts","sourceRoot":"","sources":["../src/datetime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;CAAG;AAElD;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAE3B,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,GAAG,CAAA;AAE1E;;;;GAIG;AACH,MAAM,WAAW,WAAY,SAAQ,IAAI;IACvC,WAAW,IAAI,iBAAiB,CAAA;CACjC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,WAAW,CAKzE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,CAGrD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,IAAI,WAAW,CAE7D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,SAAS,CAEjE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,cAAc,GAEtB,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,GAAG,GAC9D,GAAG,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,IAAI,MAAM,EAAE,CAAA;AAEhG;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,KAAK,EAAE,CAAC,GACP,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,cAAc,CAKrC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,cAAc,CAGhE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,cAAc,CAEzE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,KAAK,EAAE,CAAC,GACP,SAAS,GAAG,CAAC,CAAC,GAAG,cAAc,CAAC,CAElC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,cAAc,CAEtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,cAAc,CAE3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAkBlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAMxE;AAGD,OAAO,EACL,oBAAoB,IAAI,mBAAmB,EAC3C,gBAAgB,IAAI,eAAe,GACpC,CAAA"}