@layers/amba 4.1.7 → 4.1.8

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.
package/dist/index.js CHANGED
@@ -597,12 +597,36 @@ const RESERVED_BINDING_PREFIXES = ["AMBA_", "EDGE_"];
597
597
  const RESERVED_BINDING_EXACT_NAMES = ["STORAGE", "EDGE_DB_PROXY"];
598
598
  const VALID_BINDING_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
599
599
  const MAX_BINDING_NAME_LENGTH = 64;
600
+ const INJECTED_BINDINGS_BY_PREFIX = {
601
+ AMBA_: [
602
+ "AMBA_API_URL",
603
+ "AMBA_PROJECT_ID",
604
+ "AMBA_INTERNAL_TOKEN",
605
+ "AMBA_AI_GATEWAY_URL"
606
+ ],
607
+ EDGE_: ["EDGE_HEADER_SIGNING_SECRET"]
608
+ };
609
+ const RESERVED_EXACT_PURPOSE = {
610
+ STORAGE: "the platform's built-in object-storage binding (env.STORAGE)",
611
+ EDGE_DB_PROXY: "a platform database binding"
612
+ };
613
+ const SUGGESTED_BINDING_PREFIX = "APP_";
614
+ function suggestedBindingName(name) {
615
+ const reservedPrefix = RESERVED_BINDING_PREFIXES.find((prefix) => name.startsWith(prefix)) ?? "";
616
+ const rest = name.slice(reservedPrefix.length);
617
+ const candidate = `${SUGGESTED_BINDING_PREFIX}${rest}`;
618
+ return rest.length > 0 && VALID_BINDING_NAME_RE.test(candidate) ? candidate : `${SUGGESTED_BINDING_PREFIX}SECRET`;
619
+ }
600
620
  /** Return why a binding name is reserved/invalid, or `null` if acceptable. */
601
621
  function getBindingReservationReason(name) {
602
622
  if (typeof name !== "string" || name.length === 0) return "Binding name must be a non-empty string";
603
623
  if (name.length > MAX_BINDING_NAME_LENGTH) return `Binding name must be at most ${MAX_BINDING_NAME_LENGTH} characters`;
604
- for (const prefix of RESERVED_BINDING_PREFIXES) if (name.startsWith(prefix)) return `Binding name starts with reserved prefix "${prefix}" (platform namespace)`;
605
- for (const exact of RESERVED_BINDING_EXACT_NAMES) if (name === exact) return `Binding name "${exact}" is reserved by a platform binding`;
624
+ for (const exact of RESERVED_BINDING_EXACT_NAMES) if (name === exact) return `"${exact}" is reserved for ${RESERVED_EXACT_PURPOSE[exact]}. Use your own name instead, for example "${suggestedBindingName(name)}"`;
625
+ for (const prefix of RESERVED_BINDING_PREFIXES) if (name.startsWith(prefix)) {
626
+ const injected = INJECTED_BINDINGS_BY_PREFIX[prefix];
627
+ if (injected.includes(name)) return `"${name}" is injected into every function by the platform; read env.${name} instead of setting it`;
628
+ return `names starting with "${prefix}" are reserved for values the platform injects into every function (${injected.join(", ")}). Use your own prefix instead, for example "${suggestedBindingName(name)}"`;
629
+ }
606
630
  if (!VALID_BINDING_NAME_RE.test(name)) return "Binding name must match /^[A-Z][A-Z0-9_]*$/ (uppercase ASCII, digits, underscore; must start with a letter)";
607
631
  return null;
608
632
  }
