graze-client 0.8.1 → 0.9.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 (49) hide show
  1. package/build/dts/GrazeClient.d.ts +368 -242
  2. package/build/dts/GrazeClient.d.ts.map +1 -1
  3. package/build/dts/builder.d.ts +2 -2
  4. package/build/dts/builder.d.ts.map +1 -1
  5. package/build/dts/common.d.ts +2 -3
  6. package/build/dts/common.d.ts.map +1 -1
  7. package/build/dts/index.d.ts +12 -12
  8. package/build/dts/index.d.ts.map +1 -1
  9. package/build/dts/schema/Post.d.ts +52 -52
  10. package/build/dts/schema/Post.d.ts.map +1 -1
  11. package/build/dts/schema/StickyPosts.d.ts +55 -56
  12. package/build/dts/schema/StickyPosts.d.ts.map +1 -1
  13. package/build/dts/schema/UpdateAlgorithmPayload.d.ts +137 -137
  14. package/build/dts/schema/UpdateAlgorithmPayload.d.ts.map +1 -1
  15. package/build/dts/schema/index.d.ts.map +1 -1
  16. package/build/dts/schema/shared.d.ts +126 -126
  17. package/build/dts/schema/shared.d.ts.map +1 -1
  18. package/build/dts/stickyposts.d.ts +80 -78
  19. package/build/dts/stickyposts.d.ts.map +1 -1
  20. package/build/esm/GrazeClient.js +47 -31
  21. package/build/esm/GrazeClient.js.map +1 -1
  22. package/build/esm/builder.js +20 -20
  23. package/build/esm/builder.js.map +1 -1
  24. package/build/esm/common.js +4 -3
  25. package/build/esm/common.js.map +1 -1
  26. package/build/esm/index.js +11 -8
  27. package/build/esm/index.js.map +1 -1
  28. package/build/esm/schema/Post.js +9 -9
  29. package/build/esm/schema/Post.js.map +1 -1
  30. package/build/esm/schema/StickyPosts.js +8 -9
  31. package/build/esm/schema/StickyPosts.js.map +1 -1
  32. package/build/esm/schema/UpdateAlgorithmPayload.js +130 -53
  33. package/build/esm/schema/UpdateAlgorithmPayload.js.map +1 -1
  34. package/build/esm/schema/index.js.map +1 -1
  35. package/build/esm/schema/shared.js +14 -14
  36. package/build/esm/schema/shared.js.map +1 -1
  37. package/build/esm/stickyposts.js +28 -13
  38. package/build/esm/stickyposts.js.map +1 -1
  39. package/package.json +21 -23
  40. package/src/GrazeClient.ts +83 -76
  41. package/src/builder.ts +78 -74
  42. package/src/common.ts +5 -10
  43. package/src/index.ts +61 -52
  44. package/src/schema/Post.ts +16 -16
  45. package/src/schema/StickyPosts.ts +22 -26
  46. package/src/schema/UpdateAlgorithmPayload.ts +153 -145
  47. package/src/schema/index.ts +2 -2
  48. package/src/schema/shared.ts +32 -32
  49. package/src/stickyposts.ts +48 -27
@@ -1,90 +1,92 @@
1
- import {
2
- FetchHttpClient,
3
- HttpApi,
4
- HttpApiClient,
5
- HttpApiEndpoint,
6
- HttpApiGroup,
7
- HttpApiSchema,
8
- HttpClient,
9
- HttpClientRequest
10
- } from "@effect/platform"
11
- import { Config, Data, Effect, Redacted, Schema } from "effect"
1
+ import { Config, Context, Data, Effect, Layer, Redacted, Schema } from "effect";
12
2
  import {
13
3
  AlgoUpdateResponse,
14
4
  GetAlgoResponse,
15
5
  GetAlgorithmsResponse,
16
6
  HidePostBody,
17
- UnhidePostBody
18
- } from "./schema/shared.js"
7
+ UnhidePostBody,
8
+ } from "./schema/shared.js";
19
9
 
