run402 1.35.3 → 1.36.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.
package/lib/agent.mjs CHANGED
@@ -41,6 +41,10 @@ async function contact(args) {
41
41
 
42
42
  export async function run(sub, args) {
43
43
  if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
44
+ if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
45
+ console.log(HELP);
46
+ process.exit(0);
47
+ }
44
48
  if (sub !== "contact") {
45
49
  console.error(`Unknown subcommand: ${sub}\n`);
46
50
  console.log(HELP);
package/lib/auth.mjs CHANGED
@@ -47,7 +47,11 @@ async function magicLink(args) {
47
47
 
48
48
  const res = await fetch(`${API}/auth/v1/magic-link`, {
49
49
  method: "POST",
50
- headers: { "Authorization": `Bearer ${p.anon_key}`, "Content-Type": "application/json" },
50
+ headers: {
51
+ "apikey": p.anon_key,
52
+ "Authorization": `Bearer ${p.anon_key}`,
53
+ "Content-Type": "application/json",
54
+ },
51
55
  body: JSON.stringify({ email, redirect_url: redirect }),
52
56
  });
53
57
  const data = await res.json();
@@ -67,7 +71,11 @@ async function verify(args) {
67
71
 
68
72
  const res = await fetch(`${API}/auth/v1/token?grant_type=magic_link`, {
69
73
  method: "POST",
70
- headers: { "Authorization": `Bearer ${p.anon_key}`, "Content-Type": "application/json" },
74
+ headers: {
75
+ "apikey": p.anon_key,
76
+ "Authorization": `Bearer ${p.anon_key}`,
77
+ "Content-Type": "application/json",
78
+ },
71
79
  body: JSON.stringify({ token }),
72
80
  });
73
81
  const data = await res.json();
@@ -111,7 +119,11 @@ async function settings(args) {
111
119
 
112
120
  const res = await fetch(`${API}/auth/v1/settings`, {
113
121
  method: "PATCH",
114
- headers: { "Authorization": `Bearer ${p.service_key}`, "Content-Type": "application/json" },
122
+ headers: {
123
+ "apikey": p.anon_key,
124
+ "Authorization": `Bearer ${p.service_key}`,
125
+ "Content-Type": "application/json",
126
+ },
115
127
  body: JSON.stringify({ allow_password_set: allowPasswordSet === "true" }),
116
128
  });
117
129
  const data = await res.json();
@@ -127,7 +139,10 @@ async function providers(args) {
127
139
  const p = findProject(projectId);
128
140
 
129
141
  const res = await fetch(`${API}/auth/v1/providers`, {
130
- headers: { "Authorization": `Bearer ${p.anon_key}` },
142
+ headers: {
143
+ "apikey": p.anon_key,
144
+ "Authorization": `Bearer ${p.anon_key}`,
145
+ },
131
146
  });
132
147
  const data = await res.json();
133
148
  if (!res.ok) {
@@ -139,6 +154,10 @@ async function providers(args) {
139
154
 
140
155
  export async function run(sub, args) {
141
156
  if (!sub || sub === "--help" || sub === "-h") { console.log(HELP); process.exit(0); }
157
+ if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
158
+ console.log(HELP);
159
+ process.exit(0);
160
+ }
142
161
  switch (sub) {
143
162
  case "magic-link": await magicLink(args); break;
144
163
  case "verify": await verify(args); break;
package/lib/blob.mjs CHANGED
@@ -427,6 +427,10 @@ export async function run(sub, args) {
427
427
  console.log(HELP);
428
428
  process.exit(0);
429
429
  }
430
+ if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
431
+ console.log(HELP);
432
+ process.exit(0);
433
+ }
430
434
  const defaultProject = process.env.RUN402_PROJECT ?? null;
431
435
  switch (sub) {
432
436
  case "put": await put(defaultProject, args); break;
package/lib/deploy.mjs CHANGED
@@ -94,8 +94,9 @@ Manifest format (JSON):
94
94
  "migrations": "CREATE TABLE items (...)",
95
95
  "migrations_file": "setup.sql",
96
96
  "rls": {
97
- "template": "public_read_write",
98
- "tables": [{ "table": "items" }]
97
+ "template": "public_read_write_UNRESTRICTED",
98
+ "tables": [{ "table": "items" }],
99
+ "i_understand_this_is_unrestricted": true
99
100
  },
100
101
  "secrets": [{ "key": "OPENAI_API_KEY", "value": "sk-..." }],
101
102
  "functions": [{
@@ -128,10 +129,20 @@ Manifest format (JSON):
128
129
  Paths are resolved relative to the manifest file's directory.
129
130
  Binary files (images, fonts, etc.) are auto-detected and base64-encoded.
130
131
 
131
- RLS templates:
132
- user_owns_rowsusers see only their rows (requires owner_column per table)
133
- public_read — anyone reads, authenticated users write
134
- public_read_write anyone reads and writes
132
+ RLS templates (prefer user_owns_rows for anything user-scoped):
133
+ user_owns_rows users see only their own rows (requires
134
+ owner_column per table; uuid columns get
135
+ index-friendly policies automatically)
136
+ public_read_authenticated_write anyone reads; any authenticated user can
137
+ INSERT/UPDATE/DELETE any row (not just
138
+ their own). For collaborative content
139
+ like shared boards or announcements.
140
+ public_read_write_UNRESTRICTED ⚠ fully open — anon_key can read AND
141
+ write any row. Only for intentionally
142
+ public tables (guestbooks, waitlists,
143
+ feedback forms). REQUIRES the manifest's
144
+ rls block to include
145
+ "i_understand_this_is_unrestricted": true.
135
146
 
136
147
  ⚠️ Without RLS, tables are read-only via anon_key. If your app writes
137
148
  data from the browser, you almost certainly need an rls block.
package/lib/functions.mjs CHANGED
@@ -212,6 +212,10 @@ async function deleteFunction(projectId, name) {
212
212
 
213
213
  export async function run(sub, args) {
214
214
  if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
215
+ if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
216
+ console.log(HELP);
217
+ process.exit(0);
218
+ }
215
219
  switch (sub) {
216
220
  case "deploy": await deploy(args[0], args[1], args.slice(2)); break;
217
221
  case "invoke": await invoke(args[0], args[1], args.slice(2)); break;
package/lib/message.mjs CHANGED
@@ -29,6 +29,10 @@ async function send(text) {
29
29
 
30
30
  export async function run(sub, args) {
31
31
  if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
32
+ if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
33
+ console.log(HELP);
34
+ process.exit(0);
35
+ }
32
36
  if (sub !== "send") {
33
37
  console.error(`Unknown subcommand: ${sub}\n`);
34
38
  console.log(HELP);
package/lib/projects.mjs CHANGED
@@ -36,7 +36,7 @@ Examples:
36
36
  run402 projects rest abc123 users "limit=10&select=id,name"
37
37
  run402 projects usage abc123
38
38
  run402 projects schema abc123
39
- run402 projects rls abc123 public_read '[{"table":"posts"}]'
39
+ run402 projects rls abc123 public_read_authenticated_write '[{"table":"posts"}]'
40
40
  run402 projects keys abc123
41
41
  run402 projects delete abc123
42
42
 
@@ -45,7 +45,11 @@ Notes:
45
45
  - Most commands that take <id> default to the active project if omitted
46
46
  - 'rest' uses PostgREST query syntax (table name + optional query string)
47
47
  - 'provision' requires a funded allowance — payment is automatic via x402
48
- - RLS templates: user_owns_rows, public_read, public_read_write
48
+ - RLS templates (prefer user_owns_rows for user-scoped data):
49
+ user_owns_rows users access only their own rows (requires owner_column)
50
+ public_read_authenticated_write anyone reads; any authenticated user writes any row
51
+ public_read_write_UNRESTRICTED fully open (anon_key writes); use 'run402 deploy' with a manifest
52
+ that includes "i_understand_this_is_unrestricted": true
49
53
  `;
50
54
 
51
55
  async function quote() {
@@ -179,20 +183,13 @@ async function use(projectId) {
179
183
 
180
184
  async function pin(projectId) {
181
185
  if (!projectId) { console.error(JSON.stringify({ status: "error", message: "Usage: run402 projects pin <project_id>" })); process.exit(1); }
182
- const authHeaders = allowanceAuthHeaders(`/projects/v1/admin/${projectId}/pin`);
186
+ const p = findProject(projectId);
183
187
  const res = await fetch(`${API}/projects/v1/admin/${projectId}/pin`, {
184
188
  method: "POST",
185
- headers: { ...authHeaders },
189
+ headers: { "Authorization": `Bearer ${p.service_key}` },
186
190
  });
187
191
  const data = await res.json();
188
- if (!res.ok) {
189
- if (res.status === 403 && data.admin_required) {
190
- console.error(JSON.stringify({ status: "error", message: "This command requires admin access." }));
191
- } else {
192
- console.error(JSON.stringify({ status: "error", http: res.status, ...data }));
193
- }
194
- process.exit(1);
195
- }
192
+ if (!res.ok) { console.error(JSON.stringify({ status: "error", http: res.status, ...data })); process.exit(1); }
196
193
  console.log(JSON.stringify(data, null, 2));
197
194
  }
198
195
 
@@ -239,6 +236,10 @@ export async function run(sub, args) {
239
236
  console.log(HELP);
240
237
  process.exit(0);
241
238
  }
239
+ if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
240
+ console.log(HELP);
241
+ process.exit(0);
242
+ }
242
243
  switch (sub) {
243
244
  case "quote": await quote(); break;
244
245
  case "provision": await provision(args); break;
package/lib/secrets.mjs CHANGED
@@ -68,6 +68,10 @@ async function deleteSecret(projectId, key) {
68
68
 
69
69
  export async function run(sub, args) {
70
70
  if (!sub || sub === '--help' || sub === '-h') { console.log(HELP); process.exit(0); }
71
+ if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
72
+ console.log(HELP);
73
+ process.exit(0);
74
+ }
71
75
  switch (sub) {
72
76
  case "set": await set(args[0], args[1], args.slice(2)); break;
73
77
  case "list": await list(args[0]); break;
@@ -44,7 +44,7 @@ async function register(args) {
44
44
 
45
45
  const res = await fetch(`${API}/email/v1/domains`, {
46
46
  method: "POST",
47
- headers: { apikey: p.service_key, "Content-Type": "application/json" },
47
+ headers: { Authorization: `Bearer ${p.service_key}`, "Content-Type": "application/json" },
48
48
  body: JSON.stringify({ domain }),
49
49
  });
50
50
  const data = await res.json();
@@ -60,7 +60,7 @@ async function status(args) {
60
60
  const p = findProject(projectId);
61
61
 
62
62
  const res = await fetch(`${API}/email/v1/domains`, {
63
- headers: { apikey: p.service_key },
63
+ headers: { Authorization: `Bearer ${p.service_key}` },
64
64
  });
65
65
  const data = await res.json();
66
66
  if (!res.ok) {
@@ -76,7 +76,7 @@ async function remove(args) {
76
76
 
77
77
  const res = await fetch(`${API}/email/v1/domains`, {
78
78
  method: "DELETE",
79
- headers: { apikey: p.service_key },
79
+ headers: { Authorization: `Bearer ${p.service_key}` },
80
80
  });
81
81
  const data = await res.json();
82
82
  if (!res.ok) {
@@ -104,7 +104,7 @@ async function inboundToggle(action, args) {
104
104
  const method = action === "enable" ? "POST" : "DELETE";
105
105
  const res = await fetch(`${API}/email/v1/domains/inbound`, {
106
106
  method,
107
- headers: { apikey: p.service_key, "Content-Type": "application/json" },
107
+ headers: { Authorization: `Bearer ${p.service_key}`, "Content-Type": "application/json" },
108
108
  body: JSON.stringify({ domain }),
109
109
  });
110
110
  const data = await res.json();
package/lib/service.mjs CHANGED
@@ -32,6 +32,10 @@ async function fetchAndEmit(path) {
32
32
 
33
33
  export async function run(sub, args) {
34
34
  if (!sub || sub === "--help" || sub === "-h") { console.log(HELP); process.exit(0); }
35
+ if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
36
+ console.log(HELP);
37
+ process.exit(0);
38
+ }
35
39
  switch (sub) {
36
40
  case "status":
37
41
  await fetchAndEmit("/status");
package/lib/tier.mjs CHANGED
@@ -55,6 +55,10 @@ export async function run(sub, args) {
55
55
  console.log(HELP);
56
56
  process.exit(0);
57
57
  }
58
+ if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) {
59
+ console.log(HELP);
60
+ process.exit(0);
61
+ }
58
62
  switch (sub) {
59
63
  case "status": await status(); break;
60
64
  case "set": await set(args[0]); break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "1.35.3",
3
+ "version": "1.36.0",
4
4
  "description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 and MPP micropayments.",
5
5
  "type": "module",
6
6
  "bin": {