neon 4.18.0 → 4.19.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/README.md +5 -0
- package/dist/analytics.js +25 -1
- package/dist/commands/bootstrap.js +5 -1
- package/dist/commands/init.js +10 -0
- package/dist/commands/mcp.js +2 -0
- package/dist/commands/plugins.js +2 -0
- package/dist/commands/skills.js +2 -0
- package/dist/commands/triggers.js +108 -33
- package/dist/config_template.js +17 -13
- package/dist/index.js +3 -9
- package/dist/utils/service_picker.js +5 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -610,6 +610,8 @@ export default defineConfig({
|
|
|
610
610
|
? Which Neon services should neon.ts declare? (space to toggle, enter to confirm) ›
|
|
611
611
|
◯ Managed Better Auth
|
|
612
612
|
Authentication with users and sessions stored in Postgres.
|
|
613
|
+
◯ Data API
|
|
614
|
+
PostgREST-compatible HTTP API. Also declares Auth; the default provider needs it.
|
|
613
615
|
◯ Functions
|
|
614
616
|
Long-running, without timeouts, and closer to your database.
|
|
615
617
|
◯ Object Storage
|
|
@@ -627,6 +629,9 @@ neon config init
|
|
|
627
629
|
# Declare services with no prompt
|
|
628
630
|
neon config init --services auth,functions,object-storage,ai-gateway
|
|
629
631
|
|
|
632
|
+
# Data API also writes auth: true (the default provider requires it)
|
|
633
|
+
neon config init --services data-api
|
|
634
|
+
|
|
630
635
|
# Repeat the flag instead, and shorten it — every services flag takes all three spellings
|
|
631
636
|
neon config init -s auth -s functions
|
|
632
637
|
|
package/dist/analytics.js
CHANGED
|
@@ -195,6 +195,30 @@ const trackEvent = (event, properties) => {
|
|
|
195
195
|
});
|
|
196
196
|
log.debug("Sent CLI event: %s", event);
|
|
197
197
|
};
|
|
198
|
+
let commandSuccessExtras = {};
|
|
199
|
+
const recordCommandSuccessExtras = (patch) => {
|
|
200
|
+
commandSuccessExtras = {
|
|
201
|
+
...commandSuccessExtras,
|
|
202
|
+
...patch
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
const recordScaffoldedTemplate = (templateId) => {
|
|
206
|
+
recordCommandSuccessExtras({ template: templateId });
|
|
207
|
+
};
|
|
208
|
+
const takeCommandSuccessExtras = () => {
|
|
209
|
+
const extras = commandSuccessExtras;
|
|
210
|
+
commandSuccessExtras = {};
|
|
211
|
+
return extras;
|
|
212
|
+
};
|
|
213
|
+
const commandSuccessProperties = (args) => ({
|
|
214
|
+
...getAnalyticsEventProperties(args),
|
|
215
|
+
projectId: args.projectId,
|
|
216
|
+
branchId: args.branchId,
|
|
217
|
+
accountId: args.accountId,
|
|
218
|
+
authMethod: args.authMethod,
|
|
219
|
+
authData: args.authData,
|
|
220
|
+
...takeCommandSuccessExtras()
|
|
221
|
+
});
|
|
198
222
|
const analyticsCommand = (args) => {
|
|
199
223
|
const command = args._.join(" ");
|
|
200
224
|
const raw = args._[0] !== "ask" || typeof args.prompt !== "string" ? command : `${command} ${args.prompt}`;
|
|
@@ -209,4 +233,4 @@ const getAnalyticsEventProperties = (args) => ({
|
|
|
209
233
|
githubEnvVars: getGithubEnvVars(process.env)
|
|
210
234
|
});
|
|
211
235
|
//#endregion
|
|
212
|
-
export { analyticsMiddleware, analyticsUserId, closeAnalytics, getAnalyticsEventProperties, getErrorAnalyticsEventProperties, initAnalyticsClientMiddleware, sendError, storedCredentialAttribution, telemetryCredential, trackEvent };
|
|
236
|
+
export { analyticsMiddleware, analyticsUserId, closeAnalytics, commandSuccessProperties, getAnalyticsEventProperties, getErrorAnalyticsEventProperties, initAnalyticsClientMiddleware, recordCommandSuccessExtras, recordScaffoldedTemplate, sendError, storedCredentialAttribution, takeCommandSuccessExtras, telemetryCredential, trackEvent };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "../_chunks/rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { isCi } from "../env.js";
|
|
3
3
|
import { log } from "../log.js";
|
|
4
|
+
import { recordCommandSuccessExtras, recordScaffoldedTemplate } from "../analytics.js";
|
|
4
5
|
import { t as credentialInputs } from "../_chunks/auth_selection-pitMFzDe.js";
|
|
5
6
|
import { getCliName } from "../utils/cli_name.js";
|
|
6
7
|
import { helpCsv, helpEpilogue } from "../utils/help_text.js";
|
|
@@ -114,8 +115,11 @@ const handler = async (props) => {
|
|
|
114
115
|
const targetDir = await resolveTargetDir(props, interactive, template);
|
|
115
116
|
ensureTargetUsable(targetDir, props.force);
|
|
116
117
|
await scaffold(template, targetDir);
|
|
118
|
+
recordScaffoldedTemplate(template.id);
|
|
117
119
|
printScaffolded(template, targetDir);
|
|
118
|
-
|
|
120
|
+
const result = await runPostScaffoldSteps(props, targetDir, interactive, template, named);
|
|
121
|
+
recordCommandSuccessExtras({ agent_setup: result.agentSetup });
|
|
122
|
+
return result;
|
|
119
123
|
};
|
|
120
124
|
/**
|
|
121
125
|
* The template list to choose from. When --template is given we try the
|
package/dist/commands/init.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "../_chunks/rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { log } from "../log.js";
|
|
3
3
|
import { contextBranch, readContextFile } from "../context.js";
|
|
4
|
+
import { recordCommandSuccessExtras } from "../analytics.js";
|
|
4
5
|
import { t as credentialInputs } from "../_chunks/auth_selection-pitMFzDe.js";
|
|
5
6
|
import { getCliName } from "../utils/cli_name.js";
|
|
6
7
|
import { deprecatedServiceMessage, parseServices, servicesFlagValue, servicesOption } from "../neon_services.js";
|
|
@@ -184,6 +185,12 @@ const noteTemplateKeepsShippedConfig = (config, services) => {
|
|
|
184
185
|
if (config === void 0 && services === void 0) return;
|
|
185
186
|
log.warning(INIT_TEMPLATE_KEEPS_CONFIG);
|
|
186
187
|
};
|
|
188
|
+
const recordInitSuccess = (kind, agentSetup) => {
|
|
189
|
+
recordCommandSuccessExtras({
|
|
190
|
+
init_kind: kind,
|
|
191
|
+
...agentSetup !== void 0 ? { agent_setup: agentSetup } : {}
|
|
192
|
+
});
|
|
193
|
+
};
|
|
187
194
|
const handler = async (props) => {
|
|
188
195
|
if (props.output === "json" || props.output === "yaml") throw new Error(`\`${getCliName()} init\` does not support --output. The commands it runs print their own output.`);
|
|
189
196
|
const cwd = props.cwd ?? process.cwd();
|
|
@@ -228,6 +235,7 @@ const handler = async (props) => {
|
|
|
228
235
|
...templateChoice.kind === "template" ? { id: templateChoice.id } : {}
|
|
229
236
|
}, linkInputs));
|
|
230
237
|
printNestedBootstrapDone(result, cwd, templateChoice.kind === "template" ? templateChoice.id : "default");
|
|
238
|
+
recordInitSuccess("empty-template", result?.agentSetup);
|
|
231
239
|
return;
|
|
232
240
|
}
|
|
233
241
|
if (templateChoice.kind === "ask") {
|
|
@@ -242,6 +250,7 @@ const handler = async (props) => {
|
|
|
242
250
|
useDefault: false
|
|
243
251
|
}, linkInputs));
|
|
244
252
|
printNestedBootstrapDone(result, cwd, picked.template.id);
|
|
253
|
+
recordInitSuccess("empty-template", result?.agentSetup);
|
|
245
254
|
return;
|
|
246
255
|
}
|
|
247
256
|
}
|
|
@@ -351,6 +360,7 @@ Run \`${getCliName()} env pull\` once resolved.`, message);
|
|
|
351
360
|
],
|
|
352
361
|
next: []
|
|
353
362
|
}));
|
|
363
|
+
recordInitSuccess(templateChoice.kind === "existing" ? "existing" : "empty-skip", agentSetup);
|
|
354
364
|
};
|
|
355
365
|
//#endregion
|
|
356
366
|
export { builder, command, describe, handler, initChildEnv, init_exports as t };
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "../_chunks/rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { log } from "../log.js";
|
|
3
3
|
import { readContextFile } from "../context.js";
|
|
4
|
+
import { recordCommandSuccessExtras } from "../analytics.js";
|
|
4
5
|
import { getCliName } from "../utils/cli_name.js";
|
|
5
6
|
import { helpCsv, helpEpilogue } from "../utils/help_text.js";
|
|
6
7
|
import { writer } from "../writer.js";
|
|
@@ -217,6 +218,7 @@ const handler = async (props) => {
|
|
|
217
218
|
if (minted) log.info("Minted API key %s (id %d, %s). Revoke with: %s", minted.name, minted.id, minted.projectId ? "project" : "account", mintedKeyRevokeCommand(minted));
|
|
218
219
|
if (plan.auth === "oauth") log.info("The agent will prompt for Neon sign-in on first use.");
|
|
219
220
|
if (failedAgents.length > 0) throw new Error(`Failed to write Neon MCP config for: ${failedAgents.join(", ")}.`);
|
|
221
|
+
recordCommandSuccessExtras({ scope: plan.scope });
|
|
220
222
|
};
|
|
221
223
|
//#endregion
|
|
222
224
|
export { builder, command, describe, handler, mcp_exports as t };
|
package/dist/commands/plugins.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "../_chunks/rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { log } from "../log.js";
|
|
3
|
+
import { recordCommandSuccessExtras } from "../analytics.js";
|
|
3
4
|
import { helpCsv, helpEpilogue } from "../utils/help_text.js";
|
|
4
5
|
import { writer } from "../writer.js";
|
|
5
6
|
import { noPassthrough } from "../utils/flags.js";
|
|
@@ -124,6 +125,7 @@ const handler = async (props) => {
|
|
|
124
125
|
});
|
|
125
126
|
out.end();
|
|
126
127
|
if (failed.length === 0) {
|
|
128
|
+
recordCommandSuccessExtras({ scope: plan.scope });
|
|
127
129
|
log.info(plan.scope === "project" ? "Installed the Neon plugin (project)." : "Installed the Neon plugin (user).");
|
|
128
130
|
return;
|
|
129
131
|
}
|
package/dist/commands/skills.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "../_chunks/rolldown-runtime-8H4AJuhK.js";
|
|
2
2
|
import { log } from "../log.js";
|
|
3
|
+
import { recordCommandSuccessExtras } from "../analytics.js";
|
|
3
4
|
import { helpCsv, helpEpilogue } from "../utils/help_text.js";
|
|
4
5
|
import { writer } from "../writer.js";
|
|
5
6
|
import { noPassthrough } from "../utils/flags.js";
|
|
@@ -160,6 +161,7 @@ const handler = async (props) => {
|
|
|
160
161
|
});
|
|
161
162
|
out.end();
|
|
162
163
|
if (failed.length === 0) {
|
|
164
|
+
recordCommandSuccessExtras({ scope: plan.scope });
|
|
163
165
|
log.info(plan.scope === "project" ? "Wrote skills in this directory." : "Wrote user-level skills.");
|
|
164
166
|
return;
|
|
165
167
|
}
|
|
@@ -27,17 +27,112 @@ async function withTriggerNotFound(triggerId, branchId, run) {
|
|
|
27
27
|
throw err;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
+
const TRIGGER_COMMON_FIELDS = [
|
|
31
|
+
"trigger_id",
|
|
32
|
+
"name",
|
|
33
|
+
"function_slug",
|
|
34
|
+
"function_path",
|
|
35
|
+
"enabled",
|
|
36
|
+
"inherited"
|
|
37
|
+
];
|
|
30
38
|
const TRIGGER_FIELDS = [
|
|
31
39
|
"trigger_id",
|
|
32
40
|
"name",
|
|
41
|
+
"type",
|
|
33
42
|
"function_slug",
|
|
34
43
|
"function_path",
|
|
35
44
|
"schedule",
|
|
45
|
+
"storage",
|
|
36
46
|
"enabled",
|
|
37
47
|
"inherited",
|
|
38
48
|
"next_run_at"
|
|
39
49
|
];
|
|
40
|
-
|
|
50
|
+
function storageMatch(config) {
|
|
51
|
+
return config.prefix === void 0 ? config.bucket_name : `${config.bucket_name} ${config.prefix}`;
|
|
52
|
+
}
|
|
53
|
+
function triggerTableRow(t) {
|
|
54
|
+
if (t.type === "schedule") return {
|
|
55
|
+
trigger_id: t.trigger_id,
|
|
56
|
+
name: t.name,
|
|
57
|
+
type: t.type,
|
|
58
|
+
function_slug: t.function_slug,
|
|
59
|
+
function_path: t.function_path,
|
|
60
|
+
schedule: t.schedule.cron,
|
|
61
|
+
storage: "",
|
|
62
|
+
enabled: t.enabled,
|
|
63
|
+
inherited: t.inherited,
|
|
64
|
+
next_run_at: t.next_run_at ?? ""
|
|
65
|
+
};
|
|
66
|
+
return {
|
|
67
|
+
trigger_id: t.trigger_id,
|
|
68
|
+
name: t.name,
|
|
69
|
+
type: t.type,
|
|
70
|
+
function_slug: t.function_slug,
|
|
71
|
+
function_path: t.function_path,
|
|
72
|
+
schedule: "",
|
|
73
|
+
storage: storageMatch(t.storage_object_created),
|
|
74
|
+
enabled: t.enabled,
|
|
75
|
+
inherited: t.inherited,
|
|
76
|
+
next_run_at: ""
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function writeTrigger(props, data, extra) {
|
|
80
|
+
if (props.output !== "table") {
|
|
81
|
+
writer(props).end(data, {
|
|
82
|
+
fields: TRIGGER_COMMON_FIELDS,
|
|
83
|
+
...extra
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const rows = Array.isArray(data) ? data.map(triggerTableRow) : triggerTableRow(data);
|
|
88
|
+
writer(props).end(rows, {
|
|
89
|
+
fields: TRIGGER_FIELDS,
|
|
90
|
+
...extra
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function enabledPatch(type, enabled) {
|
|
94
|
+
if (type === "schedule") return {
|
|
95
|
+
type: "schedule",
|
|
96
|
+
enabled
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
type: "storage_object_created",
|
|
100
|
+
enabled
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function updatePatch(type, props) {
|
|
104
|
+
if (type === "schedule") {
|
|
105
|
+
const body = { type: "schedule" };
|
|
106
|
+
if (props["function-slug"] !== void 0) body.function_slug = props["function-slug"];
|
|
107
|
+
if (props.name !== void 0) body.name = props.name;
|
|
108
|
+
if (props.cron !== void 0) body.schedule = { cron: props.cron };
|
|
109
|
+
if (props["function-path"] !== void 0) body.function_path = props["function-path"];
|
|
110
|
+
if (props.enabled !== void 0) body.enabled = props.enabled;
|
|
111
|
+
return body;
|
|
112
|
+
}
|
|
113
|
+
const body = { type: "storage_object_created" };
|
|
114
|
+
if (props["function-slug"] !== void 0) body.function_slug = props["function-slug"];
|
|
115
|
+
if (props.name !== void 0) body.name = props.name;
|
|
116
|
+
if (props["function-path"] !== void 0) body.function_path = props["function-path"];
|
|
117
|
+
if (props.enabled !== void 0) body.enabled = props.enabled;
|
|
118
|
+
return body;
|
|
119
|
+
}
|
|
120
|
+
function noFieldsToUpdateMessage(type) {
|
|
121
|
+
const flags = type === "schedule" ? [
|
|
122
|
+
"--function-slug",
|
|
123
|
+
"--name",
|
|
124
|
+
"--cron",
|
|
125
|
+
"--function-path",
|
|
126
|
+
"--enabled"
|
|
127
|
+
] : [
|
|
128
|
+
"--function-slug",
|
|
129
|
+
"--name",
|
|
130
|
+
"--function-path",
|
|
131
|
+
"--enabled"
|
|
132
|
+
];
|
|
133
|
+
const last = flags[flags.length - 1];
|
|
134
|
+
return `No fields to update. Pass at least one of ${flags.slice(0, -1).join(", ")}, or ${last}.`;
|
|
135
|
+
}
|
|
41
136
|
const command = "triggers";
|
|
42
137
|
const describe = "Manage function triggers";
|
|
43
138
|
const aliases = ["trigger"];
|
|
@@ -117,19 +212,12 @@ const handler = (args) => {
|
|
|
117
212
|
const list = async (props) => {
|
|
118
213
|
const branchId = await branchIdFromProps(props);
|
|
119
214
|
const { data } = await props.apiClient.listProjectBranchTriggers(props.projectId, branchId);
|
|
120
|
-
|
|
121
|
-
fields: TRIGGER_FIELDS,
|
|
122
|
-
renderColumns,
|
|
123
|
-
emptyMessage: "No triggers found on this branch."
|
|
124
|
-
});
|
|
215
|
+
writeTrigger(props, data.triggers, { emptyMessage: "No triggers found on this branch." });
|
|
125
216
|
};
|
|
126
217
|
const get = async (props) => {
|
|
127
218
|
const branchId = await branchIdFromProps(props);
|
|
128
219
|
const { data } = await withTriggerNotFound(props.id, branchId, () => props.apiClient.getProjectBranchTrigger(props.projectId, branchId, props.id));
|
|
129
|
-
|
|
130
|
-
fields: TRIGGER_FIELDS,
|
|
131
|
-
renderColumns
|
|
132
|
-
});
|
|
220
|
+
writeTrigger(props, data.trigger);
|
|
133
221
|
};
|
|
134
222
|
const create = async (props) => {
|
|
135
223
|
const branchId = await branchIdFromProps(props);
|
|
@@ -142,36 +230,23 @@ const create = async (props) => {
|
|
|
142
230
|
if (props["function-path"] !== void 0) body.function_path = props["function-path"];
|
|
143
231
|
if (props.enabled !== void 0) body.enabled = props.enabled;
|
|
144
232
|
const { data } = await retryOnLock(() => props.apiClient.createProjectBranchTrigger(props.projectId, branchId, body));
|
|
145
|
-
|
|
146
|
-
fields: TRIGGER_FIELDS,
|
|
147
|
-
renderColumns
|
|
148
|
-
});
|
|
233
|
+
writeTrigger(props, data.trigger);
|
|
149
234
|
};
|
|
150
235
|
const update = async (props) => {
|
|
151
236
|
const branchId = await branchIdFromProps(props);
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
if (props.
|
|
155
|
-
|
|
156
|
-
if (
|
|
157
|
-
if (props.enabled !== void 0) body.enabled = props.enabled;
|
|
158
|
-
if (Object.keys(body).filter((k) => k !== "type").length === 0) throw new Error("No fields to update. Pass at least one of --function-slug, --name, --cron, --function-path, or --enabled.");
|
|
237
|
+
const { data: existing } = await withTriggerNotFound(props.id, branchId, () => props.apiClient.getProjectBranchTrigger(props.projectId, branchId, props.id));
|
|
238
|
+
const trigger = existing.trigger;
|
|
239
|
+
if (props.cron !== void 0 && trigger.type !== "schedule") throw new Error(`Trigger ${props.id} is type ${trigger.type}; --cron applies to schedule triggers.`);
|
|
240
|
+
const body = updatePatch(trigger.type, props);
|
|
241
|
+
if (Object.keys(body).filter((k) => k !== "type").length === 0) throw new Error(noFieldsToUpdateMessage(trigger.type));
|
|
159
242
|
const { data } = await withTriggerNotFound(props.id, branchId, () => retryOnLock(() => props.apiClient.updateProjectBranchTrigger(props.projectId, branchId, props.id, body)));
|
|
160
|
-
|
|
161
|
-
fields: TRIGGER_FIELDS,
|
|
162
|
-
renderColumns
|
|
163
|
-
});
|
|
243
|
+
writeTrigger(props, data.trigger);
|
|
164
244
|
};
|
|
165
245
|
const setEnabled = async (props, enabled) => {
|
|
166
246
|
const branchId = await branchIdFromProps(props);
|
|
167
|
-
const { data } = await withTriggerNotFound(props.id, branchId, () =>
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
})));
|
|
171
|
-
writer(props).end(data.trigger, {
|
|
172
|
-
fields: TRIGGER_FIELDS,
|
|
173
|
-
renderColumns
|
|
174
|
-
});
|
|
247
|
+
const { data: existing } = await withTriggerNotFound(props.id, branchId, () => props.apiClient.getProjectBranchTrigger(props.projectId, branchId, props.id));
|
|
248
|
+
const { data } = await withTriggerNotFound(props.id, branchId, () => retryOnLock(() => props.apiClient.updateProjectBranchTrigger(props.projectId, branchId, props.id, enabledPatch(existing.trigger.type, enabled))));
|
|
249
|
+
writeTrigger(props, data.trigger);
|
|
175
250
|
};
|
|
176
251
|
const deleteTrigger = async (props) => {
|
|
177
252
|
const branchId = await branchIdFromProps(props);
|
package/dist/config_template.js
CHANGED
|
@@ -15,24 +15,21 @@ const REQUIRED_PACKAGES = [CONFIG_PACKAGE, ENV_PACKAGE];
|
|
|
15
15
|
/**
|
|
16
16
|
* The services `config init` can declare in the `neon.ts` it scaffolds — the subset of
|
|
17
17
|
* {@link NEON_SERVICES} a policy has a field for. {@link renderNeonConfig} owns the mapping
|
|
18
|
-
* from these names to the `neon.ts` fields (`aiGateway`, `buckets`).
|
|
18
|
+
* from these names to the `neon.ts` fields (`aiGateway`, `buckets`, `dataApi`).
|
|
19
19
|
*
|
|
20
|
-
* Postgres is absent because every branch has it, so there is nothing to declare.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* Postgres is absent because every branch has it, so there is nothing to declare. Selecting
|
|
21
|
+
* `data-api` also writes `auth: true`: the default Data API provider requires Neon Auth, and
|
|
22
|
+
* `defineConfig` type-errors the file without it.
|
|
23
23
|
*/
|
|
24
|
-
const CONFIG_INIT_SERVICES = NEON_SERVICES.filter((service) => service !== "postgres"
|
|
24
|
+
const CONFIG_INIT_SERVICES = NEON_SERVICES.filter((service) => service !== "postgres");
|
|
25
25
|
/**
|
|
26
26
|
* What `config init --services none` produces. One constant because it is both the help text
|
|
27
27
|
* and what tells the parser `none` is a value here — passing the literal at each call site
|
|
28
28
|
* lets the two drift into documenting something the parser does not accept.
|
|
29
29
|
*/
|
|
30
30
|
const CONFIG_INIT_NONE_MEANS = "the bare starter policy";
|
|
31
|
-
/** Why
|
|
32
|
-
const CONFIG_INIT_UNAVAILABLE = {
|
|
33
|
-
postgres: "every branch has Postgres, so a policy has nothing to declare for it",
|
|
34
|
-
"data-api": "enabling it with the default provider requires auth, so declare auth here and turn the Data API on with `neon data-api create`"
|
|
35
|
-
};
|
|
31
|
+
/** Why a policy cannot declare a real Neon service, for the refusal message. */
|
|
32
|
+
const CONFIG_INIT_UNAVAILABLE = { postgres: "every branch has Postgres, so a policy has nothing to declare for it" };
|
|
36
33
|
/** Slug, display name, and source path of the function scaffolded for `functions`. */
|
|
37
34
|
const FUNCTION_SLUG = "hello";
|
|
38
35
|
const FUNCTION_NAME = "Hello World";
|
|
@@ -70,13 +67,19 @@ const renderPreview = (services) => {
|
|
|
70
67
|
* policy — an explicit `auth: false`, no `preview` block, and a `branch` closure that gives
|
|
71
68
|
* new non-default branches a 7-day TTL — so the picker's "skip everything" answer and a
|
|
72
69
|
* non-interactive run produce the identical file.
|
|
70
|
+
*
|
|
71
|
+
* `data-api` writes `dataApi: true` and forces `auth: true`. The default provider is Neon
|
|
72
|
+
* Auth; omitting auth is a `defineConfig` type error rather than a deploy-time surprise.
|
|
73
73
|
*/
|
|
74
|
-
const renderNeonConfig = (services) =>
|
|
74
|
+
const renderNeonConfig = (services) => {
|
|
75
|
+
const auth = services.includes("auth") || services.includes("data-api");
|
|
76
|
+
const dataApi = services.includes("data-api") ? " dataApi: true,\n" : "";
|
|
77
|
+
return `import { defineConfig } from "${CONFIG_PACKAGE}/v1";
|
|
75
78
|
|
|
76
79
|
export default defineConfig({
|
|
77
80
|
// Declare your Neon services here
|
|
78
|
-
auth: ${
|
|
79
|
-
${renderPreview(services)} // Branch policy: per-branch tuning
|
|
81
|
+
auth: ${auth},
|
|
82
|
+
${dataApi}${renderPreview(services)} // Branch policy: per-branch tuning
|
|
80
83
|
branch: (branch) => {
|
|
81
84
|
if (branch.isDefault) {
|
|
82
85
|
// Default branch: no overrides, uses project defaults
|
|
@@ -92,6 +95,7 @@ ${renderPreview(services)} // Branch policy: per-branch tuning
|
|
|
92
95
|
},
|
|
93
96
|
});
|
|
94
97
|
`;
|
|
98
|
+
};
|
|
95
99
|
/** Render a scalar the way it has to appear in TypeScript source. */
|
|
96
100
|
const renderScalar = (value) => typeof value === "string" ? `"${value}"` : String(value);
|
|
97
101
|
/**
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { getAuthContext } from "./auth_context.js";
|
|
|
5
5
|
import { r as defaultDir } from "./_chunks/paths-DMq0Lt7a.js";
|
|
6
6
|
import { ensureConfigDir } from "./config.js";
|
|
7
7
|
import { currentContextFile, enrichFromContext } from "./context.js";
|
|
8
|
-
import { analyticsMiddleware, closeAnalytics,
|
|
8
|
+
import { analyticsMiddleware, closeAnalytics, commandSuccessProperties, initAnalyticsClientMiddleware, sendError, takeCommandSuccessExtras, trackEvent } from "./analytics.js";
|
|
9
9
|
import { NETWORK_ERROR_MESSAGE, isNetworkError, matchErrorCode } from "./errors.js";
|
|
10
10
|
import { AuthRefreshError, defaultClientID } from "./auth.js";
|
|
11
11
|
import { ensureAuth } from "./commands/auth.js";
|
|
@@ -187,14 +187,7 @@ async function handleError(msg, err, canRetry) {
|
|
|
187
187
|
const MAX_ATTEMPTS = 2;
|
|
188
188
|
while (attempts < MAX_ATTEMPTS) try {
|
|
189
189
|
const args = await builder.argv;
|
|
190
|
-
trackEvent("cli_command_success",
|
|
191
|
-
...getAnalyticsEventProperties(args),
|
|
192
|
-
projectId: args.projectId,
|
|
193
|
-
branchId: args.branchId,
|
|
194
|
-
accountId: args.accountId,
|
|
195
|
-
authMethod: args.authMethod,
|
|
196
|
-
authData: args.authData
|
|
197
|
-
});
|
|
190
|
+
trackEvent("cli_command_success", commandSuccessProperties(args));
|
|
198
191
|
if (args._.length === 0 || args.help) {
|
|
199
192
|
await showHelp(builder);
|
|
200
193
|
process.exit(0);
|
|
@@ -202,6 +195,7 @@ async function handleError(msg, err, canRetry) {
|
|
|
202
195
|
await closeAnalytics();
|
|
203
196
|
break;
|
|
204
197
|
} catch (err) {
|
|
198
|
+
takeCommandSuccessExtras();
|
|
205
199
|
attempts++;
|
|
206
200
|
if (!await handleError("", err, attempts < MAX_ATTEMPTS) || attempts >= MAX_ATTEMPTS) {
|
|
207
201
|
await closeAnalytics();
|
|
@@ -12,6 +12,11 @@ const CHOICES = [
|
|
|
12
12
|
title: "Managed Better Auth",
|
|
13
13
|
description: "Authentication with users and sessions stored in Postgres."
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
value: "data-api",
|
|
17
|
+
title: "Data API",
|
|
18
|
+
description: "PostgREST-compatible HTTP API. Also declares Auth; the default provider needs it."
|
|
19
|
+
},
|
|
15
20
|
{
|
|
16
21
|
value: "functions",
|
|
17
22
|
title: "Functions",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neon",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.19.0",
|
|
4
4
|
"description": "CLI tool for Neon, the cloud backend primitives built around Lakebase Postgres",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"neon",
|
|
@@ -63,9 +63,9 @@
|
|
|
63
63
|
"yaml": "^2.9.0",
|
|
64
64
|
"yargs": "17.7.2",
|
|
65
65
|
"yoctocolors": "^2.1.2",
|
|
66
|
-
"@neon/config": "1.
|
|
67
|
-
"@neon/sdk": "
|
|
68
|
-
"@neon/config
|
|
66
|
+
"@neon/config-runtime": "1.4.1",
|
|
67
|
+
"@neon/sdk": "6.0.0",
|
|
68
|
+
"@neon/config": "1.5.1"
|
|
69
69
|
},
|
|
70
70
|
"optionalDependencies": {
|
|
71
71
|
"@napi-rs/keyring": "1.3.0",
|
|
@@ -98,9 +98,9 @@
|
|
|
98
98
|
"typescript": "^5.9.0",
|
|
99
99
|
"vitest": "^3.0.9",
|
|
100
100
|
"@neon-internals/cli-core": "0.0.0",
|
|
101
|
-
"@neon-internals/env-core": "0.0.
|
|
101
|
+
"@neon-internals/env-core": "0.0.17",
|
|
102
102
|
"@neon/e2e-harness": "0.0.0",
|
|
103
|
-
"@neon/functions": "0.
|
|
103
|
+
"@neon/functions": "0.11.0"
|
|
104
104
|
},
|
|
105
105
|
"publishConfig": {
|
|
106
106
|
"access": "public",
|