@fragno-dev/api-fragment 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/LICENSE.md +16 -0
  2. package/README.md +249 -2
  3. package/dist/browser/client/client-3ZV9sw3i.js +2580 -0
  4. package/dist/browser/client/client-3ZV9sw3i.js.map +1 -0
  5. package/dist/browser/client/client-DPjmoaJQ.d.ts +711 -0
  6. package/dist/browser/client/client-DPjmoaJQ.d.ts.map +1 -0
  7. package/dist/browser/client/client.d.ts +1645 -0
  8. package/dist/browser/client/client.d.ts.map +1 -0
  9. package/dist/browser/client/client.js +2 -0
  10. package/dist/browser/client/react.d.ts +1665 -0
  11. package/dist/browser/client/react.d.ts.map +1 -0
  12. package/dist/browser/client/react.js +194 -0
  13. package/dist/browser/client/react.js.map +1 -0
  14. package/dist/browser/client/solid.d.ts +1668 -0
  15. package/dist/browser/client/solid.d.ts.map +1 -0
  16. package/dist/browser/client/solid.js +129 -0
  17. package/dist/browser/client/solid.js.map +1 -0
  18. package/dist/browser/client/svelte.d.ts +1668 -0
  19. package/dist/browser/client/svelte.d.ts.map +1 -0
  20. package/dist/browser/client/svelte.js +131 -0
  21. package/dist/browser/client/svelte.js.map +1 -0
  22. package/dist/browser/client/vanilla.d.ts +1695 -0
  23. package/dist/browser/client/vanilla.d.ts.map +1 -0
  24. package/dist/browser/client/vanilla.js +159 -0
  25. package/dist/browser/client/vanilla.js.map +1 -0
  26. package/dist/browser/client/vue.d.ts +1668 -0
  27. package/dist/browser/client/vue.d.ts.map +1 -0
  28. package/dist/browser/client/vue.js +127 -0
  29. package/dist/browser/client/vue.js.map +1 -0
  30. package/dist/browser/client-D4NnY-zV.d.ts +713 -0
  31. package/dist/browser/client-D4NnY-zV.d.ts.map +1 -0
  32. package/dist/browser/client-DQE0c7GI.d.ts +711 -0
  33. package/dist/browser/client-DQE0c7GI.d.ts.map +1 -0
  34. package/dist/browser/index.d.ts +3130 -0
  35. package/dist/browser/index.d.ts.map +1 -0
  36. package/dist/browser/index.js +2 -0
  37. package/dist/browser/src-BrYPVbAN.js +2404 -0
  38. package/dist/browser/src-BrYPVbAN.js.map +1 -0
  39. package/dist/browser/src-t-4wp9-f.js +2400 -0
  40. package/dist/browser/src-t-4wp9-f.js.map +1 -0
  41. package/dist/node/api-types.d.ts +731 -0
  42. package/dist/node/api-types.d.ts.map +1 -0
  43. package/dist/node/api-types.js +281 -0
  44. package/dist/node/api-types.js.map +1 -0
  45. package/dist/node/crypto.d.ts +6 -0
  46. package/dist/node/crypto.d.ts.map +1 -0
  47. package/dist/node/crypto.js +103 -0
  48. package/dist/node/crypto.js.map +1 -0
  49. package/dist/node/definition.d.ts +638 -0
  50. package/dist/node/definition.d.ts.map +1 -0
  51. package/dist/node/definition.js +315 -0
  52. package/dist/node/definition.js.map +1 -0
  53. package/dist/node/oauth.js +124 -0
  54. package/dist/node/oauth.js.map +1 -0
  55. package/dist/node/routes.d.ts +1585 -0
  56. package/dist/node/routes.d.ts.map +1 -0
  57. package/dist/node/routes.js +1100 -0
  58. package/dist/node/routes.js.map +1 -0
  59. package/dist/node/schema.d.ts +99 -0
  60. package/dist/node/schema.d.ts.map +1 -0
  61. package/dist/node/schema.js +16 -0
  62. package/dist/node/schema.js.map +1 -0
  63. package/dist/node/server.d.ts +1585 -0
  64. package/dist/node/server.d.ts.map +1 -0
  65. package/dist/node/server.js +12 -0
  66. package/dist/node/server.js.map +1 -0
  67. package/dist/node/services.d.ts +10 -0
  68. package/dist/node/services.d.ts.map +1 -0
  69. package/dist/node/services.js +304 -0
  70. package/dist/node/services.js.map +1 -0
  71. package/dist/node/webhooks/auth.d.ts +133 -0
  72. package/dist/node/webhooks/auth.d.ts.map +1 -0
  73. package/dist/node/webhooks/auth.js +268 -0
  74. package/dist/node/webhooks/auth.js.map +1 -0
  75. package/dist/node/webhooks/verification.d.ts +102 -0
  76. package/dist/node/webhooks/verification.d.ts.map +1 -0
  77. package/dist/node/webhooks/verification.js +119 -0
  78. package/dist/node/webhooks/verification.js.map +1 -0
  79. package/package.json +136 -3
