@semilayer/cli 1.1.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/dist/auth-config-3MWVCUTJ.js +117 -0
- package/dist/auth-config-3MWVCUTJ.js.map +1 -0
- package/dist/billing-OY5GJP5X.js +265 -0
- package/dist/billing-OY5GJP5X.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +49 -0
- package/dist/bin.js.map +1 -0
- package/dist/chunk-7TA63VHV.js +38 -0
- package/dist/chunk-7TA63VHV.js.map +1 -0
- package/dist/chunk-ALA4X7UU.js +19 -0
- package/dist/chunk-ALA4X7UU.js.map +1 -0
- package/dist/chunk-NIDLPHWY.js +53 -0
- package/dist/chunk-NIDLPHWY.js.map +1 -0
- package/dist/chunk-QMF7LD67.js +39 -0
- package/dist/chunk-QMF7LD67.js.map +1 -0
- package/dist/chunk-QXIVJY7K.js +56 -0
- package/dist/chunk-QXIVJY7K.js.map +1 -0
- package/dist/chunk-T3UROBMA.js +169 -0
- package/dist/chunk-T3UROBMA.js.map +1 -0
- package/dist/chunk-WZYOSGN3.js +88 -0
- package/dist/chunk-WZYOSGN3.js.map +1 -0
- package/dist/config-DACYO7JC.js +103 -0
- package/dist/config-DACYO7JC.js.map +1 -0
- package/dist/dev-R3AZSONQ.js +57 -0
- package/dist/dev-R3AZSONQ.js.map +1 -0
- package/dist/envs-RNZQ3OQP.js +105 -0
- package/dist/envs-RNZQ3OQP.js.map +1 -0
- package/dist/export-YRFR3JH2.js +81 -0
- package/dist/export-YRFR3JH2.js.map +1 -0
- package/dist/generate-QUETX3TN.js +41 -0
- package/dist/generate-QUETX3TN.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/init-TWJAGUN3.js +187 -0
- package/dist/init-TWJAGUN3.js.map +1 -0
- package/dist/keys-JBKCYKJU.js +111 -0
- package/dist/keys-JBKCYKJU.js.map +1 -0
- package/dist/lenses-VZSDFH3D.js +51 -0
- package/dist/lenses-VZSDFH3D.js.map +1 -0
- package/dist/login-BZ6ZPFHC.js +119 -0
- package/dist/login-BZ6ZPFHC.js.map +1 -0
- package/dist/logout-VMPRV62T.js +38 -0
- package/dist/logout-VMPRV62T.js.map +1 -0
- package/dist/members-DVE5FDLZ.js +110 -0
- package/dist/members-DVE5FDLZ.js.map +1 -0
- package/dist/observe-W346RZBX.js +149 -0
- package/dist/observe-W346RZBX.js.map +1 -0
- package/dist/orgs-YA3TVA3T.js +67 -0
- package/dist/orgs-YA3TVA3T.js.map +1 -0
- package/dist/pause-GQ6PKBUA.js +50 -0
- package/dist/pause-GQ6PKBUA.js.map +1 -0
- package/dist/projects-DMA2AXH3.js +107 -0
- package/dist/projects-DMA2AXH3.js.map +1 -0
- package/dist/push-3ZK3W2AC.js +145 -0
- package/dist/push-3ZK3W2AC.js.map +1 -0
- package/dist/resume-KVRPLXZZ.js +50 -0
- package/dist/resume-KVRPLXZZ.js.map +1 -0
- package/dist/run-IR5B4AE3.js +375 -0
- package/dist/run-IR5B4AE3.js.map +1 -0
- package/dist/sources-S52HUWRK.js +170 -0
- package/dist/sources-S52HUWRK.js.map +1 -0
- package/dist/status-AUECH6RX.js +130 -0
- package/dist/status-AUECH6RX.js.map +1 -0
- package/dist/stream-V7RGHTPR.js +344 -0
- package/dist/stream-V7RGHTPR.js.map +1 -0
- package/dist/sync-NRTC3WX4.js +68 -0
- package/dist/sync-NRTC3WX4.js.map +1 -0
- package/dist/whoami-EQGW6V5D.js +50 -0
- package/dist/whoami-EQGW6V5D.js.map +1 -0
- package/dist/wizard-QLAR33T2.js +306 -0
- package/dist/wizard-QLAR33T2.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadContext
|
|
4
|
+
} from "./chunk-QMF7LD67.js";
|
|
5
|
+
import {
|
|
6
|
+
confirm,
|
|
7
|
+
input
|
|
8
|
+
} from "./chunk-QXIVJY7K.js";
|
|
9
|
+
import {
|
|
10
|
+
createApiClient
|
|
11
|
+
} from "./chunk-T3UROBMA.js";
|
|
12
|
+
import "./chunk-7TA63VHV.js";
|
|
13
|
+
import {
|
|
14
|
+
bold,
|
|
15
|
+
dim,
|
|
16
|
+
error,
|
|
17
|
+
info,
|
|
18
|
+
label,
|
|
19
|
+
newline,
|
|
20
|
+
success
|
|
21
|
+
} from "./chunk-WZYOSGN3.js";
|
|
22
|
+
|
|
23
|
+
// src/commands/auth-config.ts
|
|
24
|
+
import { defineCommand } from "citty";
|
|
25
|
+
async function requireContext() {
|
|
26
|
+
const ctx = await loadContext();
|
|
27
|
+
if (!ctx) {
|
|
28
|
+
error("No project context found. Run `semilayer init` first.");
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return ctx;
|
|
33
|
+
}
|
|
34
|
+
var auth_config_default = defineCommand({
|
|
35
|
+
meta: { name: "auth", description: "Configure end-user authentication (JWKS) for the current environment" },
|
|
36
|
+
subCommands: {
|
|
37
|
+
configure: defineCommand({
|
|
38
|
+
meta: { name: "configure", description: "Set JWKS auth provider for the current environment" },
|
|
39
|
+
args: {
|
|
40
|
+
"jwks-url": { type: "string", description: "JWKS URL" },
|
|
41
|
+
issuer: { type: "string", description: "JWT issuer" },
|
|
42
|
+
audience: { type: "string", description: "JWT audience (optional)" }
|
|
43
|
+
},
|
|
44
|
+
async run({ args }) {
|
|
45
|
+
try {
|
|
46
|
+
const ctx = await requireContext();
|
|
47
|
+
if (!ctx) return;
|
|
48
|
+
const api = await createApiClient();
|
|
49
|
+
const envPath = `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}/envs/${ctx.envSlug}`;
|
|
50
|
+
const jwksUrl = args["jwks-url"] || await input("JWKS URL", "https://your-tenant.us.auth0.com/.well-known/jwks.json");
|
|
51
|
+
const issuer = args.issuer || await input("Issuer");
|
|
52
|
+
const audience = args.audience || await input("Audience (optional, press Enter to skip)");
|
|
53
|
+
await api.patch(`${envPath}/auth`, {
|
|
54
|
+
jwksUrl,
|
|
55
|
+
issuer,
|
|
56
|
+
...audience ? { audience } : {}
|
|
57
|
+
});
|
|
58
|
+
newline();
|
|
59
|
+
success(`Auth provider configured for ${bold(ctx.envSlug)} environment`);
|
|
60
|
+
info(`Lens rules can now use ${bold("'authenticated'")} and claim checks with user JWT claims`);
|
|
61
|
+
info(`End users send their JWT via the ${bold("X-User-Token")} header alongside the publishable key`);
|
|
62
|
+
} catch (err) {
|
|
63
|
+
error(err.message);
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}),
|
|
68
|
+
status: defineCommand({
|
|
69
|
+
meta: { name: "status", description: "Show auth config for the current environment" },
|
|
70
|
+
async run() {
|
|
71
|
+
try {
|
|
72
|
+
const ctx = await requireContext();
|
|
73
|
+
if (!ctx) return;
|
|
74
|
+
const api = await createApiClient();
|
|
75
|
+
const envPath = `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}/envs/${ctx.envSlug}`;
|
|
76
|
+
const res = await api.get(envPath);
|
|
77
|
+
const authConfig = res.environment.authConfig;
|
|
78
|
+
newline();
|
|
79
|
+
label("Environment", ctx.envSlug);
|
|
80
|
+
if (!authConfig) {
|
|
81
|
+
info("No auth provider configured");
|
|
82
|
+
info(`Run ${bold("semilayer auth configure")} to set up JWKS-based user authentication`);
|
|
83
|
+
} else {
|
|
84
|
+
label("JWKS URL", authConfig.jwksUrl);
|
|
85
|
+
label("Issuer", authConfig.issuer);
|
|
86
|
+
label("Audience", authConfig.audience ?? dim("(not set)"));
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
error(err.message);
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}),
|
|
94
|
+
remove: defineCommand({
|
|
95
|
+
meta: { name: "remove", description: "Remove auth config from the current environment" },
|
|
96
|
+
async run() {
|
|
97
|
+
try {
|
|
98
|
+
const ctx = await requireContext();
|
|
99
|
+
if (!ctx) return;
|
|
100
|
+
const yes = await confirm(`Remove auth config from ${ctx.envSlug}?`);
|
|
101
|
+
if (!yes) return;
|
|
102
|
+
const api = await createApiClient();
|
|
103
|
+
const envPath = `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}/envs/${ctx.envSlug}`;
|
|
104
|
+
await api.del(`${envPath}/auth`);
|
|
105
|
+
success(`Auth provider removed from ${bold(ctx.envSlug)} environment`);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
error(err.message);
|
|
108
|
+
process.exitCode = 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
export {
|
|
115
|
+
auth_config_default as default
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=auth-config-3MWVCUTJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/auth-config.ts"],"sourcesContent":["import { defineCommand } from 'citty'\nimport type { EnvironmentAuthConfig } from '@semilayer/core'\nimport { createApiClient } from '../lib/api.js'\nimport { loadContext } from '../lib/context.js'\nimport { success, error, info, bold, dim, newline, label } from '../lib/output.js'\nimport { input, confirm } from '../lib/prompt.js'\n\nasync function requireContext() {\n const ctx = await loadContext()\n if (!ctx) {\n error('No project context found. Run `semilayer init` first.')\n process.exitCode = 1\n return null\n }\n return ctx\n}\n\nexport default defineCommand({\n meta: { name: 'auth', description: 'Configure end-user authentication (JWKS) for the current environment' },\n subCommands: {\n configure: defineCommand({\n meta: { name: 'configure', description: 'Set JWKS auth provider for the current environment' },\n args: {\n 'jwks-url': { type: 'string', description: 'JWKS URL' },\n issuer: { type: 'string', description: 'JWT issuer' },\n audience: { type: 'string', description: 'JWT audience (optional)' },\n },\n async run({ args }) {\n try {\n const ctx = await requireContext()\n if (!ctx) return\n const api = await createApiClient()\n const envPath = `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}/envs/${ctx.envSlug}`\n\n const jwksUrl = args['jwks-url'] || await input('JWKS URL', 'https://your-tenant.us.auth0.com/.well-known/jwks.json')\n const issuer = args.issuer || await input('Issuer')\n const audience = args.audience || await input('Audience (optional, press Enter to skip)')\n\n await api.patch(`${envPath}/auth`, {\n jwksUrl,\n issuer,\n ...(audience ? { audience } : {}),\n })\n\n newline()\n success(`Auth provider configured for ${bold(ctx.envSlug)} environment`)\n info(`Lens rules can now use ${bold(\"'authenticated'\")} and claim checks with user JWT claims`)\n info(`End users send their JWT via the ${bold('X-User-Token')} header alongside the publishable key`)\n } catch (err) {\n error((err as Error).message)\n process.exitCode = 1\n }\n },\n }),\n\n status: defineCommand({\n meta: { name: 'status', description: 'Show auth config for the current environment' },\n async run() {\n try {\n const ctx = await requireContext()\n if (!ctx) return\n const api = await createApiClient()\n const envPath = `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}/envs/${ctx.envSlug}`\n\n const res = await api.get<{\n environment: { authConfig?: EnvironmentAuthConfig | null }\n }>(envPath)\n\n const authConfig = res.environment.authConfig\n\n newline()\n label('Environment', ctx.envSlug)\n\n if (!authConfig) {\n info('No auth provider configured')\n info(`Run ${bold('semilayer auth configure')} to set up JWKS-based user authentication`)\n } else {\n label('JWKS URL', authConfig.jwksUrl)\n label('Issuer', authConfig.issuer)\n label('Audience', authConfig.audience ?? dim('(not set)'))\n }\n } catch (err) {\n error((err as Error).message)\n process.exitCode = 1\n }\n },\n }),\n\n remove: defineCommand({\n meta: { name: 'remove', description: 'Remove auth config from the current environment' },\n async run() {\n try {\n const ctx = await requireContext()\n if (!ctx) return\n\n const yes = await confirm(`Remove auth config from ${ctx.envSlug}?`)\n if (!yes) return\n\n const api = await createApiClient()\n const envPath = `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}/envs/${ctx.envSlug}`\n\n await api.del(`${envPath}/auth`)\n\n success(`Auth provider removed from ${bold(ctx.envSlug)} environment`)\n } catch (err) {\n error((err as Error).message)\n process.exitCode = 1\n }\n },\n }),\n },\n})\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
loadContext
|
|
4
|
+
} from "./chunk-QMF7LD67.js";
|
|
5
|
+
import {
|
|
6
|
+
createApiClient
|
|
7
|
+
} from "./chunk-T3UROBMA.js";
|
|
8
|
+
import "./chunk-7TA63VHV.js";
|
|
9
|
+
import {
|
|
10
|
+
bold,
|
|
11
|
+
dim,
|
|
12
|
+
error,
|
|
13
|
+
info,
|
|
14
|
+
label,
|
|
15
|
+
newline,
|
|
16
|
+
success,
|
|
17
|
+
table,
|
|
18
|
+
usageBar
|
|
19
|
+
} from "./chunk-WZYOSGN3.js";
|
|
20
|
+
|
|
21
|
+
// src/commands/billing.ts
|
|
22
|
+
import { defineCommand } from "citty";
|
|
23
|
+
async function ensureSaas() {
|
|
24
|
+
try {
|
|
25
|
+
const api = await createApiClient();
|
|
26
|
+
const me = await api.get("/auth/me");
|
|
27
|
+
return { enterprise: me.deploymentMode === "enterprise" };
|
|
28
|
+
} catch {
|
|
29
|
+
return { enterprise: false };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function getOrgSlug() {
|
|
33
|
+
const ctx = await loadContext();
|
|
34
|
+
return ctx?.orgSlug ?? null;
|
|
35
|
+
}
|
|
36
|
+
var status = defineCommand({
|
|
37
|
+
meta: { name: "status", description: "Show current billing plan and cycle" },
|
|
38
|
+
async run() {
|
|
39
|
+
try {
|
|
40
|
+
const { enterprise } = await ensureSaas();
|
|
41
|
+
if (enterprise) {
|
|
42
|
+
info("Billing is unavailable in self-hosted (enterprise) mode.");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const orgSlug = await getOrgSlug();
|
|
46
|
+
if (!orgSlug) {
|
|
47
|
+
error("No .semilayerrc found. Run `semilayer init` first.");
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const api = await createApiClient();
|
|
52
|
+
const snapshot = await api.get(`/v1/orgs/${orgSlug}/billing`);
|
|
53
|
+
newline();
|
|
54
|
+
label("Plan", snapshot.plan?.tierName ?? "Free");
|
|
55
|
+
if (snapshot.plan && snapshot.plan.priceCents > 0) {
|
|
56
|
+
label(
|
|
57
|
+
"Price",
|
|
58
|
+
`$${(snapshot.plan.priceCents / 100).toFixed(0)}/${snapshot.plan.interval ?? "month"}`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
label(
|
|
62
|
+
"Cycle",
|
|
63
|
+
`${snapshot.cycle.periodStart} \u2192 ${snapshot.cycle.periodEnd} ${dim(`(${snapshot.cycle.daysRemaining}d remaining)`)}`
|
|
64
|
+
);
|
|
65
|
+
label("Status", snapshot.cycle.status);
|
|
66
|
+
newline();
|
|
67
|
+
} catch (err) {
|
|
68
|
+
error(err.message);
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
var usage = defineCommand({
|
|
74
|
+
meta: { name: "usage", description: "Show current cycle usage with bars" },
|
|
75
|
+
async run() {
|
|
76
|
+
try {
|
|
77
|
+
const { enterprise } = await ensureSaas();
|
|
78
|
+
if (enterprise) {
|
|
79
|
+
info("Billing is unavailable in self-hosted mode (no quotas to show).");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const orgSlug = await getOrgSlug();
|
|
83
|
+
if (!orgSlug) {
|
|
84
|
+
error("No .semilayerrc found. Run `semilayer init` first.");
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const api = await createApiClient();
|
|
89
|
+
const snapshot = await api.get(`/v1/orgs/${orgSlug}/billing`);
|
|
90
|
+
newline();
|
|
91
|
+
console.log(` ${bold("Current cycle usage")}`);
|
|
92
|
+
newline();
|
|
93
|
+
const order = ["embedding_tokens", "api_requests", "vectors_stored", "ingest_jobs"];
|
|
94
|
+
for (const key of order) {
|
|
95
|
+
const m = snapshot.usage[key];
|
|
96
|
+
if (!m) continue;
|
|
97
|
+
console.log(
|
|
98
|
+
` ${prettyName(key).padEnd(20)} ${usageBar(m.current, m.limit)} ${dim(
|
|
99
|
+
`(${m.current.toLocaleString()} / ${m.limit?.toLocaleString() ?? "\u221E"})`
|
|
100
|
+
)}`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
newline();
|
|
104
|
+
} catch (err) {
|
|
105
|
+
error(err.message);
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
var upgrade = defineCommand({
|
|
111
|
+
meta: { name: "upgrade", description: "Open Stripe Checkout for a tier upgrade" },
|
|
112
|
+
args: {
|
|
113
|
+
tier: { type: "positional", required: true, description: "Tier slug (e.g. pro, team, scale)" },
|
|
114
|
+
interval: { type: "string", default: "monthly", description: "monthly | yearly" }
|
|
115
|
+
},
|
|
116
|
+
async run(ctx) {
|
|
117
|
+
try {
|
|
118
|
+
const { enterprise } = await ensureSaas();
|
|
119
|
+
if (enterprise) {
|
|
120
|
+
info("Upgrades are unavailable in self-hosted mode.");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const orgSlug = await getOrgSlug();
|
|
124
|
+
if (!orgSlug) {
|
|
125
|
+
error("No .semilayerrc found. Run `semilayer init` first.");
|
|
126
|
+
process.exitCode = 1;
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const interval = ctx.args.interval === "yearly" ? "yearly" : "monthly";
|
|
130
|
+
const api = await createApiClient();
|
|
131
|
+
const res = await api.post(
|
|
132
|
+
`/v1/orgs/${orgSlug}/billing/checkout`,
|
|
133
|
+
{ tierSlug: ctx.args.tier, interval }
|
|
134
|
+
);
|
|
135
|
+
success(`Open this URL in your browser to complete checkout:`);
|
|
136
|
+
console.log(` ${res.url}`);
|
|
137
|
+
} catch (err) {
|
|
138
|
+
error(err.message);
|
|
139
|
+
process.exitCode = 1;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
var portal = defineCommand({
|
|
144
|
+
meta: { name: "portal", description: "Open Stripe Customer Portal" },
|
|
145
|
+
async run() {
|
|
146
|
+
try {
|
|
147
|
+
const { enterprise } = await ensureSaas();
|
|
148
|
+
if (enterprise) {
|
|
149
|
+
info("Portal is unavailable in self-hosted mode.");
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const orgSlug = await getOrgSlug();
|
|
153
|
+
if (!orgSlug) {
|
|
154
|
+
error("No .semilayerrc found. Run `semilayer init` first.");
|
|
155
|
+
process.exitCode = 1;
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const api = await createApiClient();
|
|
159
|
+
const res = await api.post(
|
|
160
|
+
`/v1/orgs/${orgSlug}/billing/portal`,
|
|
161
|
+
{}
|
|
162
|
+
);
|
|
163
|
+
success(`Open this URL in your browser:`);
|
|
164
|
+
console.log(` ${res.url}`);
|
|
165
|
+
} catch (err) {
|
|
166
|
+
error(err.message);
|
|
167
|
+
process.exitCode = 1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
var invoices = defineCommand({
|
|
172
|
+
meta: { name: "invoices", description: "List recent invoices" },
|
|
173
|
+
async run() {
|
|
174
|
+
try {
|
|
175
|
+
const { enterprise } = await ensureSaas();
|
|
176
|
+
if (enterprise) {
|
|
177
|
+
info("No invoices in self-hosted mode.");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const orgSlug = await getOrgSlug();
|
|
181
|
+
if (!orgSlug) {
|
|
182
|
+
error("No .semilayerrc found. Run `semilayer init` first.");
|
|
183
|
+
process.exitCode = 1;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const api = await createApiClient();
|
|
187
|
+
const res = await api.get(
|
|
188
|
+
`/v1/orgs/${orgSlug}/billing/invoices`
|
|
189
|
+
);
|
|
190
|
+
if (res.invoices.length === 0) {
|
|
191
|
+
info("No invoices yet.");
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
newline();
|
|
195
|
+
table(
|
|
196
|
+
["Date", "Amount", "Status", "PDF"],
|
|
197
|
+
res.invoices.map((inv) => [
|
|
198
|
+
new Date(inv.created).toLocaleDateString(),
|
|
199
|
+
`$${(inv.amountCents / 100).toFixed(2)} ${inv.currency.toUpperCase()}`,
|
|
200
|
+
inv.status,
|
|
201
|
+
inv.pdfUrl ?? "\u2014"
|
|
202
|
+
])
|
|
203
|
+
);
|
|
204
|
+
newline();
|
|
205
|
+
} catch (err) {
|
|
206
|
+
error(err.message);
|
|
207
|
+
process.exitCode = 1;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
var cancel = defineCommand({
|
|
212
|
+
meta: { name: "cancel", description: "Cancel subscription (at end of period)" },
|
|
213
|
+
args: {
|
|
214
|
+
immediately: { type: "boolean", default: false, description: "Cancel immediately instead of at period end" }
|
|
215
|
+
},
|
|
216
|
+
async run(ctx) {
|
|
217
|
+
try {
|
|
218
|
+
const { enterprise } = await ensureSaas();
|
|
219
|
+
if (enterprise) {
|
|
220
|
+
info("No subscription to cancel in self-hosted mode.");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const orgSlug = await getOrgSlug();
|
|
224
|
+
if (!orgSlug) {
|
|
225
|
+
error("No .semilayerrc found. Run `semilayer init` first.");
|
|
226
|
+
process.exitCode = 1;
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const api = await createApiClient();
|
|
230
|
+
await api.post(`/v1/orgs/${orgSlug}/billing/cancel`, {
|
|
231
|
+
immediately: Boolean(ctx.args.immediately)
|
|
232
|
+
});
|
|
233
|
+
success(
|
|
234
|
+
ctx.args.immediately ? "Subscription canceled immediately." : "Subscription will cancel at end of current cycle."
|
|
235
|
+
);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
error(err.message);
|
|
238
|
+
process.exitCode = 1;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
var billing_default = defineCommand({
|
|
243
|
+
meta: { name: "billing", description: "Manage billing, plans, and usage" },
|
|
244
|
+
subCommands: {
|
|
245
|
+
status,
|
|
246
|
+
usage,
|
|
247
|
+
upgrade,
|
|
248
|
+
portal,
|
|
249
|
+
invoices,
|
|
250
|
+
cancel
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
function prettyName(metric) {
|
|
254
|
+
const map = {
|
|
255
|
+
embedding_tokens: "Embedding tokens",
|
|
256
|
+
api_requests: "API requests",
|
|
257
|
+
vectors_stored: "Vectors stored",
|
|
258
|
+
ingest_jobs: "Ingest jobs"
|
|
259
|
+
};
|
|
260
|
+
return map[metric] ?? metric;
|
|
261
|
+
}
|
|
262
|
+
export {
|
|
263
|
+
billing_default as default
|
|
264
|
+
};
|
|
265
|
+
//# sourceMappingURL=billing-OY5GJP5X.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/billing.ts"],"sourcesContent":["import { defineCommand } from 'citty'\nimport type {\n BillingSnapshot,\n Invoice,\n MeResponse,\n} from '@semilayer/core'\nimport { loadContext } from '../lib/context.js'\nimport { createApiClient } from '../lib/api.js'\nimport {\n bold,\n dim,\n error,\n info,\n label,\n newline,\n success,\n table,\n usageBar,\n} from '../lib/output.js'\n\n/**\n * Step 12 — `semilayer billing` command group.\n *\n * semilayer billing status — current plan + cycle window\n * semilayer billing usage — usage bars for all 4 quota dimensions\n * semilayer billing upgrade — opens Stripe Checkout in browser\n * semilayer billing portal — opens Stripe Customer Portal in browser\n * semilayer billing invoices — list of invoices\n * semilayer billing cancel — cancel subscription (cancel_at_period_end)\n *\n * In enterprise mode (`/auth/me` returns `deploymentMode: 'enterprise'`)\n * every subcommand bails with a friendly note rather than calling the\n * server (which would 404 anyway).\n */\n\nasync function ensureSaas(): Promise<{ enterprise: boolean }> {\n try {\n const api = await createApiClient()\n const me = await api.get<MeResponse>('/auth/me')\n return { enterprise: me.deploymentMode === 'enterprise' }\n } catch {\n return { enterprise: false }\n }\n}\n\nasync function getOrgSlug(): Promise<string | null> {\n const ctx = await loadContext()\n return ctx?.orgSlug ?? null\n}\n\nconst status = defineCommand({\n meta: { name: 'status', description: 'Show current billing plan and cycle' },\n async run() {\n try {\n const { enterprise } = await ensureSaas()\n if (enterprise) {\n info('Billing is unavailable in self-hosted (enterprise) mode.')\n return\n }\n const orgSlug = await getOrgSlug()\n if (!orgSlug) {\n error('No .semilayerrc found. Run `semilayer init` first.')\n process.exitCode = 1\n return\n }\n const api = await createApiClient()\n const snapshot = await api.get<BillingSnapshot>(`/v1/orgs/${orgSlug}/billing`)\n newline()\n label('Plan', snapshot.plan?.tierName ?? 'Free')\n if (snapshot.plan && snapshot.plan.priceCents > 0) {\n label(\n 'Price',\n `$${(snapshot.plan.priceCents / 100).toFixed(0)}/${snapshot.plan.interval ?? 'month'}`,\n )\n }\n label(\n 'Cycle',\n `${snapshot.cycle.periodStart} → ${snapshot.cycle.periodEnd} ${dim(`(${snapshot.cycle.daysRemaining}d remaining)`)}`,\n )\n label('Status', snapshot.cycle.status)\n newline()\n } catch (err) {\n error((err as Error).message)\n process.exitCode = 1\n }\n },\n})\n\nconst usage = defineCommand({\n meta: { name: 'usage', description: 'Show current cycle usage with bars' },\n async run() {\n try {\n const { enterprise } = await ensureSaas()\n if (enterprise) {\n info('Billing is unavailable in self-hosted mode (no quotas to show).')\n return\n }\n const orgSlug = await getOrgSlug()\n if (!orgSlug) {\n error('No .semilayerrc found. Run `semilayer init` first.')\n process.exitCode = 1\n return\n }\n const api = await createApiClient()\n const snapshot = await api.get<BillingSnapshot>(`/v1/orgs/${orgSlug}/billing`)\n newline()\n console.log(` ${bold('Current cycle usage')}`)\n newline()\n const order = ['embedding_tokens', 'api_requests', 'vectors_stored', 'ingest_jobs']\n for (const key of order) {\n const m = snapshot.usage[key]\n if (!m) continue\n console.log(\n ` ${prettyName(key).padEnd(20)} ${usageBar(m.current, m.limit)} ${dim(\n `(${m.current.toLocaleString()} / ${m.limit?.toLocaleString() ?? '∞'})`,\n )}`,\n )\n }\n newline()\n } catch (err) {\n error((err as Error).message)\n process.exitCode = 1\n }\n },\n})\n\nconst upgrade = defineCommand({\n meta: { name: 'upgrade', description: 'Open Stripe Checkout for a tier upgrade' },\n args: {\n tier: { type: 'positional', required: true, description: 'Tier slug (e.g. pro, team, scale)' },\n interval: { type: 'string', default: 'monthly', description: 'monthly | yearly' },\n },\n async run(ctx) {\n try {\n const { enterprise } = await ensureSaas()\n if (enterprise) {\n info('Upgrades are unavailable in self-hosted mode.')\n return\n }\n const orgSlug = await getOrgSlug()\n if (!orgSlug) {\n error('No .semilayerrc found. Run `semilayer init` first.')\n process.exitCode = 1\n return\n }\n const interval = ctx.args.interval === 'yearly' ? 'yearly' : 'monthly'\n const api = await createApiClient()\n const res = await api.post<{ url: string }>(\n `/v1/orgs/${orgSlug}/billing/checkout`,\n { tierSlug: ctx.args.tier as string, interval },\n )\n success(`Open this URL in your browser to complete checkout:`)\n console.log(` ${res.url}`)\n } catch (err) {\n error((err as Error).message)\n process.exitCode = 1\n }\n },\n})\n\nconst portal = defineCommand({\n meta: { name: 'portal', description: 'Open Stripe Customer Portal' },\n async run() {\n try {\n const { enterprise } = await ensureSaas()\n if (enterprise) {\n info('Portal is unavailable in self-hosted mode.')\n return\n }\n const orgSlug = await getOrgSlug()\n if (!orgSlug) {\n error('No .semilayerrc found. Run `semilayer init` first.')\n process.exitCode = 1\n return\n }\n const api = await createApiClient()\n const res = await api.post<{ url: string }>(\n `/v1/orgs/${orgSlug}/billing/portal`,\n {},\n )\n success(`Open this URL in your browser:`)\n console.log(` ${res.url}`)\n } catch (err) {\n error((err as Error).message)\n process.exitCode = 1\n }\n },\n})\n\nconst invoices = defineCommand({\n meta: { name: 'invoices', description: 'List recent invoices' },\n async run() {\n try {\n const { enterprise } = await ensureSaas()\n if (enterprise) {\n info('No invoices in self-hosted mode.')\n return\n }\n const orgSlug = await getOrgSlug()\n if (!orgSlug) {\n error('No .semilayerrc found. Run `semilayer init` first.')\n process.exitCode = 1\n return\n }\n const api = await createApiClient()\n const res = await api.get<{ invoices: Invoice[] }>(\n `/v1/orgs/${orgSlug}/billing/invoices`,\n )\n if (res.invoices.length === 0) {\n info('No invoices yet.')\n return\n }\n newline()\n table(\n ['Date', 'Amount', 'Status', 'PDF'],\n res.invoices.map((inv) => [\n new Date(inv.created).toLocaleDateString(),\n `$${(inv.amountCents / 100).toFixed(2)} ${inv.currency.toUpperCase()}`,\n inv.status,\n inv.pdfUrl ?? '—',\n ]),\n )\n newline()\n } catch (err) {\n error((err as Error).message)\n process.exitCode = 1\n }\n },\n})\n\nconst cancel = defineCommand({\n meta: { name: 'cancel', description: 'Cancel subscription (at end of period)' },\n args: {\n immediately: { type: 'boolean', default: false, description: 'Cancel immediately instead of at period end' },\n },\n async run(ctx) {\n try {\n const { enterprise } = await ensureSaas()\n if (enterprise) {\n info('No subscription to cancel in self-hosted mode.')\n return\n }\n const orgSlug = await getOrgSlug()\n if (!orgSlug) {\n error('No .semilayerrc found. Run `semilayer init` first.')\n process.exitCode = 1\n return\n }\n const api = await createApiClient()\n await api.post(`/v1/orgs/${orgSlug}/billing/cancel`, {\n immediately: Boolean(ctx.args.immediately),\n })\n success(\n ctx.args.immediately\n ? 'Subscription canceled immediately.'\n : 'Subscription will cancel at end of current cycle.',\n )\n } catch (err) {\n error((err as Error).message)\n process.exitCode = 1\n }\n },\n})\n\nexport default defineCommand({\n meta: { name: 'billing', description: 'Manage billing, plans, and usage' },\n subCommands: {\n status,\n usage,\n upgrade,\n portal,\n invoices,\n cancel,\n },\n})\n\nfunction prettyName(metric: string): string {\n const map: Record<string, string> = {\n embedding_tokens: 'Embedding tokens',\n api_requests: 'API requests',\n vectors_stored: 'Vectors stored',\n ingest_jobs: 'Ingest jobs',\n }\n return map[metric] ?? metric\n}\n"],"mappings":"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","names":[]}
|
package/dist/bin.d.ts
ADDED
package/dist/bin.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/bin.ts
|
|
4
|
+
import { defineCommand, runMain } from "citty";
|
|
5
|
+
var main = defineCommand({
|
|
6
|
+
meta: {
|
|
7
|
+
name: "semilayer",
|
|
8
|
+
version: "0.0.0",
|
|
9
|
+
description: "The intelligence layer for any database"
|
|
10
|
+
},
|
|
11
|
+
subCommands: {
|
|
12
|
+
// Auth
|
|
13
|
+
login: () => import("./login-BZ6ZPFHC.js").then((m) => m.default),
|
|
14
|
+
logout: () => import("./logout-VMPRV62T.js").then((m) => m.default),
|
|
15
|
+
whoami: () => import("./whoami-EQGW6V5D.js").then((m) => m.default),
|
|
16
|
+
// Setup
|
|
17
|
+
init: () => import("./init-TWJAGUN3.js").then((m) => m.default),
|
|
18
|
+
wizard: () => import("./wizard-QLAR33T2.js").then((m) => m.default),
|
|
19
|
+
generate: () => import("./generate-QUETX3TN.js").then((m) => m.default),
|
|
20
|
+
push: () => import("./push-3ZK3W2AC.js").then((m) => m.default),
|
|
21
|
+
status: () => import("./status-AUECH6RX.js").then((m) => m.default),
|
|
22
|
+
dev: () => import("./dev-R3AZSONQ.js").then((m) => m.default),
|
|
23
|
+
// Config
|
|
24
|
+
auth: () => import("./auth-config-3MWVCUTJ.js").then((m) => m.default),
|
|
25
|
+
config: () => import("./config-DACYO7JC.js").then((m) => m.default),
|
|
26
|
+
export: () => import("./export-YRFR3JH2.js").then((m) => m.default),
|
|
27
|
+
// Management
|
|
28
|
+
orgs: () => import("./orgs-YA3TVA3T.js").then((m) => m.default),
|
|
29
|
+
members: () => import("./members-DVE5FDLZ.js").then((m) => m.default),
|
|
30
|
+
projects: () => import("./projects-DMA2AXH3.js").then((m) => m.default),
|
|
31
|
+
envs: () => import("./envs-RNZQ3OQP.js").then((m) => m.default),
|
|
32
|
+
keys: () => import("./keys-JBKCYKJU.js").then((m) => m.default),
|
|
33
|
+
sources: () => import("./sources-S52HUWRK.js").then((m) => m.default),
|
|
34
|
+
lenses: () => import("./lenses-VZSDFH3D.js").then((m) => m.default),
|
|
35
|
+
// Operations
|
|
36
|
+
pause: () => import("./pause-GQ6PKBUA.js").then((m) => m.default),
|
|
37
|
+
resume: () => import("./resume-KVRPLXZZ.js").then((m) => m.default),
|
|
38
|
+
sync: () => import("./sync-NRTC3WX4.js").then((m) => m.default),
|
|
39
|
+
// Data
|
|
40
|
+
run: () => import("./run-IR5B4AE3.js").then((m) => m.default),
|
|
41
|
+
// Streaming
|
|
42
|
+
stream: () => import("./stream-V7RGHTPR.js").then((m) => m.default),
|
|
43
|
+
observe: () => import("./observe-W346RZBX.js").then((m) => m.default),
|
|
44
|
+
// Billing
|
|
45
|
+
billing: () => import("./billing-OY5GJP5X.js").then((m) => m.default)
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
runMain(main);
|
|
49
|
+
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bin.ts"],"sourcesContent":["import { defineCommand, runMain } from 'citty'\n\nconst main = defineCommand({\n meta: {\n name: 'semilayer',\n version: '0.0.0',\n description: 'The intelligence layer for any database',\n },\n subCommands: {\n // Auth\n login: () => import('./commands/login.js').then((m) => m.default),\n logout: () => import('./commands/logout.js').then((m) => m.default),\n whoami: () => import('./commands/whoami.js').then((m) => m.default),\n // Setup\n init: () => import('./commands/init.js').then((m) => m.default),\n wizard: () => import('./commands/wizard.js').then((m) => m.default),\n generate: () => import('./commands/generate.js').then((m) => m.default),\n push: () => import('./commands/push.js').then((m) => m.default),\n status: () => import('./commands/status.js').then((m) => m.default),\n dev: () => import('./commands/dev.js').then((m) => m.default),\n // Config\n auth: () => import('./commands/auth-config.js').then((m) => m.default),\n config: () => import('./commands/config.js').then((m) => m.default),\n export: () => import('./commands/export.js').then((m) => m.default),\n // Management\n orgs: () => import('./commands/orgs.js').then((m) => m.default),\n members: () => import('./commands/members.js').then((m) => m.default),\n projects: () => import('./commands/projects.js').then((m) => m.default),\n envs: () => import('./commands/envs.js').then((m) => m.default),\n keys: () => import('./commands/keys.js').then((m) => m.default),\n sources: () => import('./commands/sources.js').then((m) => m.default),\n lenses: () => import('./commands/lenses.js').then((m) => m.default),\n // Operations\n pause: () => import('./commands/pause.js').then((m) => m.default),\n resume: () => import('./commands/resume.js').then((m) => m.default),\n sync: () => import('./commands/sync.js').then((m) => m.default),\n // Data\n run: () => import('./commands/run.js').then((m) => m.default),\n // Streaming\n stream: () => import('./commands/stream.js').then((m) => m.default),\n observe: () => import('./commands/observe.js').then((m) => m.default),\n // Billing\n billing: () => import('./commands/billing.js').then((m) => m.default),\n },\n})\n\nrunMain(main)\n"],"mappings":";;;AAAA,SAAS,eAAe,eAAe;AAEvC,IAAM,OAAO,cAAc;AAAA,EACzB,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,aAAa;AAAA;AAAA,IAEX,OAAO,MAAM,OAAO,qBAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAChE,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAClE,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA;AAAA,IAElE,MAAM,MAAM,OAAO,oBAAoB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAC9D,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAClE,UAAU,MAAM,OAAO,wBAAwB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IACtE,MAAM,MAAM,OAAO,oBAAoB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAC9D,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAClE,KAAK,MAAM,OAAO,mBAAmB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA;AAAA,IAE5D,MAAM,MAAM,OAAO,2BAA2B,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IACrE,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAClE,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA;AAAA,IAElE,MAAM,MAAM,OAAO,oBAAoB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAC9D,SAAS,MAAM,OAAO,uBAAuB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IACpE,UAAU,MAAM,OAAO,wBAAwB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IACtE,MAAM,MAAM,OAAO,oBAAoB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAC9D,MAAM,MAAM,OAAO,oBAAoB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAC9D,SAAS,MAAM,OAAO,uBAAuB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IACpE,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA;AAAA,IAElE,OAAO,MAAM,OAAO,qBAAqB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAChE,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAClE,MAAM,MAAM,OAAO,oBAAoB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA;AAAA,IAE9D,KAAK,MAAM,OAAO,mBAAmB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA;AAAA,IAE5D,QAAQ,MAAM,OAAO,sBAAsB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,IAClE,SAAS,MAAM,OAAO,uBAAuB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA;AAAA,IAEpE,SAAS,MAAM,OAAO,uBAAuB,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO;AAAA,EACtE;AACF,CAAC;AAED,QAAQ,IAAI;","names":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/credentials.ts
|
|
4
|
+
import { mkdir, readFile, writeFile, unlink } from "fs/promises";
|
|
5
|
+
import { homedir } from "os";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
function semilayerDir() {
|
|
8
|
+
return join(homedir(), ".semilayer");
|
|
9
|
+
}
|
|
10
|
+
function credentialsPath() {
|
|
11
|
+
return join(semilayerDir(), "credentials.json");
|
|
12
|
+
}
|
|
13
|
+
async function loadCredentials() {
|
|
14
|
+
try {
|
|
15
|
+
const raw = await readFile(credentialsPath(), "utf-8");
|
|
16
|
+
return JSON.parse(raw);
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function saveCredentials(creds) {
|
|
22
|
+
await mkdir(semilayerDir(), { recursive: true });
|
|
23
|
+
await writeFile(credentialsPath(), JSON.stringify(creds, null, 2) + "\n", "utf-8");
|
|
24
|
+
}
|
|
25
|
+
async function clearCredentials() {
|
|
26
|
+
try {
|
|
27
|
+
await unlink(credentialsPath());
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
credentialsPath,
|
|
34
|
+
loadCredentials,
|
|
35
|
+
saveCredentials,
|
|
36
|
+
clearCredentials
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=chunk-7TA63VHV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/credentials.ts"],"sourcesContent":["import { mkdir, readFile, writeFile, unlink } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nexport interface Credentials {\n accessToken: string\n refreshToken: string\n expiresAt: string // ISO timestamp\n email: string\n serviceUrl: string\n}\n\nfunction semilayerDir(): string {\n return join(homedir(), '.semilayer')\n}\n\nexport function credentialsPath(): string {\n return join(semilayerDir(), 'credentials.json')\n}\n\nexport async function loadCredentials(): Promise<Credentials | null> {\n try {\n const raw = await readFile(credentialsPath(), 'utf-8')\n return JSON.parse(raw) as Credentials\n } catch {\n return null\n }\n}\n\nexport async function saveCredentials(creds: Credentials): Promise<void> {\n await mkdir(semilayerDir(), { recursive: true })\n await writeFile(credentialsPath(), JSON.stringify(creds, null, 2) + '\\n', 'utf-8')\n}\n\nexport async function clearCredentials(): Promise<void> {\n try {\n await unlink(credentialsPath())\n } catch {\n // already gone — fine\n }\n}\n"],"mappings":";;;AAAA,SAAS,OAAO,UAAU,WAAW,cAAc;AACnD,SAAS,eAAe;AACxB,SAAS,YAAY;AAUrB,SAAS,eAAuB;AAC9B,SAAO,KAAK,QAAQ,GAAG,YAAY;AACrC;AAEO,SAAS,kBAA0B;AACxC,SAAO,KAAK,aAAa,GAAG,kBAAkB;AAChD;AAEA,eAAsB,kBAA+C;AACnE,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,gBAAgB,GAAG,OAAO;AACrD,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,gBAAgB,OAAmC;AACvE,QAAM,MAAM,aAAa,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/C,QAAM,UAAU,gBAAgB,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,IAAI,MAAM,OAAO;AACnF;AAEA,eAAsB,mBAAkC;AACtD,MAAI;AACF,UAAM,OAAO,gBAAgB,CAAC;AAAA,EAChC,QAAQ;AAAA,EAER;AACF;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/env-path.ts
|
|
4
|
+
function envPath(ctx) {
|
|
5
|
+
return `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}/envs/${ctx.envSlug}`;
|
|
6
|
+
}
|
|
7
|
+
function orgPath(ctx) {
|
|
8
|
+
return `/v1/orgs/${ctx.orgSlug}`;
|
|
9
|
+
}
|
|
10
|
+
function projectPath(ctx) {
|
|
11
|
+
return `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
envPath,
|
|
16
|
+
orgPath,
|
|
17
|
+
projectPath
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=chunk-ALA4X7UU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/env-path.ts"],"sourcesContent":["import type { ProjectContext } from './context.js'\n\n/** Build the API path prefix for an environment-scoped resource */\nexport function envPath(ctx: ProjectContext): string {\n return `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}/envs/${ctx.envSlug}`\n}\n\n/** Build the API path prefix for an org-scoped resource */\nexport function orgPath(ctx: ProjectContext): string {\n return `/v1/orgs/${ctx.orgSlug}`\n}\n\n/** Build the API path prefix for a project-scoped resource */\nexport function projectPath(ctx: ProjectContext): string {\n return `/v1/orgs/${ctx.orgSlug}/projects/${ctx.projectSlug}`\n}\n"],"mappings":";;;AAGO,SAAS,QAAQ,KAA6B;AACnD,SAAO,YAAY,IAAI,OAAO,aAAa,IAAI,WAAW,SAAS,IAAI,OAAO;AAChF;AAGO,SAAS,QAAQ,KAA6B;AACnD,SAAO,YAAY,IAAI,OAAO;AAChC;AAGO,SAAS,YAAY,KAA6B;AACvD,SAAO,YAAY,IAAI,OAAO,aAAa,IAAI,WAAW;AAC5D;","names":[]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/config-loader.ts
|
|
4
|
+
import { dirname, join, resolve } from "path";
|
|
5
|
+
import { existsSync } from "fs";
|
|
6
|
+
import { createRequire } from "module";
|
|
7
|
+
import { validateConfig } from "@semilayer/core";
|
|
8
|
+
var CONFIG_NAMES = [
|
|
9
|
+
"sl.config.ts",
|
|
10
|
+
"sl.config.js",
|
|
11
|
+
"sl.config.mjs",
|
|
12
|
+
// Legacy names — still supported
|
|
13
|
+
"semilayer.config.ts",
|
|
14
|
+
"semilayer.config.js",
|
|
15
|
+
"semilayer.config.mjs"
|
|
16
|
+
];
|
|
17
|
+
function findConfigFile(cwd) {
|
|
18
|
+
let dir = cwd;
|
|
19
|
+
while (true) {
|
|
20
|
+
for (const name of CONFIG_NAMES) {
|
|
21
|
+
const candidate = join(dir, name);
|
|
22
|
+
if (existsSync(candidate)) return candidate;
|
|
23
|
+
}
|
|
24
|
+
const parent = dirname(dir);
|
|
25
|
+
if (parent === dir) return null;
|
|
26
|
+
dir = parent;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function loadConfig(cwd) {
|
|
30
|
+
const startDir = resolve(cwd ?? process.cwd());
|
|
31
|
+
const configPath = findConfigFile(startDir);
|
|
32
|
+
if (!configPath) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"No sl.config.ts found. Run `semilayer init` to get started."
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const { default: jiti } = await import("jiti");
|
|
38
|
+
const cliRequire = createRequire(import.meta.url);
|
|
39
|
+
const corePath = cliRequire.resolve("@semilayer/core");
|
|
40
|
+
const loader = jiti(configPath, {
|
|
41
|
+
interopDefault: true,
|
|
42
|
+
alias: { "@semilayer/core": corePath }
|
|
43
|
+
});
|
|
44
|
+
const mod = loader(configPath);
|
|
45
|
+
const config = "default" in mod && mod.default ? mod.default : mod;
|
|
46
|
+
validateConfig(config);
|
|
47
|
+
return { config, configPath };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
loadConfig
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=chunk-NIDLPHWY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/config-loader.ts"],"sourcesContent":["import { dirname, join, resolve } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport type { SemiLayerConfig } from '@semilayer/core'\nimport { validateConfig } from '@semilayer/core'\n\nconst CONFIG_NAMES = [\n 'sl.config.ts',\n 'sl.config.js',\n 'sl.config.mjs',\n // Legacy names — still supported\n 'semilayer.config.ts',\n 'semilayer.config.js',\n 'semilayer.config.mjs',\n]\n\nexport interface LoadedConfig {\n config: SemiLayerConfig\n configPath: string\n}\n\nfunction findConfigFile(cwd: string): string | null {\n let dir = cwd\n while (true) {\n for (const name of CONFIG_NAMES) {\n const candidate = join(dir, name)\n if (existsSync(candidate)) return candidate\n }\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n\nexport async function loadConfig(cwd?: string): Promise<LoadedConfig> {\n const startDir = resolve(cwd ?? process.cwd())\n const configPath = findConfigFile(startDir)\n if (!configPath) {\n throw new Error(\n 'No sl.config.ts found. Run `semilayer init` to get started.',\n )\n }\n\n // Use jiti for TypeScript config loading.\n // Alias @semilayer/core to the CLI's own copy so it resolves even when\n // the user's project doesn't have it installed.\n const { default: jiti } = await import('jiti')\n const cliRequire = createRequire(import.meta.url)\n const corePath = cliRequire.resolve('@semilayer/core')\n const loader = jiti(configPath, {\n interopDefault: true,\n alias: { '@semilayer/core': corePath },\n })\n const mod = loader(configPath) as { default?: SemiLayerConfig } | SemiLayerConfig\n\n const config = (\n 'default' in mod && mod.default ? mod.default : mod\n ) as SemiLayerConfig\n\n validateConfig(config)\n\n return { config, configPath }\n}\n"],"mappings":";;;AAAA,SAAS,SAAS,MAAM,eAAe;AACvC,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAE9B,SAAS,sBAAsB;AAE/B,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AACF;AAOA,SAAS,eAAe,KAA4B;AAClD,MAAI,MAAM;AACV,SAAO,MAAM;AACX,eAAW,QAAQ,cAAc;AAC/B,YAAM,YAAY,KAAK,KAAK,IAAI;AAChC,UAAI,WAAW,SAAS,EAAG,QAAO;AAAA,IACpC;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,WAAW,KAAqC;AACpE,QAAM,WAAW,QAAQ,OAAO,QAAQ,IAAI,CAAC;AAC7C,QAAM,aAAa,eAAe,QAAQ;AAC1C,MAAI,CAAC,YAAY;AACf,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAKA,QAAM,EAAE,SAAS,KAAK,IAAI,MAAM,OAAO,MAAM;AAC7C,QAAM,aAAa,cAAc,YAAY,GAAG;AAChD,QAAM,WAAW,WAAW,QAAQ,iBAAiB;AACrD,QAAM,SAAS,KAAK,YAAY;AAAA,IAC9B,gBAAgB;AAAA,IAChB,OAAO,EAAE,mBAAmB,SAAS;AAAA,EACvC,CAAC;AACD,QAAM,MAAM,OAAO,UAAU;AAE7B,QAAM,SACJ,aAAa,OAAO,IAAI,UAAU,IAAI,UAAU;AAGlD,iBAAe,MAAM;AAErB,SAAO,EAAE,QAAQ,WAAW;AAC9B;","names":[]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/lib/context.ts
|
|
4
|
+
import { readFile, writeFile } from "fs/promises";
|
|
5
|
+
import { join, dirname } from "path";
|
|
6
|
+
import { existsSync } from "fs";
|
|
7
|
+
var CONTEXT_FILE = ".semilayerrc";
|
|
8
|
+
function findContextFile(cwd) {
|
|
9
|
+
let dir = cwd ?? process.cwd();
|
|
10
|
+
const root = dirname(dir) === dir ? dir : void 0;
|
|
11
|
+
while (true) {
|
|
12
|
+
const candidate = join(dir, CONTEXT_FILE);
|
|
13
|
+
if (existsSync(candidate)) return candidate;
|
|
14
|
+
const parent = dirname(dir);
|
|
15
|
+
if (parent === dir || parent === root) return null;
|
|
16
|
+
dir = parent;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function loadContext(cwd) {
|
|
20
|
+
const file = findContextFile(cwd);
|
|
21
|
+
if (!file) return null;
|
|
22
|
+
try {
|
|
23
|
+
const raw = await readFile(file, "utf-8");
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function saveContext(ctx, cwd) {
|
|
30
|
+
const target = join(cwd ?? process.cwd(), CONTEXT_FILE);
|
|
31
|
+
await writeFile(target, JSON.stringify(ctx, null, 2) + "\n", "utf-8");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export {
|
|
35
|
+
findContextFile,
|
|
36
|
+
loadContext,
|
|
37
|
+
saveContext
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=chunk-QMF7LD67.js.map
|