@knpkv/atlassian-common 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +25 -10
  3. package/dist/Brand.d.ts +15 -15
  4. package/dist/Brand.d.ts.map +1 -1
  5. package/dist/Brand.js +5 -5
  6. package/dist/Brand.js.map +1 -1
  7. package/dist/Hash.d.ts +12 -14
  8. package/dist/Hash.d.ts.map +1 -1
  9. package/dist/Hash.js +18 -24
  10. package/dist/Hash.js.map +1 -1
  11. package/dist/ast/BlockNode.d.ts +120 -177
  12. package/dist/ast/BlockNode.d.ts.map +1 -1
  13. package/dist/ast/BlockNode.js +28 -8
  14. package/dist/ast/BlockNode.js.map +1 -1
  15. package/dist/ast/Document.d.ts +114 -156
  16. package/dist/ast/Document.d.ts.map +1 -1
  17. package/dist/ast/Document.js +1 -1
  18. package/dist/ast/Document.js.map +1 -1
  19. package/dist/ast/InlineNode.d.ts +59 -247
  20. package/dist/ast/InlineNode.d.ts.map +1 -1
  21. package/dist/ast/InlineNode.js +28 -3
  22. package/dist/ast/InlineNode.js.map +1 -1
  23. package/dist/ast/MacroNode.d.ts +62 -102
  24. package/dist/ast/MacroNode.d.ts.map +1 -1
  25. package/dist/ast/MacroNode.js +12 -5
  26. package/dist/ast/MacroNode.js.map +1 -1
  27. package/dist/auth/OAuthOperations.d.ts +1 -1
  28. package/dist/auth/OAuthOperations.d.ts.map +1 -1
  29. package/dist/auth/OAuthOperations.js +5 -6
  30. package/dist/auth/OAuthOperations.js.map +1 -1
  31. package/dist/auth/OAuthResponseSchemas.d.ts +13 -13
  32. package/dist/bin.d.ts +3 -0
  33. package/dist/bin.d.ts.map +1 -0
  34. package/dist/bin.js +58 -0
  35. package/dist/bin.js.map +1 -0
  36. package/dist/config/AuthProfiles.d.ts +342 -0
  37. package/dist/config/AuthProfiles.d.ts.map +1 -0
  38. package/dist/config/AuthProfiles.js +275 -0
  39. package/dist/config/AuthProfiles.js.map +1 -0
  40. package/dist/config/ConfigPaths.d.ts +12 -26
  41. package/dist/config/ConfigPaths.d.ts.map +1 -1
  42. package/dist/config/ConfigPaths.js +33 -3
  43. package/dist/config/ConfigPaths.js.map +1 -1
  44. package/dist/config/OAuthSchemas.d.ts +24 -24
  45. package/dist/config/ProfileManager.d.ts +92 -0
  46. package/dist/config/ProfileManager.d.ts.map +1 -0
  47. package/dist/config/ProfileManager.js +175 -0
  48. package/dist/config/ProfileManager.js.map +1 -0
  49. package/dist/config/TokenStorage.d.ts +5 -24
  50. package/dist/config/TokenStorage.d.ts.map +1 -1
  51. package/dist/config/TokenStorage.js +35 -22
  52. package/dist/config/TokenStorage.js.map +1 -1
  53. package/dist/config/index.d.ts +3 -1
  54. package/dist/config/index.d.ts.map +1 -1
  55. package/dist/config/index.js +5 -1
  56. package/dist/config/index.js.map +1 -1
  57. package/dist/index.d.ts +1 -1
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +1 -1
  60. package/dist/index.js.map +1 -1
  61. package/package.json +17 -11
  62. package/src/Brand.ts +5 -17
  63. package/src/Hash.ts +27 -27
  64. package/src/ast/BlockNode.ts +13 -13
  65. package/src/ast/Document.ts +1 -1
  66. package/src/ast/InlineNode.ts +5 -5
  67. package/src/ast/MacroNode.ts +7 -6
  68. package/src/auth/OAuthOperations.ts +5 -6
  69. package/src/bin.ts +115 -0
  70. package/src/config/AuthProfiles.ts +384 -0
  71. package/src/config/ConfigPaths.ts +21 -7
  72. package/src/config/ProfileManager.ts +268 -0
  73. package/src/config/TokenStorage.ts +23 -27
  74. package/src/config/index.ts +42 -0
  75. package/src/index.ts +1 -1
  76. package/test/AuthProfiles.test.ts +131 -0
  77. package/test/Hash.test.ts +52 -0
  78. package/test/OAuthOperations.test.ts +2 -3
  79. package/test/ProfileManager.test.ts +188 -0
  80. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @knpkv/atlassian-common
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#103](https://github.com/knpkv/npm/pull/103) [`477e4c6`](https://github.com/knpkv/npm/commit/477e4c60fa5c501883be6c03629da5a3cc91444c) Thanks [@konopkov](https://github.com/konopkov)! - Add shared Atlassian auth profile storage for multi-account and multi-site OAuth use.
8
+
9
+ Jira and Confluence now expose `auth profiles`, `auth use <profile>`, and `auth remove <profile>` commands backed by shared profile management in `@knpkv/atlassian-common`. Confluence also migrates existing legacy auth/config files on first use. Agent skills and docs now describe the profile commands and active-profile checks.
10
+
11
+ - [#105](https://github.com/knpkv/npm/pull/105) [`a3a4d3a`](https://github.com/knpkv/npm/commit/a3a4d3a14fafe235bc901ed5015bb9bd82c59281) Thanks [@konopkov](https://github.com/konopkov)! - Add a unified Atlassian profile manager CLI with cross-tool profile listing, selection, diagnostics, token refresh, and scope validation helpers.
12
+
13
+ Update bundled Jira, Confluence, and Jira Clockify agent skills to recommend the unified profile diagnostics workflow.
14
+
15
+ ## 0.3.0
16
+
17
+ ### Minor Changes
18
+
19
+ - [#71](https://github.com/knpkv/npm/pull/71) [`e3c3805`](https://github.com/knpkv/npm/commit/e3c3805ee527a6edb69ed91977c95c586b563ff9) Thanks [@konopkov](https://github.com/konopkov)! - Migrate the package workspace to Effect v4 beta.
20
+
21
+ This updates runtime and peer dependencies to the Effect v4 beta module layout,
22
+ adopts Effect platform/runtime services for Node process, HTTP, filesystem, and
23
+ clock access, and refreshes package export metadata to point published type
24
+ entries at emitted `dist/*.d.ts` declarations.
25
+
26
+ CodeCommit packages now use Effect v4-compatible AWS and cache layers, including
27
+ typed `distilled-aws` context services, shared cached-comment decoding, and
28
+ schema-derived config defaults. Jira and Confluence OAuth callback servers bind
29
+ the expected local callback port range again under the Effect v4 Node HTTP
30
+ server layer.
31
+
32
+ The retired Claude AI packages have been removed from the workspace.
33
+
3
34
  ## 0.2.0
4
35
 
5
36
  ### Minor Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @knpkv/atlassian-common
2
2
 
3
- Shared utilities for Atlassian tools: OAuth2 + PKCE auth, token storage, config paths, AST types, and markdown serialization.
3
+ Shared utilities for Atlassian tools: OAuth2 + PKCE auth, shared auth profiles, token storage, config paths, AST types, and markdown serialization.
4
4
 
5
5
  ## Installation
6
6
 
@@ -15,7 +15,7 @@ pnpm add @knpkv/atlassian-common
15
15
  | `@knpkv/atlassian-common` | Everything (AST, auth, config, serializers) |
16
16
  | `@knpkv/atlassian-common/ast` | Inline, block, macro, and document AST nodes |
17
17
  | `@knpkv/atlassian-common/auth` | OAuth2 endpoints, PKCE, token exchange |
18
- | `@knpkv/atlassian-common/config` | Config paths, schemas, token storage |
18
+ | `@knpkv/atlassian-common/config` | Config paths, schemas, token/profile storage |
19
19
  | `@knpkv/atlassian-common/serializers` | Markdown serializer for AST nodes |
20
20
 
21
21
  ## OAuth2 + PKCE
@@ -59,15 +59,17 @@ const program = Effect.gen(function* () {
59
59
  })
60
60
  ```
61
61
 
62
- ## Token Storage
62
+ ## Token And Profile Storage
63
63
 
64
- Stores OAuth config and tokens in `~/.config/atlassian/` with 0600 permissions.
64
+ Stores OAuth config, auth profiles, and the active token mirror in `~/.config/atlassian/<tool>/` with 0600 permissions.
65
65
 
66
66
  ```typescript
67
67
  import { Effect } from "effect"
68
68
  import {
69
- saveToken,
70
- loadToken,
69
+ saveProfileToken,
70
+ loadActiveProfileToken,
71
+ loadProfiles,
72
+ setActiveProfileBySelector,
71
73
  isTokenExpired,
72
74
  saveOAuthConfig,
73
75
  loadOAuthConfig,
@@ -75,15 +77,28 @@ import {
75
77
  } from "@knpkv/atlassian-common/config"
76
78
 
77
79
  const program = Effect.gen(function* () {
78
- yield* saveOAuthConfig({ clientId: "...", clientSecret: "..." }, "jira")
80
+ yield* saveOAuthConfig("jira", { clientId: "...", clientSecret: "..." })
79
81
  const config = yield* loadOAuthConfig("jira")
80
82
 
81
- yield* saveToken({ access_token: "...", refresh_token: "...", expires_in: 3600 }, "jira")
82
- const token = yield* loadToken("jira")
83
- const expired = isTokenExpired(token)
83
+ yield* saveProfileToken("jira", {
84
+ access_token: "...",
85
+ refresh_token: "...",
86
+ expires_at: Date.now() + 3600_000,
87
+ scope: "read:jira-work offline_access",
88
+ cloud_id: "...",
89
+ site_url: "https://example.atlassian.net"
90
+ })
91
+
92
+ const profiles = yield* loadProfiles("jira")
93
+ yield* setActiveProfileBySelector("jira", "https://example.atlassian.net")
94
+
95
+ const token = yield* loadActiveProfileToken("jira")
96
+ const expired = token ? isTokenExpired(token) : true
84
97
  }).pipe(Effect.provide(HomeDirectoryLive))
85
98
  ```
86
99
 
100
+ `profiles.json` is the multi-account/site source of truth. `auth.json` is still mirrored to the active profile so older single-profile consumers keep working.
101
+
87
102
  ## AST Types
88
103
 
89
104
  Typed Atlassian Document Format nodes — used by `@knpkv/jira-cli` and `@knpkv/confluence-to-markdown`.
package/dist/Brand.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * **Mental model**
5
5
  *
6
6
  * - **Brand = runtime validation + compile-time narrowing**: Each brand combines
7
- * an Effect `Brand.refined` (throws on invalid values) with an Effect `Schema`
7
+ * an Effect `Brand.make` (throws on invalid values) with an Effect `Schema`
8
8
  * (composable validation). The `Type` property exposes the branded type for use
9
9
  * in type annotations.
10
10
  * - **Pattern-guarded strings**: `SpaceKey`, `IssueKey`, `ProjectKey` are regex-branded;
@@ -41,8 +41,8 @@ import * as Schema from "effect/Schema";
41
41
  *
42
42
  * @category Brand
43
43
  */
44
- export declare const makeBrandedString: <B extends string>(name: B, pattern: RegExp) => Brand.Brand.Constructor<string & Brand.Brand<B>> & {
45
- schema: Schema.brand<Schema.filter<typeof Schema.String>, B>;
44
+ export declare const makeBrandedString: <B extends string>(name: B, pattern: RegExp) => Brand.Constructor<string & Brand.Brand<B>> & {
45
+ schema: Schema.brand<Schema.String, B>;
46
46
  Type: string & Brand.Brand<B>;
47
47
  };
48
48
  /**
@@ -61,8 +61,8 @@ export declare const makeBrandedString: <B extends string>(name: B, pattern: Reg
61
61
  *
62
62
  * @category Brand
63
63
  */
64
- export declare const makeBrandedNonEmptyString: <B extends string>(name: B) => Brand.Brand.Constructor<string & Brand.Brand<B>> & {
65
- schema: Schema.brand<Schema.filter<typeof Schema.String>, B>;
64
+ export declare const makeBrandedNonEmptyString: <B extends string>(name: B) => Brand.Constructor<string & Brand.Brand<B>> & {
65
+ schema: Schema.brand<Schema.NonEmptyString, B>;
66
66
  Type: string & Brand.Brand<B>;
67
67
  };
68
68
  /**
@@ -70,8 +70,8 @@ export declare const makeBrandedNonEmptyString: <B extends string>(name: B) => B
70
70
  *
71
71
  * @category Brand
72
72
  */
73
- export declare const PageId: Brand.Brand.Constructor<string & Brand.Brand<"PageId">> & {
74
- schema: Schema.brand<Schema.filter<typeof Schema.String>, "PageId">;
73
+ export declare const PageId: Brand.Constructor<string & Brand.Brand<"PageId">> & {
74
+ schema: Schema.brand<Schema.NonEmptyString, "PageId">;
75
75
  Type: string & Brand.Brand<"PageId">;
76
76
  };
77
77
  export type PageId = typeof PageId.Type;
@@ -80,8 +80,8 @@ export type PageId = typeof PageId.Type;
80
80
  *
81
81
  * @category Brand
82
82
  */
83
- export declare const SpaceKey: Brand.Brand.Constructor<string & Brand.Brand<"SpaceKey">> & {
84
- schema: Schema.brand<Schema.filter<typeof Schema.String>, "SpaceKey">;
83
+ export declare const SpaceKey: Brand.Constructor<string & Brand.Brand<"SpaceKey">> & {
84
+ schema: Schema.brand<Schema.String, "SpaceKey">;
85
85
  Type: string & Brand.Brand<"SpaceKey">;
86
86
  };
87
87
  export type SpaceKey = typeof SpaceKey.Type;
@@ -90,8 +90,8 @@ export type SpaceKey = typeof SpaceKey.Type;
90
90
  *
91
91
  * @category Brand
92
92
  */
93
- export declare const IssueKey: Brand.Brand.Constructor<string & Brand.Brand<"IssueKey">> & {
94
- schema: Schema.brand<Schema.filter<typeof Schema.String>, "IssueKey">;
93
+ export declare const IssueKey: Brand.Constructor<string & Brand.Brand<"IssueKey">> & {
94
+ schema: Schema.brand<Schema.String, "IssueKey">;
95
95
  Type: string & Brand.Brand<"IssueKey">;
96
96
  };
97
97
  export type IssueKey = typeof IssueKey.Type;
@@ -100,8 +100,8 @@ export type IssueKey = typeof IssueKey.Type;
100
100
  *
101
101
  * @category Brand
102
102
  */
103
- export declare const ProjectKey: Brand.Brand.Constructor<string & Brand.Brand<"ProjectKey">> & {
104
- schema: Schema.brand<Schema.filter<typeof Schema.String>, "ProjectKey">;
103
+ export declare const ProjectKey: Brand.Constructor<string & Brand.Brand<"ProjectKey">> & {
104
+ schema: Schema.brand<Schema.String, "ProjectKey">;
105
105
  Type: string & Brand.Brand<"ProjectKey">;
106
106
  };
107
107
  export type ProjectKey = typeof ProjectKey.Type;
@@ -110,8 +110,8 @@ export type ProjectKey = typeof ProjectKey.Type;
110
110
  *
111
111
  * @category Brand
112
112
  */
113
- export declare const ContentHash: Brand.Brand.Constructor<string & Brand.Brand<"ContentHash">> & {
114
- schema: Schema.brand<Schema.filter<typeof Schema.String>, "ContentHash">;
113
+ export declare const ContentHash: Brand.Constructor<string & Brand.Brand<"ContentHash">> & {
114
+ schema: Schema.brand<Schema.String, "ContentHash">;
115
115
  Type: string & Brand.Brand<"ContentHash">;
116
116
  };
117
117
  export type ContentHash = typeof ContentHash.Type;
@@ -1 +1 @@
1
- {"version":3,"file":"Brand.d.ts","sourceRoot":"","sources":["../src/Brand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,EAChD,MAAM,CAAC,EACP,SAAS,MAAM;;;CAkBhB,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,MAAM,EAAE,MAAM,CAAC;;;CAiBlE,CAAA;AAID;;;;GAIG;AACH,eAAO,MAAM,MAAM;;;CAAsC,CAAA;AACzD,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AAEvC;;;;GAIG;AACH,eAAO,MAAM,QAAQ;;;CAAoD,CAAA;AACzE,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C;;;;GAIG;AACH,eAAO,MAAM,QAAQ;;;CAAwD,CAAA;AAC7E,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;CAAsD,CAAA;AAC7E,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAA;AAE/C;;;;GAIG;AACH,eAAO,MAAM,WAAW;;;CAAqD,CAAA;AAC7E,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA"}
1
+ {"version":3,"file":"Brand.d.ts","sourceRoot":"","sources":["../src/Brand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,EAChD,MAAM,CAAC,EACP,SAAS,MAAM;;;CAYhB,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,MAAM,EAAE,MAAM,CAAC;;;CAWlE,CAAA;AAID;;;;GAIG;AACH,eAAO,MAAM,MAAM;;;CAAsC,CAAA;AACzD,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AAEvC;;;;GAIG;AACH,eAAO,MAAM,QAAQ;;;CAAoD,CAAA;AACzE,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C;;;;GAIG;AACH,eAAO,MAAM,QAAQ;;;CAAwD,CAAA;AAC7E,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;CAAsD,CAAA;AAC7E,MAAM,MAAM,UAAU,GAAG,OAAO,UAAU,CAAC,IAAI,CAAA;AAE/C;;;;GAIG;AACH,eAAO,MAAM,WAAW;;;CAAqD,CAAA;AAC7E,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA"}
package/dist/Brand.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * **Mental model**
5
5
  *
6
6
  * - **Brand = runtime validation + compile-time narrowing**: Each brand combines
7
- * an Effect `Brand.refined` (throws on invalid values) with an Effect `Schema`
7
+ * an Effect `Brand.make` (throws on invalid values) with an Effect `Schema`
8
8
  * (composable validation). The `Type` property exposes the branded type for use
9
9
  * in type annotations.
10
10
  * - **Pattern-guarded strings**: `SpaceKey`, `IssueKey`, `ProjectKey` are regex-branded;
@@ -42,8 +42,8 @@ import * as Schema from "effect/Schema";
42
42
  * @category Brand
43
43
  */
44
44
  export const makeBrandedString = (name, pattern) => {
45
- const brand = Brand.refined((s) => pattern.test(s), (s) => Brand.error(`Invalid ${name}: ${s} does not match ${pattern}`));
46
- const schema = Schema.String.pipe(Schema.pattern(pattern), Schema.brand(name));
45
+ const brand = Brand.make((s) => pattern.test(s) || `Invalid ${name}: ${s} does not match ${pattern}`);
46
+ const schema = Schema.String.check(Schema.isPattern(pattern)).pipe(Schema.brand(name));
47
47
  return Object.assign(brand, {
48
48
  schema,
49
49
  Type: undefined
@@ -66,8 +66,8 @@ export const makeBrandedString = (name, pattern) => {
66
66
  * @category Brand
67
67
  */
68
68
  export const makeBrandedNonEmptyString = (name) => {
69
- const brand = Brand.refined((s) => s.length > 0, (_s) => Brand.error(`${name} cannot be empty`));
70
- const schema = Schema.String.pipe(Schema.nonEmptyString(), Schema.brand(name));
69
+ const brand = Brand.make((s) => s.length > 0 || `${name} cannot be empty`);
70
+ const schema = Schema.NonEmptyString.pipe(Schema.brand(name));
71
71
  return Object.assign(brand, {
72
72
  schema,
73
73
  Type: undefined
package/dist/Brand.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Brand.js","sourceRoot":"","sources":["../src/Brand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,IAAO,EACP,OAAe,EACf,EAAE;IAGF,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CACzB,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EACtB,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,mBAAmB,OAAO,EAAE,CAAC,CACtE,CAAA;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAC/B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EACvB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CACnB,CAAA;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC1B,MAAM;QACN,IAAI,EAAE,SAAmC;KAC1C,CAAC,CAAA;AACJ,CAAC,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAmB,IAAO,EAAE,EAAE;IAGrE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CACzB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EACnB,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,kBAAkB,CAAC,CAC/C,CAAA;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAC/B,MAAM,CAAC,cAAc,EAAE,EACvB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CACnB,CAAA;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC1B,MAAM;QACN,IAAI,EAAE,SAAmC;KAC1C,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,8CAA8C;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAA;AAGzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAA;AAGzE;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAA;AAG7E;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAA;AAG7E;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAA"}
1
+ {"version":3,"file":"Brand.js","sourceRoot":"","sources":["../src/Brand.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,IAAO,EACP,OAAe,EACf,EAAE;IAGF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAc,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,WAAW,IAAI,KAAK,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAA;IAElH,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IAEtF,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC1B,MAAM;QACN,IAAI,EAAE,SAAmC;KAC1C,CAAC,CAAA;AACJ,CAAC,CAAA;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAmB,IAAO,EAAE,EAAE;IAGrE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAc,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,IAAI,kBAAkB,CAAC,CAAA;IAEvF,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA;IAE7D,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE;QAC1B,MAAM;QACN,IAAI,EAAE,SAAmC;KAC1C,CAAC,CAAA;AACJ,CAAC,CAAA;AAED,8CAA8C;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,yBAAyB,CAAC,QAAQ,CAAC,CAAA;AAGzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAA;AAGzE;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAA;AAG7E;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAA;AAG7E;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAA"}
package/dist/Hash.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * SHA256 content hashing via Node.js crypto, returning branded {@link ContentHash} values.
2
+ * SHA256 content hashing via Effect's platform `Crypto` service, returning branded {@link ContentHash} values.
3
3
  *
4
4
  * **Mental model**
5
5
  *
6
- * - **Effect-wrapped crypto**: {@link hashContent} and {@link hashBuffer} return
7
- * `Effect<ContentHash>` so hashing composes into pipelines without try/catch.
8
- * - **Sync escape hatch**: {@link hashContentSync} for contexts where Effect isn't needed.
6
+ * - **Service-backed crypto**: {@link hashContent} and {@link hashBuffer} use
7
+ * the `Crypto` service from Effect context, so applications provide the
8
+ * platform implementation at the runtime edge.
9
9
  *
10
10
  * **Common tasks**
11
11
  *
@@ -15,39 +15,37 @@
15
15
  *
16
16
  * @module
17
17
  */
18
+ import * as Crypto from "effect/Crypto";
18
19
  import * as Effect from "effect/Effect";
20
+ import type * as PlatformError from "effect/PlatformError";
19
21
  import { ContentHash } from "./Brand.js";
20
22
  /**
21
23
  * Compute SHA256 hash of a string.
22
24
  *
23
25
  * @example
24
26
  * ```typescript
25
- * import { hashContent } from "@knpkv/atlassian-common"
27
+ * import * as Crypto from "effect/Crypto"
26
28
  * import * as Effect from "effect/Effect"
29
+ * import { hashContent } from "@knpkv/atlassian-common"
27
30
  *
28
- * const hash = Effect.runSync(hashContent("hello world"))
31
+ * declare const crypto: Crypto.Crypto
32
+ * const hash = Effect.runSync(hashContent("hello world").pipe(Effect.provideService(Crypto.Crypto, crypto)))
29
33
  * // => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
30
34
  * ```
31
35
  *
32
36
  * @category Hash
33
37
  */
34
- export declare const hashContent: (content: string) => Effect.Effect<ContentHash>;
38
+ export declare const hashContent: (content: string) => Effect.Effect<ContentHash, PlatformError.PlatformError, Crypto.Crypto>;
35
39
  /**
36
40
  * Compute SHA256 hash of a buffer.
37
41
  *
38
42
  * @category Hash
39
43
  */
40
- export declare const hashBuffer: (buffer: Buffer | Uint8Array) => Effect.Effect<ContentHash>;
44
+ export declare const hashBuffer: (buffer: Uint8Array) => Effect.Effect<ContentHash, PlatformError.PlatformError, Crypto.Crypto>;
41
45
  /**
42
46
  * Check if two hashes are equal.
43
47
  *
44
48
  * @category Hash
45
49
  */
46
50
  export declare const hashEquals: (a: ContentHash, b: ContentHash) => boolean;
47
- /**
48
- * Synchronous version of hashContent for simple use cases.
49
- *
50
- * @category Hash
51
- */
52
- export declare const hashContentSync: (content: string) => ContentHash;
53
51
  //# sourceMappingURL=Hash.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Hash.d.ts","sourceRoot":"","sources":["../src/Hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAInE,CAAA;AAEJ;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,GAAG,UAAU,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAI9E,CAAA;AAEJ;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,WAAW,EAAE,GAAG,WAAW,KAAG,OAAkB,CAAA;AAE9E;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,KAAG,WAGjD,CAAA"}
1
+ {"version":3,"file":"Hash.d.ts","sourceRoot":"","sources":["../src/Hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,KAAK,aAAa,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAaxC;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,WAAW,GAAI,SAAS,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CACxE,CAAA;AAE3C;;;;GAIG;AACH,eAAO,MAAM,UAAU,GACrB,QAAQ,UAAU,KACjB,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,aAAa,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAyB,CAAA;AAEjG;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,GAAG,WAAW,EAAE,GAAG,WAAW,KAAG,OAAkB,CAAA"}
package/dist/Hash.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * SHA256 content hashing via Node.js crypto, returning branded {@link ContentHash} values.
2
+ * SHA256 content hashing via Effect's platform `Crypto` service, returning branded {@link ContentHash} values.
3
3
  *
4
4
  * **Mental model**
5
5
  *
6
- * - **Effect-wrapped crypto**: {@link hashContent} and {@link hashBuffer} return
7
- * `Effect<ContentHash>` so hashing composes into pipelines without try/catch.
8
- * - **Sync escape hatch**: {@link hashContentSync} for contexts where Effect isn't needed.
6
+ * - **Service-backed crypto**: {@link hashContent} and {@link hashBuffer} use
7
+ * the `Crypto` service from Effect context, so applications provide the
8
+ * platform implementation at the runtime edge.
9
9
  *
10
10
  * **Common tasks**
11
11
  *
@@ -15,49 +15,43 @@
15
15
  *
16
16
  * @module
17
17
  */
18
+ import * as Crypto from "effect/Crypto";
18
19
  import * as Effect from "effect/Effect";
19
- import * as crypto from "node:crypto";
20
+ import * as Encoding from "effect/Encoding";
20
21
  import { ContentHash } from "./Brand.js";
22
+ const textEncoder = new TextEncoder();
23
+ const digestSha256 = (bytes) => Effect.gen(function* () {
24
+ const crypto = yield* Crypto.Crypto;
25
+ const digest = yield* crypto.digest("SHA-256", bytes);
26
+ return ContentHash(Encoding.encodeHex(digest));
27
+ });
21
28
  /**
22
29
  * Compute SHA256 hash of a string.
23
30
  *
24
31
  * @example
25
32
  * ```typescript
26
- * import { hashContent } from "@knpkv/atlassian-common"
33
+ * import * as Crypto from "effect/Crypto"
27
34
  * import * as Effect from "effect/Effect"
35
+ * import { hashContent } from "@knpkv/atlassian-common"
28
36
  *
29
- * const hash = Effect.runSync(hashContent("hello world"))
37
+ * declare const crypto: Crypto.Crypto
38
+ * const hash = Effect.runSync(hashContent("hello world").pipe(Effect.provideService(Crypto.Crypto, crypto)))
30
39
  * // => "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
31
40
  * ```
32
41
  *
33
42
  * @category Hash
34
43
  */
35
- export const hashContent = (content) => Effect.sync(() => {
36
- const hash = crypto.createHash("sha256").update(content, "utf8").digest("hex");
37
- return ContentHash(hash);
38
- });
44
+ export const hashContent = (content) => digestSha256(textEncoder.encode(content));
39
45
  /**
40
46
  * Compute SHA256 hash of a buffer.
41
47
  *
42
48
  * @category Hash
43
49
  */
44
- export const hashBuffer = (buffer) => Effect.sync(() => {
45
- const hash = crypto.createHash("sha256").update(buffer).digest("hex");
46
- return ContentHash(hash);
47
- });
50
+ export const hashBuffer = (buffer) => digestSha256(buffer);
48
51
  /**
49
52
  * Check if two hashes are equal.
50
53
  *
51
54
  * @category Hash
52
55
  */
53
56
  export const hashEquals = (a, b) => a === b;
54
- /**
55
- * Synchronous version of hashContent for simple use cases.
56
- *
57
- * @category Hash
58
- */
59
- export const hashContentSync = (content) => {
60
- const hash = crypto.createHash("sha256").update(content, "utf8").digest("hex");
61
- return ContentHash(hash);
62
- };
63
57
  //# sourceMappingURL=Hash.js.map
package/dist/Hash.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Hash.js","sourceRoot":"","sources":["../src/Hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAe,EAA8B,EAAE,CACzE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;IACf,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC9E,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC,CAAC,CAAA;AAEJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAA2B,EAA8B,EAAE,CACpF,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;IACf,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACrE,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC,CAAC,CAAA;AAEJ;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAc,EAAE,CAAc,EAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAA;AAE9E;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,OAAe,EAAe,EAAE;IAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC9E,OAAO,WAAW,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC,CAAA"}
1
+ {"version":3,"file":"Hash.js","sourceRoot":"","sources":["../src/Hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAA;AAErC,MAAM,YAAY,GAAG,CACnB,KAAiB,EACuD,EAAE,CAC1E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAA;IACnC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;IACrD,OAAO,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;AAChD,CAAC,CAAC,CAAA;AAEJ;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAe,EAA0E,EAAE,CACrH,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;AAE3C;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,MAAkB,EACsD,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;AAEjG;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAc,EAAE,CAAc,EAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAA"}