20
- import { FeedIdParam, UserIdParam } from "./common.js"
21
- import * as Form from "./schema/UpdateAlgorithmPayload.js"
22
- import { StickyPostsApiGroup } from "./stickyposts.js"
10
+ import { FeedIdParam, UserIdParam } from "./common.js";
11
+ import * as Form from "./schema/UpdateAlgorithmPayload.js";
12
+ import { StickyPostsApiGroup } from "./stickyposts.js";
13
+ import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
14
+ import * as HttpApi from "effect/unstable/httpapi/HttpApi";
15
+ import * as HttpApiClient from "effect/unstable/httpapi/HttpApiClient";
16
+ import * as HttpApiEndpoint from "effect/unstable/httpapi/HttpApiEndpoint";
17
+ import * as HttpApiGroup from "effect/unstable/httpapi/HttpApiGroup";
18
+ import * as HttpApiSchema from "effect/unstable/httpapi/HttpApiSchema";
19
+ import * as HttpClient from "effect/unstable/http/HttpClient";
20
+ import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
23
21
 
24
22
  function isStringOrBlob(val: unknown): val is string | Blob {
25
- return typeof val === "string" || val instanceof Blob
23
+ return typeof val === "string" || val instanceof Blob;
26
24
  }
27
25
 
28
26
  const encodeForm = (obj: Form.FullForm) =>
29
- Effect.gen(function*() {
30
- const encoded = yield* Schema.encode(Form.FullForm)(obj)
31
- const formData = new FormData()
27
+ Effect.gen(function* () {
28
+ const encoded = yield* Schema.encodeEffect(Form.FullForm)(obj);
29
+ const formData = new FormData();
32
30
  for (const key in encoded) {
33
31
  if (Object.prototype.hasOwnProperty.call(encoded, key)) {
34
- const val = encoded[key as keyof Form.FullForm]
32
+ const val = encoded[key as keyof Form.FullForm];
35
33
  if (isStringOrBlob(val)) {
36
- formData.append(key, val)
34
+ formData.append(key, val);
37
35
  }
38
36
  }
39
37
  }
40
- return formData
41
- })
38
+ return formData;
39
+ });
42
40
 
43
41
  const GrazeApiGroup = HttpApiGroup.make("graze", { topLevel: true })
44
42
  .add(
45
- HttpApiEndpoint.get("getFeeds")`/app/my_feeds`
46
- .addSuccess(GetAlgorithmsResponse)
47
- .setPayload(
48
- Schema.Struct({
49
- user_id: UserIdParam
50
- })
51
- )
43
+ HttpApiEndpoint.get("getFeeds", "/app/my_feeds", {
44
+ // v3 GET `setPayload` serialised to query params (GET has no body); v4
45
+ // expresses that as `query`.
46
+ query: Schema.Struct({
47
+ user_id: UserIdParam,
48
+ }),
49
+ success: GetAlgorithmsResponse,
50
+ }),
52
51
  )
53
52
  .add(
54
- HttpApiEndpoint.get("getFeed")`/app/my_feeds/${FeedIdParam}`.addSuccess(
55
- GetAlgoResponse
56
- )
53
+ HttpApiEndpoint.get("getFeed", "/app/my_feeds/:feedId", {
54
+ params: { feedId: FeedIdParam },
55
+ success: GetAlgoResponse,
56
+ }),
57
57
  )
58
58
  .add(
59
- HttpApiEndpoint.post("updateAlgorithm")`/app/edit_algo_image`
60
- .setPayload(HttpApiSchema.Multipart(Form.FullForm))
61
- .addSuccess(AlgoUpdateResponse)
59
+ HttpApiEndpoint.post("updateAlgorithm", "/app/edit_algo_image", {
60
+ payload: Form.FullForm.pipe(HttpApiSchema.asMultipart()),
61
+ success: AlgoUpdateResponse,
62
+ }),
62
63
  )
63
64
  .add(
64
- HttpApiEndpoint.get(
65
- "publishAlgorithm"
66
- )`/app/publish_algo/${FeedIdParam}`.addSuccess(Schema.Unknown)
65
+ HttpApiEndpoint.get("publishAlgorithm", "/app/publish_algo/:feedId", {
66
+ params: { feedId: FeedIdParam },
67
+ success: Schema.Unknown,
68
+ }),
67
69
  )