package/LICENSE.md ADDED
@@ -0,0 +1,16 @@
1
+ Copyright 2025 - present "ReJot Nederland B.V.", and individual contributors.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
4
+ associated documentation files (the “Software”), to deal in the Software without restriction,
5
+ including without limitation the rights to use, copy, modify, merge, publish, distribute,
6
+ sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
7
+ furnished to do so, subject to the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be included in all copies or substantial
10
+ portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
13
+ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
15
+ OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,250 @@
1
- # Temporary Holding Version
1
+ # api-fragment
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ `@fragno-dev/api-fragment` is a Fragno fragment for configuring outbound HTTP API connections and
4
+ executing authenticated requests through server-side routes.
5
+
6
+ ## Auth modes
7
+
8
+ - `none`
9
+ - static bearer token
10
+ - OAuth 2.0 authorization-code flow with PKCE
11
+ - OAuth 2.0 client-credentials flow
12
+
13
+ ## Server setup
14
+
15
+ ```ts
16
+ import { createApiFragment } from "@fragno-dev/api-fragment/server";
17
+
18
+ const oauthRedirectUri = "https://app.example.com/api/integrations/oauth/callback";
19
+ const api = createApiFragment(
20
+ {
21
+ allowedBaseUrls: (url) => url.hostname.endsWith(".example.com"),
22
+ allowedOAuthRedirectUris: (url) => url.toString() === oauthRedirectUri,
23
+ onConnectionReadinessChanged: async ({ connectionId, ready }) => {
24
+ console.log("API connection readiness changed", connectionId, ready);
25
+ },
26
+ },
27
+ fragnoConfig,
28
+ );
29
+ ```
30
+
31
+ Always provide `allowedBaseUrls` in production so users cannot configure arbitrary server-side
32
+ request targets. OAuth start is denied unless `allowedOAuthRedirectUris` explicitly accepts the
33
+ callback URL.
34
+
35
+ ## Client usage
36
+
37
+ ```ts
38
+ import { createApiFragmentClient } from "@fragno-dev/api-fragment/react";
39
+
40
+ const api = createApiFragmentClient();
41
+
42
+ await api.createConnection.mutate(
43
+ {
44
+ baseUrl: "https://api.example.com",
45
+ auth: { type: "none" },
46
+ },
47
+ { pathParams: { slug: "example" } },
48
+ );
49
+ ```
50
+
51
+ ## Routes
52
+
53
+ Connection management:
54
+
55
+ - `PUT /connections/:slug` - create a connection with an explicit slug.
56
+ - `GET /connections` - list configured connections.
57
+ - `GET /connections/:slug` - read one connection.
58
+ - `DELETE /connections/:slug` - delete connection, auth secrets, and pending OAuth state.
59
+
60
+ Auth:
61
+
62
+ - `GET /connections/:slug/auth/status`
63
+ - `POST /connections/:slug/auth/token` - store or replace a bearer token.
64
+ - `POST /connections/:slug/auth/oauth/start` - start authorization-code + PKCE with an explicit
65
+ `redirectUri` query parameter.
66
+ - `GET /oauth/callback` - complete authorization-code + PKCE.
67
+ - `DELETE /connections/:slug/auth`
68
+
69
+ Requests:
70
+
71
+ - `POST /connections/:slug/request` - execute an HTTP request against the configured `baseUrl`.
72
+
73
+ Webhook endpoints:
74
+
75
+ - `PUT /webhooks/endpoints/:endpointId` - create or replace an endpoint.
76
+ - `GET /webhooks/endpoints/:endpointId/events` - answer configured GET verification challenges.
77
+ - `POST /webhooks/endpoints/:endpointId/events` - answer configured POST verification challenges or
78
+ accept a delivery.
79
+
80
+ Each endpoint's `deliveries` reports the last accepted request (a delivery or an answered challenge)
81
+ and the last rejected one with its error code. Any configuration write clears both, so they describe
82
+ only the current configuration. Rejections need no credentials, so anyone with the URL can record
83
+ one; treat them as diagnostics.
84
+
85
+ The request route only accepts relative paths. Caller-provided `Authorization` headers are ignored
86
+ and replaced with stored connection auth.
87
+
88
+ ## Bearer auth
89
+
90
+ ```ts
91
+ await api.createConnection.mutate(
92
+ {
93
+ baseUrl: "https://api.example.com",
94
+ auth: { type: "none" },
95
+ },
96
+ { pathParams: { slug: "example" } },
97
+ );
98
+
99
+ await api.setBearerToken.mutate({ token: "..." }, { pathParams: { slug: "example" } });
100
+ ```
101
+
102
+ ## Client credentials auth
103
+
104
+ ```ts
105
+ await api.createConnection.mutate(
106
+ {
107
+ baseUrl: "https://api.example.com",
108
+ auth: {
109
+ type: "client_credentials",
110
+ tokenEndpoint: "https://auth.example.com/oauth/token",
111
+ clientId: "...",
112
+ clientSecret: "...",
113
+ tokenEndpointAuthMethod: "client_secret_basic",
114
+ scopes: ["read"],
115
+ },
116
+ },
117
+ { pathParams: { slug: "machine" } },
118
+ );
119
+ ```
120
+
121
+ The fragment acquires a token on the first API request, stores it with expiry, reuses it while
122
+ valid, and refreshes it when it is close to expiring.
123
+
124
+ ## OAuth authorization code auth
125
+
126
+ ```ts
127
+ await api.createConnection.mutate(
128
+ {
129
+ baseUrl: "https://api.example.com",
130
+ auth: {
131
+ type: "oauth",
132
+ authorizationEndpoint: "https://auth.example.com/oauth/authorize",
133
+ tokenEndpoint: "https://auth.example.com/oauth/token",
134
+ clientId: "...",
135
+ clientSecret: "...",
136
+ tokenEndpointAuthMethod: "client_secret_basic",
137
+ scopes: ["read"],
138
+ },
139
+ },
140
+ { pathParams: { slug: "oauth-api" } },
141
+ );
142
+
143
+ const start = await api.startOAuth.mutate(
144
+ {},
145
+ {
146
+ pathParams: { slug: "oauth-api" },
147
+ query: { redirectUri: oauthRedirectUri },
148
+ },
149
+ );
150
+ window.location.href = start.authorizationUrl;
151
+ ```
152
+
153
+ The callback route stores access/refresh tokens; when the connection was not ready before, it
154
+ triggers `onConnectionReadinessChanged` with `ready: true`.
155
+
156
+ ## Executing requests
157
+
158
+ ```ts
159
+ const response = await api.request.mutate(
160
+ {
161
+ method: "GET",
162
+ path: "/v1/profile",
163
+ query: { include: "teams" },
164
+ },
165
+ { pathParams: { slug: "oauth-api" } },
166
+ );
167
+ ```
168
+
169
+ Response bodies are parsed as JSON when the upstream response has a JSON content type. Other
170
+ responses are returned as text. Binary responses are out of scope for the MVP.
171
+
172
+ ## Webhook verification challenges
173
+
174
+ Webhook verification runs after endpoint authentication and before delivery ID extraction. A matched
175
+ challenge returns synchronously and does not trigger `onWebhookReceived`.
176
+
177
+ ```ts
178
+ await api.createWebhookEndpoint.mutate(
179
+ {
180
+ name: "Slack",
181
+ status: "active",
182
+ verification: {
183
+ type: "challenge",
184
+ method: "POST",
185
+ when: {
186
+ type: "equals",
187
+ source: { type: "jsonBodyPath", path: ["type"] },
188
+ value: "url_verification",
189
+ },
190
+ response: {
191
+ type: "echoText",
192
+ source: { type: "jsonBodyPath", path: ["challenge"] },
193
+ },
194
+ },
195
+ deliveryIdentity: { type: "jsonBodyPath", path: ["event_id"] },
196
+ auth: {
197
+ type: "hmac",
198
+ secret: "signing-secret",
199
+ algorithm: "sha256",
200
+ signature: {
201
+ location: "header",
202
+ name: "x-slack-signature",
203
+ encoding: "hex",
204
+ prefix: "v0=",
205
+ },
206
+ signedPayload: {
207
+ type: "timestampedBody",
208
+ prefix: "v0:",
209
+ timestampHeader: "x-slack-request-timestamp",
210
+ delimiter: ":",
211
+ toleranceSeconds: 300,
212
+ },
213
+ },
214
+ },
215
+ { pathParams: { endpointId: "slack" } },
216
+ );
217
+ ```
218
+
219
+ Request value sources can read a header, query parameter, or JSON body path. Challenge predicates
220
+ can require that a value is present or equals a configured string. `echoText` responds with the
221
+ selected value as `text/plain`.
222
+
223
+ ## Hooks
224
+
225
+ - `onConnectionChanged` receives `{ connectionId, connection }`.
226
+ - `onConnectionDeleted` receives `{ connectionId, previous }`.
227
+ - `onConnectionReadinessChanged` receives `{ connectionId, ready }` when a write changes whether
228
+ stored auth can authorize requests: on creation, and afterwards whenever credentials, consent, or
229
+ token changes flip readiness. It also fires when an access token without a refresh token expires.
230
+ - `onWebhookEndpointChanged` receives `{ change: "created", endpointId, endpoint }`,
231
+ `{ change: "updated", endpointId, endpoint, previousStatus }`, or
232
+ `{ change: "deleted", endpointId }`. Compare `previousStatus` with `endpoint.status` to tell
233
+ whether a write changed if the endpoint accepts deliveries.
234
+ - `onWebhookReceived` receives the authenticated webhook payload and its derived delivery ID.
235
+
236
+ Durable hook callbacks, including `onWebhookReceived`, may execute concurrently and may complete out
237
+ of delivery order. Use the delivery ID for idempotency and use an upstream sequence or version when
238
+ the provider's event order affects state.
239
+
240
+ Hook callbacks receive the durable hook context as their second argument, including
241
+ `idempotencyKey`, `hookId`, retry metadata, and transaction access.
242
+
243
+ ## Security notes
244
+
245
+ - Use `allowedBaseUrls` in production to avoid SSRF.
246
+ - Request paths must be relative; absolute request URLs are rejected.
247
+ - Stored auth replaces caller-provided `Authorization` headers.
248
+ - Secrets and tokens are stored in the fragment database as JSON/plaintext for MVP.
249
+ - OAuth state is one-time use and expires after 10 minutes.
250
+ - Do not log secret payloads, authorization headers, refresh tokens, or token endpoint responses.