@ankhorage/studio 0.1.6 → 0.3.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 +1 -1
- package/dist/host/http/secretRoutes.d.ts +7 -0
- package/dist/host/http/secretRoutes.d.ts.map +1 -0
- package/dist/host/http/secretRoutes.js +165 -0
- package/dist/host/http/secretRoutes.js.map +1 -0
- package/dist/host/index.d.ts +4 -0
- package/dist/host/index.d.ts.map +1 -1
- package/dist/host/index.js +4 -0
- package/dist/host/index.js.map +1 -1
- package/dist/host/secrets/bunSupabaseVaultClient.d.ts +12 -0
- package/dist/host/secrets/bunSupabaseVaultClient.d.ts.map +1 -0
- package/dist/host/secrets/bunSupabaseVaultClient.js +43 -0
- package/dist/host/secrets/bunSupabaseVaultClient.js.map +1 -0
- package/dist/host/secrets/projectSecretService.d.ts +81 -0
- package/dist/host/secrets/projectSecretService.d.ts.map +1 -0
- package/dist/host/secrets/projectSecretService.js +240 -0
- package/dist/host/secrets/projectSecretService.js.map +1 -0
- package/dist/host/secrets/resolveProjectSecretDatabaseUrl.d.ts +12 -0
- package/dist/host/secrets/resolveProjectSecretDatabaseUrl.d.ts.map +1 -0
- package/dist/host/secrets/resolveProjectSecretDatabaseUrl.js +68 -0
- package/dist/host/secrets/resolveProjectSecretDatabaseUrl.js.map +1 -0
- package/dist/projectSecretApi.d.ts +70 -0
- package/dist/projectSecretApi.d.ts.map +1 -0
- package/dist/projectSecretApi.js +233 -0
- package/dist/projectSecretApi.js.map +1 -0
- package/dist/studioAdminRouteModel.d.ts +6 -5
- package/dist/studioAdminRouteModel.d.ts.map +1 -1
- package/dist/studioAdminRouteModel.js +1 -1
- package/dist/studioAdminRouteModel.js.map +1 -1
- package/dist/ui/StudioAdminOverlay.d.ts +11 -0
- package/dist/ui/StudioAdminOverlay.d.ts.map +1 -0
- package/dist/ui/StudioAdminOverlay.js +359 -0
- package/dist/ui/StudioAdminOverlay.js.map +1 -0
- package/dist/ui/useStudioAppBarAugmentation.d.ts +1 -1
- package/dist/ui/useStudioAppBarAugmentation.d.ts.map +1 -1
- package/dist/ui/useStudioAppBarAugmentation.js +38 -1
- package/dist/ui/useStudioAppBarAugmentation.js.map +1 -1
- package/package.json +15 -6
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
# @ankhorage/studio
|
|
5
5
|
|
|
6
|
-
         