68
70
  .add(
69
- HttpApiEndpoint.post("hidePost")`/app/hide_post`
70
- .setPayload(HidePostBody)
71
- .addSuccess(Schema.Unknown)
71
+ HttpApiEndpoint.post("hidePost", "/app/hide_post", {
72
+ payload: HidePostBody,
73
+ success: Schema.Unknown,
74
+ }),
72
75
  )
73
76
  .add(
74
- HttpApiEndpoint.post("unhidePost")`/app/unhide_post`
75
- .setPayload(UnhidePostBody)
76
- .addSuccess(Schema.Unknown)
77
- )
77
+ HttpApiEndpoint.post("unhidePost", "/app/unhide_post", {
78
+ payload: UnhidePostBody,
79
+ success: Schema.Unknown,
80
+ }),
81
+ );
78
82
 
79
83
  class GrazeApiDef extends HttpApi.make("grazeApi")
80
84
  .add(GrazeApiGroup)
81
- .add(StickyPostsApiGroup)
82
- .addError(Schema.Unknown)
83
- {}
85
+ .add(StickyPostsApiGroup) {}
84
86
 
85
- const grazeLive = Effect.gen(function*() {
86
- const baseUrl = yield* Config.url("GRAZE_API_URL")
87
- const cookie = yield* Config.redacted("GRAZE_COOKIE")
87
+ const grazeLive = Effect.gen(function* () {
88
+ const baseUrl = yield* Config.url("GRAZE_API_URL");
89
+ const cookie = yield* Config.redacted("GRAZE_COOKIE");
88
90
 
89
91
  const client = yield* HttpApiClient.make(GrazeApiDef, {
90
92
  baseUrl: baseUrl.toString(),
@@ -93,38 +95,43 @@ const grazeLive = Effect.gen(function*() {
93
95
  HttpClient.filterStatusOk,
94
96
  HttpClient.mapRequest(
95
97
  HttpClientRequest.setHeaders({
96
- cookie: Redacted.value(cookie)
97
- })
98
- )
99
- )
100
- })
98
+ cookie: Redacted.value(cookie),
99
+ }),
100
+ ),
101
+ ),
102
+ });
101
103
 
102
104
  const updateAlgorithm = (data: Form.FullForm) =>
103
- Effect.gen(function*() {
104
- const formData = yield* encodeForm(data)
105
- return yield* client.updateAlgorithm({ payload: formData })
106
- })
105
+ Effect.gen(function* () {
106
+ const formData = yield* encodeForm(data);
107
+ return yield* client.updateAlgorithm({ payload: formData });
108
+ });
107
109
 
108
- const userId = yield* Config.integer("GRAZE_USER_ID")
109
- const getFeeds = () => client.getFeeds({ payload: { user_id: userId } })
110
+ const userId = yield* Config.int("GRAZE_USER_ID");
111
+ const getFeeds = () => client.getFeeds({ query: { user_id: userId } });
110
112
 
111
113
  return {
112
114
  ...client,
113
115
  updateAlgorithm,
114
- getFeeds
115
- }
116
- })
116
+ getFeeds,
117
+ };
118
+ });
117
119
 
118
- export class GrazeClient extends Effect.Service<GrazeClient>()("GrazeClient", {
119
- effect: grazeLive,
120
- dependencies: [FetchHttpClient.layer]
121
- }) {
122
- // TODO: test service
120
+ export class GrazeClient extends Context.Service<
121
+ GrazeClient,
122
+ Effect.Success<typeof grazeLive>
123
+ >()("GrazeClient") {
124
+ static readonly layer = Layer.effect(GrazeClient, grazeLive).pipe(
125
+ Layer.provide(FetchHttpClient.layer),
126
+ );
123
127
  }
124
128
 
129
+ /** The resolved service shape (v4 has no `.Service` namespace on the tag). */
130
+ export type GrazeClientService = Effect.Success<typeof grazeLive>;
131
+
125
132
  export class GrazeError extends Data.TaggedError("GrazeError")<{
126
- message: string
127
- status: number
128
- statusText: string
129
- json: unknown
133
+ message: string;
134
+ status: number;
135
+ statusText: string;
136
+ json: unknown;
130
137
  }> {}
package/src/builder.ts CHANGED
@@ -11,144 +11,148 @@ import type {
11
11
  RegexNegationMatches,
12
12
  SocialGraph,
13
13
  TextMatchesAny,
14
- TextMatchesNone
15
- } from "./schema/index.js"
14
+ TextMatchesNone,
15
+ } from "./schema/index.js";
16
16
 
