anpord 0.0.0 → 0.1.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.
@@ -0,0 +1,236 @@
1
+ import { FetchHttpClient, HttpApi, HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, HttpApiSecurity, HttpClient, HttpClientRequest, OpenApi } from "@effect/platform";
2
+ import { Context, Effect, Layer, Redacted, Schema } from "effect";
3
+ //#region ../schema/src/domain/errors.ts
4
+ var NotFound = class extends Schema.TaggedError()("NotFound", { message: Schema.String }, HttpApiSchema.annotations({ status: 404 })) {};
5
+ var Conflict = class extends Schema.TaggedError()("Conflict", { message: Schema.String }, HttpApiSchema.annotations({ status: 409 })) {};
6
+ var BadRequest = class extends Schema.TaggedError()("BadRequest", { message: Schema.String }, HttpApiSchema.annotations({ status: 400 })) {};
7
+ var Unauthorized = class extends Schema.TaggedError()("Unauthorized", { message: Schema.String }, HttpApiSchema.annotations({ status: 401 })) {};
8
+ Schema.TaggedError()("InternalError", { message: Schema.String }, HttpApiSchema.annotations({ status: 500 }));
9
+ //#endregion
10
+ //#region ../schema/src/internal/authentication.ts
11
+ var CurrentActor = class extends Context.Tag("@anpord/schema/CurrentActor")() {};
12
+ HttpApiMiddleware.Tag()("@anpord/schema/Authentication", {
13
+ failure: Unauthorized,
14
+ provides: CurrentActor,
15
+ security: { session: HttpApiSecurity.apiKey({
16
+ in: "cookie",
17
+ key: "anpord.session_token"
18
+ }) }
19
+ });
20
+ //#endregion
21
+ //#region ../schema/src/public/authentication.ts
22
+ var ApiKeyAuthentication = class extends HttpApiMiddleware.Tag()("@anpord/schema/ApiKeyAuthentication", {
23
+ failure: Unauthorized,
24
+ provides: CurrentActor,
25
+ security: { bearer: HttpApiSecurity.bearer }
26
+ }) {};
27
+ //#endregion
28
+ //#region ../schema/src/domain/prompts.ts
29
+ const ChannelName = Schema.String.pipe(Schema.minLength(1), Schema.maxLength(36), Schema.pattern(/^[a-z0-9][a-z0-9_-]*$/, { message: () => "Channel must be lowercase alphanumeric, optionally with - or _" }), Schema.brand("ChannelName")).annotations({ description: "Addresses a version. `latest` is derived from the highest version rather than stored, so it cannot drift from the version table." });
30
+ ChannelName.make("production");
31
+ ChannelName.make("latest");
32
+ const PromptId = Schema.String.pipe(Schema.minLength(1), Schema.maxLength(255), Schema.pattern(/^[a-z0-9][a-z0-9/_-]*$/, { message: () => "Prompt id must be lowercase alphanumeric, optionally with / _ or -" }), Schema.brand("PromptId"));
33
+ const PromptName = Schema.String.pipe(Schema.minLength(1), Schema.maxLength(255), Schema.brand("PromptName"));
34
+ const VersionNumber = Schema.Int.pipe(Schema.positive(), Schema.brand("VersionNumber"));
35
+ Schema.NumberFromString.pipe(Schema.int(), Schema.positive(), Schema.brand("VersionNumber"));
36
+ Schema.NumberFromString.pipe(Schema.int(), Schema.positive(), Schema.lessThanOrEqualTo(100));
37
+ const Timestamp = Schema.Union(Schema.DateFromSelf, Schema.Date);
38
+ const CommitMessage = Schema.String.pipe(Schema.maxLength(500));
39
+ const PromptConfig = Schema.Record({
40
+ key: Schema.String,
41
+ value: Schema.Unknown
42
+ });
43
+ const Author = Schema.Struct({
44
+ image: Schema.NullOr(Schema.String),
45
+ name: Schema.String
46
+ });
47
+ Schema.Struct({
48
+ author: Schema.NullOr(Author),
49
+ channel: Schema.NullOr(ChannelName),
50
+ commitMessage: Schema.NullOr(CommitMessage),
51
+ config: PromptConfig,
52
+ content: Schema.String,
53
+ createdAt: Timestamp,
54
+ id: PromptId,
55
+ name: PromptName,
56
+ version: VersionNumber,
57
+ versionId: Schema.String
58
+ });
59
+ Schema.Struct({
60
+ channel: ChannelName,
61
+ updatedAt: Timestamp,
62
+ updatedBy: Schema.NullOr(Author),
63
+ version: VersionNumber
64
+ });
65
+ const PromptSummary = Schema.Struct({
66
+ description: Schema.NullOr(Schema.String),
67
+ id: PromptId,
68
+ latestVersion: Schema.NullOr(VersionNumber),
69
+ name: PromptName,
70
+ productionVersion: Schema.NullOr(VersionNumber),
71
+ updatedAt: Timestamp
72
+ });
73
+ Schema.Struct({
74
+ id: PromptId,
75
+ updatedAt: Timestamp
76
+ });
77
+ Schema.Literal("all", "draft", "live");
78
+ Schema.Literal("name", "updated");
79
+ Schema.Struct({
80
+ items: Schema.Array(PromptSummary),
81
+ /** Opaque to callers, and null once the last page has been read. */
82
+ nextCursor: Schema.NullOr(Schema.String)
83
+ });
84
+ Schema.Struct({
85
+ commitMessage: Schema.optional(CommitMessage),
86
+ config: Schema.optional(PromptConfig),
87
+ content: Schema.String.pipe(Schema.minLength(1)),
88
+ description: Schema.optional(Schema.String),
89
+ id: PromptId,
90
+ name: PromptName,
91
+ publish: Schema.optional(Schema.Boolean)
92
+ });
93
+ Schema.Struct({
94
+ commitMessage: Schema.optional(CommitMessage),
95
+ config: Schema.optional(PromptConfig),
96
+ content: Schema.String.pipe(Schema.minLength(1)),
97
+ publish: Schema.optional(Schema.Boolean)
98
+ });
99
+ Schema.Struct({
100
+ commitMessage: Schema.optional(CommitMessage),
101
+ config: Schema.optional(PromptConfig),
102
+ content: Schema.String.pipe(Schema.minLength(1))
103
+ });
104
+ Schema.Struct({
105
+ description: Schema.optional(Schema.String),
106
+ id: Schema.optional(PromptId),
107
+ name: Schema.optional(PromptName)
108
+ });
109
+ Schema.Struct({
110
+ channel: ChannelName,
111
+ version: VersionNumber
112
+ });
113
+ Schema.Struct({
114
+ channel: Schema.optional(ChannelName),
115
+ version: Schema.optional(VersionNumber)
116
+ });
117
+ //#endregion
118
+ //#region ../schema/src/public/requests.ts
119
+ const GetPromptRequest = Schema.Struct({
120
+ channel: Schema.optional(ChannelName),
121
+ id: PromptId,
122
+ includeVersions: Schema.optional(Schema.Boolean),
123
+ version: Schema.optional(VersionNumber)
124
+ }).annotations({
125
+ description: "Resolve a prompt. Give a version to pin one, a channel to follow one, or neither for production.",
126
+ identifier: "GetPromptRequest"
127
+ });
128
+ Schema.Struct({ id: PromptId }).annotations({
129
+ description: "Show a prompt's version history.",
130
+ identifier: "ListVersionsRequest"
131
+ });
132
+ const ListPromptsRequest = Schema.Struct({}).annotations({
133
+ description: "No parameters; returns every prompt in the organization.",
134
+ identifier: "ListPromptsRequest"
135
+ });
136
+ const CreatePromptRequest = Schema.Struct({
137
+ config: Schema.optional(PromptConfig),
138
+ content: Schema.String.pipe(Schema.minLength(1)),
139
+ description: Schema.optional(Schema.String),
140
+ id: PromptId,
141
+ message: Schema.optional(CommitMessage),
142
+ name: PromptName
143
+ }).annotations({
144
+ description: "Create a prompt and its first version.",
145
+ identifier: "CreatePromptRequest"
146
+ });
147
+ const UpdatePromptRequest = Schema.Struct({
148
+ config: Schema.optional(PromptConfig),
149
+ content: Schema.String.pipe(Schema.minLength(1)),
150
+ id: PromptId,
151
+ message: Schema.optional(CommitMessage)
152
+ }).annotations({
153
+ description: "Add a version to a prompt. The new version becomes the latest.",
154
+ identifier: "UpdatePromptRequest"
155
+ });
156
+ const PromotePromptRequest = Schema.Struct({
157
+ channel: ChannelName,
158
+ id: PromptId,
159
+ version: VersionNumber
160
+ }).annotations({
161
+ description: "Point a channel at a version.",
162
+ identifier: "PromotePromptRequest"
163
+ });
164
+ const ArchivePromptRequest = Schema.Struct({ id: PromptId }).annotations({
165
+ description: "Archive a prompt. Existing versions stay readable by number.",
166
+ identifier: "ArchivePromptRequest"
167
+ });
168
+ const Ok = Schema.Struct({ ok: Schema.Literal(true) }).annotations({
169
+ description: "The operation succeeded.",
170
+ identifier: "Ok"
171
+ });
172
+ //#endregion
173
+ //#region ../schema/src/public/shapes.ts
174
+ const Instant = Schema.DateTimeUtc.annotations({
175
+ description: "An ISO-8601 timestamp in UTC.",
176
+ identifier: "Instant"
177
+ });
178
+ const PublicPrompt = Schema.Struct({
179
+ channel: Schema.NullOr(ChannelName),
180
+ config: PromptConfig,
181
+ content: Schema.String,
182
+ createdAt: Instant,
183
+ id: PromptId,
184
+ message: Schema.NullOr(CommitMessage),
185
+ name: PromptName,
186
+ version: VersionNumber
187
+ }).annotations({
188
+ description: "A prompt resolved at a specific version.",
189
+ identifier: "ResolvedPrompt"
190
+ });
191
+ const PublicVersion = Schema.Struct({
192
+ createdAt: Instant,
193
+ message: Schema.NullOr(CommitMessage),
194
+ version: VersionNumber
195
+ }).annotations({
196
+ description: "One entry in a prompt's history.",
197
+ identifier: "Version"
198
+ });
199
+ const PublicPromptWithVersions = Schema.extend(PublicPrompt, Schema.Struct({ versions: Schema.optional(Schema.Array(PublicVersion)) })).annotations({
200
+ description: "A prompt, with its version history when `includeVersions` is set.",
201
+ identifier: "Prompt"
202
+ });
203
+ const PublicPromptSummary = Schema.Struct({
204
+ id: PromptId,
205
+ latestVersion: Schema.NullOr(VersionNumber),
206
+ name: PromptName,
207
+ productionVersion: Schema.NullOr(VersionNumber),
208
+ updatedAt: Instant
209
+ }).annotations({
210
+ description: "A prompt without its content.",
211
+ identifier: "PromptSummary"
212
+ });
213
+ const PromptList = Schema.Struct({ data: Schema.Array(PublicPromptSummary) }).annotations({
214
+ description: "Every prompt in the organization.",
215
+ identifier: "PromptList"
216
+ });
217
+ //#endregion
218
+ //#region ../schema/src/public/prompts-api.ts
219
+ var PublicPromptsGroup = class extends HttpApiGroup.make("prompts").add(HttpApiEndpoint.post("get", "/prompts.get").setPayload(GetPromptRequest).addSuccess(PublicPromptWithVersions).annotate(OpenApi.Summary, "Resolve a prompt").annotate(OpenApi.Description, "Returns the content a caller should send to a model. With no selector this is the production version.")).add(HttpApiEndpoint.post("list", "/prompts.list").setPayload(ListPromptsRequest).addSuccess(PromptList).annotate(OpenApi.Summary, "List prompts").annotate(OpenApi.Description, "Every prompt in the organization, without content.")).add(HttpApiEndpoint.post("create", "/prompts.create").setPayload(CreatePromptRequest).addSuccess(PublicPromptWithVersions).annotate(OpenApi.Summary, "Create a prompt").annotate(OpenApi.Description, "Creates the prompt and its first version in one call.")).add(HttpApiEndpoint.post("update", "/prompts.update").setPayload(UpdatePromptRequest).addSuccess(PublicPromptWithVersions).annotate(OpenApi.Summary, "Add a version").annotate(OpenApi.Description, "Content is versioned, so updating a prompt appends a version rather than overwriting one. Earlier versions stay readable.")).add(HttpApiEndpoint.post("promote", "/prompts.promote").setPayload(PromotePromptRequest).addSuccess(Ok).annotate(OpenApi.Summary, "Promote a version to a channel").annotate(OpenApi.Description, "Points a channel, such as production, at a version. This is how a version goes live without callers changing anything.")).add(HttpApiEndpoint.post("archive", "/prompts.archive").setPayload(ArchivePromptRequest).addSuccess(Ok).annotate(OpenApi.Summary, "Archive a prompt").annotate(OpenApi.Description, "Hides the prompt from listings. Pinned versions keep resolving.")).addError(BadRequest).addError(Conflict).addError(NotFound).middleware(ApiKeyAuthentication).annotate(OpenApi.Title, "Prompts").annotate(OpenApi.Description, "Read and write prompts. Content is versioned, so writes append rather than overwrite, and channels decide which version callers receive.") {};
220
+ //#endregion
221
+ //#region ../schema/src/public/api.ts
222
+ var PublicApi = class extends HttpApi.make("anpord-public").add(PublicPromptsGroup).prefix("/v1").annotate(OpenApi.Title, "Anpord API").annotate(OpenApi.Version, "1.0.0").annotate(OpenApi.Description, "Prompt management. Every endpoint takes a JSON body over POST and authenticates with a bearer API key.").annotate(OpenApi.Servers, [{
223
+ description: "Production",
224
+ url: "https://api.anpord.com"
225
+ }]) {};
226
+ //#endregion
227
+ //#region ../schema/src/public/client.ts
228
+ const DEFAULT_BASE_URL = "https://api.anpord.com";
229
+ const make = ({ apiKey, baseUrl = DEFAULT_BASE_URL }) => HttpApiClient.make(PublicApi, {
230
+ baseUrl,
231
+ transformClient: HttpClient.mapRequest(HttpClientRequest.bearerToken(Redacted.value(apiKey)))
232
+ });
233
+ var AnpordApi = class extends Effect.Tag("@anpord/sdk/AnpordApi")() {};
234
+ const layer = (options) => Layer.effect(AnpordApi, make(options)).pipe(Layer.provide(FetchHttpClient.layer));
235
+ //#endregion
236
+ export { ChannelName as a, make as i, DEFAULT_BASE_URL as n, PromptId as o, layer as r, VersionNumber as s, AnpordApi as t };
@@ -0,0 +1,14 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_client = require("./client-Cno4LwRq.cjs");
3
+ let effect = require("effect");
4
+ //#region src/client/config.ts
5
+ const apiKeyConfig = effect.Config.redacted("ANPORD_API_KEY");
6
+ const baseUrlConfig = effect.Config.string("ANPORD_BASE_URL").pipe(effect.Config.withDefault(require_client.DEFAULT_BASE_URL));
7
+ const clientOptionsConfig = effect.Config.all({
8
+ apiKey: apiKeyConfig,
9
+ baseUrl: baseUrlConfig
10
+ });
11
+ //#endregion
12
+ exports.apiKeyConfig = apiKeyConfig;
13
+ exports.baseUrlConfig = baseUrlConfig;
14
+ exports.clientOptionsConfig = clientOptionsConfig;
@@ -0,0 +1,10 @@
1
+ import { Config } from "effect";
2
+ //#region src/client/config.d.ts
3
+ declare const apiKeyConfig: Config.Config<import("effect/Redacted").Redacted<string>>;
4
+ declare const baseUrlConfig: Config.Config<string>;
5
+ declare const clientOptionsConfig: Config.Config<{
6
+ apiKey: import("effect/Redacted").Redacted<string>;
7
+ baseUrl: string;
8
+ }>;
9
+ //#endregion
10
+ export { apiKeyConfig, baseUrlConfig, clientOptionsConfig };
@@ -0,0 +1,10 @@
1
+ import { Config } from "effect";
2
+ //#region src/client/config.d.ts
3
+ declare const apiKeyConfig: Config.Config<import("effect/Redacted").Redacted<string>>;
4
+ declare const baseUrlConfig: Config.Config<string>;
5
+ declare const clientOptionsConfig: Config.Config<{
6
+ apiKey: import("effect/Redacted").Redacted<string>;
7
+ baseUrl: string;
8
+ }>;
9
+ //#endregion
10
+ export { apiKeyConfig, baseUrlConfig, clientOptionsConfig };
@@ -0,0 +1,11 @@
1
+ import { n as DEFAULT_BASE_URL } from "./client-bJBNwTKq.mjs";
2
+ import { Config } from "effect";
3
+ //#region src/client/config.ts
4
+ const apiKeyConfig = Config.redacted("ANPORD_API_KEY");
5
+ const baseUrlConfig = Config.string("ANPORD_BASE_URL").pipe(Config.withDefault(DEFAULT_BASE_URL));
6
+ const clientOptionsConfig = Config.all({
7
+ apiKey: apiKeyConfig,
8
+ baseUrl: baseUrlConfig
9
+ });
10
+ //#endregion
11
+ export { apiKeyConfig, baseUrlConfig, clientOptionsConfig };
@@ -0,0 +1,67 @@
1
+ let effect_ParseResult = require("effect/ParseResult");
2
+ //#region src/client/errors.ts
3
+ var MissingApiKey = class extends Error {
4
+ name = "MissingApiKey";
5
+ constructor() {
6
+ super("No API key. Pass { apiKey } to the Anpord constructor or set ANPORD_API_KEY.");
7
+ }
8
+ };
9
+ var AnpordError = class extends Error {
10
+ name = "AnpordError";
11
+ status;
12
+ cause;
13
+ constructor(message, options) {
14
+ super(message);
15
+ this.cause = options.cause;
16
+ this.status = options.status;
17
+ }
18
+ };
19
+ const statusOf = (error) => {
20
+ if (typeof error !== "object" || error === null) return;
21
+ switch (error._tag) {
22
+ case "BadRequest": return 400;
23
+ case "Unauthorized": return 401;
24
+ case "NotFound": return 404;
25
+ case "Conflict": return 409;
26
+ case "InternalError": return 500;
27
+ default: return;
28
+ }
29
+ };
30
+ const rejectedFields = (error) => {
31
+ if (error._tag !== "ParseError") return;
32
+ return effect_ParseResult.ArrayFormatter.formatErrorSync(error).map((issue) => issue.path.length > 0 ? `${issue.path.join(".")}: ${issue.message}` : issue.message).join("; ");
33
+ };
34
+ const messageOf = (error) => {
35
+ if (typeof error === "object" && error !== null) {
36
+ const rejected = rejectedFields(error);
37
+ if (rejected) return rejected;
38
+ const message = error.message;
39
+ if (typeof message === "string" && message.length > 0) return message;
40
+ const tag = error._tag;
41
+ if (typeof tag === "string") return tag;
42
+ }
43
+ return "The request failed.";
44
+ };
45
+ const asAnpordError = (error) => error instanceof AnpordError ? error : new AnpordError(messageOf(error), {
46
+ cause: error,
47
+ status: statusOf(error)
48
+ });
49
+ //#endregion
50
+ Object.defineProperty(exports, "AnpordError", {
51
+ enumerable: true,
52
+ get: function() {
53
+ return AnpordError;
54
+ }
55
+ });
56
+ Object.defineProperty(exports, "MissingApiKey", {
57
+ enumerable: true,
58
+ get: function() {
59
+ return MissingApiKey;
60
+ }
61
+ });
62
+ Object.defineProperty(exports, "asAnpordError", {
63
+ enumerable: true,
64
+ get: function() {
65
+ return asAnpordError;
66
+ }
67
+ });
@@ -0,0 +1,50 @@
1
+ import { ArrayFormatter } from "effect/ParseResult";
2
+ //#region src/client/errors.ts
3
+ var MissingApiKey = class extends Error {
4
+ name = "MissingApiKey";
5
+ constructor() {
6
+ super("No API key. Pass { apiKey } to the Anpord constructor or set ANPORD_API_KEY.");
7
+ }
8
+ };
9
+ var AnpordError = class extends Error {
10
+ name = "AnpordError";
11
+ status;
12
+ cause;
13
+ constructor(message, options) {
14
+ super(message);
15
+ this.cause = options.cause;
16
+ this.status = options.status;
17
+ }
18
+ };
19
+ const statusOf = (error) => {
20
+ if (typeof error !== "object" || error === null) return;
21
+ switch (error._tag) {
22
+ case "BadRequest": return 400;
23
+ case "Unauthorized": return 401;
24
+ case "NotFound": return 404;
25
+ case "Conflict": return 409;
26
+ case "InternalError": return 500;
27
+ default: return;
28
+ }
29
+ };
30
+ const rejectedFields = (error) => {
31
+ if (error._tag !== "ParseError") return;
32
+ return ArrayFormatter.formatErrorSync(error).map((issue) => issue.path.length > 0 ? `${issue.path.join(".")}: ${issue.message}` : issue.message).join("; ");
33
+ };
34
+ const messageOf = (error) => {
35
+ if (typeof error === "object" && error !== null) {
36
+ const rejected = rejectedFields(error);
37
+ if (rejected) return rejected;
38
+ const message = error.message;
39
+ if (typeof message === "string" && message.length > 0) return message;
40
+ const tag = error._tag;
41
+ if (typeof tag === "string") return tag;
42
+ }
43
+ return "The request failed.";
44
+ };
45
+ const asAnpordError = (error) => error instanceof AnpordError ? error : new AnpordError(messageOf(error), {
46
+ cause: error,
47
+ status: statusOf(error)
48
+ });
49
+ //#endregion
50
+ export { MissingApiKey as n, asAnpordError as r, AnpordError as t };
package/dist/index.cjs CHANGED
@@ -1,9 +1,35 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region src/index.ts
3
- /**
4
- * Placeholder release. The client lands in a future version — this exists so
5
- * the package name is reserved and consumers can pin something real.
6
- */
7
- const VERSION = "0.0.0";
2
+ const require_client = require("./client-Cno4LwRq.cjs");
3
+ const require_errors = require("./errors-C0E5A8fN.cjs");
4
+ let _effect_platform = require("@effect/platform");
5
+ let effect = require("effect");
6
+ //#region src/client/anpord.ts
7
+ const resolveApiKey = (provided) => {
8
+ const apiKey = provided ?? globalThis.process?.env?.ANPORD_API_KEY;
9
+ if (!apiKey) throw new require_errors.MissingApiKey();
10
+ return apiKey;
11
+ };
12
+ var Anpord = class {
13
+ prompts;
14
+ constructor(options = {}) {
15
+ const apiKey = resolveApiKey(options.apiKey);
16
+ const client = require_client.make({
17
+ apiKey: effect.Redacted.make(apiKey),
18
+ baseUrl: options.baseUrl ?? "https://api.anpord.com"
19
+ }).pipe(effect.Effect.provide(_effect_platform.FetchHttpClient.layer), effect.Effect.runSync);
20
+ this.prompts = promised(client.prompts);
21
+ }
22
+ };
23
+ const promised = (group) => Object.fromEntries(Object.entries(group).map(([method, run]) => [method, async (request) => {
24
+ const exit = await effect.Effect.runPromiseExit(run({ payload: request ?? {} }));
25
+ if (effect.Exit.isSuccess(exit)) return exit.value;
26
+ throw require_errors.asAnpordError(effect.Cause.failureOption(exit.cause).pipe(effect.Option.getOrElse(() => effect.Cause.squash(exit.cause))));
27
+ }]));
8
28
  //#endregion
9
- exports.VERSION = VERSION;
29
+ exports.Anpord = Anpord;
30
+ exports.AnpordApi = require_client.AnpordApi;
31
+ exports.AnpordError = require_errors.AnpordError;
32
+ exports.DEFAULT_BASE_URL = require_client.DEFAULT_BASE_URL;
33
+ exports.MissingApiKey = require_errors.MissingApiKey;
34
+ exports.layer = require_client.layer;
35
+ exports.make = require_client.make;