@@ -1300,6 +1324,8 @@ function generateSandboxEmail() {
1300
1324
  function generateSandboxPassword() {
1301
1325
  return randomBytes(24).toString("base64url");
1302
1326
  }
1327
+ /** Request header carrying AMBA_SIGNUP_TOKEN on the signup call. */
1328
+ const SIGNUP_TOKEN_HEADER = "X-Amba-Signup-Token";
1303
1329
  /**
1304
1330
  * POST the synthesized credentials at the public signup endpoint.
1305
1331
  *
@@ -1315,12 +1341,17 @@ function generateSandboxPassword() {
1315
1341
  */
1316
1342
  async function performSandboxSignup(req, options = {}) {
1317
1343
  const apiUrl = options.apiUrl ?? process.env["AMBA_API_URL"] ?? "https://api.amba.dev";
1318
- const res = await (options.fetchImpl ?? fetch)(`${apiUrl}/v1/auth/developer/signup`, {
1344
+ const fetchImpl = options.fetchImpl ?? fetch;
1345
+ const url = `${apiUrl}/v1/auth/developer/signup`;
1346
+ const headers = {
1347
+ "Content-Type": "application/json",
1348
+ "User-Agent": "amba-cli/sandbox"
1349
+ };
1350
+ const signupToken = process.env["AMBA_SIGNUP_TOKEN"]?.trim();
1351
+ if (signupToken) headers[SIGNUP_TOKEN_HEADER] = signupToken;
1352
+ const res = await fetchImpl(url, {
1319
1353
  method: "POST",
1320
- headers: {
1321
- "Content-Type": "application/json",
1322
- "User-Agent": "amba-cli/sandbox"
1323
- },
1354
+ headers,
1324
1355
  body: JSON.stringify({
1325
1356
  email: req.email,
1326
1357
  password: req.password,
@@ -9780,7 +9811,7 @@ async function diffConfigCommand(file = DEFAULT_BUNDLE_FILE, options = {}) {
9780
9811
  //#endregion
9781
9812
  //#region src/index.ts
9782
9813
  const program = new Command();
9783
- program.name("amba").description("amba — agent-native backend-as-a-service for mobile apps.").version("4.1.7");
9814
+ program.name("amba").description("amba — agent-native backend-as-a-service for mobile apps.").version("4.1.8");
9784
9815
  program.option("--token <pat>", "Use a Personal Access Token for headless / CI / agent use (overrides ~/.amba/credentials.json + AMBA_PAT env)");
9785
9816
  program.hook("preAction", (thisCommand) => {
9786
9817
  setBearerOverride(resolveTokenSource({
@@ -9985,7 +10016,7 @@ functionDomains.command("remove <name> <hostname>").description("Detach an exact
9985
10016
  await runAction(() => functionDomainsRemoveCommand(name, hostname));
9986
10017
  });
9987
10018
  const secrets = program.command("secrets").description("Function secrets (GCP canonical, Workers-Secret synced)");
9988
- secrets.command("set <name> [value]").description("Store a secret and queue its sync to your deployed function(s). Omit --function for a project-wide secret. Use --from-stdin to keep the value out of shell history.").option("--function <name>", "Function the secret binds to. OMIT this flag to set a PROJECT-WIDE secret — one value visible to every function in the project (and to any function deployed later). With it, the secret is scoped to just that function and overrides a same-name project-wide value. Use the same name as the entry passed to 'amba functions deploy'. Secrets may be set before the function is deployed; the sync drains once you deploy.").option("--env <env>", "'dev' | 'prod' — INFORMATIONAL ONLY. Both share one secret namespace per project. Use distinct secret names (e.g. STRIPE_KEY_DEV / STRIPE_KEY_PROD) or two amba projects for real env isolation.").option("--from-stdin", "Read the secret value from stdin instead of the positional arg. Mutually exclusive with <value>. Pipe in: `echo $KEY | amba secrets set NAME --from-stdin`.").action(async (name, value, opts) => {
10019
+ secrets.command("set <name> [value]").description("Store a secret and queue its sync to your deployed function(s). Omit --function for a project-wide secret. Use --from-stdin to keep the value out of shell history. Names starting with AMBA_ or EDGE_ are reserved for values every function already receives (env.AMBA_PROJECT_ID, env.AMBA_API_URL, env.AMBA_INTERNAL_TOKEN); use your own prefix, e.g. APP_CLIENT_KEY.").option("--function <name>", "Function the secret binds to. OMIT this flag to set a PROJECT-WIDE secret — one value visible to every function in the project (and to any function deployed later). With it, the secret is scoped to just that function and overrides a same-name project-wide value. Use the same name as the entry passed to 'amba functions deploy'. Secrets may be set before the function is deployed; the sync drains once you deploy.").option("--env <env>", "'dev' | 'prod' — INFORMATIONAL ONLY. Both share one secret namespace per project. Use distinct secret names (e.g. STRIPE_KEY_DEV / STRIPE_KEY_PROD) or two amba projects for real env isolation.").option("--from-stdin", "Read the secret value from stdin instead of the positional arg. Mutually exclusive with <value>. Pipe in: `echo $KEY | amba secrets set NAME --from-stdin`.").action(async (name, value, opts) => {
9989
10020
  await runAction(() => secretsSetCommand(name, value, {
9990
10021
  function: opts.function,
9991
10022
  env: opts.env ?? "dev",
package/dist/sandbox.d.ts CHANGED
@@ -146,6 +146,8 @@ export declare function generateSandboxEmail(): string;
146
146
  * accept "agent signup" with no password and we'd drop this entirely.
147
147
  */
148
148
  export declare function generateSandboxPassword(): string;
149
+ /** Request header carrying AMBA_SIGNUP_TOKEN on the signup call. */
150
+ export declare const SIGNUP_TOKEN_HEADER = "X-Amba-Signup-Token";
149
151
  /**
150
152
  * POST the synthesized credentials at the public signup endpoint.
151
153
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@layers/amba",
3
- "version": "4.1.7",
3
+ "version": "4.1.8",
4
4
  "description": "amba — agent-native backend-as-a-service. Functions, collections, storage, AI, email, queues, sites, and `amba ship` to take an Expo app live on the App Store + Google Play. `npx @layers/amba init` to start.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -49,8 +49,8 @@
49
49
  "tsdown": "^0.12.5",
50
50
  "typescript": "^5.8.3",
51
51
  "vitest": "^3.2.4",
52
- "@layers/amba-mcp": "4.0.10",
53
- "@layers/amba-shared": "4.0.5"
52
+ "@layers/amba-shared": "4.0.6",
53
+ "@layers/amba-mcp": "4.0.11"
54
54
  },
55
55
  "scripts": {
56
56
  "build": "tsdown && tsc --emitDeclarationOnly",