17
17
  const neverMatch: Filter = {
18
- or: []
19
- }
18
+ or: [],
19
+ };
20
20
 
21
21
  const and = (...filters: Array<Filter | null>): Filter => {
22
- const flatFilters: Array<Filter> = []
22
+ const flatFilters: Array<Filter> = [];
23
23
  filters.forEach((f) => {
24
24
  if (f === null) {
25
25
  // if the filter is null, we never want to match this block.
26
- flatFilters.push(neverMatch)
26
+ flatFilters.push(neverMatch);
27
27
  } else if ("and" in f) {
28
28
  // Automatically flatten nested ands.
29
- flatFilters.push(...f.and)
29
+ flatFilters.push(...f.and);
30
30
  } else {
31
- flatFilters.push(f)
31
+ flatFilters.push(f);
32
32
  }
33
- })
34
- return { and: flatFilters }
35
- }
33
+ });
34
+ return { and: flatFilters };
35
+ };
36
36
  const or = (...filters: Array<Filter | null>): Filter => {
37
- const flatFilters: Array<Filter> = []
37
+ const flatFilters: Array<Filter> = [];
38
38
  filters
39
39
  .filter((f) => f !== null)
40
40
  .forEach((f) => {
41
41
  if ("or" in f) {
42
- flatFilters.push(...f.or)
42
+ flatFilters.push(...f.or);
43
43
  } else {
44
- flatFilters.push(f)
44
+ flatFilters.push(f);
45
45
  }
46
- })
47
- return { or: flatFilters }
48
- }
46
+ });
47
+ return { or: flatFilters };
48
+ };
49
49
 
50
50
  const regexMatches = (
51
51
  attribute: RegexMatches["regex_matches"][0],
52
- regex: string
52
+ regex: string,
53
53
  ): RegexMatches => ({
54
- regex_matches: [attribute, regex, true]
55
- })
54
+ regex_matches: [attribute, regex, true],
55
+ });
56
56
 
57
57
  const regexNegationMatches = (
58
58
  attribute: RegexNegationMatches["regex_negation_matches"][0],
59
- regex: string
59
+ regex: string,
60
60
  ): RegexNegationMatches => ({
61
- regex_negation_matches: [attribute, regex, true]
62
- })
61
+ regex_negation_matches: [attribute, regex, true],
62
+ });
63
63
 
64
64
  const textMatchesAny = ({
65
65
  attribute,
66
66
  caseInsensitive = true,
67
67
  patterns,
68
- useRegex = false
68
+ useRegex = false,
69
69
  }: {
70
- attribute: AttributeName
71
- patterns: Array<string>
72
- caseInsensitive?: boolean
73
- useRegex?: boolean
70
+ attribute: AttributeName;
71
+ patterns: Array<string>;
72
+ caseInsensitive?: boolean;
73
+ useRegex?: boolean;
74
74
  }): TextMatchesAny => ({
75
- regex_any: [attribute, patterns, caseInsensitive, useRegex]
76
- })
75
+ regex_any: [attribute, patterns, caseInsensitive, useRegex],
76
+ });
77
77
 
78
78
  const textMatchesNone = ({
79
79
  attribute,
80
80
  caseInsensitive = true,
81
81
  patterns,
82
- useRegex = false
82
+ useRegex = false,
83
83
  }: {
84
- attribute: AttributeName
85
- patterns: Array<string>
86
- caseInsensitive?: boolean
87
- useRegex?: boolean
84
+ attribute: AttributeName;
85
+ patterns: Array<string>;
86
+ caseInsensitive?: boolean;
87
+ useRegex?: boolean;
88
88
  }): TextMatchesNone => ({
89
- regex_none: [attribute, patterns, caseInsensitive, useRegex]
90
- })
89
+ regex_none: [attribute, patterns, caseInsensitive, useRegex],
90
+ });
91
91
 
