@gettersethya/mira-client 0.1.0-alpha.10

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 (168) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +140 -0
  3. package/dist/src/client/auth.d.ts +73 -0
  4. package/dist/src/client/auth.d.ts.map +1 -0
  5. package/dist/src/client/auth.js +72 -0
  6. package/dist/src/client/auth.js.map +1 -0
  7. package/dist/src/client/collection.d.ts +239 -0
  8. package/dist/src/client/collection.d.ts.map +1 -0
  9. package/dist/src/client/collection.js +137 -0
  10. package/dist/src/client/collection.js.map +1 -0
  11. package/dist/src/client/errors.d.ts +46 -0
  12. package/dist/src/client/errors.d.ts.map +1 -0
  13. package/dist/src/client/errors.js +40 -0
  14. package/dist/src/client/errors.js.map +1 -0
  15. package/dist/src/client/factory.d.ts +78 -0
  16. package/dist/src/client/factory.d.ts.map +1 -0
  17. package/dist/src/client/factory.js +108 -0
  18. package/dist/src/client/factory.js.map +1 -0
  19. package/dist/src/client/file.d.ts +116 -0
  20. package/dist/src/client/file.d.ts.map +1 -0
  21. package/dist/src/client/file.js +99 -0
  22. package/dist/src/client/file.js.map +1 -0
  23. package/dist/src/client/handler.d.ts +92 -0
  24. package/dist/src/client/handler.d.ts.map +1 -0
  25. package/dist/src/client/handler.js +62 -0
  26. package/dist/src/client/handler.js.map +1 -0
  27. package/dist/src/client/index.d.ts +13 -0
  28. package/dist/src/client/index.d.ts.map +1 -0
  29. package/dist/src/client/index.js +7 -0
  30. package/dist/src/client/index.js.map +1 -0
  31. package/dist/src/client/telemetry.d.ts +50 -0
  32. package/dist/src/client/telemetry.d.ts.map +1 -0
  33. package/dist/src/client/telemetry.js +32 -0
  34. package/dist/src/client/telemetry.js.map +1 -0
  35. package/dist/src/client/types.d.ts +137 -0
  36. package/dist/src/client/types.d.ts.map +1 -0
  37. package/dist/src/client/types.js +2 -0
  38. package/dist/src/client/types.js.map +1 -0
  39. package/dist/src/collection/auth.d.ts +79 -0
  40. package/dist/src/collection/auth.d.ts.map +1 -0
  41. package/dist/src/collection/auth.js +50 -0
  42. package/dist/src/collection/auth.js.map +1 -0
  43. package/dist/src/collection/base.d.ts +64 -0
  44. package/dist/src/collection/base.d.ts.map +1 -0
  45. package/dist/src/collection/base.js +40 -0
  46. package/dist/src/collection/base.js.map +1 -0
  47. package/dist/src/collection/bytes.d.ts +51 -0
  48. package/dist/src/collection/bytes.d.ts.map +1 -0
  49. package/dist/src/collection/bytes.js +51 -0
  50. package/dist/src/collection/bytes.js.map +1 -0
  51. package/dist/src/collection/errors.d.ts +29 -0
  52. package/dist/src/collection/errors.d.ts.map +1 -0
  53. package/dist/src/collection/errors.js +23 -0
  54. package/dist/src/collection/errors.js.map +1 -0
  55. package/dist/src/collection/field.d.ts +300 -0
  56. package/dist/src/collection/field.d.ts.map +1 -0
  57. package/dist/src/collection/field.js +175 -0
  58. package/dist/src/collection/field.js.map +1 -0
  59. package/dist/src/collection/index-builder.d.ts +59 -0
  60. package/dist/src/collection/index-builder.d.ts.map +1 -0
  61. package/dist/src/collection/index-builder.js +43 -0
  62. package/dist/src/collection/index-builder.js.map +1 -0
  63. package/dist/src/collection/index.d.ts +22 -0
  64. package/dist/src/collection/index.d.ts.map +1 -0
  65. package/dist/src/collection/index.js +21 -0
  66. package/dist/src/collection/index.js.map +1 -0
  67. package/dist/src/collection/serialize.d.ts +24 -0
  68. package/dist/src/collection/serialize.d.ts.map +1 -0
  69. package/dist/src/collection/serialize.js +127 -0
  70. package/dist/src/collection/serialize.js.map +1 -0
  71. package/dist/src/collection/types.d.ts +119 -0
  72. package/dist/src/collection/types.d.ts.map +1 -0
  73. package/dist/src/collection/types.js +2 -0
  74. package/dist/src/collection/types.js.map +1 -0
  75. package/dist/src/collection/view.d.ts +57 -0
  76. package/dist/src/collection/view.d.ts.map +1 -0
  77. package/dist/src/collection/view.js +49 -0
  78. package/dist/src/collection/view.js.map +1 -0
  79. package/dist/src/filter/builder.d.ts +127 -0
  80. package/dist/src/filter/builder.d.ts.map +1 -0
  81. package/dist/src/filter/builder.js +72 -0
  82. package/dist/src/filter/builder.js.map +1 -0
  83. package/dist/src/filter/compiler.d.ts +48 -0
  84. package/dist/src/filter/compiler.d.ts.map +1 -0
  85. package/dist/src/filter/compiler.js +132 -0
  86. package/dist/src/filter/compiler.js.map +1 -0
  87. package/dist/src/filter/index.d.ts +6 -0
  88. package/dist/src/filter/index.d.ts.map +1 -0
  89. package/dist/src/filter/index.js +4 -0
  90. package/dist/src/filter/index.js.map +1 -0
  91. package/dist/src/filter/types.d.ts +96 -0
  92. package/dist/src/filter/types.d.ts.map +1 -0
  93. package/dist/src/filter/types.js +44 -0
  94. package/dist/src/filter/types.js.map +1 -0
  95. package/dist/src/index.d.ts +3 -0
  96. package/dist/src/index.d.ts.map +1 -0
  97. package/dist/src/index.js +3 -0
  98. package/dist/src/index.js.map +1 -0
  99. package/dist/src/rule/builder.d.ts +97 -0
  100. package/dist/src/rule/builder.d.ts.map +1 -0
  101. package/dist/src/rule/builder.js +126 -0
  102. package/dist/src/rule/builder.js.map +1 -0
  103. package/dist/src/rule/index.d.ts +3 -0
  104. package/dist/src/rule/index.d.ts.map +1 -0
  105. package/dist/src/rule/index.js +3 -0
  106. package/dist/src/rule/index.js.map +1 -0
  107. package/dist/src/rule/types.d.ts +129 -0
  108. package/dist/src/rule/types.d.ts.map +1 -0
  109. package/dist/src/rule/types.js +2 -0
  110. package/dist/src/rule/types.js.map +1 -0
  111. package/dist/tests/client/auth.test.d.ts +2 -0
  112. package/dist/tests/client/auth.test.d.ts.map +1 -0
  113. package/dist/tests/client/auth.test.js +67 -0
  114. package/dist/tests/client/auth.test.js.map +1 -0
  115. package/dist/tests/client/collection.test.d.ts +2 -0
  116. package/dist/tests/client/collection.test.d.ts.map +1 -0
  117. package/dist/tests/client/collection.test.js +593 -0
  118. package/dist/tests/client/collection.test.js.map +1 -0
  119. package/dist/tests/client/file.test.d.ts +2 -0
  120. package/dist/tests/client/file.test.d.ts.map +1 -0
  121. package/dist/tests/client/file.test.js +21 -0
  122. package/dist/tests/client/file.test.js.map +1 -0
  123. package/dist/tests/client/handler.test.d.ts +2 -0
  124. package/dist/tests/client/handler.test.d.ts.map +1 -0
  125. package/dist/tests/client/handler.test.js +24 -0
  126. package/dist/tests/client/handler.test.js.map +1 -0
  127. package/dist/tests/client/types.test.d.ts +2 -0
  128. package/dist/tests/client/types.test.d.ts.map +1 -0
  129. package/dist/tests/client/types.test.js +168 -0
  130. package/dist/tests/client/types.test.js.map +1 -0
  131. package/dist/tests/collection/auth.test.d.ts +2 -0
  132. package/dist/tests/collection/auth.test.d.ts.map +1 -0
  133. package/dist/tests/collection/auth.test.js +44 -0
  134. package/dist/tests/collection/auth.test.js.map +1 -0
  135. package/dist/tests/collection/base.test.d.ts +2 -0
  136. package/dist/tests/collection/base.test.d.ts.map +1 -0
  137. package/dist/tests/collection/base.test.js +70 -0
  138. package/dist/tests/collection/base.test.js.map +1 -0
  139. package/dist/tests/collection/bytes.test.d.ts +2 -0
  140. package/dist/tests/collection/bytes.test.d.ts.map +1 -0
  141. package/dist/tests/collection/bytes.test.js +9 -0
  142. package/dist/tests/collection/bytes.test.js.map +1 -0
  143. package/dist/tests/collection/field.test.d.ts +2 -0
  144. package/dist/tests/collection/field.test.d.ts.map +1 -0
  145. package/dist/tests/collection/field.test.js +140 -0
  146. package/dist/tests/collection/field.test.js.map +1 -0
  147. package/dist/tests/collection/index-type.test.d.ts +2 -0
  148. package/dist/tests/collection/index-type.test.d.ts.map +1 -0
  149. package/dist/tests/collection/index-type.test.js +28 -0
  150. package/dist/tests/collection/index-type.test.js.map +1 -0
  151. package/dist/tests/collection/serialize.test.d.ts +2 -0
  152. package/dist/tests/collection/serialize.test.d.ts.map +1 -0
  153. package/dist/tests/collection/serialize.test.js +165 -0
  154. package/dist/tests/collection/serialize.test.js.map +1 -0
  155. package/dist/tests/collection/view.test.d.ts +2 -0
  156. package/dist/tests/collection/view.test.d.ts.map +1 -0
  157. package/dist/tests/collection/view.test.js +66 -0
  158. package/dist/tests/collection/view.test.js.map +1 -0
  159. package/dist/tests/filter/compiler.test.d.ts +2 -0
  160. package/dist/tests/filter/compiler.test.d.ts.map +1 -0
  161. package/dist/tests/filter/compiler.test.js +156 -0
  162. package/dist/tests/filter/compiler.test.js.map +1 -0
  163. package/dist/tests/rule/builder.test.d.ts +2 -0
  164. package/dist/tests/rule/builder.test.d.ts.map +1 -0
  165. package/dist/tests/rule/builder.test.js +290 -0
  166. package/dist/tests/rule/builder.test.js.map +1 -0
  167. package/dist/tsconfig.tsbuildinfo +1 -0
  168. package/package.json +39 -0
