@ampless/backend 0.2.0-alpha.11 → 0.2.0-alpha.13

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.
@@ -627,17 +627,26 @@ async function validateBearer(plaintext) {
627
627
  );
628
628
  const row = res.Item;
629
629
  if (!row?.value) return null;
630
- let meta;
631
- try {
632
- meta = JSON.parse(row.value);
633
- } catch {
634
- console.error("[mcp-handler] could not parse token row", { hash });
630
+ const meta = decodeTokenMeta(row.value);
631
+ if (!meta) {
632
+ console.error("[mcp-handler] could not decode token row", { hash, valueType: typeof row.value });
635
633
  return null;
636
634
  }
637
635
  if (meta.revokedAt) return null;
638
636
  if (meta.expiresAt && new Date(meta.expiresAt).getTime() <= Date.now()) return null;
639
637
  return meta;
640
638
  }
639
+ function decodeTokenMeta(value) {
640
+ if (typeof value === "object") return value;
641
+ if (typeof value === "string") {
642
+ try {
643
+ return JSON.parse(value);
644
+ } catch {
645
+ return null;
646
+ }
647
+ }
648
+ return null;
649
+ }
641
650
  var cachedCtx = null;
642
651
  function makeContext(meta) {
643
652
  if (cachedCtx && cachedCtx.defaultSiteId === (meta.scope.siteId ?? "default")) {
package/dist/index.d.ts CHANGED
@@ -149,22 +149,6 @@ interface AmplessSchemaModelsOpts {
149
149
  * pattern as `AmplessAuthConfigOpts.postConfirmation`.
150
150
  */
151
151
  userAdminFunction?: unknown;
152
- /**
153
- * Optional Amplify `defineFunction` ref backing the MCP HTTP Lambda.
154
- * When supplied, the Post and PostTag models gain an `allow.resource(...)`
155
- * authorization clause granting the Lambda `query` + `mutate` access
156
- * via AppSync IAM auth. The existing group-based clauses stay intact —
157
- * this just adds a second principal so the Lambda can dispatch tool
158
- * calls under its own scoped role, with no Cognito identity or
159
- * shared API key involved.
160
- *
161
- * Phase 4 covers Post + PostTag only (the read/write surface for the
162
- * post CRUD tools). Media gets the same treatment in Phase 5 once
163
- * the presigned-PUT upload flow lands.
164
- *
165
- * Typed as `unknown` for the same reason as `userAdminFunction`.
166
- */
167
- mcpHandlerFunction?: unknown;
168
152
  }
169
153
  /**
170
154
  * The Ampless model + custom query definitions, returned as a plain
@@ -205,6 +189,44 @@ declare function amplessSchemaModels(a: any, opts?: AmplessSchemaModelsOpts): {
205
189
  * when there are no custom models.
206
190
  */
207
191
  declare function extendAmplessSchema(a: any, custom?: Record<string, any>, opts?: AmplessSchemaModelsOpts): any;
192
+ interface AmplessSchemaAuthorizationOpts {
193
+ /**
194
+ * Optional Amplify `defineFunction` ref for the MCP HTTP handler.
195
+ * When supplied, the schema gains `allow.resource(fn).to(['query',
196
+ * 'mutate'])` so the Lambda can sign AppSync requests with SigV4
197
+ * under its own IAM role (no Cognito identity / shared API key).
198
+ *
199
+ * Resource auth is currently only honoured at schema scope by
200
+ * `@aws-amplify/data-schema` (model-level `.authorization` callbacks
201
+ * destructure `resource` out of their `allow` parameter), so this
202
+ * grant applies broadly — every model the Lambda calls is reachable.
203
+ * That's wider than strictly necessary; the MCP tools' GraphQL
204
+ * operations narrow the effective surface to Post / PostTag in
205
+ * Phase 4 and Media in Phase 5.
206
+ *
207
+ * Typed as `unknown` for the same reason `userAdminFunction` /
208
+ * `mcpHandlerFunction` are in other helpers — `defineFunction`'s
209
+ * return type carries internal pnpm paths that don't survive
210
+ * declaration emit.
211
+ */
212
+ mcpHandlerFunction?: unknown;
213
+ }
214
+ /**
215
+ * Schema-level authorization rules for ampless. Pass the result into
216
+ * `a.schema({...}).authorization((allow) => [...])` in the user's
217
+ * `amplify/data/resource.ts`. When no Lambda function refs are
218
+ * supplied the function returns `[]`, so the schema stays unaffected.
219
+ *
220
+ * Usage:
221
+ *
222
+ * const schema = a.schema({
223
+ * ...amplessSchemaModels(a, { resolverPaths, userAdminFunction }),
224
+ * ...customSchemaModels(a),
225
+ * }).authorization((allow) => amplessSchemaAuthorization(allow, {
226
+ * mcpHandlerFunction: mcpHandler,
227
+ * }))
228
+ */
229
+ declare function amplessSchemaAuthorization(allow: any, opts?: AmplessSchemaAuthorizationOpts): unknown[];
208
230
  /**
209
231
  * Standard authorization modes for ampless. `userPool` is the default
210
232
  * (admin/editor access); the API key serves the public read endpoints
@@ -215,4 +237,4 @@ declare function extendAmplessSchema(a: any, custom?: Record<string, any>, opts?
215
237
  */
216
238
  declare const defaultAuthorizationModes: Parameters<typeof defineData>[0]['authorizationModes'];
217
239
 
218
- export { type AmplessAuthConfigOpts, type AmplessBackend, type AmplessResolverPaths, type AmplessSchemaModelsOpts, DEFAULT_RESOLVER_PATHS, type DefineAmplessBackendOpts, amplessAuthConfig, amplessSchemaModels, amplessStorageConfig, defaultAuthorizationModes, defineAmplessBackend, extendAmplessSchema };
240
+ export { type AmplessAuthConfigOpts, type AmplessBackend, type AmplessResolverPaths, type AmplessSchemaAuthorizationOpts, type AmplessSchemaModelsOpts, DEFAULT_RESOLVER_PATHS, type DefineAmplessBackendOpts, amplessAuthConfig, amplessSchemaAuthorization, amplessSchemaModels, amplessStorageConfig, defaultAuthorizationModes, defineAmplessBackend, extendAmplessSchema };
package/dist/index.js CHANGED
@@ -277,8 +277,7 @@ function amplessSchemaModels(a, opts = {}) {
277
277
  index("siteIdStatus").sortKeys(["publishedAt"]).name("bySiteIdStatus"),
278
278
  index("siteIdSlug").name("bySiteIdSlug")
279
279
  ]).authorization((allow) => [
280
- allow.groups(["ampless-admin", "ampless-editor"]),
281
- ...opts.mcpHandlerFunction ? [allow.resource(opts.mcpHandlerFunction).to(["query", "mutate"])] : []
280
+ allow.groups(["ampless-admin", "ampless-editor"])
282
281
  ]),
283
282
  Page: a.model({
284
283
  siteId: a.string().required(),
@@ -332,8 +331,7 @@ function amplessSchemaModels(a, opts = {}) {
332
331
  // Full tag list of the post (for chip rendering on tag pages).
333
332
  tags: a.string().array()
334
333
  }).identifier(["siteIdTag", "publishedAtPostId"]).authorization((allow) => [
335
- allow.groups(["ampless-admin", "ampless-editor"]),
336
- ...opts.mcpHandlerFunction ? [allow.resource(opts.mcpHandlerFunction).to(["query", "mutate"])] : []
334
+ allow.groups(["ampless-admin", "ampless-editor"])
337
335
  ]),
338
336
  // Generic key/value store. Two roles in one table:
339
337
  // - Site settings: PK = `siteconfig:{siteId}`, SK = dotted key
@@ -456,6 +454,13 @@ function extendAmplessSchema(a, custom, opts) {
456
454
  ...custom ?? {}
457
455
  });
458
456
  }
457
+ function amplessSchemaAuthorization(allow, opts = {}) {
458
+ const rules = [];
459
+ if (opts.mcpHandlerFunction) {
460
+ rules.push(allow.resource(opts.mcpHandlerFunction).to(["query", "mutate"]));
461
+ }
462
+ return rules;
463
+ }
459
464
  var defaultAuthorizationModes = {
460
465
  defaultAuthorizationMode: "userPool",
461
466
  apiKeyAuthorizationMode: { expiresInDays: 365 }
@@ -463,6 +468,7 @@ var defaultAuthorizationModes = {
463
468
  export {
464
469
  DEFAULT_RESOLVER_PATHS,
465
470
  amplessAuthConfig,
471
+ amplessSchemaAuthorization,
466
472
  amplessSchemaModels,
467
473
  amplessStorageConfig,
468
474
  defaultAuthorizationModes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ampless/backend",
3
- "version": "0.2.0-alpha.11",
3
+ "version": "0.2.0-alpha.13",
4
4
  "description": "Amplify Gen 2 backend factories for ampless: auth, data, storage, event processors, API key renewer",
5
5
  "license": "MIT",
6
6
  "type": "module",