92
92
  const isListMember = (uri: string): ListMemberFilter => ({
93
- list_member: [uri, "in"]
94
- })
93
+ list_member: [uri, "in"],
94
+ });
95
95
  const isNotListMember = (uri: string): ListMemberFilter => ({
96
- list_member: [uri, "not_in"]
97
- })
96
+ list_member: [uri, "not_in"],
97
+ });
98
98
  const socialGraph = (
99
99
  identifier: string,
100
100
  op: SocialGraph["social_graph"][1],
101
- relation: SocialGraph["social_graph"][2]
101
+ relation: SocialGraph["social_graph"][2],
102
102
  ): SocialGraph => ({
103
- social_graph: [identifier, op, relation]
104
- })
105
- const posterIsFollowedBy = (identifier: string) => socialGraph(identifier, "in", "followers")
106
- const posterFollows = (identifier: string) => socialGraph(identifier, "in", "follows")
107
- const posterIsNotFollowedBy = (identifier: string) => socialGraph(identifier, "not_in", "followers")
108
- const posterDoesNotFollow = (identifier: string) => socialGraph(identifier, "not_in", "follows")
103
+ social_graph: [identifier, op, relation],
104
+ });
105
+ const posterIsFollowedBy = (identifier: string) =>
106
+ socialGraph(identifier, "in", "followers");
107
+ const posterFollows = (identifier: string) =>
108
+ socialGraph(identifier, "in", "follows");
109
+ const posterIsNotFollowedBy = (identifier: string) =>
110
+ socialGraph(identifier, "not_in", "followers");
111
+ const posterDoesNotFollow = (identifier: string) =>
112
+ socialGraph(identifier, "not_in", "follows");
109
113
 
110
114
  const embedContains = (type: EmbedType["embed_type"][1]): Filter => ({
111
- embed_type: ["==", type]
112
- })
115
+ embed_type: ["==", type],
116
+ });
113
117
  const embedDoesNotContain = (type: EmbedType["embed_type"][1]): Filter => ({
114
- embed_type: ["!=", type]
115
- })
118
+ embed_type: ["!=", type],
119
+ });
116
120
 
117
121
  const postTypeIs = (...types: PostTypeFilter["post_type"][1]): Filter => ({
118
- post_type: ["in", types]
119
- })
122
+ post_type: ["in", types],
123
+ });
120
124
  const postTypeIsNot = (...types: PostTypeFilter["post_type"][1]): Filter => ({
121
- post_type: ["not_in", types]
122
- })
125
+ post_type: ["not_in", types],
126
+ });
123
127
 
124
- const hasVideo: Filter = embedContains("video")
128
+ const hasVideo: Filter = embedContains("video");
125
129
 
126
130
  const hasNoNSFWLabels: Filter = {
127
- entity_excludes: ["labels", ["porn", "sexual", "nudity"]]
128
- }
131
+ entity_excludes: ["labels", ["porn", "sexual", "nudity"]],
132
+ };
129
133
  const attributeCompare = (
130
134
  attr: AttributeName,
131
135
  op: AttributeComparison,
132
- value: AttributeValue
136
+ value: AttributeValue,
133
137
  ): Filter => ({
134
- attribute_compare: [attr, op, value]
135
- })
138
+ attribute_compare: [attr, op, value],
139
+ });
136
140
 
137
- const isPost: Filter = postTypeIsNot("reply", "quote")
138
- const isReply: Filter = postTypeIs("reply")
139
- const isQuote: Filter = postTypeIs("quote")
140
- const isNotReply: Filter = postTypeIsNot("reply")
141
- const isNotQuote: Filter = postTypeIsNot("quote")
141
+ const isPost: Filter = postTypeIsNot("reply", "quote");
142
+ const isReply: Filter = postTypeIs("reply");
143
+ const isQuote: Filter = postTypeIs("quote");
144
+ const isNotReply: Filter = postTypeIsNot("reply");
145
+ const isNotQuote: Filter = postTypeIsNot("quote");
142
146
 