@@ -0,0 +1,137 @@
1
+ import { HttpClientRequest as HCR } from "@effect/platform";
2
+ import { Effect, MutableRef, Option, Schema } from "effect";
3
+ import { Filter, FilterNodeSchema } from "@gettersethya/mira-collection";
4
+ import { MiraError } from "./errors.js";
5
+ import { makeClientHandler as makeHandler, makeMutationHandler } from "./handler.js";
6
+ import { makeFileFields } from "./file.js";
7
+ function toExecuteEffect(reqEffect, execute) {
8
+ return reqEffect.pipe(Effect.flatMap((req) => execute(req)), Effect.catchTag("HttpBodyError", (e) => Effect.fail(new MiraError({ status: 500, body: String(e) }))));
9
+ }
10
+ function hasFileOrBlob(input) {
11
+ return Object.values(input).some((v) => v instanceof Blob);
12
+ }
13
+ function buildFormData(input) {
14
+ const fd = new FormData();
15
+ for (const [key, value] of Object.entries(input)) {
16
+ if (value instanceof Blob) {
17
+ fd.append(key, value);
18
+ }
19
+ else if (value !== null && value !== undefined) {
20
+ fd.append(key, String(value));
21
+ }
22
+ }
23
+ return fd;
24
+ }
25
+ function makeFilterBuilder() {
26
+ return {
27
+ field: (name) => Filter.field(name),
28
+ and: (left, right) => Filter.and(left, right),
29
+ or: (left, right) => Filter.or(left, right),
30
+ not: (node) => Filter.not(node),
31
+ };
32
+ }
33
+ function buildQueryParams(params) {
34
+ const sp = new URLSearchParams();
35
+ for (const [k, v] of Object.entries(params)) {
36
+ if (v !== undefined)
37
+ sp.set(k, v);
38
+ }
39
+ const qs = sp.toString();
40
+ return qs ? `?${qs}` : "";
41
+ }
42
+ /**
43
+ * Construct a `CollectionClient<F>` for a given collection definition.
44
+ * This is the internal factory — users should use `createMiraClient()` which
45
+ * handles all wiring (auth, execute, file fields).
46
+ *
47
+ * @internal Use `createMiraClient().collection(def)` or `withCollections()` instead.
48
+ */
49
+ export function makeCollectionClient(params) {
50
+ const { collectionName, schema, fields, execute, baseUrl, authTokenRef, loggedInRef, fileTokenCacheRef, isAuth, defaultRetryOptions } = params;
51
+ function withRetry(effect, methodOptions) {
52
+ const schedule = methodOptions?.retryOptions?.schedule ?? defaultRetryOptions?.schedule;
53
+ return schedule ? Effect.retry(effect, schedule) : effect;
54
+ }
55
+ const fileFields = makeFileFields({ name: collectionName, fields, schema }, schema, baseUrl, execute, fileTokenCacheRef, makeHandler);
56
+ function getList(options) {
57
+ const filterNode = options?.filter?.(makeFilterBuilder());
58
+ const queryParams = buildQueryParams({
59
+ ...(filterNode ? { filter: Schema.encodeSync(Schema.parseJson(FilterNodeSchema))(filterNode) } : {}),
60
+ ...(options?.sort ? { sort: options.sort } : {}),
61
+ ...(options?.order ? { order: options.order } : {}),
62
+ ...(options?.cursor != null ? { after: String(options.cursor) } : {}),
63
+ ...(options?.limit ? { limit: String(options.limit) } : {}),
64
+ ...(options?.select ? { select: options.select.join(",") } : {}),
65
+ ...(options?.expand ? { expand: options.expand.join(",") } : {}),
66
+ });
67
+ const effect = execute(HCR.get(`/api/collections/${collectionName}${queryParams}`));
68
+ return makeHandler(withRetry(effect, options));
69
+ }
70
+ function getFirstOrNone(filter, options) {
71
+ const effect = getList({ ...options, filter, limit: 1 })
72
+ .toEffect()
73
+ .pipe(Effect.map(({ items }) => Option.fromNullable(items[0] ?? null)));
74
+ return makeHandler(effect);
75
+ }
76
+ function getFullList(options) {
77
+ const effect = getList({ ...options, limit: options?.limit ?? 1000 })
78
+ .toEffect()
79
+ .pipe(Effect.map(({ items }) => items));
80
+ return makeHandler(effect);
81
+ }
82
+ function getOne(id, options) {
83
+ const queryParams = buildQueryParams({
84
+ ...(options?.select ? { select: options.select.join(",") } : {}),
85
+ ...(options?.expand ? { expand: options.expand.join(",") } : {}),
86
+ });
87
+ const effect = execute(HCR.get(`/api/collections/${collectionName}/${id}${queryParams}`));
88
+ return makeHandler(withRetry(effect, options));
89
+ }
90
+ function create() {
91
+ return makeMutationHandler((input) => {
92
+ const reqEffect = hasFileOrBlob(input)
93
+ ? Effect.succeed(HCR.bodyFormData(HCR.post(`/api/collections/${collectionName}`), buildFormData(input)))
94
+ : HCR.bodyJson(HCR.post(`/api/collections/${collectionName}`), input);
95
+ return withRetry(toExecuteEffect(reqEffect, execute));
96
+ });
97
+ }
98
+ function update() {
99
+ return makeMutationHandler(({ id, data }) => {
100
+ const reqEffect = hasFileOrBlob(data)
101
+ ? Effect.succeed(HCR.bodyFormData(HCR.patch(`/api/collections/${collectionName}/${id}`), buildFormData(data)))
102
+ : HCR.bodyJson(HCR.patch(`/api/collections/${collectionName}/${id}`), data);
103
+ return withRetry(toExecuteEffect(reqEffect, execute));
104
+ });
105
+ }
106
+ function deleteFn() {
107
+ return makeMutationHandler((id) => {
108
+ const effect = execute(HCR.del(`/api/collections/${collectionName}/${id}`));
109
+ return withRetry(effect);
110
+ });
111
+ }
112
+ function authWithPassword() {
113
+ return makeMutationHandler(({ email, password }) => withRetry(Effect.gen(function* () {
114
+ const res = yield* toExecuteEffect(HCR.bodyJson(HCR.post(`/api/collections/${collectionName}/auth-with-password`), { email, password }), execute);
115
+ if (authTokenRef !== null) {
116
+ MutableRef.set(authTokenRef, res.token);
117
+ }
118
+ if (loggedInRef !== null) {
119
+ MutableRef.set(loggedInRef, true);
120
+ }
121
+ return res;
122
+ })));
123
+ }
124
+ const client = {
125
+ getList,
126
+ getFirstOrNone,
127
+ getFullList,
128
+ getOne,
129
+ create,
130
+ update,
131
+ delete: deleteFn,
132
+ ...(isAuth ? { authWithPassword } : {}),
133
+ fields: fileFields,
134
+ };
135
+ return client;
136
+ }
137
+ //# sourceMappingURL=collection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection.js","sourceRoot":"","sources":["../../../src/client/collection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ declare const MiraError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
2
+ readonly _tag: "MiraError";
3
+ } & Readonly<A>;
4
+ /**
5
+ * Error thrown by `ClientHandler.raw()` when an HTTP request to the Mira server fails.
6
+ *
7
+ * Wraps the HTTP status code and response body. The `status` field corresponds to
8
+ * the HTTP status code (e.g., 404, 403, 422, 0 for network errors). The `body`
9
+ * field contains the server's JSON error response (typically `{ error, message, issues }`).
10
+ *
11
+ * `MiraError` is thrown **directly** from `.raw()` — it is NOT wrapped in `FiberFailure`.
12
+ * In the Effect channel (`toEffect()`), it is available in the error channel and can
13
+ * be caught via `Effect.catchTag("MiraError", ...)`.
14
+ *
15
+ * @example
16
+ * import { createMiraClient, MiraError } from "@gettersethya/mira-client"
17
+ *
18
+ * const mira = createMiraClient("/")
19
+ *
20
+ * try {
21
+ * await mira.posts.getOne("nonexistent").raw()
22
+ * } catch (e) {
23
+ * if (e instanceof MiraError) {
24
+ * console.error(`HTTP ${e.status}:`, e.body)
25
+ * }
26
+ * }
27
+ *
28
+ * @example
29
+ * // In Effect context via toEffect()
30
+ * import { Effect } from "effect"
31
+ *
32
+ * mira.posts.getOne("nonexistent").toEffect().pipe(
33
+ * Effect.catchTag("MiraError", (e) =>
34
+ * Effect.logError(`HTTP ${e.status}: ${JSON.stringify(e.body)}`)
35
+ * )
36
+ * )
37
+ *
38
+ * @see ClientHandler — the interface that throws MiraError from .raw()
39
+ */
40
+ export declare class MiraError extends MiraError_base<{
41
+ readonly status: number;
42
+ readonly body: unknown;
43
+ }> {
44
+ }
45
+ export {};
46
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/client/errors.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,SAAU,SAAQ,eAA8B;IAC3D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB,CAAC;CAAG"}
@@ -0,0 +1,40 @@
1
+ import { Data } from "effect";
2
+ /**
3
+ * Error thrown by `ClientHandler.raw()` when an HTTP request to the Mira server fails.
4
+ *
5
+ * Wraps the HTTP status code and response body. The `status` field corresponds to
6
+ * the HTTP status code (e.g., 404, 403, 422, 0 for network errors). The `body`
7
+ * field contains the server's JSON error response (typically `{ error, message, issues }`).
8
+ *
9
+ * `MiraError` is thrown **directly** from `.raw()` — it is NOT wrapped in `FiberFailure`.
10
+ * In the Effect channel (`toEffect()`), it is available in the error channel and can
11
+ * be caught via `Effect.catchTag("MiraError", ...)`.
12
+ *
13
+ * @example
14
+ * import { createMiraClient, MiraError } from "@gettersethya/mira-client"
15
+ *
16
+ * const mira = createMiraClient("/")
17
+ *
18
+ * try {
19
+ * await mira.posts.getOne("nonexistent").raw()
20
+ * } catch (e) {
21
+ * if (e instanceof MiraError) {
22
+ * console.error(`HTTP ${e.status}:`, e.body)
23
+ * }
24
+ * }
25
+ *
26
+ * @example
27
+ * // In Effect context via toEffect()
28
+ * import { Effect } from "effect"
29
+ *
30
+ * mira.posts.getOne("nonexistent").toEffect().pipe(
31
+ * Effect.catchTag("MiraError", (e) =>
32
+ * Effect.logError(`HTTP ${e.status}: ${JSON.stringify(e.body)}`)
33
+ * )
34
+ * )
35
+ *
36
+ * @see ClientHandler — the interface that throws MiraError from .raw()
37
+ */
38
+ export class MiraError extends Data.TaggedError("MiraError") {
39
+ }
40
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/client/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAE7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,OAAO,SAAU,SAAQ,IAAI,CAAC,WAAW,CAAC,WAAW,CAGzD;CAAG"}
@@ -0,0 +1,78 @@
1
+ import type { AnyCollectionDef, FieldsMap } from "@gettersethya/mira-collection";
2
+ import type { BrowserAuth, ServerAuth } from "./auth.js";
3
+ import type { CollectionClient, RetryOptions } from "./collection.js";
4
+ import type { ClientHandler } from "./handler.js";
5
+ import type { InferRecord } from "./types.js";
6
+ import type { TelemetryClient } from "./telemetry.js";
7
+ type CollectionAdapter = <F extends FieldsMap>(client: CollectionClient<F>, name: string) => CollectionClient<F>;
8
+ type BaseClient<A extends BrowserAuth | ServerAuth = BrowserAuth | ServerAuth> = {
9
+ collection<C extends AnyCollectionDef>(def: C): CollectionClient<C["fields"]>;
10
+ auth: A;
11
+ telemetry: TelemetryClient;
12
+ withCollections<M extends Record<string, AnyCollectionDef>>(map: M, opts?: {
13
+ adapter?: CollectionAdapter;
14
+ }): BaseClient<A> & CollectionAccessors<M>;
15
+ };
16
+ type CollectionAccessors<M extends Record<string, AnyCollectionDef>> = {
17
+ [K in keyof M]: CollectionClient<M[K]["fields"]> & (M[K]["schema"]["x-collection-kind"] extends "auth" ? {
18
+ authWithPassword(): ClientHandler<{
19
+ token: string;
20
+ record: InferRecord<M[K]["fields"]>;
21
+ }, {
22
+ email: string;
23
+ password: string;
24
+ }>;
25
+ } : {});
26
+ };
27
+ type BrowserMiraClient = BaseClient<BrowserAuth>;
28
+ type ServerMiraClient = BaseClient<ServerAuth>;
29
+ /**
30
+ * Create a Mira client instance for the browser (default mode).
31
+ * Uses cookies for auth — the client tracks login state via `auth.isLoggedIn()`.
32
+ *
33
+ * @param baseUrl - Base URL of the Mira server (default: "/" for same-origin)
34
+ * @param opts.defaultRetryOptions - Optional default retry schedule for all operations
35
+ * @returns A BrowserMiraClient with `auth: BrowserAuth`
36
+ *
37
+ * @example
38
+ * import { createMiraClient } from "@gettersethya/mira-client"
39
+ *
40
+ * const mira = createMiraClient("http://localhost:3000")
41
+ * const posts = await mira.posts.getList().raw()
42
+ *
43
+ * @example
44
+ * // With retry options
45
+ * import { Schedule } from "effect"
46
+ * const mira = createMiraClient("/", {
47
+ * defaultRetryOptions: { schedule: Schedule.exponential(100) }
48
+ * })
49
+ */
50
+ export declare function createMiraClient(baseUrl?: string, opts?: {
51
+ type?: "browser";
52
+ defaultRetryOptions?: RetryOptions;
53
+ }): BrowserMiraClient;
54
+ /**
55
+ * Create a Mira client instance for server-side rendering (SSR).
56
+ * Uses `type: "server"` to enable manual JWT token management via `auth: ServerAuth`.
57
+ *
58
+ * In server mode, the client does NOT track login state — you must call
59
+ * `mira.auth.setToken(token)` explicitly with the JWT from your SSR context.
60
+ *
61
+ * @param baseUrl - Base URL of the Mira server
62
+ * @param opts.type - Must be "server"
63
+ * @param opts.defaultRetryOptions - Optional default retry schedule
64
+ * @returns A ServerMiraClient with `auth: ServerAuth`
65
+ *
66
+ * @example
67
+ * import { createMiraClient } from "@gettersethya/mira-client"
68
+ *
69
+ * const mira = createMiraClient("http://localhost:3000", { type: "server" })
70
+ * mira.auth.setToken("eyJ...") // set token from SSR context
71
+ * const posts = await mira.posts.getList().raw()
72
+ */
73
+ export declare function createMiraClient(baseUrl: string | undefined, opts: {
74
+ type: "server";
75
+ defaultRetryOptions?: RetryOptions;
76
+ }): ServerMiraClient;
77
+ export {};
78
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/client/factory.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAA;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAExD,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAa,MAAM,cAAc,CAAA;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAGrD,KAAK,iBAAiB,GAAG,CAAC,CAAC,SAAS,SAAS,EAC3C,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC3B,IAAI,EAAE,MAAM,KACT,gBAAgB,CAAC,CAAC,CAAC,CAAA;AAExB,KAAK,UAAU,CAAC,CAAC,SAAS,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,IAAI;IAC/E,UAAU,CAAC,CAAC,SAAS,gBAAgB,EAAE,GAAG,EAAE,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC7E,IAAI,EAAE,CAAC,CAAA;IACP,SAAS,EAAE,eAAe,CAAA;IAC1B,eAAe,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACxD,GAAG,EAAE,CAAC,EACN,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,iBAAiB,CAAA;KAAE,GACrC,UAAU,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAA;CAC1C,CAAA;AAED,KAAK,mBAAmB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,IAAI;KACpE,CAAC,IAAI,MAAM,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAC9C,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,mBAAmB,CAAC,SAAS,MAAM,GAC/C;QACE,gBAAgB,IAAI,aAAa,CAC/B;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;SAAE,EACtD;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CACpC,CAAA;KACF,GACD,EAAE,CAAC;CACV,CAAA;AAED,KAAK,iBAAiB,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;AAEhD,KAAK,gBAAgB,GAAG,UAAU,CAAC,UAAU,CAAC,CAAA;AAyG9C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,CAAC,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,mBAAmB,CAAC,EAAE,YAAY,CAAA;CAAE,GAC9D,iBAAiB,CAAA;AAEpB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,mBAAmB,CAAC,EAAE,YAAY,CAAA;CAAE,GAC3D,gBAAgB,CAAA"}
@@ -0,0 +1,108 @@
1
+ import { HttpClient, HttpClientRequest as HCR } from "@effect/platform";
2
+ import { Effect, MutableRef } from "effect";
3
+ import { makeBrowserAuth, makeServerAuth } from "./auth.js";
4
+ import { makeCollectionClient } from "./collection.js";
5
+ import { MiraError } from "./errors.js";
6
+ import { makeClientHandler as makeHandler } from "./handler.js";
7
+ import { makeTelemetryClient } from "./telemetry.js";
8
+ function catchAllErrors(effect) {
9
+ return effect.pipe(Effect.catchTags({
10
+ RequestError: (e) => Effect.fail(new MiraError({ status: 0, body: e.message })),
11
+ ResponseError: (e) => Effect.fail(new MiraError({ status: e.response.status, body: e.message })),
12
+ HttpBodyError: (e) => Effect.fail(new MiraError({ status: 500, body: String(e) }))
13
+ }));
14
+ }
15
+ function createExecute(baseUrl, authTokenRef) {
16
+ return (req) => {
17
+ const raw = Effect.gen(function* () {
18
+ const http = yield* HttpClient.HttpClient;
19
+ const token = authTokenRef ? MutableRef.get(authTokenRef) : null;
20
+ const finalReq = HCR.prependUrl(baseUrl)(token ? HCR.setHeader(req, "Authorization", `Bearer ${token}`) : req);
21
+ const res = yield* http.execute(finalReq);
22
+ if (res.status >= 400) {
23
+ const body = yield* res.json;
24
+ return yield* new MiraError({ status: res.status, body });
25
+ }
26
+ if (res.status === 204) {
27
+ return undefined;
28
+ }
29
+ return (yield* res.json);
30
+ });
31
+ return catchAllErrors(raw);
32
+ };
33
+ }
34
+ function createMiraClientInternal(baseUrl = "/", type = "browser", defaultRetryOptions) {
35
+ const fileTokenCacheRef = MutableRef.make(new Map());
36
+ const authTokenRef = type === "server" ? MutableRef.make(null) : null;
37
+ const loggedInRef = type === "browser" ? MutableRef.make(false) : null;
38
+ const execute = createExecute(baseUrl, authTokenRef);
39
+ const makeClientHandler = (effect) => makeHandler(effect);
40
+ function buildCollectionClient(def) {
41
+ const isAuth = def.schema["x-collection-kind"] === "auth";
42
+ return makeCollectionClient({
43
+ collectionName: def.name,
44
+ schema: def.schema,
45
+ fields: def.fields,
46
+ execute,
47
+ baseUrl,
48
+ authTokenRef,
49
+ loggedInRef,
50
+ fileTokenCacheRef,
51
+ isAuth,
52
+ ...(defaultRetryOptions !== undefined ? { defaultRetryOptions } : {})
53
+ });
54
+ }
55
+ function makeAuth() {
56
+ if (type === "server" && authTokenRef !== null) {
57
+ return makeServerAuth(authTokenRef, fileTokenCacheRef);
58
+ }
59
+ if (loggedInRef !== null) {
60
+ return makeBrowserAuth(execute, makeClientHandler, loggedInRef);
61
+ }
62
+ return makeBrowserAuth(execute, makeClientHandler, MutableRef.make(false));
63
+ }
64
+ function withCollections(map, opts) {
65
+ const baseClient = buildBaseClient();
66
+ const collections = {};
67
+ for (const key of Object.keys(map)) {
68
+ const raw = buildCollectionClient(map[key]);
69
+ collections[key] = (opts?.adapter ? opts.adapter(raw, String(key)) : raw);
70
+ }
71
+ return Object.assign(baseClient, collections);
72
+ }
73
+ function buildBaseClient() {
74
+ return {
75
+ collection: (def) => buildCollectionClient(def),
76
+ auth: makeAuth(),
77
+ telemetry: makeTelemetryClient(execute),
78
+ withCollections
79
+ };
80
+ }
81
+ return buildBaseClient();
82
+ }
83
+ /**
84
+ * Create a Mira client instance.
85
+ *
86
+ * In browser mode (default), auth is cookie-based and `isLoggedIn()` reflects
87
+ * client-side login state. In server mode, you manage the JWT token explicitly
88
+ * via `auth.setToken()`.
89
+ *
90
+ * Use `withCollections()` to create typed accessors for each collection:
91
+ *
92
+ * @example
93
+ * const mira = createMiraClient("/").withCollections({ posts, users })
94
+ * const posts = await mira.posts.getList().raw()
95
+ * const loginResult = await mira.users.authWithPassword().raw({
96
+ * email: "admin@test.com",
97
+ * password: "admin1234"
98
+ * })
99
+ *
100
+ * @see BrowserAuth — client-side auth
101
+ * @see ServerAuth — server-side auth
102
+ * @see CollectionClient — the per-collection client interface
103
+ */
104
+ export function createMiraClient(baseUrl = "/", opts = {}) {
105
+ const { type = "browser", defaultRetryOptions } = opts;
106
+ return createMiraClientInternal(baseUrl, type, defaultRetryOptions);
107
+ }
108
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/client/factory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ import type { HttpClient } from "@effect/platform";
2
+ import { Effect, MutableRef } from "effect";
3
+ import type { AnyCollectionDef, FieldsMap } from "@gettersethya/mira-collection";
4
+ import { MiraError } from "./errors.js";
5
+ import type { ClientHandler, ExecuteFn } from "./handler.js";
6
+ import type { CollectionFileFields } from "./types.js";
7
+ /**
8
+ * Build a file request URL for the Mira file-serving endpoint.
9
+ *
10
+ * Constructs a URL of the form:
11
+ * `{baseUrl}/api/files/{collection}/{id}/{filename}?token={token}&thumb={spec}`
12
+ *
13
+ * Query parameters are only appended when defined.
14
+ *
15
+ * @param baseUrl - The base URL of the Mira server (e.g., "http://localhost:3000" or "/" for same-origin)
16
+ * @param collection - The collection name
17
+ * @param id - The record ID
18
+ * @param filename - The filename as stored in the record's file field
19
+ * @param opts.token - Optional short-lived JWT token for protected files
20
+ * @param opts.thumb - Optional thumbnail spec (e.g., "200x200", "100x100_fit")
21
+ * @returns The fully constructed file URL string
22
+ *
23
+ * @example
24
+ * buildFileUrl("/", "posts", "abc123", "cover.jpg")
25
+ * // "/api/files/posts/abc123/cover.jpg"
26
+ *
27
+ * @example
28
+ * buildFileUrl("http://localhost:8090", "users", "u1", "avatar.png", {
29
+ * token: "eyJ...",
30
+ * thumb: "200x200"
31
+ * })
32
+ * // "http://localhost:8090/api/files/users/u1/avatar.png?token=eyJ...&thumb=200x200"
33
+ */
34
+ export declare function buildFileUrl(baseUrl: string, collection: string, id: string, filename: string, opts?: {
35
+ token?: string;
36
+ thumb?: string;
37
+ }): string;
38
+ /**
39
+ * Create a function that retrieves a short-lived file-access JWT token for a collection.
40
+ * Tokens are cached per collection with a 30-second freshness buffer before expiry.
41
+ *
42
+ * @internal Called internally by `makeFileFields`. Use `ProtectedFileFieldClient.getToken()` instead.
43
+ */
44
+ export declare function makeGetFileToken(execute: ExecuteFn, cacheRef: MutableRef.MutableRef<Map<string, {
45
+ token: string;
46
+ expiresAt: number;
47
+ }>>): (collection: string) => Effect.Effect<string, MiraError, HttpClient.HttpClient>;
48
+ /**
49
+ * Client interface for a public (non-protected) file field.
50
+ * File URLs are constructed synchronously because no auth token is needed.
51
+ *
52
+ * @example
53
+ * // Given a post with a public "cover" file field
54
+ * const url = post.fields.cover.url(post.id, "cover.jpg")
55
+ * // "/api/files/posts/abc/cover.jpg"
56
+ *
57
+ * @example
58
+ * // With thumbnail variant
59
+ * const thumbUrl = post.fields.cover.url(post.id, "cover.jpg", { thumb: "200x200" })
60
+ *
61
+ * @see ProtectedFileFieldClient — file client that requires auth tokens
62
+ * @see buildFileUrl — underlying URL builder
63
+ */
64
+ export type PublicFileFieldClient = {
65
+ isProtected: false;
66
+ url(id: string, filename: string, opts?: {
67
+ thumb?: string;
68
+ }): string;
69
+ };
70
+ /**
71
+ * Client interface for a protected file field.
72
+ * Protected files require a short-lived JWT token to access.
73
+ *
74
+ * Three modes:
75
+ * - `url(id, filename, { token })` — synchronous URL construction when you already
76
+ * have a token (e.g., from `getToken()`)
77
+ * - `asyncUrl(id, filename)` — returns a `ClientHandler<string>` that fetches a token
78
+ * and constructs the URL in one async call
79
+ * - `getToken()` — fetches a fresh file-access token (cached for 30s by collection)
80
+ *
81
+ * @example
82
+ * // Async URL construction (fetches token automatically)
83
+ * const url = await post.fields.avatar.asyncUrl(post.id, "avatar.png").raw()
84
+ *
85
+ * @example
86
+ * // Manual token management for batch operations
87
+ * const token = await post.fields.avatar.getToken().raw()
88
+ * const u1 = post.fields.avatar.url("id1", "img1.png", { token })
89
+ * const u2 = post.fields.avatar.url("id2", "img2.png", { token })
90
+ *
91
+ * @see PublicFileFieldClient — file client for unprotected files
92
+ * @see buildFileUrl — underlying URL builder
93
+ */
94
+ export type ProtectedFileFieldClient = {
95
+ isProtected: true;
96
+ asyncUrl(id: string, filename: string, opts?: {
97
+ thumb?: string;
98
+ }): ClientHandler<string>;
99
+ url(id: string, filename: string, opts: {
100
+ token: string;
101
+ thumb?: string;
102
+ }): string;
103
+ getToken(): ClientHandler<string>;
104
+ };
105
+ /**
106
+ * Build the file field client interfaces for a collection.
107
+ * Iterates over the schema's properties, creating `PublicFileFieldClient` or
108
+ * `ProtectedFileFieldClient` instances for each `file`-kind field.
109
+ *
110
+ * @internal Called by `makeCollectionClient` — use `collection.fields` instead.
111
+ */
112
+ export declare function makeFileFields<F extends FieldsMap>(collection: AnyCollectionDef, schema: AnyCollectionDef["schema"], baseUrl: string, execute: ExecuteFn, cacheRef: MutableRef.MutableRef<Map<string, {
113
+ token: string;
114
+ expiresAt: number;
115
+ }>>, makeClientHandler: <T>(effect: Effect.Effect<T, MiraError, HttpClient.HttpClient>) => ClientHandler<T>): CollectionFileFields<F>;
116
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../../src/client/file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAqB,MAAM,kBAAkB,CAAA;AAGrE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAA;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,MAAM,CAOR;AAcD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,GACjF,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,CAAC,UAAU,CAAC,CAkBjF;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,WAAW,EAAE,KAAK,CAAA;IAClB,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAA;CACrE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,EAAE,IAAI,CAAA;IACjB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;IACxF,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAA;IAClF,QAAQ,IAAI,aAAa,CAAC,MAAM,CAAC,CAAA;CAClC,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,SAAS,EAChD,UAAU,EAAE,gBAAgB,EAC5B,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAClC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,EAClF,iBAAiB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,GACrG,oBAAoB,CAAC,CAAC,CAAC,CAoCzB"}