@undefineds.co/xpod 0.2.33 → 0.2.35
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/api/container/local.js +1 -5
- package/dist/api/container/local.js.map +1 -1
- package/dist/api/container/routes.js +16 -1
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/handlers/PodManagementHandler.d.ts +8 -0
- package/dist/api/handlers/PodManagementHandler.js +5 -3
- package/dist/api/handlers/PodManagementHandler.js.map +1 -1
- package/dist/api/handlers/WebIdProfileHandler.js +64 -6
- package/dist/api/handlers/WebIdProfileHandler.js.map +1 -1
- package/dist/api/runtime.js +11 -6
- package/dist/api/runtime.js.map +1 -1
- package/dist/cli/commands/start.js +4 -6
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/components/components.jsonld +1 -0
- package/dist/components/context.jsonld +36 -0
- package/dist/edge/LocalNetworkManager.d.ts +2 -7
- package/dist/edge/LocalNetworkManager.js +7 -34
- package/dist/edge/LocalNetworkManager.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/provision/LocalPodProvisioningService.d.ts +34 -0
- package/dist/provision/LocalPodProvisioningService.js +294 -0
- package/dist/provision/LocalPodProvisioningService.js.map +1 -0
- package/dist/provision/LocalPodProvisioningService.jsonld +142 -0
- package/dist/provision/ProvisionPodCreator.js +3 -4
- package/dist/provision/ProvisionPodCreator.js.map +1 -1
- package/dist/runtime/bootstrap.js +15 -3
- package/dist/runtime/bootstrap.js.map +1 -1
- package/dist/runtime/oidc-issuer.d.ts +11 -0
- package/dist/runtime/oidc-issuer.js +32 -0
- package/dist/runtime/oidc-issuer.js.map +1 -0
- package/dist/tunnel/LocalTunnelProvider.d.ts +2 -2
- package/dist/tunnel/LocalTunnelProvider.js +12 -14
- package/dist/tunnel/LocalTunnelProvider.js.map +1 -1
- package/dist/tunnel/TunnelProvider.d.ts +2 -0
- package/dist/tunnel/TunnelProvider.js.map +1 -1
- package/dist/tunnel/TunnelProvider.jsonld +4 -0
- package/package.json +1 -1
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LocalPodProvisioningService = void 0;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const n3_1 = require("n3");
|
|
11
|
+
const global_logger_factory_1 = require("global-logger-factory");
|
|
12
|
+
const serialization_1 = require("../storage/quint/serialization");
|
|
13
|
+
const SqliteRuntime_1 = require("../storage/SqliteRuntime");
|
|
14
|
+
const RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
|
|
15
|
+
const LDP = 'http://www.w3.org/ns/ldp#';
|
|
16
|
+
const DCT = 'http://purl.org/dc/terms/';
|
|
17
|
+
const MA = 'http://www.w3.org/ns/ma-ont#';
|
|
18
|
+
const PIM = 'http://www.w3.org/ns/pim/space#';
|
|
19
|
+
const FOAF = 'http://xmlns.com/foaf/0.1/';
|
|
20
|
+
const SOLID = 'http://www.w3.org/ns/solid/terms#';
|
|
21
|
+
const ACL = 'http://www.w3.org/ns/auth/acl#';
|
|
22
|
+
const ACP = 'http://www.w3.org/ns/solid/acp#';
|
|
23
|
+
const { blankNode, literal, namedNode, quad } = n3_1.DataFactory;
|
|
24
|
+
function ensureTrailingSlash(url) {
|
|
25
|
+
return url.endsWith('/') ? url : `${url}/`;
|
|
26
|
+
}
|
|
27
|
+
function stripSqlitePrefix(value, label) {
|
|
28
|
+
if (value.startsWith('sqlite:')) {
|
|
29
|
+
return value.slice('sqlite:'.length);
|
|
30
|
+
}
|
|
31
|
+
if (value === ':memory:') {
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
if (/^[a-z][a-z0-9+.-]*:/iu.test(value)) {
|
|
35
|
+
throw new Error(`${label} must be a sqlite URL for local Pod provisioning: ${value}`);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function stableUuid(input) {
|
|
40
|
+
const hex = (0, node_crypto_1.createHash)('sha256').update(input).digest('hex').slice(0, 32);
|
|
41
|
+
return [
|
|
42
|
+
hex.slice(0, 8),
|
|
43
|
+
hex.slice(8, 12),
|
|
44
|
+
`4${hex.slice(13, 16)}`,
|
|
45
|
+
`${((Number.parseInt(hex.slice(16, 18), 16) & 0x3f) | 0x80).toString(16).padStart(2, '0')}${hex.slice(18, 20)}`,
|
|
46
|
+
hex.slice(20, 32),
|
|
47
|
+
].join('-');
|
|
48
|
+
}
|
|
49
|
+
function inferIssuerFromWebId(webId) {
|
|
50
|
+
if (!webId) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const url = new URL(webId);
|
|
55
|
+
return `${url.origin}/`;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function buildWebIdFromIssuer(oidcIssuer, podName) {
|
|
62
|
+
if (!oidcIssuer) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
return new URL(`${encodeURIComponent(podName)}/profile/card#me`, ensureTrailingSlash(oidcIssuer)).toString();
|
|
66
|
+
}
|
|
67
|
+
function createQuintsTable(db) {
|
|
68
|
+
db.exec(`
|
|
69
|
+
CREATE TABLE IF NOT EXISTS quints (
|
|
70
|
+
graph TEXT NOT NULL,
|
|
71
|
+
subject TEXT NOT NULL,
|
|
72
|
+
predicate TEXT NOT NULL,
|
|
73
|
+
object TEXT NOT NULL,
|
|
74
|
+
vector TEXT,
|
|
75
|
+
PRIMARY KEY (graph, subject, predicate, object)
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_spog ON quints (subject, predicate, object, graph);
|
|
79
|
+
CREATE INDEX IF NOT EXISTS idx_ogsp ON quints (object, graph, subject, predicate);
|
|
80
|
+
CREATE INDEX IF NOT EXISTS idx_gspo ON quints (graph, subject, predicate, object);
|
|
81
|
+
CREATE INDEX IF NOT EXISTS idx_sopg ON quints (subject, object, predicate, graph);
|
|
82
|
+
CREATE INDEX IF NOT EXISTS idx_pogs ON quints (predicate, object, graph, subject);
|
|
83
|
+
CREATE INDEX IF NOT EXISTS idx_gpos ON quints (graph, predicate, object, subject);
|
|
84
|
+
`);
|
|
85
|
+
}
|
|
86
|
+
function createInternalKvTable(db) {
|
|
87
|
+
db.exec(`
|
|
88
|
+
CREATE TABLE IF NOT EXISTS internal_kv (
|
|
89
|
+
key TEXT PRIMARY KEY,
|
|
90
|
+
value TEXT NOT NULL,
|
|
91
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
92
|
+
);
|
|
93
|
+
`);
|
|
94
|
+
}
|
|
95
|
+
function meta(resource) {
|
|
96
|
+
return `meta:${resource}`;
|
|
97
|
+
}
|
|
98
|
+
function iri(base, relative) {
|
|
99
|
+
return new URL(relative, base).toString();
|
|
100
|
+
}
|
|
101
|
+
class LocalPodProvisioningService {
|
|
102
|
+
constructor(options) {
|
|
103
|
+
this.logger = (0, global_logger_factory_1.getLoggerFor)(this);
|
|
104
|
+
this.sqliteRuntime = (0, SqliteRuntime_1.getSqliteRuntime)();
|
|
105
|
+
this.baseUrl = ensureTrailingSlash(options.baseUrl);
|
|
106
|
+
this.rootDir = options.rootDir;
|
|
107
|
+
this.sparqlDbPath = stripSqlitePrefix(options.sparqlEndpoint, 'sparqlEndpoint');
|
|
108
|
+
this.identityDbPath = stripSqlitePrefix(options.identityDbUrl, 'identityDbUrl');
|
|
109
|
+
this.oidcIssuer = options.oidcIssuer ? ensureTrailingSlash(options.oidcIssuer) : undefined;
|
|
110
|
+
}
|
|
111
|
+
async createPod(input) {
|
|
112
|
+
const podUrl = ensureTrailingSlash(new URL(`${encodeURIComponent(input.podName)}/`, this.baseUrl).toString());
|
|
113
|
+
const webId = input.webId ?? buildWebIdFromIssuer(this.oidcIssuer, input.podName) ?? `${podUrl}profile/card#me`;
|
|
114
|
+
const oidcIssuer = this.oidcIssuer ?? inferIssuerFromWebId(webId) ?? this.baseUrl;
|
|
115
|
+
const accountId = stableUuid(`account:${podUrl}:${webId}`);
|
|
116
|
+
const podId = stableUuid(`pod:${podUrl}:${webId}`);
|
|
117
|
+
const ownerId = stableUuid(`owner:${podId}:${webId}`);
|
|
118
|
+
const webIdLinkId = stableUuid(`webIdLink:${accountId}:${webId}`);
|
|
119
|
+
await this.createPodFiles(input.podName, input.initialResources);
|
|
120
|
+
this.writeQuints({ podUrl, webId, oidcIssuer });
|
|
121
|
+
this.writeIdentityIndexes({ accountId, podId, ownerId, webIdLinkId, podUrl, webId });
|
|
122
|
+
this.logger.info(`Provisioned local pod ${podUrl} for ${webId}`);
|
|
123
|
+
return { podUrl, accountId, podId };
|
|
124
|
+
}
|
|
125
|
+
async createPodFiles(podName, initialResources) {
|
|
126
|
+
const podPath = node_path_1.default.join(this.rootDir, podName);
|
|
127
|
+
await node_fs_1.promises.mkdir(node_path_1.default.join(podPath, 'profile'), { recursive: true });
|
|
128
|
+
if (!initialResources) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
for (const [filename, content] of Object.entries(initialResources)) {
|
|
132
|
+
const normalized = node_path_1.default.normalize(filename);
|
|
133
|
+
if (normalized.startsWith('..') || node_path_1.default.isAbsolute(normalized)) {
|
|
134
|
+
throw new Error(`Invalid initial resource path: ${filename}`);
|
|
135
|
+
}
|
|
136
|
+
const filePath = node_path_1.default.join(podPath, normalized);
|
|
137
|
+
await node_fs_1.promises.mkdir(node_path_1.default.dirname(filePath), { recursive: true });
|
|
138
|
+
await node_fs_1.promises.writeFile(filePath, content, 'utf8');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
writeQuints(input) {
|
|
142
|
+
const db = this.sqliteRuntime.openDatabase(this.sparqlDbPath);
|
|
143
|
+
try {
|
|
144
|
+
createQuintsTable(db);
|
|
145
|
+
const rows = this.buildPodQuads(input).map((entry) => {
|
|
146
|
+
const row = (0, serialization_1.quadToRow)(entry);
|
|
147
|
+
return [row.graph, row.subject, row.predicate, row.object, row.vector];
|
|
148
|
+
});
|
|
149
|
+
const insert = db.prepare(`
|
|
150
|
+
INSERT OR IGNORE INTO quints (graph, subject, predicate, object, vector)
|
|
151
|
+
VALUES (?, ?, ?, ?, ?)
|
|
152
|
+
`);
|
|
153
|
+
db.transaction(() => {
|
|
154
|
+
for (const row of rows) {
|
|
155
|
+
insert.run(...row);
|
|
156
|
+
}
|
|
157
|
+
})();
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
db.close();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
buildPodQuads({ podUrl, webId, oidcIssuer }) {
|
|
164
|
+
const now = new Date().toISOString();
|
|
165
|
+
const root = this.baseUrl;
|
|
166
|
+
const profileUrl = iri(podUrl, 'profile/');
|
|
167
|
+
const cardUrl = iri(podUrl, 'profile/card');
|
|
168
|
+
const rootAcrUrl = iri(podUrl, '.acr');
|
|
169
|
+
const cardAcrUrl = iri(podUrl, 'profile/card.acr');
|
|
170
|
+
const rootGraph = namedNode(root);
|
|
171
|
+
const podGraph = namedNode(podUrl);
|
|
172
|
+
const profileGraph = namedNode(profileUrl);
|
|
173
|
+
const cardGraph = namedNode(cardUrl);
|
|
174
|
+
const rootAcrGraph = namedNode(rootAcrUrl);
|
|
175
|
+
const cardAcrGraph = namedNode(cardAcrUrl);
|
|
176
|
+
const out = [];
|
|
177
|
+
const add = (graph, subject, predicate, object) => {
|
|
178
|
+
out.push(quad(namedNode(subject), namedNode(predicate), namedNode(object), namedNode(graph)));
|
|
179
|
+
};
|
|
180
|
+
const addLiteral = (graph, subject, predicate, value) => {
|
|
181
|
+
out.push(quad(namedNode(subject), namedNode(predicate), literal(value), namedNode(graph)));
|
|
182
|
+
};
|
|
183
|
+
const addDate = (graph, subject) => {
|
|
184
|
+
out.push(quad(namedNode(subject), namedNode(`${DCT}modified`), literal(now, namedNode('http://www.w3.org/2001/XMLSchema#dateTime')), namedNode(graph)));
|
|
185
|
+
};
|
|
186
|
+
const addContainerMeta = (resource, storage = false) => {
|
|
187
|
+
const graph = meta(resource);
|
|
188
|
+
addDate(graph, resource);
|
|
189
|
+
add(graph, resource, `${RDF}type`, `${LDP}Resource`);
|
|
190
|
+
add(graph, resource, `${RDF}type`, `${LDP}Container`);
|
|
191
|
+
add(graph, resource, `${RDF}type`, `${LDP}BasicContainer`);
|
|
192
|
+
if (storage) {
|
|
193
|
+
add(graph, resource, `${RDF}type`, `${PIM}Storage`);
|
|
194
|
+
}
|
|
195
|
+
addLiteral(graph, resource, `${MA}format`, 'internal/quads');
|
|
196
|
+
};
|
|
197
|
+
const addDocumentMeta = (resource) => {
|
|
198
|
+
const graph = meta(resource);
|
|
199
|
+
addDate(graph, resource);
|
|
200
|
+
add(graph, resource, `${RDF}type`, `${LDP}Resource`);
|
|
201
|
+
};
|
|
202
|
+
out.push(quad(namedNode(root), namedNode(`${LDP}contains`), namedNode(podUrl), rootGraph));
|
|
203
|
+
out.push(quad(namedNode(podUrl), namedNode(`${LDP}contains`), namedNode(rootAcrUrl), podGraph));
|
|
204
|
+
out.push(quad(namedNode(podUrl), namedNode(`${LDP}contains`), namedNode(profileUrl), podGraph));
|
|
205
|
+
out.push(quad(namedNode(profileUrl), namedNode(`${LDP}contains`), namedNode(cardUrl), profileGraph));
|
|
206
|
+
out.push(quad(namedNode(profileUrl), namedNode(`${LDP}contains`), namedNode(cardAcrUrl), profileGraph));
|
|
207
|
+
addContainerMeta(root);
|
|
208
|
+
addContainerMeta(podUrl, true);
|
|
209
|
+
addContainerMeta(profileUrl);
|
|
210
|
+
addDocumentMeta(rootAcrUrl);
|
|
211
|
+
addDocumentMeta(cardUrl);
|
|
212
|
+
addDocumentMeta(cardAcrUrl);
|
|
213
|
+
out.push(quad(namedNode(cardUrl), namedNode(`${RDF}type`), namedNode(`${FOAF}PersonalProfileDocument`), cardGraph));
|
|
214
|
+
out.push(quad(namedNode(cardUrl), namedNode(`${FOAF}maker`), namedNode(webId), cardGraph));
|
|
215
|
+
out.push(quad(namedNode(cardUrl), namedNode(`${FOAF}primaryTopic`), namedNode(webId), cardGraph));
|
|
216
|
+
out.push(quad(namedNode(webId), namedNode(`${RDF}type`), namedNode(`${FOAF}Person`), cardGraph));
|
|
217
|
+
out.push(quad(namedNode(webId), namedNode(`${SOLID}oidcIssuer`), namedNode(oidcIssuer), cardGraph));
|
|
218
|
+
this.addRootAcrQuads(out, rootAcrGraph, rootAcrUrl, podUrl, webId);
|
|
219
|
+
this.addPublicReadAcrQuads(out, cardAcrGraph, cardAcrUrl, cardUrl);
|
|
220
|
+
return out;
|
|
221
|
+
}
|
|
222
|
+
addRootAcrQuads(out, graph, acrUrl, podUrl, webId) {
|
|
223
|
+
const root = namedNode(`${acrUrl}#root`);
|
|
224
|
+
const publicRead = namedNode(`${acrUrl}#publicReadAccess`);
|
|
225
|
+
const fullOwner = namedNode(`${acrUrl}#fullOwnerAccess`);
|
|
226
|
+
const publicPolicy = blankNode(`public-policy-${stableUuid(acrUrl)}`);
|
|
227
|
+
const publicMatcher = blankNode(`public-matcher-${stableUuid(acrUrl)}`);
|
|
228
|
+
const ownerPolicy = blankNode(`owner-policy-${stableUuid(acrUrl)}`);
|
|
229
|
+
const ownerMatcher = blankNode(`owner-matcher-${stableUuid(acrUrl)}`);
|
|
230
|
+
out.push(quad(root, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControlResource`), graph), quad(root, namedNode(`${ACP}resource`), namedNode(podUrl), graph), quad(root, namedNode(`${ACP}accessControl`), publicRead, graph), quad(root, namedNode(`${ACP}accessControl`), fullOwner, graph), quad(root, namedNode(`${ACP}memberAccessControl`), fullOwner, graph), quad(publicRead, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControl`), graph), quad(publicRead, namedNode(`${ACP}apply`), publicPolicy, graph), quad(publicPolicy, namedNode(`${RDF}type`), namedNode(`${ACP}Policy`), graph), quad(publicPolicy, namedNode(`${ACP}allow`), namedNode(`${ACL}Read`), graph), quad(publicPolicy, namedNode(`${ACP}anyOf`), publicMatcher, graph), quad(publicMatcher, namedNode(`${RDF}type`), namedNode(`${ACP}Matcher`), graph), quad(publicMatcher, namedNode(`${ACP}agent`), namedNode(`${ACP}PublicAgent`), graph), quad(fullOwner, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControl`), graph), quad(fullOwner, namedNode(`${ACP}apply`), ownerPolicy, graph), quad(ownerPolicy, namedNode(`${RDF}type`), namedNode(`${ACP}Policy`), graph), quad(ownerPolicy, namedNode(`${ACP}allow`), namedNode(`${ACL}Read`), graph), quad(ownerPolicy, namedNode(`${ACP}allow`), namedNode(`${ACL}Write`), graph), quad(ownerPolicy, namedNode(`${ACP}allow`), namedNode(`${ACL}Control`), graph), quad(ownerPolicy, namedNode(`${ACP}anyOf`), ownerMatcher, graph), quad(ownerMatcher, namedNode(`${RDF}type`), namedNode(`${ACP}Matcher`), graph), quad(ownerMatcher, namedNode(`${ACP}agent`), namedNode(webId), graph));
|
|
231
|
+
}
|
|
232
|
+
addPublicReadAcrQuads(out, graph, acrUrl, resourceUrl) {
|
|
233
|
+
const card = namedNode(`${acrUrl}#card`);
|
|
234
|
+
const publicRead = namedNode(`${acrUrl}#publicReadAccess`);
|
|
235
|
+
const policy = blankNode(`card-policy-${stableUuid(acrUrl)}`);
|
|
236
|
+
const matcher = blankNode(`card-matcher-${stableUuid(acrUrl)}`);
|
|
237
|
+
out.push(quad(card, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControlResource`), graph), quad(card, namedNode(`${ACP}resource`), namedNode(resourceUrl), graph), quad(card, namedNode(`${ACP}accessControl`), publicRead, graph), quad(publicRead, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControl`), graph), quad(publicRead, namedNode(`${ACP}apply`), policy, graph), quad(policy, namedNode(`${RDF}type`), namedNode(`${ACP}Policy`), graph), quad(policy, namedNode(`${ACP}allow`), namedNode(`${ACL}Read`), graph), quad(policy, namedNode(`${ACP}anyOf`), matcher, graph), quad(matcher, namedNode(`${RDF}type`), namedNode(`${ACP}Matcher`), graph), quad(matcher, namedNode(`${ACP}agent`), namedNode(`${ACP}PublicAgent`), graph));
|
|
238
|
+
}
|
|
239
|
+
writeIdentityIndexes(input) {
|
|
240
|
+
const db = this.sqliteRuntime.openDatabase(this.identityDbPath);
|
|
241
|
+
try {
|
|
242
|
+
createInternalKvTable(db);
|
|
243
|
+
const account = {
|
|
244
|
+
linkedLoginsCount: 1,
|
|
245
|
+
id: input.accountId,
|
|
246
|
+
'**pod**': {
|
|
247
|
+
[input.podId]: {
|
|
248
|
+
baseUrl: input.podUrl,
|
|
249
|
+
accountId: input.accountId,
|
|
250
|
+
id: input.podId,
|
|
251
|
+
'**owner**': {
|
|
252
|
+
[input.ownerId]: {
|
|
253
|
+
podId: input.podId,
|
|
254
|
+
webId: input.webId,
|
|
255
|
+
visible: false,
|
|
256
|
+
id: input.ownerId,
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
'**webIdLink**': {
|
|
262
|
+
[input.webIdLinkId]: {
|
|
263
|
+
webId: input.webId,
|
|
264
|
+
accountId: input.accountId,
|
|
265
|
+
id: input.webIdLinkId,
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
const rows = [
|
|
270
|
+
[`accounts/data/${input.accountId}`, JSON.stringify(account)],
|
|
271
|
+
[`accounts/index/pod/${input.podId}`, JSON.stringify([input.accountId])],
|
|
272
|
+
[`accounts/index/pod/baseUrl/${encodeURIComponent(input.podUrl)}`, JSON.stringify([input.accountId])],
|
|
273
|
+
[`accounts/index/owner/${input.ownerId}`, JSON.stringify([input.accountId])],
|
|
274
|
+
[`accounts/index/webIdLink/${input.webIdLinkId}`, JSON.stringify([input.accountId])],
|
|
275
|
+
[`accounts/index/webIdLink/webId/${encodeURIComponent(input.webId)}`, JSON.stringify([input.accountId])],
|
|
276
|
+
];
|
|
277
|
+
const insert = db.prepare(`
|
|
278
|
+
INSERT INTO internal_kv (key, value, updated_at)
|
|
279
|
+
VALUES (?, ?, datetime('now'))
|
|
280
|
+
ON CONFLICT (key) DO UPDATE SET value = excluded.value, updated_at = datetime('now')
|
|
281
|
+
`);
|
|
282
|
+
db.transaction(() => {
|
|
283
|
+
for (const row of rows) {
|
|
284
|
+
insert.run(...row);
|
|
285
|
+
}
|
|
286
|
+
})();
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
db.close();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
exports.LocalPodProvisioningService = LocalPodProvisioningService;
|
|
294
|
+
//# sourceMappingURL=LocalPodProvisioningService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalPodProvisioningService.js","sourceRoot":"","sources":["../../src/provision/LocalPodProvisioningService.ts"],"names":[],"mappings":";;;;;;AAAA,6CAAyC;AACzC,qCAAyC;AACzC,0DAA6B;AAC7B,2BAAiC;AAEjC,iEAAqD;AACrD,kEAA2D;AAC3D,4DAAiF;AAEjF,MAAM,GAAG,GAAG,6CAA6C,CAAC;AAC1D,MAAM,GAAG,GAAG,2BAA2B,CAAC;AACxC,MAAM,GAAG,GAAG,2BAA2B,CAAC;AACxC,MAAM,EAAE,GAAG,8BAA8B,CAAC;AAC1C,MAAM,GAAG,GAAG,iCAAiC,CAAC;AAC9C,MAAM,IAAI,GAAG,4BAA4B,CAAC;AAC1C,MAAM,KAAK,GAAG,mCAAmC,CAAC;AAClD,MAAM,GAAG,GAAG,gCAAgC,CAAC;AAC7C,MAAM,GAAG,GAAG,iCAAiC,CAAC;AAE9C,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,gBAAW,CAAC;AAsB5D,SAAS,mBAAmB,CAAC,GAAW;IACtC,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;AAC7C,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAa,EAAE,KAAa;IACrD,IAAI,KAAK,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IACD,IAAI,KAAK,KAAK,UAAU,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qDAAqD,KAAK,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,GAAG,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1E,OAAO;QACL,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QAChB,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE;QACvB,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE;QAC/G,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;KAClB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAyB;IACrD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,UAA8B,EAAE,OAAe;IAC3E,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,GAAG,kBAAkB,CAAC,OAAO,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC/G,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAkB;IAC3C,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;GAgBP,CAAC,CAAC;AACL,CAAC;AAED,SAAS,qBAAqB,CAAC,EAAkB;IAC/C,EAAE,CAAC,IAAI,CAAC;;;;;;GAMP,CAAC,CAAC;AACL,CAAC;AAED,SAAS,IAAI,CAAC,QAAgB;IAC5B,OAAO,QAAQ,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,GAAG,CAAC,IAAY,EAAE,QAAgB;IACzC,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC5C,CAAC;AAED,MAAa,2BAA2B;IAStC,YAAmB,OAA2C;QAR7C,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAM5B,kBAAa,GAAG,IAAA,gCAAgB,GAAE,CAAC;QAGlD,IAAI,CAAC,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;QAChF,IAAI,CAAC,cAAc,GAAG,iBAAiB,CAAC,OAAO,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;QAChF,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7F,CAAC;IAEM,KAAK,CAAC,SAAS,CAAC,KAAgC;QACrD,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,GAAG,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC9G,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,oBAAoB,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,MAAM,iBAAiB,CAAC;QAChH,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,oBAAoB,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC;QAClF,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,MAAM,IAAI,KAAK,EAAE,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,MAAM,IAAI,KAAK,EAAE,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,KAAK,IAAI,KAAK,EAAE,CAAC,CAAC;QACtD,MAAM,WAAW,GAAG,UAAU,CAAC,aAAa,SAAS,IAAI,KAAK,EAAE,CAAC,CAAC;QAElE,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;QACjE,IAAI,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,oBAAoB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAErF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,MAAM,QAAQ,KAAK,EAAE,CAAC,CAAC;QACjE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACtC,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,OAAe,EAAE,gBAAyC;QACrF,MAAM,OAAO,GAAG,mBAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,kBAAE,CAAC,KAAK,CAAC,mBAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEnE,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACnE,MAAM,UAAU,GAAG,mBAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC5C,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,mBAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/D,MAAM,IAAI,KAAK,CAAC,kCAAkC,QAAQ,EAAE,CAAC,CAAC;YAChE,CAAC;YACD,MAAM,QAAQ,GAAG,mBAAI,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAChD,MAAM,kBAAE,CAAC,KAAK,CAAC,mBAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5D,MAAM,kBAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,KAA4D;QAC9E,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9D,IAAI,CAAC;YACH,iBAAiB,CAAC,EAAE,CAAC,CAAC;YACtB,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBACnD,MAAM,GAAG,GAAG,IAAA,yBAAS,EAAC,KAAK,CAAC,CAAC;gBAC7B,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAU,CAAC;YAClF,CAAC,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC;;;OAGzB,CAAC,CAAC;YAEH,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;gBAClB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;oBACvB,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;gBACrB,CAAC;YACH,CAAC,CAAC,EAAE,CAAC;QACP,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAyD;QACxG,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;QAC1B,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QAC5C,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,YAAY,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,YAAY,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,YAAY,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAW,EAAE,CAAC;QAEvB,MAAM,GAAG,GAAG,CAAC,KAAa,EAAE,OAAe,EAAE,SAAiB,EAAE,MAAc,EAAQ,EAAE;YACtF,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAChG,CAAC,CAAC;QACF,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,OAAe,EAAE,SAAiB,EAAE,KAAa,EAAQ,EAAE;YAC5F,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7F,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,OAAe,EAAQ,EAAE;YACvD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,2CAA2C,CAAC,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC1J,CAAC,CAAC;QACF,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAE,OAAO,GAAG,KAAK,EAAQ,EAAE;YACnE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YACzB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAG,MAAM,EAAE,GAAG,GAAG,UAAU,CAAC,CAAC;YACrD,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAG,MAAM,EAAE,GAAG,GAAG,WAAW,CAAC,CAAC;YACtD,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAG,MAAM,EAAE,GAAG,GAAG,gBAAgB,CAAC,CAAC;YAC3D,IAAI,OAAO,EAAE,CAAC;gBACZ,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAG,MAAM,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;YACtD,CAAC;YACD,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QAC/D,CAAC,CAAC;QACF,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAQ,EAAE;YACjD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7B,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YACzB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAG,MAAM,EAAE,GAAG,GAAG,UAAU,CAAC,CAAC;QACvD,CAAC,CAAC;QAEF,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QAC3F,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;QAChG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;QAChG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;QACrG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;QAExG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACvB,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC7B,eAAe,CAAC,UAAU,CAAC,CAAC;QAC5B,eAAe,CAAC,OAAO,CAAC,CAAC;QACzB,eAAe,CAAC,UAAU,CAAC,CAAC;QAE5B,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,yBAAyB,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QACpH,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QAC3F,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,cAAc,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QAClG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,IAAI,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QACjG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC,GAAG,KAAK,YAAY,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC;QAEpG,IAAI,CAAC,eAAe,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACnE,IAAI,CAAC,qBAAqB,CAAC,GAAG,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAEnE,OAAO,GAAG,CAAC;IACb,CAAC;IAEO,eAAe,CAAC,GAAW,EAAE,KAAmC,EAAE,MAAc,EAAE,MAAc,EAAE,KAAa;QACrH,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,MAAM,mBAAmB,CAAC,CAAC;QAC3D,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,MAAM,kBAAkB,CAAC,CAAC;QACzD,MAAM,YAAY,GAAG,SAAS,CAAC,iBAAiB,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACtE,MAAM,aAAa,GAAG,SAAS,CAAC,kBAAkB,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxE,MAAM,WAAW,GAAG,SAAS,CAAC,gBAAgB,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpE,MAAM,YAAY,GAAG,SAAS,CAAC,iBAAiB,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEtE,GAAG,CAAC,IAAI,CACN,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,uBAAuB,CAAC,EAAE,KAAK,CAAC,EACpF,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,EACjE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,GAAG,eAAe,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,EAC/D,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,EAC9D,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,GAAG,qBAAqB,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,EACpE,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,eAAe,CAAC,EAAE,KAAK,CAAC,EAClF,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,EAC/D,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,QAAQ,CAAC,EAAE,KAAK,CAAC,EAC7E,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,EAC5E,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,EAClE,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,SAAS,CAAC,EAAE,KAAK,CAAC,EAC/E,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,aAAa,CAAC,EAAE,KAAK,CAAC,EACpF,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,eAAe,CAAC,EAAE,KAAK,CAAC,EACjF,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,EAC7D,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,QAAQ,CAAC,EAAE,KAAK,CAAC,EAC5E,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,EAC3E,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,KAAK,CAAC,EAC5E,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,SAAS,CAAC,EAAE,KAAK,CAAC,EAC9E,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,EAChE,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,SAAS,CAAC,EAAE,KAAK,CAAC,EAC9E,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CACtE,CAAC;IACJ,CAAC;IAEO,qBAAqB,CAAC,GAAW,EAAE,KAAmC,EAAE,MAAc,EAAE,WAAmB;QACjH,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,MAAM,mBAAmB,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,SAAS,CAAC,eAAe,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,SAAS,CAAC,gBAAgB,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAEhE,GAAG,CAAC,IAAI,CACN,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,uBAAuB,CAAC,EAAE,KAAK,CAAC,EACpF,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,GAAG,UAAU,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,EAAE,KAAK,CAAC,EACtE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,GAAG,eAAe,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,EAC/D,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,eAAe,CAAC,EAAE,KAAK,CAAC,EAClF,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EACzD,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,QAAQ,CAAC,EAAE,KAAK,CAAC,EACvE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,EACtE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,EACtD,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,SAAS,CAAC,EAAE,KAAK,CAAC,EACzE,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,GAAG,aAAa,CAAC,EAAE,KAAK,CAAC,CAC/E,CAAC;IACJ,CAAC;IAEO,oBAAoB,CAAC,KAO5B;QACC,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAChE,IAAI,CAAC;YACH,qBAAqB,CAAC,EAAE,CAAC,CAAC;YAC1B,MAAM,OAAO,GAAG;gBACd,iBAAiB,EAAE,CAAC;gBACpB,EAAE,EAAE,KAAK,CAAC,SAAS;gBACnB,SAAS,EAAE;oBACT,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;wBACb,OAAO,EAAE,KAAK,CAAC,MAAM;wBACrB,SAAS,EAAE,KAAK,CAAC,SAAS;wBAC1B,EAAE,EAAE,KAAK,CAAC,KAAK;wBACf,WAAW,EAAE;4BACX,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;gCACf,KAAK,EAAE,KAAK,CAAC,KAAK;gCAClB,KAAK,EAAE,KAAK,CAAC,KAAK;gCAClB,OAAO,EAAE,KAAK;gCACd,EAAE,EAAE,KAAK,CAAC,OAAO;6BAClB;yBACF;qBACF;iBACF;gBACD,eAAe,EAAE;oBACf,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;wBACnB,KAAK,EAAE,KAAK,CAAC,KAAK;wBAClB,SAAS,EAAE,KAAK,CAAC,SAAS;wBAC1B,EAAE,EAAE,KAAK,CAAC,WAAW;qBACtB;iBACF;aACF,CAAC;YAEF,MAAM,IAAI,GAA4B;gBACpC,CAAC,iBAAiB,KAAK,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBAC7D,CAAC,sBAAsB,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;gBACxE,CAAC,8BAA8B,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;gBACrG,CAAC,wBAAwB,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC5E,CAAC,4BAA4B,KAAK,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;gBACpF,CAAC,kCAAkC,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;aACzG,CAAC;YACF,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC;;;;OAIzB,CAAC,CAAC;YAEH,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;gBAClB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;oBACvB,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;gBACrB,CAAC;YACH,CAAC,CAAC,EAAE,CAAC;QACP,CAAC;gBAAS,CAAC;YACT,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;IACH,CAAC;CACF;AAjQD,kEAiQC","sourcesContent":["import { createHash } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { DataFactory } from 'n3';\nimport type { Quad } from '@rdfjs/types';\nimport { getLoggerFor } from 'global-logger-factory';\nimport { quadToRow } from '../storage/quint/serialization';\nimport { getSqliteRuntime, type SqliteDatabase } from '../storage/SqliteRuntime';\n\nconst RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';\nconst LDP = 'http://www.w3.org/ns/ldp#';\nconst DCT = 'http://purl.org/dc/terms/';\nconst MA = 'http://www.w3.org/ns/ma-ont#';\nconst PIM = 'http://www.w3.org/ns/pim/space#';\nconst FOAF = 'http://xmlns.com/foaf/0.1/';\nconst SOLID = 'http://www.w3.org/ns/solid/terms#';\nconst ACL = 'http://www.w3.org/ns/auth/acl#';\nconst ACP = 'http://www.w3.org/ns/solid/acp#';\n\nconst { blankNode, literal, namedNode, quad } = DataFactory;\n\nexport interface LocalPodProvisioningInput {\n podName: string;\n webId?: string;\n initialResources?: Record<string, string>;\n}\n\nexport interface LocalPodProvisioningResult {\n podUrl: string;\n accountId: string;\n podId: string;\n}\n\nexport interface LocalPodProvisioningServiceOptions {\n baseUrl: string;\n rootDir: string;\n sparqlEndpoint: string;\n identityDbUrl: string;\n oidcIssuer?: string;\n}\n\nfunction ensureTrailingSlash(url: string): string {\n return url.endsWith('/') ? url : `${url}/`;\n}\n\nfunction stripSqlitePrefix(value: string, label: string): string {\n if (value.startsWith('sqlite:')) {\n return value.slice('sqlite:'.length);\n }\n if (value === ':memory:') {\n return value;\n }\n if (/^[a-z][a-z0-9+.-]*:/iu.test(value)) {\n throw new Error(`${label} must be a sqlite URL for local Pod provisioning: ${value}`);\n }\n return value;\n}\n\nfunction stableUuid(input: string): string {\n const hex = createHash('sha256').update(input).digest('hex').slice(0, 32);\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n `4${hex.slice(13, 16)}`,\n `${((Number.parseInt(hex.slice(16, 18), 16) & 0x3f) | 0x80).toString(16).padStart(2, '0')}${hex.slice(18, 20)}`,\n hex.slice(20, 32),\n ].join('-');\n}\n\nfunction inferIssuerFromWebId(webId: string | undefined): string | undefined {\n if (!webId) {\n return undefined;\n }\n try {\n const url = new URL(webId);\n return `${url.origin}/`;\n } catch {\n return undefined;\n }\n}\n\nfunction buildWebIdFromIssuer(oidcIssuer: string | undefined, podName: string): string | undefined {\n if (!oidcIssuer) {\n return undefined;\n }\n return new URL(`${encodeURIComponent(podName)}/profile/card#me`, ensureTrailingSlash(oidcIssuer)).toString();\n}\n\nfunction createQuintsTable(db: SqliteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS quints (\n graph TEXT NOT NULL,\n subject TEXT NOT NULL,\n predicate TEXT NOT NULL,\n object TEXT NOT NULL,\n vector TEXT,\n PRIMARY KEY (graph, subject, predicate, object)\n );\n\n CREATE INDEX IF NOT EXISTS idx_spog ON quints (subject, predicate, object, graph);\n CREATE INDEX IF NOT EXISTS idx_ogsp ON quints (object, graph, subject, predicate);\n CREATE INDEX IF NOT EXISTS idx_gspo ON quints (graph, subject, predicate, object);\n CREATE INDEX IF NOT EXISTS idx_sopg ON quints (subject, object, predicate, graph);\n CREATE INDEX IF NOT EXISTS idx_pogs ON quints (predicate, object, graph, subject);\n CREATE INDEX IF NOT EXISTS idx_gpos ON quints (graph, predicate, object, subject);\n `);\n}\n\nfunction createInternalKvTable(db: SqliteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS internal_kv (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n `);\n}\n\nfunction meta(resource: string): string {\n return `meta:${resource}`;\n}\n\nfunction iri(base: string, relative: string): string {\n return new URL(relative, base).toString();\n}\n\nexport class LocalPodProvisioningService {\n private readonly logger = getLoggerFor(this);\n private readonly baseUrl: string;\n private readonly rootDir: string;\n private readonly sparqlDbPath: string;\n private readonly identityDbPath: string;\n private readonly oidcIssuer?: string;\n private readonly sqliteRuntime = getSqliteRuntime();\n\n public constructor(options: LocalPodProvisioningServiceOptions) {\n this.baseUrl = ensureTrailingSlash(options.baseUrl);\n this.rootDir = options.rootDir;\n this.sparqlDbPath = stripSqlitePrefix(options.sparqlEndpoint, 'sparqlEndpoint');\n this.identityDbPath = stripSqlitePrefix(options.identityDbUrl, 'identityDbUrl');\n this.oidcIssuer = options.oidcIssuer ? ensureTrailingSlash(options.oidcIssuer) : undefined;\n }\n\n public async createPod(input: LocalPodProvisioningInput): Promise<LocalPodProvisioningResult> {\n const podUrl = ensureTrailingSlash(new URL(`${encodeURIComponent(input.podName)}/`, this.baseUrl).toString());\n const webId = input.webId ?? buildWebIdFromIssuer(this.oidcIssuer, input.podName) ?? `${podUrl}profile/card#me`;\n const oidcIssuer = this.oidcIssuer ?? inferIssuerFromWebId(webId) ?? this.baseUrl;\n const accountId = stableUuid(`account:${podUrl}:${webId}`);\n const podId = stableUuid(`pod:${podUrl}:${webId}`);\n const ownerId = stableUuid(`owner:${podId}:${webId}`);\n const webIdLinkId = stableUuid(`webIdLink:${accountId}:${webId}`);\n\n await this.createPodFiles(input.podName, input.initialResources);\n this.writeQuints({ podUrl, webId, oidcIssuer });\n this.writeIdentityIndexes({ accountId, podId, ownerId, webIdLinkId, podUrl, webId });\n\n this.logger.info(`Provisioned local pod ${podUrl} for ${webId}`);\n return { podUrl, accountId, podId };\n }\n\n private async createPodFiles(podName: string, initialResources?: Record<string, string>): Promise<void> {\n const podPath = path.join(this.rootDir, podName);\n await fs.mkdir(path.join(podPath, 'profile'), { recursive: true });\n\n if (!initialResources) {\n return;\n }\n\n for (const [filename, content] of Object.entries(initialResources)) {\n const normalized = path.normalize(filename);\n if (normalized.startsWith('..') || path.isAbsolute(normalized)) {\n throw new Error(`Invalid initial resource path: ${filename}`);\n }\n const filePath = path.join(podPath, normalized);\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, content, 'utf8');\n }\n }\n\n private writeQuints(input: { podUrl: string; webId: string; oidcIssuer: string }): void {\n const db = this.sqliteRuntime.openDatabase(this.sparqlDbPath);\n try {\n createQuintsTable(db);\n const rows = this.buildPodQuads(input).map((entry) => {\n const row = quadToRow(entry);\n return [row.graph, row.subject, row.predicate, row.object, row.vector] as const;\n });\n const insert = db.prepare(`\n INSERT OR IGNORE INTO quints (graph, subject, predicate, object, vector)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n db.transaction(() => {\n for (const row of rows) {\n insert.run(...row);\n }\n })();\n } finally {\n db.close();\n }\n }\n\n private buildPodQuads({ podUrl, webId, oidcIssuer }: { podUrl: string; webId: string; oidcIssuer: string }): Quad[] {\n const now = new Date().toISOString();\n const root = this.baseUrl;\n const profileUrl = iri(podUrl, 'profile/');\n const cardUrl = iri(podUrl, 'profile/card');\n const rootAcrUrl = iri(podUrl, '.acr');\n const cardAcrUrl = iri(podUrl, 'profile/card.acr');\n const rootGraph = namedNode(root);\n const podGraph = namedNode(podUrl);\n const profileGraph = namedNode(profileUrl);\n const cardGraph = namedNode(cardUrl);\n const rootAcrGraph = namedNode(rootAcrUrl);\n const cardAcrGraph = namedNode(cardAcrUrl);\n const out: Quad[] = [];\n\n const add = (graph: string, subject: string, predicate: string, object: string): void => {\n out.push(quad(namedNode(subject), namedNode(predicate), namedNode(object), namedNode(graph)));\n };\n const addLiteral = (graph: string, subject: string, predicate: string, value: string): void => {\n out.push(quad(namedNode(subject), namedNode(predicate), literal(value), namedNode(graph)));\n };\n const addDate = (graph: string, subject: string): void => {\n out.push(quad(namedNode(subject), namedNode(`${DCT}modified`), literal(now, namedNode('http://www.w3.org/2001/XMLSchema#dateTime')), namedNode(graph)));\n };\n const addContainerMeta = (resource: string, storage = false): void => {\n const graph = meta(resource);\n addDate(graph, resource);\n add(graph, resource, `${RDF}type`, `${LDP}Resource`);\n add(graph, resource, `${RDF}type`, `${LDP}Container`);\n add(graph, resource, `${RDF}type`, `${LDP}BasicContainer`);\n if (storage) {\n add(graph, resource, `${RDF}type`, `${PIM}Storage`);\n }\n addLiteral(graph, resource, `${MA}format`, 'internal/quads');\n };\n const addDocumentMeta = (resource: string): void => {\n const graph = meta(resource);\n addDate(graph, resource);\n add(graph, resource, `${RDF}type`, `${LDP}Resource`);\n };\n\n out.push(quad(namedNode(root), namedNode(`${LDP}contains`), namedNode(podUrl), rootGraph));\n out.push(quad(namedNode(podUrl), namedNode(`${LDP}contains`), namedNode(rootAcrUrl), podGraph));\n out.push(quad(namedNode(podUrl), namedNode(`${LDP}contains`), namedNode(profileUrl), podGraph));\n out.push(quad(namedNode(profileUrl), namedNode(`${LDP}contains`), namedNode(cardUrl), profileGraph));\n out.push(quad(namedNode(profileUrl), namedNode(`${LDP}contains`), namedNode(cardAcrUrl), profileGraph));\n\n addContainerMeta(root);\n addContainerMeta(podUrl, true);\n addContainerMeta(profileUrl);\n addDocumentMeta(rootAcrUrl);\n addDocumentMeta(cardUrl);\n addDocumentMeta(cardAcrUrl);\n\n out.push(quad(namedNode(cardUrl), namedNode(`${RDF}type`), namedNode(`${FOAF}PersonalProfileDocument`), cardGraph));\n out.push(quad(namedNode(cardUrl), namedNode(`${FOAF}maker`), namedNode(webId), cardGraph));\n out.push(quad(namedNode(cardUrl), namedNode(`${FOAF}primaryTopic`), namedNode(webId), cardGraph));\n out.push(quad(namedNode(webId), namedNode(`${RDF}type`), namedNode(`${FOAF}Person`), cardGraph));\n out.push(quad(namedNode(webId), namedNode(`${SOLID}oidcIssuer`), namedNode(oidcIssuer), cardGraph));\n\n this.addRootAcrQuads(out, rootAcrGraph, rootAcrUrl, podUrl, webId);\n this.addPublicReadAcrQuads(out, cardAcrGraph, cardAcrUrl, cardUrl);\n\n return out;\n }\n\n private addRootAcrQuads(out: Quad[], graph: ReturnType<typeof namedNode>, acrUrl: string, podUrl: string, webId: string): void {\n const root = namedNode(`${acrUrl}#root`);\n const publicRead = namedNode(`${acrUrl}#publicReadAccess`);\n const fullOwner = namedNode(`${acrUrl}#fullOwnerAccess`);\n const publicPolicy = blankNode(`public-policy-${stableUuid(acrUrl)}`);\n const publicMatcher = blankNode(`public-matcher-${stableUuid(acrUrl)}`);\n const ownerPolicy = blankNode(`owner-policy-${stableUuid(acrUrl)}`);\n const ownerMatcher = blankNode(`owner-matcher-${stableUuid(acrUrl)}`);\n\n out.push(\n quad(root, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControlResource`), graph),\n quad(root, namedNode(`${ACP}resource`), namedNode(podUrl), graph),\n quad(root, namedNode(`${ACP}accessControl`), publicRead, graph),\n quad(root, namedNode(`${ACP}accessControl`), fullOwner, graph),\n quad(root, namedNode(`${ACP}memberAccessControl`), fullOwner, graph),\n quad(publicRead, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControl`), graph),\n quad(publicRead, namedNode(`${ACP}apply`), publicPolicy, graph),\n quad(publicPolicy, namedNode(`${RDF}type`), namedNode(`${ACP}Policy`), graph),\n quad(publicPolicy, namedNode(`${ACP}allow`), namedNode(`${ACL}Read`), graph),\n quad(publicPolicy, namedNode(`${ACP}anyOf`), publicMatcher, graph),\n quad(publicMatcher, namedNode(`${RDF}type`), namedNode(`${ACP}Matcher`), graph),\n quad(publicMatcher, namedNode(`${ACP}agent`), namedNode(`${ACP}PublicAgent`), graph),\n quad(fullOwner, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControl`), graph),\n quad(fullOwner, namedNode(`${ACP}apply`), ownerPolicy, graph),\n quad(ownerPolicy, namedNode(`${RDF}type`), namedNode(`${ACP}Policy`), graph),\n quad(ownerPolicy, namedNode(`${ACP}allow`), namedNode(`${ACL}Read`), graph),\n quad(ownerPolicy, namedNode(`${ACP}allow`), namedNode(`${ACL}Write`), graph),\n quad(ownerPolicy, namedNode(`${ACP}allow`), namedNode(`${ACL}Control`), graph),\n quad(ownerPolicy, namedNode(`${ACP}anyOf`), ownerMatcher, graph),\n quad(ownerMatcher, namedNode(`${RDF}type`), namedNode(`${ACP}Matcher`), graph),\n quad(ownerMatcher, namedNode(`${ACP}agent`), namedNode(webId), graph),\n );\n }\n\n private addPublicReadAcrQuads(out: Quad[], graph: ReturnType<typeof namedNode>, acrUrl: string, resourceUrl: string): void {\n const card = namedNode(`${acrUrl}#card`);\n const publicRead = namedNode(`${acrUrl}#publicReadAccess`);\n const policy = blankNode(`card-policy-${stableUuid(acrUrl)}`);\n const matcher = blankNode(`card-matcher-${stableUuid(acrUrl)}`);\n\n out.push(\n quad(card, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControlResource`), graph),\n quad(card, namedNode(`${ACP}resource`), namedNode(resourceUrl), graph),\n quad(card, namedNode(`${ACP}accessControl`), publicRead, graph),\n quad(publicRead, namedNode(`${RDF}type`), namedNode(`${ACP}AccessControl`), graph),\n quad(publicRead, namedNode(`${ACP}apply`), policy, graph),\n quad(policy, namedNode(`${RDF}type`), namedNode(`${ACP}Policy`), graph),\n quad(policy, namedNode(`${ACP}allow`), namedNode(`${ACL}Read`), graph),\n quad(policy, namedNode(`${ACP}anyOf`), matcher, graph),\n quad(matcher, namedNode(`${RDF}type`), namedNode(`${ACP}Matcher`), graph),\n quad(matcher, namedNode(`${ACP}agent`), namedNode(`${ACP}PublicAgent`), graph),\n );\n }\n\n private writeIdentityIndexes(input: {\n accountId: string;\n podId: string;\n ownerId: string;\n webIdLinkId: string;\n podUrl: string;\n webId: string;\n }): void {\n const db = this.sqliteRuntime.openDatabase(this.identityDbPath);\n try {\n createInternalKvTable(db);\n const account = {\n linkedLoginsCount: 1,\n id: input.accountId,\n '**pod**': {\n [input.podId]: {\n baseUrl: input.podUrl,\n accountId: input.accountId,\n id: input.podId,\n '**owner**': {\n [input.ownerId]: {\n podId: input.podId,\n webId: input.webId,\n visible: false,\n id: input.ownerId,\n },\n },\n },\n },\n '**webIdLink**': {\n [input.webIdLinkId]: {\n webId: input.webId,\n accountId: input.accountId,\n id: input.webIdLinkId,\n },\n },\n };\n\n const rows: Array<[string, string]> = [\n [`accounts/data/${input.accountId}`, JSON.stringify(account)],\n [`accounts/index/pod/${input.podId}`, JSON.stringify([input.accountId])],\n [`accounts/index/pod/baseUrl/${encodeURIComponent(input.podUrl)}`, JSON.stringify([input.accountId])],\n [`accounts/index/owner/${input.ownerId}`, JSON.stringify([input.accountId])],\n [`accounts/index/webIdLink/${input.webIdLinkId}`, JSON.stringify([input.accountId])],\n [`accounts/index/webIdLink/webId/${encodeURIComponent(input.webId)}`, JSON.stringify([input.accountId])],\n ];\n const insert = db.prepare(`\n INSERT INTO internal_kv (key, value, updated_at)\n VALUES (?, ?, datetime('now'))\n ON CONFLICT (key) DO UPDATE SET value = excluded.value, updated_at = datetime('now')\n `);\n\n db.transaction(() => {\n for (const row of rows) {\n insert.run(...row);\n }\n })();\n } finally {\n db.close();\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
{
|
|
2
|
+
"@context": [
|
|
3
|
+
"https://linkedsoftwaredependencies.org/bundles/npm/@undefineds.co/xpod/^0.0.0/components/context.jsonld"
|
|
4
|
+
],
|
|
5
|
+
"@id": "npmd:@undefineds.co/xpod",
|
|
6
|
+
"components": [
|
|
7
|
+
{
|
|
8
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService",
|
|
9
|
+
"@type": "Class",
|
|
10
|
+
"requireElement": "LocalPodProvisioningService",
|
|
11
|
+
"parameters": [
|
|
12
|
+
{
|
|
13
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_baseUrl",
|
|
14
|
+
"range": "xsd:string"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_rootDir",
|
|
18
|
+
"range": "xsd:string"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_sparqlEndpoint",
|
|
22
|
+
"range": "xsd:string"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_identityDbUrl",
|
|
26
|
+
"range": "xsd:string"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_oidcIssuer",
|
|
30
|
+
"range": {
|
|
31
|
+
"@type": "ParameterRangeUnion",
|
|
32
|
+
"parameterRangeElements": [
|
|
33
|
+
"xsd:string",
|
|
34
|
+
{
|
|
35
|
+
"@type": "ParameterRangeUndefined"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"memberFields": [
|
|
42
|
+
{
|
|
43
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_logger",
|
|
44
|
+
"memberFieldName": "logger"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_baseUrl",
|
|
48
|
+
"memberFieldName": "baseUrl"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_rootDir",
|
|
52
|
+
"memberFieldName": "rootDir"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_sparqlDbPath",
|
|
56
|
+
"memberFieldName": "sparqlDbPath"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_identityDbPath",
|
|
60
|
+
"memberFieldName": "identityDbPath"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_oidcIssuer",
|
|
64
|
+
"memberFieldName": "oidcIssuer"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_sqliteRuntime",
|
|
68
|
+
"memberFieldName": "sqliteRuntime"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_constructor",
|
|
72
|
+
"memberFieldName": "constructor"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_createPod",
|
|
76
|
+
"memberFieldName": "createPod"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_createPodFiles",
|
|
80
|
+
"memberFieldName": "createPodFiles"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_writeQuints",
|
|
84
|
+
"memberFieldName": "writeQuints"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_buildPodQuads",
|
|
88
|
+
"memberFieldName": "buildPodQuads"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_addRootAcrQuads",
|
|
92
|
+
"memberFieldName": "addRootAcrQuads"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_addPublicReadAcrQuads",
|
|
96
|
+
"memberFieldName": "addPublicReadAcrQuads"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService__member_writeIdentityIndexes",
|
|
100
|
+
"memberFieldName": "writeIdentityIndexes"
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
"constructorArguments": [
|
|
104
|
+
{
|
|
105
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options__constructorArgument",
|
|
106
|
+
"fields": [
|
|
107
|
+
{
|
|
108
|
+
"keyRaw": "baseUrl",
|
|
109
|
+
"value": {
|
|
110
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_baseUrl"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"keyRaw": "rootDir",
|
|
115
|
+
"value": {
|
|
116
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_rootDir"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"keyRaw": "sparqlEndpoint",
|
|
121
|
+
"value": {
|
|
122
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_sparqlEndpoint"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"keyRaw": "identityDbUrl",
|
|
127
|
+
"value": {
|
|
128
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_identityDbUrl"
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"keyRaw": "oidcIssuer",
|
|
133
|
+
"value": {
|
|
134
|
+
"@id": "undefineds:dist/provision/LocalPodProvisioningService.jsonld#LocalPodProvisioningService_options_oidcIssuer"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
}
|
|
@@ -50,6 +50,7 @@ class ProvisionPodCreator extends community_server_1.BasePodCreator {
|
|
|
50
50
|
if (!podName) {
|
|
51
51
|
throw new Error('Pod name is required for remote provisioning');
|
|
52
52
|
}
|
|
53
|
+
const webId = input.webId ?? `${this.baseUrl}${podName}/profile/card#me`;
|
|
53
54
|
// 2. 回调 SP 创建 Pod
|
|
54
55
|
const callbackUrl = `${payload.spUrl.replace(/\/$/, '')}/provision/pods`;
|
|
55
56
|
const spResponse = await fetch(callbackUrl, {
|
|
@@ -58,7 +59,7 @@ class ProvisionPodCreator extends community_server_1.BasePodCreator {
|
|
|
58
59
|
'Content-Type': 'application/json',
|
|
59
60
|
'Authorization': `Bearer ${payload.serviceToken}`,
|
|
60
61
|
},
|
|
61
|
-
body: JSON.stringify({ podName }),
|
|
62
|
+
body: JSON.stringify({ podName, webId }),
|
|
62
63
|
});
|
|
63
64
|
if (!spResponse.ok) {
|
|
64
65
|
const errBody = await spResponse.text();
|
|
@@ -72,9 +73,7 @@ class ProvisionPodCreator extends community_server_1.BasePodCreator {
|
|
|
72
73
|
: payload.spUrl.replace(/\/$/, '');
|
|
73
74
|
const canonicalStorageUrl = `${storageBase}/${podName}/`;
|
|
74
75
|
const podUrl = spResult.podUrl || canonicalStorageUrl;
|
|
75
|
-
// 3.
|
|
76
|
-
const webId = input.webId ?? `${this.baseUrl}${podName}/profile/card#me`;
|
|
77
|
-
// 4. 链接 WebID 到账户 + 在本地 PodStore 记录
|
|
76
|
+
// 3. 链接 WebID 到账户 + 在本地 PodStore 记录
|
|
78
77
|
// base.path 必须在 Cloud 的 identifier space 内(CSS PodStore 会检查),
|
|
79
78
|
// 所以用 Cloud 本地路径;真实的 SP storage URL 通过 podUrl 返回。
|
|
80
79
|
const localBase = this.identifierGenerator.generate(podName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProvisionPodCreator.js","sourceRoot":"","sources":["../../src/provision/ProvisionPodCreator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ProvisionPodCreator\n *\n * 等位替换 CSS 的 BasePodCreator。\n *\n * 检查 settings 里有没有 provisionCode:\n * - 有 → 解码 JWT,回调远端 SP 的 /provision/pods 创建 Pod\n * - 没有 → 委托给原始 BasePodCreator(标准本地创建)\n */\n\nimport { getLoggerFor } from 'global-logger-factory';\nimport {\n BasePodCreator,\n type PodCreatorInput,\n type PodCreatorOutput,\n type BasePodCreatorArgs,\n ConflictHttpError,\n} from '@solid/community-server';\nimport { ProvisionCodeCodec } from './ProvisionCodeCodec';\nimport type { WebIdProfileRepository } from '../identity/drizzle/WebIdProfileRepository';\n\nfunction joinUrlPath(baseUrl: string, relativePath: string): string {\n const normalizedBaseUrl = baseUrl.replace(/\\/+$/u, '');\n const normalizedRelativePath = relativePath.replace(/^\\/+/u, '');\n return `${normalizedBaseUrl}/${normalizedRelativePath}`;\n}\n\nexport interface ProvisionPodCreatorArgs extends BasePodCreatorArgs {\n /** 与 ProvisionHandler 使用相同的 baseUrl 派生签名密钥 */\n provisionBaseUrl?: string;\n /** Optional Cloud profile repository used to reconcile solid:storage after remote provisioning */\n webIdProfileRepo?: WebIdProfileRepository;\n}\n\nfunction remapPodConflict(error: unknown, podName: string): never {\n const message = error instanceof Error ? error.message : String(error);\n if (/There already is a resource at/i.test(message)) {\n throw new ConflictHttpError(`Pod name \"${podName}\" is already taken for this storage target.`, {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n throw error;\n}\n\nexport class ProvisionPodCreator extends BasePodCreator {\n private readonly provisionLogger = getLoggerFor(this);\n private readonly codec: ProvisionCodeCodec;\n private readonly webIdProfileRepo?: WebIdProfileRepository;\n\n public constructor(args: ProvisionPodCreatorArgs) {\n super(args);\n this.codec = new ProvisionCodeCodec(args.provisionBaseUrl ?? args.baseUrl);\n this.webIdProfileRepo = args.webIdProfileRepo;\n }\n\n public override async handle(input: PodCreatorInput): Promise<PodCreatorOutput> {\n const provisionCode = input.settings?.provisionCode as string | undefined;\n\n if (!provisionCode) {\n return this.handleStandardPodCreate(input);\n }\n\n // SP 模式:解码 provisionCode,回调远端 SP\n const payload = this.codec.decode(provisionCode);\n if (!payload) {\n throw new Error('Invalid or expired provisionCode');\n }\n\n this.provisionLogger.info(`Provisioning pod on remote SP: ${payload.spUrl}`);\n\n // 1. 确定 podName\n const podName = input.name;\n if (!podName) {\n throw new Error('Pod name is required for remote provisioning');\n }\n\n // 2. 回调 SP 创建 Pod\n const callbackUrl = `${payload.spUrl.replace(/\\/$/, '')}/provision/pods`;\n const spResponse = await fetch(callbackUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${payload.serviceToken}`,\n },\n body: JSON.stringify({ podName }),\n });\n\n if (!spResponse.ok) {\n const errBody = await spResponse.text();\n this.provisionLogger.error(`SP callback failed: ${spResponse.status} ${errBody}`);\n throw new Error(`Failed to create pod on SP: ${spResponse.status}`);\n }\n\n const spResult = await spResponse.json() as { podUrl?: string };\n\n // storage URL 优先用 Cloud 分配的子域名,回调用实际地址\n const storageBase = payload.spDomain\n ? `https://${payload.spDomain}`\n : payload.spUrl.replace(/\\/$/, '');\n const canonicalStorageUrl = `${storageBase}/${podName}/`;\n const podUrl = spResult.podUrl || canonicalStorageUrl;\n\n // 3. 生成 WebID(指向 Cloud,storage 指向 SP)\n const webId = input.webId ?? `${this.baseUrl}${podName}/profile/card#me`;\n\n // 4. 链接 WebID 到账户 + 在本地 PodStore 记录\n // base.path 必须在 Cloud 的 identifier space 内(CSS PodStore 会检查),\n // 所以用 Cloud 本地路径;真实的 SP storage URL 通过 podUrl 返回。\n const localBase = this.identifierGenerator.generate(podName);\n const podSettings = {\n ...input.settings,\n base: localBase,\n webId,\n oidcIssuer: this.baseUrl,\n };\n\n const webIdLink = await this.handleWebId(!input.webId, webId, input.accountId, podSettings);\n const podId = await this.createPod(input.accountId, podSettings, !input.name, webIdLink);\n\n if (!input.webId && this.webIdProfileRepo) {\n try {\n await this.webIdProfileRepo.updateStorage(podName, {\n storageUrl: canonicalStorageUrl,\n storageMode: 'local',\n });\n } catch (error) {\n this.provisionLogger.warn(`Failed to reconcile storage pointer for ${podName}: ${(error as Error).message}`);\n }\n }\n\n this.provisionLogger.info(`Provisioned pod ${podName} on SP ${payload.spUrl}, podUrl: ${podUrl}`);\n\n return {\n podUrl,\n webId,\n podId,\n webIdLink,\n };\n }\n\n private async handleStandardPodCreate(input: PodCreatorInput): Promise<PodCreatorOutput> {\n const totalStarted = Date.now();\n const baseIdentifier = this.generateBaseIdentifier(input.name);\n const webId = input.webId ?? joinUrlPath(baseIdentifier.path, this.relativeWebIdPath);\n const inputSettings = input.settings as Record<string, unknown> | undefined;\n const oidcIssuer = typeof inputSettings?.oidcIssuer === 'string' ? inputSettings.oidcIssuer : this.baseUrl;\n const podSettings = {\n ...inputSettings,\n base: baseIdentifier,\n webId,\n oidcIssuer,\n };\n\n const webIdStarted = Date.now();\n const webIdLink = await this.handleWebId(!input.webId, webId, input.accountId, podSettings);\n const webIdElapsed = Date.now() - webIdStarted;\n\n const podStarted = Date.now();\n let podId: string;\n try {\n podId = await this.createPod(input.accountId, podSettings, !input.name, webIdLink);\n } catch (error) {\n if (input.name) {\n remapPodConflict(error, input.name);\n }\n throw error;\n }\n const podElapsed = Date.now() - podStarted;\n const totalElapsed = Date.now() - totalStarted;\n\n this.provisionLogger.info(\n `[timing] ProvisionPodCreator.standard account=${input.accountId} pod=${baseIdentifier.path} handleWebId=${webIdElapsed}ms createPod=${podElapsed}ms total=${totalElapsed}ms`,\n );\n\n return {\n podUrl: baseIdentifier.path,\n webId,\n podId,\n webIdLink,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ProvisionPodCreator.js","sourceRoot":"","sources":["../../src/provision/ProvisionPodCreator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ProvisionPodCreator\n *\n * 等位替换 CSS 的 BasePodCreator。\n *\n * 检查 settings 里有没有 provisionCode:\n * - 有 → 解码 JWT,回调远端 SP 的 /provision/pods 创建 Pod\n * - 没有 → 委托给原始 BasePodCreator(标准本地创建)\n */\n\nimport { getLoggerFor } from 'global-logger-factory';\nimport {\n BasePodCreator,\n type PodCreatorInput,\n type PodCreatorOutput,\n type BasePodCreatorArgs,\n ConflictHttpError,\n} from '@solid/community-server';\nimport { ProvisionCodeCodec } from './ProvisionCodeCodec';\nimport type { WebIdProfileRepository } from '../identity/drizzle/WebIdProfileRepository';\n\nfunction joinUrlPath(baseUrl: string, relativePath: string): string {\n const normalizedBaseUrl = baseUrl.replace(/\\/+$/u, '');\n const normalizedRelativePath = relativePath.replace(/^\\/+/u, '');\n return `${normalizedBaseUrl}/${normalizedRelativePath}`;\n}\n\nexport interface ProvisionPodCreatorArgs extends BasePodCreatorArgs {\n /** 与 ProvisionHandler 使用相同的 baseUrl 派生签名密钥 */\n provisionBaseUrl?: string;\n /** Optional Cloud profile repository used to reconcile solid:storage after remote provisioning */\n webIdProfileRepo?: WebIdProfileRepository;\n}\n\nfunction remapPodConflict(error: unknown, podName: string): never {\n const message = error instanceof Error ? error.message : String(error);\n if (/There already is a resource at/i.test(message)) {\n throw new ConflictHttpError(`Pod name \"${podName}\" is already taken for this storage target.`, {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n throw error;\n}\n\nexport class ProvisionPodCreator extends BasePodCreator {\n private readonly provisionLogger = getLoggerFor(this);\n private readonly codec: ProvisionCodeCodec;\n private readonly webIdProfileRepo?: WebIdProfileRepository;\n\n public constructor(args: ProvisionPodCreatorArgs) {\n super(args);\n this.codec = new ProvisionCodeCodec(args.provisionBaseUrl ?? args.baseUrl);\n this.webIdProfileRepo = args.webIdProfileRepo;\n }\n\n public override async handle(input: PodCreatorInput): Promise<PodCreatorOutput> {\n const provisionCode = input.settings?.provisionCode as string | undefined;\n\n if (!provisionCode) {\n return this.handleStandardPodCreate(input);\n }\n\n // SP 模式:解码 provisionCode,回调远端 SP\n const payload = this.codec.decode(provisionCode);\n if (!payload) {\n throw new Error('Invalid or expired provisionCode');\n }\n\n this.provisionLogger.info(`Provisioning pod on remote SP: ${payload.spUrl}`);\n\n // 1. 确定 podName\n const podName = input.name;\n if (!podName) {\n throw new Error('Pod name is required for remote provisioning');\n }\n const webId = input.webId ?? `${this.baseUrl}${podName}/profile/card#me`;\n\n // 2. 回调 SP 创建 Pod\n const callbackUrl = `${payload.spUrl.replace(/\\/$/, '')}/provision/pods`;\n const spResponse = await fetch(callbackUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${payload.serviceToken}`,\n },\n body: JSON.stringify({ podName, webId }),\n });\n\n if (!spResponse.ok) {\n const errBody = await spResponse.text();\n this.provisionLogger.error(`SP callback failed: ${spResponse.status} ${errBody}`);\n throw new Error(`Failed to create pod on SP: ${spResponse.status}`);\n }\n\n const spResult = await spResponse.json() as { podUrl?: string };\n\n // storage URL 优先用 Cloud 分配的子域名,回调用实际地址\n const storageBase = payload.spDomain\n ? `https://${payload.spDomain}`\n : payload.spUrl.replace(/\\/$/, '');\n const canonicalStorageUrl = `${storageBase}/${podName}/`;\n const podUrl = spResult.podUrl || canonicalStorageUrl;\n\n // 3. 链接 WebID 到账户 + 在本地 PodStore 记录\n // base.path 必须在 Cloud 的 identifier space 内(CSS PodStore 会检查),\n // 所以用 Cloud 本地路径;真实的 SP storage URL 通过 podUrl 返回。\n const localBase = this.identifierGenerator.generate(podName);\n const podSettings = {\n ...input.settings,\n base: localBase,\n webId,\n oidcIssuer: this.baseUrl,\n };\n\n const webIdLink = await this.handleWebId(!input.webId, webId, input.accountId, podSettings);\n const podId = await this.createPod(input.accountId, podSettings, !input.name, webIdLink);\n\n if (!input.webId && this.webIdProfileRepo) {\n try {\n await this.webIdProfileRepo.updateStorage(podName, {\n storageUrl: canonicalStorageUrl,\n storageMode: 'local',\n });\n } catch (error) {\n this.provisionLogger.warn(`Failed to reconcile storage pointer for ${podName}: ${(error as Error).message}`);\n }\n }\n\n this.provisionLogger.info(`Provisioned pod ${podName} on SP ${payload.spUrl}, podUrl: ${podUrl}`);\n\n return {\n podUrl,\n webId,\n podId,\n webIdLink,\n };\n }\n\n private async handleStandardPodCreate(input: PodCreatorInput): Promise<PodCreatorOutput> {\n const totalStarted = Date.now();\n const baseIdentifier = this.generateBaseIdentifier(input.name);\n const webId = input.webId ?? joinUrlPath(baseIdentifier.path, this.relativeWebIdPath);\n const inputSettings = input.settings as Record<string, unknown> | undefined;\n const oidcIssuer = typeof inputSettings?.oidcIssuer === 'string' ? inputSettings.oidcIssuer : this.baseUrl;\n const podSettings = {\n ...inputSettings,\n base: baseIdentifier,\n webId,\n oidcIssuer,\n };\n\n const webIdStarted = Date.now();\n const webIdLink = await this.handleWebId(!input.webId, webId, input.accountId, podSettings);\n const webIdElapsed = Date.now() - webIdStarted;\n\n const podStarted = Date.now();\n let podId: string;\n try {\n podId = await this.createPod(input.accountId, podSettings, !input.name, webIdLink);\n } catch (error) {\n if (input.name) {\n remapPodConflict(error, input.name);\n }\n throw error;\n }\n const podElapsed = Date.now() - podStarted;\n const totalElapsed = Date.now() - totalStarted;\n\n this.provisionLogger.info(\n `[timing] ProvisionPodCreator.standard account=${input.accountId} pod=${baseIdentifier.path} handleWebId=${webIdElapsed}ms createPod=${podElapsed}ms total=${totalElapsed}ms`,\n );\n\n return {\n podUrl: baseIdentifier.path,\n webId,\n podId,\n webIdLink,\n };\n }\n}\n"]}
|