143
147
  const isContentOk = (threshold: number = 0.9): ContentModerationBlock => ({
144
- content_moderation: ["OK", ">=", threshold]
145
- })
148
+ content_moderation: ["OK", ">=", threshold],
149
+ });
146
150
 
147
151
  export const Algo = {
148
152
  filter: (...filters: Array<Filter>): { filter: Filter } => ({
149
- filter: and(...filters)
150
- })
151
- }
153
+ filter: and(...filters),
154
+ }),
155
+ };
152
156
 
153
157
  export const F = {
154
158
  and,
@@ -176,5 +180,5 @@ export const F = {
176
180
  isNotQuote,
177
181
  isContentOk,
178
182
  embedContains,
179
- embedDoesNotContain
180
- }
183
+ embedDoesNotContain,
184
+ };
package/src/common.ts CHANGED
@@ -1,11 +1,6 @@
1
- import { HttpApiSchema } from "@effect/platform"
2
- import { Schema } from "effect"
1
+ import { Schema } from "effect";
3
2
 
4
- export const UserIdParam = HttpApiSchema.param(
5
- "userId",
6
- Schema.NumberFromString
7
- )
8
- export const FeedIdParam = HttpApiSchema.param(
9
- "feedId",
10
- Schema.NumberFromString
11
- )
3
+ // v4 has no `HttpApiSchema.param`: path params are declared inline in the
4
+ // endpoint path (`:feedId`) with a `params: { feedId: FeedIdParam }` schema map.
5
+ export const UserIdParam = Schema.NumberFromString;
6
+ export const FeedIdParam = Schema.NumberFromString;
package/src/index.ts CHANGED
@@ -1,85 +1,94 @@
1
- import { ConfigProvider, Effect, Layer } from "effect"
2
- import { GrazeClient } from "./GrazeClient.js"
1
+ import { ConfigProvider, Effect } from "effect";
2
+ import { GrazeClient, type GrazeClientService } from "./GrazeClient.js";
3
3
 
4
4
  type Promisify<T> = T extends (
5
5
  ...args: Array<any>
6
- ) => Effect.Effect<infer A, infer _E, never> ? (...args: Parameters<T>) => Promise<A>
7
- : never
6
+ ) => Effect.Effect<infer A, infer _E, never>
7
+ ? (...args: Parameters<T>) => Promise<A>
8
+ : never;
8
9
 
9
10
  export class GrazeService {
10
- getFeed: Promisify<typeof GrazeClient.Service.getFeed>
11
- getFeeds: Promisify<typeof GrazeClient.Service.getFeeds>
12
- hidePost: Promisify<typeof GrazeClient.Service.hidePost>
13
- unhidePost: Promisify<typeof GrazeClient.Service.unhidePost>
14
- updateAlgorithm: Promisify<typeof GrazeClient.Service.updateAlgorithm>
15
- publishAlgorithm: Promisify<typeof GrazeClient.Service.publishAlgorithm>
11
+ getFeed: Promisify<GrazeClientService["getFeed"]>;
12
+ getFeeds: Promisify<GrazeClientService["getFeeds"]>;
13
+ hidePost: Promisify<GrazeClientService["hidePost"]>;
14
+ unhidePost: Promisify<GrazeClientService["unhidePost"]>;
15
+ updateAlgorithm: Promisify<GrazeClientService["updateAlgorithm"]>;
16
+ publishAlgorithm: Promisify<GrazeClientService["publishAlgorithm"]>;
16
17
  stickyposts: {
17
- get: Promisify<typeof GrazeClient.Service.stickyposts.get>
18
- create: Promisify<typeof GrazeClient.Service.stickyposts.create>
19
- delete: Promisify<typeof GrazeClient.Service.stickyposts.delete>
20
- update: Promisify<typeof GrazeClient.Service.stickyposts.update>
21
- }
18
+ get: Promisify<GrazeClientService["stickyposts"]["get"]>;
19
+ create: Promisify<GrazeClientService["stickyposts"]["create"]>;
20
+ delete: Promisify<GrazeClientService["stickyposts"]["delete"]>;
21
+ update: Promisify<GrazeClientService["stickyposts"]["update"]>;
22
+ };
22
23
 
