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 +4 -0
- package/lib/auth.mjs +23 -4
- package/lib/blob.mjs +4 -0
- package/lib/deploy.mjs +17 -6
- package/lib/functions.mjs +4 -0
- package/lib/message.mjs +4 -0
- package/lib/projects.mjs +13 -12
- package/lib/secrets.mjs +4 -0
- package/lib/sender-domain.mjs +4 -4
- package/lib/service.mjs +4 -0
- package/lib/tier.mjs +4 -0
- package/package.json +1 -1
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: {
|
|
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: {
|
|
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: {
|
|
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: {
|
|
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": "
|
|
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_rows
|
|
133
|
-
|
|
134
|
-
|
|
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
|
|
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
|
|
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
|
|
186
|
+
const p = findProject(projectId);
|
|
183
187
|
const res = await fetch(`${API}/projects/v1/admin/${projectId}/pin`, {
|
|
184
188
|
method: "POST",
|
|
185
|
-
headers: {
|
|
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;
|
package/lib/sender-domain.mjs
CHANGED
|
@@ -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: {
|
|
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: {
|
|
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: {
|
|
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: {
|
|
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