|
|
7
7
|
|
|
8
8
|
Standalone Studio authoring package for Ankhorage apps.
|
|
9
9
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
import type { ProjectManager } from '../orchestrator/projectManager';
|
|
3
|
+
export declare function registerProjectSecretRoutes(fastify: FastifyInstance, options: {
|
|
4
|
+
readonly projectManager: ProjectManager;
|
|
5
|
+
readonly workspaceRoot: string;
|
|
6
|
+
}): void;
|
|
7
|
+
//# sourceMappingURL=secretRoutes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secretRoutes.d.ts","sourceRoot":"","sources":["../../../src/host/http/secretRoutes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAE7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGrE,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE;IACP,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC,GACA,IAAI,CAkJN"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { ProjectSecretService } from '../secrets/projectSecretService';
|
|
2
|
+
export function registerProjectSecretRoutes(fastify, options) {
|
|
3
|
+
const service = new ProjectSecretService(options);
|
|
4
|
+
fastify.get('/api/projects/:id/secrets', async (request, reply) => {
|
|
5
|
+
const { id } = request.params;
|
|
6
|
+
const query = request.query;
|
|
7
|
+
return sendSecretResult(reply, await service.list({
|
|
8
|
+
projectId: id,
|
|
9
|
+
environment: query.environment,
|
|
10
|
+
kind: query.kind,
|
|
11
|
+
provider: query.provider,
|
|
12
|
+
}));
|
|
13
|
+
});
|
|
14
|
+
fastify.get('/api/projects/:id/secrets/metadata', async (request, reply) => {
|
|
15
|
+
const { id } = request.params;
|
|
16
|
+
const query = request.query;
|
|
17
|
+
if (typeof query.ref !== 'string' || query.ref.trim().length === 0) {
|
|
18
|
+
return reply.status(400).send({
|
|
19
|
+
error: { code: 'invalid_reference', message: 'A secret ref query parameter is required.' },
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return sendSecretResult(reply, await service.getMetadata({
|
|
23
|
+
projectId: id,
|
|
24
|
+
environment: query.environment,
|
|
25
|
+
ref: query.ref,
|
|
26
|
+
}));
|
|
27
|
+
});
|
|
28
|
+
fastify.post('/api/projects/:id/secrets', async (request, reply) => {
|
|
29
|
+
const { id } = request.params;
|
|
30
|
+
const body = asRecord(request.body);
|
|
31
|
+
const payload = readSecretPayload(body.payload);
|
|
32
|
+
if (!payload || typeof body.ref !== 'string' || typeof body.kind !== 'string') {
|
|
33
|
+
return reply.status(400).send({
|
|
34
|
+
error: {
|
|
35
|
+
code: 'invalid_payload',
|
|
36
|
+
message: 'Secret creation requires ref, kind, and a non-empty string payload object.',
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return sendSecretResult(reply, await service.create({
|
|
41
|
+
projectId: id,
|
|
42
|
+
environment: readOptionalString(body.environment),
|
|
43
|
+
ref: body.ref,
|
|
44
|
+
kind: body.kind,
|
|
45
|
+
provider: readOptionalString(body.provider),
|
|
46
|
+
payload,
|
|
47
|
+
}));
|
|
48
|
+
});
|
|
49
|
+
fastify.put('/api/projects/:id/secrets', async (request, reply) => {
|
|
50
|
+
const { id } = request.params;
|
|
51
|
+
const body = asRecord(request.body);
|
|
52
|
+
const payload = readSecretPayload(body.payload);
|
|
53
|
+
if (!payload || typeof body.ref !== 'string') {
|
|
54
|
+
return reply.status(400).send({
|
|
55
|
+
error: {
|
|
56
|
+
code: 'invalid_payload',
|
|
57
|
+
message: 'Secret replacement requires ref and a complete non-empty string payload object.',
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return sendSecretResult(reply, await service.replace({
|
|
62
|
+
projectId: id,
|
|
63
|
+
environment: readOptionalString(body.environment),
|
|
64
|
+
ref: body.ref,
|
|
65
|
+
payload,
|
|
66
|
+
}));
|
|
67
|
+
});
|
|
68
|
+
fastify.delete('/api/projects/:id/secrets', async (request, reply) => {
|
|
69
|
+
const { id } = request.params;
|
|
70
|
+
const query = request.query;
|
|
71
|
+
if (typeof query.ref !== 'string' || query.ref.trim().length === 0) {
|
|
72
|
+
return reply.status(400).send({
|
|
73
|
+
error: { code: 'invalid_reference', message: 'A secret ref query parameter is required.' },
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return sendSecretResult(reply, await service.remove({
|
|
77
|
+
projectId: id,
|
|
78
|
+
environment: query.environment,
|
|
79
|
+
ref: query.ref,
|
|
80
|
+
}));
|
|
81
|
+
});
|
|
82
|
+
fastify.post('/api/projects/:id/auth/oauth/:providerId', async (request, reply) => {
|
|
83
|
+
const { id, providerId } = request.params;
|
|
84
|
+
const body = asRecord(request.body);
|
|
85
|
+
const payload = readSecretPayload(body.payload);
|
|
86
|
+
if (!payload) {
|
|
87
|
+
return reply.status(400).send({
|
|
88
|
+
error: {
|
|
89
|
+
code: 'invalid_payload',
|
|
90
|
+
message: 'OAuth configuration requires a complete non-empty credential payload.',
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const result = await service.configureOAuthProvider({
|
|
95
|
+
projectId: id,
|
|
96
|
+
providerId,
|
|
97
|
+
payload,
|
|
98
|
+
environment: readOptionalString(body.environment),
|
|
99
|
+
credentialsRef: readOptionalString(body.credentialsRef),
|
|
100
|
+
enabled: typeof body.enabled === 'boolean' ? body.enabled : undefined,
|
|
101
|
+
label: readOptionalString(body.label),
|
|
102
|
+
scopes: readStringArray(body.scopes),
|
|
103
|
+
callbackRoute: readOptionalString(body.callbackRoute),
|
|
104
|
+
});
|
|
105
|
+
if (!result.ok) {
|
|
106
|
+
const status = result.state === 'secret_saved_manifest_failed' ? 409 : 400;
|
|
107
|
+
return reply.status(status).send(result);
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function sendSecretResult(reply, result) {
|
|
113
|
+
if (result.ok)
|
|
114
|
+
return result;
|
|
115
|
+
const status = resolveErrorStatus(result.error.code);
|
|
116
|
+
return reply.status(status).send({
|
|
117
|
+
ok: false,
|
|
118
|
+
error: {
|
|
119
|
+
code: result.error.code,
|
|
120
|
+
message: result.error.message,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function resolveErrorStatus(code) {
|
|
125
|
+
if (code === 'not_found')
|
|
126
|
+
return 404;
|
|
127
|
+
if (code === 'conflict')
|
|
128
|
+
return 409;
|
|
129
|
+
if (code === 'permission_denied')
|
|
130
|
+
return 403;
|
|
131
|
+
if (code === 'unavailable' || code === 'provider_error')
|
|
132
|
+
return 503;
|
|
133
|
+
return 400;
|
|
134
|
+
}
|
|
135
|
+
function asRecord(value) {
|
|
136
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
137
|
+
? value
|
|
138
|
+
: {};
|
|
139
|
+
}
|
|
140
|
+
function readOptionalString(value) {
|
|
141
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
|
|
142
|
+
}
|
|
143
|
+
function readStringArray(value) {
|
|
144
|
+
if (!Array.isArray(value))
|
|
145
|
+
return undefined;
|
|
146
|
+
const result = [];
|
|
147
|
+
for (const item of value) {
|
|
148
|
+
if (typeof item !== 'string')
|
|
149
|
+
return undefined;
|
|
150
|
+
const normalized = item.trim();
|
|
151
|
+
if (normalized)
|
|
152
|
+
result.push(normalized);
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
function readSecretPayload(value) {
|
|
157
|
+
const record = asRecord(value);
|
|
158
|
+
const entries = Object.entries(record);
|
|
159
|
+
if (entries.length === 0 ||
|
|
160
|
+
entries.some(([field, fieldValue]) => !field.trim() || typeof fieldValue !== 'string' || !fieldValue)) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
return Object.freeze(Object.fromEntries(entries));
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=secretRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secretRoutes.js","sourceRoot":"","sources":["../../../src/host/http/secretRoutes.ts"],"names":[],"mappings":"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"}
|
package/dist/host/index.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
export { createStudioHost, type CreateStudioHostOptions, type StudioHost, } from './createStudioHost';
|
|
2
|
+
export { registerProjectSecretRoutes } from './http/secretRoutes';
|
|
2
3
|
export { isOriginAllowed } from './http/security';
|
|
3
4
|
export { createStudioHostServer, startStudioHostServer, type StartStudioHostServerOptions, } from './http/server';
|
|
4
5
|
export { ModuleManager } from './orchestrator/moduleManager';
|
|
5
6
|
export { ProjectManager } from './orchestrator/projectManager';
|
|
6
7
|
export { assertProjectId, getAppsRoot, getProjectPath } from './orchestrator/projectPaths';
|
|
7
8
|
export { ProjectStore, type ProjectSummary } from './orchestrator/projectStore';
|
|
9
|
+
export { type BunSupabaseVaultClient, createBunSupabaseVaultClient, } from './secrets/bunSupabaseVaultClient';
|
|
10
|
+
export { configureManifestOAuthProvider, type ConfigureOAuthProviderInput, type ConfigureOAuthProviderResult, ProjectSecretService, type ProjectSecretServiceOptions, } from './secrets/projectSecretService';
|
|
11
|
+
export { resolveProjectSecretDatabaseUrl } from './secrets/resolveProjectSecretDatabaseUrl';
|
|
8
12
|
export { getProjectTemplate, getTemplateSummaries } from './templateRegistry';
|
|
9
13
|
export { resolveWorkspaceRoot } from './utils/workspaceRoot';
|
|
10
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/host/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/host/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/host/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,UAAU,GAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,4BAA4B,GAClC,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EACL,KAAK,sBAAsB,EAC3B,4BAA4B,GAC7B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,8BAA8B,EAC9B,KAAK,2BAA2B,EAChC,KAAK,4BAA4B,EACjC,oBAAoB,EACpB,KAAK,2BAA2B,GACjC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/host/index.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
export { createStudioHost, } from './createStudioHost';
|
|
2
|
+
export { registerProjectSecretRoutes } from './http/secretRoutes';
|
|
2
3
|
export { isOriginAllowed } from './http/security';
|
|
3
4
|
export { createStudioHostServer, startStudioHostServer, } from './http/server';
|
|
4
5
|
export { ModuleManager } from './orchestrator/moduleManager';
|
|
5
6
|
export { ProjectManager } from './orchestrator/projectManager';
|
|
6
7
|
export { assertProjectId, getAppsRoot, getProjectPath } from './orchestrator/projectPaths';
|
|
7
8
|
export { ProjectStore } from './orchestrator/projectStore';
|
|
9
|
+
export { createBunSupabaseVaultClient, } from './secrets/bunSupabaseVaultClient';
|
|
10
|
+
export { configureManifestOAuthProvider, ProjectSecretService, } from './secrets/projectSecretService';
|
|
11
|
+
export { resolveProjectSecretDatabaseUrl } from './secrets/resolveProjectSecretDatabaseUrl';
|
|
8
12
|
export { getProjectTemplate, getTemplateSummaries } from './templateRegistry';
|
|
9
13
|
export { resolveWorkspaceRoot } from './utils/workspaceRoot';
|
|
10
14
|
//# sourceMappingURL=index.js.map
|
package/dist/host/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/host/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAGjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GAEtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAuB,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/host/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAGjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GAEtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAuB,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAEL,4BAA4B,GAC7B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,8BAA8B,EAG9B,oBAAoB,GAErB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SupabaseVaultSqlClient } from '@ankhorage/supabase-vault';
|
|
2
|
+
export interface BunSupabaseVaultClient extends SupabaseVaultSqlClient {
|
|
3
|
+
close(): Promise<void>;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Trusted server-only PostgreSQL transport for the Supabase Vault adapter.
|
|
7
|
+
*
|
|
8
|
+
* The connection URL must come from Studio host configuration or the generated local Supabase
|
|
9
|
+
* environment. It must never be read from an application manifest or exposed to browser code.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createBunSupabaseVaultClient(databaseUrl: string): BunSupabaseVaultClient;
|
|
12
|
+
//# sourceMappingURL=bunSupabaseVaultClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bunSupabaseVaultClient.d.ts","sourceRoot":"","sources":["../../../src/host/secrets/bunSupabaseVaultClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,2BAA2B,CAAC;AAGnC,MAAM,WAAW,sBAAuB,SAAQ,sBAAsB;IACpE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,sBAAsB,CAyCxF"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { SQL } from 'bun';
|
|
2
|
+
/**
|
|
3
|
+
* Trusted server-only PostgreSQL transport for the Supabase Vault adapter.
|
|
4
|
+
*
|
|
5
|
+
* The connection URL must come from Studio host configuration or the generated local Supabase
|
|
6
|
+
* environment. It must never be read from an application manifest or exposed to browser code.
|
|
7
|
+
*/
|
|
8
|
+
export function createBunSupabaseVaultClient(databaseUrl) {
|
|
9
|
+
const normalizedUrl = databaseUrl.trim();
|
|
10
|
+
if (!normalizedUrl) {
|
|
11
|
+
throw new Error('Supabase Vault requires a trusted PostgreSQL database URL.');
|
|
12
|
+
}
|
|
13
|
+
const sql = new SQL(normalizedUrl, {
|
|
14
|
+
adapter: 'postgres',
|
|
15
|
+
max: 4,
|
|
16
|
+
connectionTimeout: 10,
|
|
17
|
+
});
|
|
18
|
+
const query = async (statement, parameters = []) => {
|
|
19
|
+
const rawRows = await sql.unsafe(statement, [...parameters]);
|
|
20
|
+
return { rows: assertRows(rawRows) };
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
query,
|
|
24
|
+
transaction(operation) {
|
|
25
|
+
return sql.begin((transaction) => operation({
|
|
26
|
+
async query(statement, parameters = []) {
|
|
27
|
+
const rawRows = await transaction.unsafe(statement, [...parameters]);
|
|
28
|
+
return { rows: assertRows(rawRows) };
|
|
29
|
+
},
|
|
30
|
+
}));
|
|
31
|
+
},
|
|
32
|
+
close() {
|
|
33
|
+
return sql.close({ timeout: 5 });
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function assertRows(value) {
|
|
38
|
+
if (!Array.isArray(value)) {
|
|
39
|
+
throw new Error('Supabase Vault query returned an unexpected result shape.');
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=bunSupabaseVaultClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bunSupabaseVaultClient.js","sourceRoot":"","sources":["../../../src/host/secrets/bunSupabaseVaultClient.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAM1B;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,WAAmB;IAC9D,MAAM,aAAa,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC;IACzC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,aAAa,EAAE;QACjC,OAAO,EAAE,UAAU;QACnB,GAAG,EAAE,CAAC;QACN,iBAAiB,EAAE,EAAE;KACtB,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,KAAK,EACjB,SAAiB,EACjB,aAAiC,EAAE,EACM,EAAE;QAC3C,MAAM,OAAO,GAAY,MAAM,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;QACtE,OAAO,EAAE,IAAI,EAAE,UAAU,CAAO,OAAO,CAAC,EAAE,CAAC;IAC7C,CAAC,CAAC;IAEF,OAAO;QACL,KAAK;QACL,WAAW,CACT,SAAmE;YAEnE,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,CAC/B,SAAS,CAAC;gBACR,KAAK,CAAC,KAAK,CACT,SAAiB,EACjB,aAAiC,EAAE;oBAEnC,MAAM,OAAO,GAAY,MAAM,WAAW,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;oBAC9E,OAAO,EAAE,IAAI,EAAE,UAAU,CAAO,OAAO,CAAC,EAAE,CAAC;gBAC7C,CAAC;aACF,CAAC,CACH,CAAC;QACJ,CAAC;QACD,KAAK;YACH,OAAO,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;QACnC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAuC,KAAc;IACtE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,CAAC;IAED,OAAO,KAAwB,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type AppManifest, type AuthOAuthProviderConfig, type AuthOAuthProviderId } from '@ankhorage/contracts';
|
|
2
|
+
import { type SecretMetadata, type SecretPayload, type SecretStoreResult } from '@ankhorage/contracts/secrets';
|
|
3
|
+
import type { ProjectManager } from '../orchestrator/projectManager';
|
|
4
|
+
import { type BunSupabaseVaultClient } from './bunSupabaseVaultClient';
|
|
5
|
+
export interface ProjectSecretServiceOptions {
|
|
6
|
+
readonly projectManager: ProjectManager;
|
|
7
|
+
readonly workspaceRoot: string;
|
|
8
|
+
readonly createClient?: (databaseUrl: string) => BunSupabaseVaultClient;
|
|
9
|
+
readonly resolveDatabaseUrl?: (projectPath: string) => Promise<string>;
|
|
10
|
+
}
|
|
11
|
+
export interface ConfigureOAuthProviderInput {
|
|
12
|
+
readonly projectId: string;
|
|
13
|
+
readonly environment?: string;
|
|
14
|
+
readonly providerId: AuthOAuthProviderId;
|
|
15
|
+
readonly payload: SecretPayload;
|
|
16
|
+
readonly credentialsRef?: string;
|
|
17
|
+
readonly enabled?: boolean;
|
|
18
|
+
readonly label?: string;
|
|
19
|
+
readonly scopes?: readonly string[];
|
|
20
|
+
readonly callbackRoute?: string;
|
|
21
|
+
}
|
|
22
|
+
export type ConfigureOAuthProviderResult = {
|
|
23
|
+
readonly ok: true;
|
|
24
|
+
readonly state: 'saved';
|
|
25
|
+
readonly metadata: SecretMetadata;
|
|
26
|
+
readonly credentialsRef: string;
|
|
27
|
+
} | {
|
|
28
|
+
readonly ok: false;
|
|
29
|
+
readonly state: 'secret_write_failed' | 'secret_saved_manifest_failed';
|
|
30
|
+
readonly error: {
|
|
31
|
+
readonly code: string;
|
|
32
|
+
readonly message: string;
|
|
33
|
+
};
|
|
34
|
+
readonly metadata?: SecretMetadata;
|
|
35
|
+
readonly credentialsRef?: string;
|
|
36
|
+
};
|
|
37
|
+
export declare class ProjectSecretService {
|
|
38
|
+
private readonly projectManager;
|
|
39
|
+
private readonly workspaceRoot;
|
|
40
|
+
private readonly createClient;
|
|
41
|
+
private readonly resolveDatabaseUrl;
|
|
42
|
+
constructor(options: ProjectSecretServiceOptions);
|
|
43
|
+
list(input: {
|
|
44
|
+
readonly projectId: string;
|
|
45
|
+
readonly environment?: string;
|
|
46
|
+
readonly kind?: string;
|
|
47
|
+
readonly provider?: string;
|
|
48
|
+
}): Promise<SecretStoreResult<readonly SecretMetadata[]>>;
|
|
49
|
+
getMetadata(input: {
|
|
50
|
+
readonly projectId: string;
|
|
51
|
+
readonly environment?: string;
|
|
52
|
+
readonly ref: string;
|
|
53
|
+
}): Promise<SecretStoreResult<SecretMetadata>>;
|
|
54
|
+
create(input: {
|
|
55
|
+
readonly projectId: string;
|
|
56
|
+
readonly environment?: string;
|
|
57
|
+
readonly ref: string;
|
|
58
|
+
readonly kind: string;
|
|
59
|
+
readonly provider?: string;
|
|
60
|
+
readonly payload: SecretPayload;
|
|
61
|
+
}): Promise<SecretStoreResult<SecretMetadata>>;
|
|
62
|
+
replace(input: {
|
|
63
|
+
readonly projectId: string;
|
|
64
|
+
readonly environment?: string;
|
|
65
|
+
readonly ref: string;
|
|
66
|
+
readonly payload: SecretPayload;
|
|
67
|
+
}): Promise<SecretStoreResult<SecretMetadata>>;
|
|
68
|
+
remove(input: {
|
|
69
|
+
readonly projectId: string;
|
|
70
|
+
readonly environment?: string;
|
|
71
|
+
readonly ref: string;
|
|
72
|
+
}): Promise<SecretStoreResult>;
|
|
73
|
+
configureOAuthProvider(input: ConfigureOAuthProviderInput): Promise<ConfigureOAuthProviderResult>;
|
|
74
|
+
private readEditableManifest;
|
|
75
|
+
private withAdapter;
|
|
76
|
+
}
|
|
77
|
+
export declare function configureManifestOAuthProvider(manifest: AppManifest, input: {
|
|
78
|
+
readonly provider: AuthOAuthProviderConfig;
|
|
79
|
+
readonly callbackRoute?: string;
|
|
80
|
+
}): AppManifest;
|
|
81
|
+
//# sourceMappingURL=projectSecretService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectSecretService.d.ts","sourceRoot":"","sources":["../../../src/host/secrets/projectSecretService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { DEFAULT_AUTH_FLOW, } from '@ankhorage/contracts';
|
|
2
|
+
import { normalizeSecretRef, } from '@ankhorage/contracts/secrets';
|
|
3
|
+
import { createInfraSecretStoreAdapter } from '@ankhorage/infra';
|
|
4
|
+
import { getSupabaseOAuthProviderDefinition, validateSupabaseOAuthSecretPayload, } from '@ankhorage/supabase-auth';
|
|
5
|
+
import { getProjectPath } from '../orchestrator/projectPaths';
|
|
6
|
+
import { createBunSupabaseVaultClient, } from './bunSupabaseVaultClient';
|
|
7
|
+
import { resolveProjectSecretDatabaseUrl } from './resolveProjectSecretDatabaseUrl';
|
|
8
|
+
export class ProjectSecretService {
|
|
9
|
+
projectManager;
|
|
10
|
+
workspaceRoot;
|
|
11
|
+
createClient;
|
|
12
|
+
resolveDatabaseUrl;
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.projectManager = options.projectManager;
|
|
15
|
+
this.workspaceRoot = options.workspaceRoot;
|
|
16
|
+
this.createClient = options.createClient ?? createBunSupabaseVaultClient;
|
|
17
|
+
this.resolveDatabaseUrl =
|
|
18
|
+
options.resolveDatabaseUrl ??
|
|
19
|
+
((projectPath) => resolveProjectSecretDatabaseUrl({ projectPath }));
|
|
20
|
+
}
|
|
21
|
+
list(input) {
|
|
22
|
+
return this.withAdapter(input.projectId, (adapter) => adapter.list({
|
|
23
|
+
scope: createScope(input.projectId, input.environment),
|
|
24
|
+
...(input.kind ? { kind: input.kind } : {}),
|
|
25
|
+
...(input.provider ? { provider: input.provider } : {}),
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
getMetadata(input) {
|
|
29
|
+
return this.withAdapter(input.projectId, (adapter) => adapter.getMetadata({
|
|
30
|
+
scope: createScope(input.projectId, input.environment),
|
|
31
|
+
ref: input.ref,
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
create(input) {
|
|
35
|
+
return this.withAdapter(input.projectId, (adapter) => adapter.create({
|
|
36
|
+
scope: createScope(input.projectId, input.environment),
|
|
37
|
+
ref: input.ref,
|
|
38
|
+
kind: input.kind,
|
|
39
|
+
...(input.provider ? { provider: input.provider } : {}),
|
|
40
|
+
payload: input.payload,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
replace(input) {
|
|
44
|
+
return this.withAdapter(input.projectId, (adapter) => adapter.replace({
|
|
45
|
+
scope: createScope(input.projectId, input.environment),
|
|
46
|
+
ref: input.ref,
|
|
47
|
+
payload: input.payload,
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
remove(input) {
|
|
51
|
+
return this.withAdapter(input.projectId, (adapter) => adapter.remove({
|
|
52
|
+
scope: createScope(input.projectId, input.environment),
|
|
53
|
+
ref: input.ref,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
async configureOAuthProvider(input) {
|
|
57
|
+
const definition = getSupabaseOAuthProviderDefinition(input.providerId);
|
|
58
|
+
if (!definition) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
state: 'secret_write_failed',
|
|
62
|
+
error: {
|
|
63
|
+
code: 'invalid_config',
|
|
64
|
+
message: `OAuth provider "${input.providerId}" is not supported by the current Supabase provider registry.`,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const payloadResult = validateSupabaseOAuthSecretPayload(input.providerId, input.payload);
|
|
69
|
+
if (!payloadResult.ok) {
|
|
70
|
+
return {
|
|
71
|
+
ok: false,
|
|
72
|
+
state: 'secret_write_failed',
|
|
73
|
+
error: toPublicError(payloadResult.error),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const refResult = normalizeSecretRef(input.credentialsRef ?? `auth/oauth/${definition.id}`);
|
|
77
|
+
if (!refResult.ok) {
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
state: 'secret_write_failed',
|
|
81
|
+
error: toPublicError(refResult.error),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const scope = createScope(input.projectId, input.environment);
|
|
85
|
+
const secretResult = await this.withAdapter(input.projectId, async (adapter) => {
|
|
86
|
+
const existing = await adapter.getMetadata({ scope, ref: refResult.data });
|
|
87
|
+
if (existing.ok) {
|
|
88
|
+
return adapter.replace({ scope, ref: refResult.data, payload: payloadResult.data });
|
|
89
|
+
}
|
|
90
|
+
if (existing.error.code !== 'not_found')
|
|
91
|
+
return existing;
|
|
92
|
+
return adapter.create({
|
|
93
|
+
scope,
|
|
94
|
+
ref: refResult.data,
|
|
95
|
+
kind: 'oauth',
|
|
96
|
+
provider: definition.id,
|
|
97
|
+
payload: payloadResult.data,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
if (!secretResult.ok) {
|
|
101
|
+
return {
|
|
102
|
+
ok: false,
|
|
103
|
+
state: 'secret_write_failed',
|
|
104
|
+
error: toPublicError(secretResult.error),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const manifest = await this.readEditableManifest(input.projectId);
|
|
108
|
+
const nextManifest = configureManifestOAuthProvider(manifest, {
|
|
109
|
+
provider: {
|
|
110
|
+
id: definition.id,
|
|
111
|
+
label: normalizeOptionalText(input.label) ?? definition.label,
|
|
112
|
+
enabled: input.enabled ?? true,
|
|
113
|
+
scopes: normalizeScopes(input.scopes ?? definition.defaultScopes),
|
|
114
|
+
credentialsRef: refResult.data,
|
|
115
|
+
},
|
|
116
|
+
callbackRoute: input.callbackRoute,
|
|
117
|
+
});
|
|
118
|
+
try {
|
|
119
|
+
await this.projectManager.saveStudioManifest({
|
|
120
|
+
projectId: input.projectId,
|
|
121
|
+
manifest: nextManifest,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return {
|
|
126
|
+
ok: false,
|
|
127
|
+
state: 'secret_saved_manifest_failed',
|
|
128
|
+
metadata: secretResult.data,
|
|
129
|
+
credentialsRef: refResult.data,
|
|
130
|
+
error: {
|
|
131
|
+
code: 'manifest_write_failed',
|
|
132
|
+
message: 'OAuth credentials were saved, but the manifest update failed. Retry the manifest save or remove the stored secret explicitly.',
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
ok: true,
|
|
138
|
+
state: 'saved',
|
|
139
|
+
metadata: secretResult.data,
|
|
140
|
+
credentialsRef: refResult.data,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async readEditableManifest(projectId) {
|
|
144
|
+
try {
|
|
145
|
+
return await this.projectManager.getStudioManifest(projectId);
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return this.projectManager.getProjectManifest(projectId);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async withAdapter(projectId, operation) {
|
|
152
|
+
let client = null;
|
|
153
|
+
try {
|
|
154
|
+
const manifest = await this.readEditableManifest(projectId);
|
|
155
|
+
const projectPath = getProjectPath(this.workspaceRoot, projectId);
|
|
156
|
+
const databaseUrl = await this.resolveDatabaseUrl(projectPath);
|
|
157
|
+
client = this.createClient(databaseUrl);
|
|
158
|
+
const adapter = createInfraSecretStoreAdapter({
|
|
159
|
+
manifest: manifest.infra,
|
|
160
|
+
providers: {
|
|
161
|
+
supabaseVault: { client },
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
if (!adapter) {
|
|
165
|
+
return {
|
|
166
|
+
ok: false,
|
|
167
|
+
error: {
|
|
168
|
+
code: 'invalid_config',
|
|
169
|
+
message: 'This project does not configure infra.secretStore.provider.',
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return await operation(adapter);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return {
|
|
177
|
+
ok: false,
|
|
178
|
+
error: {
|
|
179
|
+
code: 'unavailable',
|
|
180
|
+
message: 'The project secret store is unavailable. Verify local Supabase is running and the trusted database URL is configured.',
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
await client?.close();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
export function configureManifestOAuthProvider(manifest, input) {
|
|
190
|
+
const currentAuth = manifest.infra.auth;
|
|
191
|
+
const currentOAuth = currentAuth?.oauth;
|
|
192
|
+
const existingCallbackRoute = currentOAuth ? currentOAuth.callbackRoute : undefined;
|
|
193
|
+
const callbackRoute = normalizeOptionalText(input.callbackRoute) ??
|
|
194
|
+
normalizeOptionalText(existingCallbackRoute) ??
|
|
195
|
+
'/auth/callback';
|
|
196
|
+
const providers = [...(currentOAuth?.providers ?? [])];
|
|
197
|
+
const existingIndex = providers.findIndex((provider) => provider.id === input.provider.id);
|
|
198
|
+
if (existingIndex >= 0)
|
|
199
|
+
providers[existingIndex] = input.provider;
|
|
200
|
+
else
|
|
201
|
+
providers.push(input.provider);
|
|
202
|
+
return {
|
|
203
|
+
...manifest,
|
|
204
|
+
infra: {
|
|
205
|
+
...manifest.infra,
|
|
206
|
+
auth: {
|
|
207
|
+
...(currentAuth ?? {
|
|
208
|
+
provider: 'supabase',
|
|
209
|
+
scope: 'global',
|
|
210
|
+
flow: { ...DEFAULT_AUTH_FLOW },
|
|
211
|
+
signIn: { identifiers: ['email'] },
|
|
212
|
+
}),
|
|
213
|
+
oauth: {
|
|
214
|
+
enabled: true,
|
|
215
|
+
callbackRoute,
|
|
216
|
+
providers,
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function createScope(projectId, environment = 'local') {
|
|
223
|
+
return {
|
|
224
|
+
projectId,
|
|
225
|
+
environment: normalizeOptionalText(environment) ?? 'local',
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
function normalizeScopes(scopes) {
|
|
229
|
+
return [...new Set(scopes.map((scope) => scope.trim()).filter(Boolean))];
|
|
230
|
+
}
|
|
231
|
+
function normalizeOptionalText(value) {
|
|
232
|
+
const normalized = value?.trim();
|
|
233
|
+
if (!normalized)
|
|
234
|
+
return undefined;
|
|
235
|
+
return normalized;
|
|
236
|
+
}
|
|
237
|
+
function toPublicError(error) {
|
|
238
|
+
return { code: error.code, message: error.message };
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=projectSecretService.js.map
|