23
24
  constructor({
24
25
  apiUrl,
25
26
  cookie,
26
- userId
27
+ userId,
27
28
  }: {
28
- apiUrl: string
29
- cookie: string
30
- userId: number
29
+ apiUrl: string;
30
+ cookie: string;
31
+ userId: number;
31
32
  }) {
32
33
  const envMap = new Map([
33
34
  ["GRAZE_API_URL", apiUrl],
34
35
  ["GRAZE_COOKIE", cookie],
35
- ["GRAZE_USER_ID", userId.toString()]
36
- ])
37
- const provider = ConfigProvider.fromMap(envMap)
38
- const layer = Layer.setConfigProvider(provider)
36
+ ["GRAZE_USER_ID", userId.toString()],
37
+ ]);
38
+ const provider = ConfigProvider.make((path) => {
39
+ const value = envMap.get(path.join("."));
40
+ return Effect.succeed(
41
+ value !== undefined ? ConfigProvider.makeValue(value) : undefined,
42
+ );
43
+ });
44
+ const layer = ConfigProvider.layer(provider);
39
45
  const make = setup.pipe(
40
- Effect.provide(GrazeClient.Default),
41
- Effect.provide(layer)
42
- )
43
- const api = Effect.runSync(make)
44
- this.getFeed = api.getFeed
45
- this.getFeeds = api.getFeeds
46
- this.hidePost = api.hidePost
47
- this.unhidePost = api.unhidePost
48
- this.updateAlgorithm = api.updateAlgorithm
49
- this.publishAlgorithm = api.publishAlgorithm
46
+ Effect.provide(GrazeClient.layer),
47
+ Effect.provide(layer),
48
+ );
49
+ const api = Effect.runSync(make);
50
+ this.getFeed = api.getFeed;
51
+ this.getFeeds = api.getFeeds;
52
+ this.hidePost = api.hidePost;
53
+ this.unhidePost = api.unhidePost;
54
+ this.updateAlgorithm = api.updateAlgorithm;
55
+ this.publishAlgorithm = api.publishAlgorithm;
50
56
  this.stickyposts = {
51
57
  get: api.getStickyPosts,
52
58
  create: api.createStickyPost,
53
59
  delete: api.deleteStickyPost,
54
- update: api.updateStickyPost
55
- }
60
+ update: api.updateStickyPost,
61
+ };
56
62
  }
57
63
  }
58
64
 
59
- const setup = Effect.gen(function*() {
60
- const client = yield* GrazeClient
61
- const getFeed = (...args: Parameters<typeof client.getFeed>) => client.getFeed(...args).pipe(Effect.runPromise)
62
- const getFeeds = (...args: Parameters<typeof client.getFeeds>) => client.getFeeds(...args).pipe(Effect.runPromise)
63
- const hidePost = (...args: Parameters<typeof client.hidePost>) => client.hidePost(...args).pipe(Effect.runPromise)
65
+ const setup = Effect.gen(function* () {
66
+ const client = yield* GrazeClient;
67
+ const getFeed = (...args: Parameters<typeof client.getFeed>) =>
68
+ client.getFeed(...args).pipe(Effect.runPromise);
69
+ const getFeeds = (...args: Parameters<typeof client.getFeeds>) =>
70
+ client.getFeeds(...args).pipe(Effect.runPromise);
71
+ const hidePost = (...args: Parameters<typeof client.hidePost>) =>
72
+ client.hidePost(...args).pipe(Effect.runPromise);
64
73
  const unhidePost = (...args: Parameters<typeof client.unhidePost>) =>
65
- client.unhidePost(...args).pipe(Effect.runPromise)
74
+ client.unhidePost(...args).pipe(Effect.runPromise);
66
75
  const updateAlgorithm = (
67
76
  ...args: Parameters<typeof client.updateAlgorithm>
68
- ) => client.updateAlgorithm(...args).pipe(Effect.runPromise)
77
+ ) => client.updateAlgorithm(...args).pipe(Effect.runPromise);
69
78
  const publishAlgorithm = (
70
79
  ...args: Parameters<typeof client.publishAlgorithm>
71
- ) => client.publishAlgorithm(...args).pipe(Effect.runPromise)
80
+ ) => client.publishAlgorithm(...args).pipe(Effect.runPromise);
72
81
  const getStickyPosts = (...args: Parameters<typeof client.stickyposts.get>) =>
73
- client.stickyposts.get(...args).pipe(Effect.runPromise)
82
+ client.stickyposts.get(...args).pipe(Effect.runPromise);
74
83
  const createStickyPost = (
75
84
  ...args: Parameters<typeof client.stickyposts.create>
76
- ) => client.stickyposts.create(...args).pipe(Effect.runPromise)
85
+ ) => client.stickyposts.create(...args).pipe(Effect.runPromise);
77
86
  const deleteStickyPost = (
78
87
  ...args: Parameters<typeof client.stickyposts.delete>
79
- ) => client.stickyposts.delete(...args).pipe(Effect.runPromise)
88
+ ) => client.stickyposts.delete(...args).pipe(Effect.runPromise);
80
89
  const updateStickyPost = (
81
90
  ...args: Parameters<typeof client.stickyposts.update>
82
- ) => client.stickyposts.update(...args).pipe(Effect.runPromise)
91
+ ) => client.stickyposts.update(...args).pipe(Effect.runPromise);
83
92
 
84
93
  return {
85
94
  getFeed,
@@ -91,9 +100,9 @@ const setup = Effect.gen(function*() {
91
100
  getStickyPosts,
92
101
  createStickyPost,
93
102
  deleteStickyPost,
94
- updateStickyPost
95
- }
96
- })
103
+ updateStickyPost,
104
+ };
105
+ });
97
106
 
98
- export { Algo, F } from "./builder.js"
99
- export * from "./schema/index.js"
107
+ export { Algo, F } from "./builder.js";
108
+ export * from "./schema/index.js";
@@ -1,4 +1,4 @@
1
- import { Schema as S } from "effect"
1
+ import { Schema as S } from "effect";
2
2
 
3
3
  /**
4
4
  * Schema for Bluesky objects
@@ -12,24 +12,24 @@ export const Author = S.Struct({
12
12
  labels: S.Array(S.Any),
13
13
  viewer: S.Any,
14
14
  createdAt: S.String,
15
- associated: S.Union(S.Null, S.Any),
16
- displayName: S.String
17
- })
18
- export type Author = typeof Author.Type
15
+ associated: S.Union([S.Null, S.Any]),
16
+ displayName: S.String,
17
+ });
18
+ export type Author = typeof Author.Type;
19
19
 
20
20
  export const Record = S.Struct({
21
- tags: S.Union(S.Null, S.Any),
21
+ tags: S.Union([S.Null, S.Any]),
22
22
  text: S.String,
23
23
  $type: S.String,
24
24
  embed: S.Any,
25
25
  langs: S.NullOr(S.Array(S.String)),
26
- reply: S.Union(S.Null, S.Any),
26
+ reply: S.Union([S.Null, S.Any]),
27
27
  facets: S.NullOr(S.Array(S.Any)),
28
- labels: S.Union(S.Null, S.Any),
29
- entities: S.Union(S.Null, S.Any),
30
- createdAt: S.String
31
- })
32
- export type Record = typeof Record.Type
28
+ labels: S.Union([S.Null, S.Any]),
29
+ entities: S.Union([S.Null, S.Any]),
30
+ createdAt: S.String,
31
+ });
32
+ export type Record = typeof Record.Type;
33
33
 
34
34
  export const Post = S.Struct({
35
35
  cid: S.String,
@@ -44,7 +44,7 @@ export const Post = S.Struct({
44
44
  likeCount: S.Number,
45
45
  quoteCount: S.Number,
46
46
  replyCount: S.Number,
47
- threadgate: S.Union(S.Null, S.Unknown),
48
- repostCount: S.Number
49
- })
50
- export type Post = typeof Post.Type
47
+ threadgate: S.Union([S.Null, S.Unknown]),
48
+ repostCount: S.Number,
49
+ });
50
+ export type Post = typeof Post.Type;