zephyr-agent
Version:
Zephyr plugin agent
486 lines (485 loc) • 22.6 kB
JavaScript
;
var __webpack_require__ = {};
(()=>{
__webpack_require__.d = (exports1, getters, values)=>{
var define = (defs, kind)=>{
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
enumerable: true,
[kind]: defs[key]
});
};
define(getters, "get");
define(values, "value");
};
})();
(()=>{
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
})();
(()=>{
__webpack_require__.r = (exports1)=>{
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
value: 'Module'
});
Object.defineProperty(exports1, '__esModule', {
value: true
});
};
})();
var __webpack_exports__ = {};
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
claimPartialAssetMap: ()=>claimPartialAssetMap,
claimPartialAssetMapBatch: ()=>claimPartialAssetMapBatch,
commitPartialAssetMapClaim: ()=>commitPartialAssetMapClaim,
commitPartialAssetMapClaimBatch: ()=>commitPartialAssetMapClaimBatch,
deserializePartialAssetMaps: ()=>deserializePartialAssetMaps,
getLegacyPartialAssetStorePath: ()=>getLegacyPartialAssetStorePath,
getPartialAssetLockPath: ()=>getPartialAssetLockPath,
getPartialAssetMap: ()=>getPartialAssetMap,
getPartialAssetStorePath: ()=>getPartialAssetStorePath,
removePartialAssetMap: ()=>removePartialAssetMap,
rollbackPartialAssetMapClaim: ()=>rollbackPartialAssetMapClaim,
rollbackPartialAssetMapClaimBatch: ()=>rollbackPartialAssetMapClaimBatch,
savePartialAssetMap: ()=>savePartialAssetMap,
serializePartialAssetMaps: ()=>serializePartialAssetMaps,
takePartialAssetMap: ()=>takePartialAssetMap
});
const external_node_crypto_namespaceObject = require("node:crypto");
const promises_namespaceObject = require("node:fs/promises");
const external_node_path_namespaceObject = require("node:path");
const ze_build_assets_js_namespaceObject = require("../transformers/ze-build-assets.js");
const external_atomic_file_js_namespaceObject = require("./atomic-file.js");
const external_storage_keys_js_namespaceObject = require("./storage-keys.js");
const external_storage_lock_js_namespaceObject = require("./storage-lock.js");
const BUFFER_ENCODING_KEY = '__zephyr_buffer_base64__';
const STORE_VERSION_KEY = '__zephyr_partial_store_version__';
const STORE_VERSION = 2;
const CLAIM_STALE_MS = 1800000;
const GROUP_STALE_MS = 86400000;
const LEGACY_SCOPE = {
invocationId: '__zephyr_legacy_unscoped__',
generation: 0
};
function isRecord(value) {
return 'object' == typeof value && null !== value && !Array.isArray(value);
}
function decodeBuffer(value) {
if (Buffer.isBuffer(value) || 'string' == typeof value) return value;
if (isRecord(value) && 'string' == typeof value[BUFFER_ENCODING_KEY]) return Buffer.from(value[BUFFER_ENCODING_KEY], 'base64');
if (isRecord(value) && 'Buffer' === value['type'] && Array.isArray(value['data']) && value['data'].every((byte)=>Number.isInteger(byte) && byte >= 0 && byte <= 255)) return Buffer.from(value['data']);
throw new TypeError('Persisted partial asset contains an invalid buffer');
}
function serializePartialAssetMaps(partialAssetMaps) {
return Object.fromEntries(Object.entries(partialAssetMaps).map(([partialKey, assetsMap])=>[
partialKey,
Object.fromEntries(Object.entries(assetsMap).map(([hash, asset])=>[
hash,
{
...asset,
buffer: Buffer.isBuffer(asset.buffer) ? {
[BUFFER_ENCODING_KEY]: asset.buffer.toString('base64')
} : asset.buffer
}
]))
]));
}
function deserializePartialAssetMaps(value) {
if (null == value) return;
if (!isRecord(value)) throw new TypeError('Persisted partial asset maps must be an object');
return Object.fromEntries(Object.entries(value).map(([partialKey, rawAssetsMap])=>{
if (!isRecord(rawAssetsMap)) throw new TypeError(`Persisted partial "${partialKey}" must be an object`);
return [
partialKey,
Object.fromEntries(Object.entries(rawAssetsMap).map(([hash, rawAsset])=>{
if (!isRecord(rawAsset)) throw new TypeError(`Persisted partial asset "${partialKey}:${hash}" must be an object`);
const assetPath = rawAsset['path'];
if ('string' != typeof assetPath) throw new TypeError(`Persisted partial asset "${partialKey}:${hash}" has no valid path`);
const slashPath = assetPath.replace(/\\/g, '/');
const pathSegments = slashPath.split('/').filter((segment)=>segment && '.' !== segment);
if (!slashPath || slashPath.includes('\0') || slashPath.startsWith('/') || /^[A-Za-z]:/.test(slashPath) || 0 === pathSegments.length || pathSegments.includes('..')) throw new TypeError(`Persisted partial asset "${partialKey}:${hash}" escapes the snapshot root`);
const buffer = decodeBuffer(rawAsset['buffer']);
const rebuilt = (0, ze_build_assets_js_namespaceObject.zeBuildAssets)({
filepath: assetPath,
content: buffer
});
if (rawAsset['hash'] !== hash || rebuilt.hash !== hash || rawAsset['size'] !== rebuilt.size) throw new TypeError(`Persisted partial asset "${partialKey}:${hash}" failed its content integrity check`);
const normalizedPath = pathSegments.join('/');
const normalizedAsset = normalizedPath === assetPath ? rebuilt : (0, ze_build_assets_js_namespaceObject.zeBuildAssets)({
filepath: normalizedPath,
content: buffer
});
return [
normalizedAsset.hash,
{
...rawAsset,
path: normalizedAsset.path,
hash: normalizedAsset.hash,
size: normalizedAsset.size,
extname: normalizedAsset.extname,
buffer
}
];
}))
];
}));
}
function assertScope(scope) {
if (!scope.invocationId.trim()) throw new TypeError('Partial asset invocationId must not be empty');
if (!Number.isSafeInteger(scope.generation) || scope.generation < 0) throw new TypeError('Partial asset generation must be a non-negative safe integer');
}
function getScopeKey(scope) {
assertScope(scope);
return JSON.stringify([
scope.invocationId,
scope.generation
]);
}
function emptyStore() {
return {
[STORE_VERSION_KEY]: STORE_VERSION,
nextRevision: 1,
groups: {},
claims: {}
};
}
function parseScope(value) {
if (!isRecord(value) || 'string' != typeof value['invocationId'] || 'number' != typeof value['generation']) throw new TypeError('Persisted partial group has an invalid scope');
const scope = {
invocationId: value['invocationId'],
generation: value['generation']
};
assertScope(scope);
return scope;
}
function readStore(value) {
if (null == value) return emptyStore();
if (isRecord(value) && value[STORE_VERSION_KEY] === STORE_VERSION) {
if (!Number.isSafeInteger(value['nextRevision']) || value['nextRevision'] < 1 || !isRecord(value['groups']) || !isRecord(value['claims'])) throw new TypeError('Persisted partial asset store is malformed');
const store = value;
for (const [scopeKey, group] of Object.entries(store.groups)){
if (!isRecord(group) || !isRecord(group.entries) || 'number' != typeof group.updatedAt) throw new TypeError(`Persisted partial group "${scopeKey}" is malformed`);
const scope = parseScope(group.scope);
if (getScopeKey(scope) !== scopeKey) throw new TypeError(`Persisted partial group "${scopeKey}" has a mismatched scope`);
for (const [partialKey, entry] of Object.entries(group.entries)){
if (!isRecord(entry) || !Number.isSafeInteger(entry.revision) || entry.revision < 1 || !isRecord(entry.assets)) throw new TypeError(`Persisted partial contribution "${scopeKey}:${partialKey}" is malformed`);
deserializePartialAssetMaps({
[partialKey]: entry.assets
});
}
}
for (const [claimId, claim] of Object.entries(store.claims))if (!isRecord(claim) || 'string' != typeof claim.scopeKey || !isRecord(claim.revisions) || 'number' != typeof claim.createdAt || !Object.values(claim.revisions).every((revision)=>Number.isSafeInteger(revision) && revision >= 1)) throw new TypeError(`Persisted partial claim "${claimId}" is malformed`);
return store;
}
const legacyMaps = deserializePartialAssetMaps(value);
const store = emptyStore();
if (legacyMaps && Object.keys(legacyMaps).length > 0) {
const scopeKey = getScopeKey(LEGACY_SCOPE);
store.groups[scopeKey] = {
scope: {
...LEGACY_SCOPE
},
entries: {},
updatedAt: Date.now()
};
for (const [partialKey, assetsMap] of Object.entries(legacyMaps))store.groups[scopeKey].entries[partialKey] = {
revision: store.nextRevision++,
assets: serializePartialAssetMaps({
[partialKey]: assetsMap
})[partialKey]
};
}
return store;
}
function readVersionedStore(value) {
if (!isRecord(value) || value[STORE_VERSION_KEY] !== STORE_VERSION) throw new TypeError('Persisted partial asset store has an unsupported schema');
return readStore(value);
}
function pruneStaleStore(store, now = Date.now()) {
for (const [claimId, claim] of Object.entries(store.claims))if (now - claim.createdAt >= CLAIM_STALE_MS) delete store.claims[claimId];
const claimedScopes = new Set(Object.values(store.claims).map((claim)=>claim.scopeKey));
for (const [scopeKey, group] of Object.entries(store.groups))if (!claimedScopes.has(scopeKey) && now - group.updatedAt >= GROUP_STALE_MS) delete store.groups[scopeKey];
}
function deserializeGroup(group) {
return Object.fromEntries(Object.entries(group.entries).map(([partialKey, entry])=>{
const assetsMap = deserializePartialAssetMaps({
[partialKey]: entry.assets
});
return [
partialKey,
assetsMap?.[partialKey] ?? {}
];
}));
}
function get_key(application_uid) {
return [
external_storage_keys_js_namespaceObject.StorageKeys.ze_app_partial_asset_map,
application_uid
].join('.');
}
function get_application_digest(application_uid) {
return (0, external_node_crypto_namespaceObject.createHash)('sha256').update(application_uid).digest('hex');
}
function getPartialAssetStorePath(application_uid) {
return external_node_path_namespaceObject.join(external_storage_keys_js_namespaceObject.ZE_PATH, 'partial-assets', `${get_application_digest(application_uid)}.json`);
}
function getLegacyPartialAssetStorePath(application_uid) {
const legacyKeyDigest = (0, external_node_crypto_namespaceObject.createHash)('sha256').update(get_key(application_uid)).digest('hex');
return external_node_path_namespaceObject.join(external_storage_keys_js_namespaceObject.ZE_STORAGE_PATH, legacyKeyDigest);
}
function getPartialAssetLockName(application_uid) {
return `partial-assets-${get_application_digest(application_uid)}`;
}
function getPartialAssetLockPath(application_uid) {
return (0, external_storage_lock_js_namespaceObject.getStorageLockPath)(getPartialAssetLockName(application_uid));
}
function withPartialAssetsLock(application_uid, action) {
return (0, external_storage_lock_js_namespaceObject.withStorageLock)(getPartialAssetLockName(application_uid), action, {
retries: {
retries: 8,
factor: 1.5,
minTimeout: 25,
maxTimeout: 500
},
staleMs: external_storage_keys_js_namespaceObject.PARTIAL_ASSET_LOCK_STALE_MS,
whenUnavailable: 'throw'
});
}
async function readJsonFileStrict(filePath) {
let content;
try {
content = await (0, promises_namespaceObject.readFile)(filePath, 'utf8');
} catch (error) {
if (error?.code === 'ENOENT') return;
throw error;
}
try {
return JSON.parse(content);
} catch (error) {
throw Object.assign(new TypeError(`Partial asset store "${filePath}" contains invalid JSON`), {
cause: error
});
}
}
async function readLegacyStoreValue(application_uid) {
const legacyPath = getLegacyPartialAssetStorePath(application_uid);
const datum = await readJsonFileStrict(legacyPath);
if (void 0 === datum) return {
found: false
};
if (!isRecord(datum) || datum['key'] !== get_key(application_uid)) throw new TypeError(`Legacy partial asset store "${legacyPath}" is malformed`);
if ('number' == typeof datum['ttl'] && Number.isFinite(datum['ttl']) && datum['ttl'] < Date.now()) {
await (0, promises_namespaceObject.rm)(legacyPath, {
force: true
});
return {
found: false
};
}
if (!Object.prototype.hasOwnProperty.call(datum, 'value')) throw new TypeError(`Legacy partial asset store "${legacyPath}" has no value`);
return {
found: true,
value: datum['value']
};
}
async function writeStore(application_uid, store) {
await (0, external_atomic_file_js_namespaceObject.writeFileAtomically)(getPartialAssetStorePath(application_uid), JSON.stringify(store));
}
async function readApplicationStore(application_uid) {
const storePath = getPartialAssetStorePath(application_uid);
const persisted = await readJsonFileStrict(storePath);
if (void 0 !== persisted) return readVersionedStore(persisted);
const legacy = await readLegacyStoreValue(application_uid);
if (!legacy.found) return emptyStore();
const migrated = readStore(legacy.value);
await writeStore(application_uid, migrated);
await (0, promises_namespaceObject.rm)(getLegacyPartialAssetStorePath(application_uid), {
force: true
});
return migrated;
}
async function savePartialAssetMap(application_uid, partial_key, assetMap, scope = LEGACY_SCOPE) {
assertScope(scope);
await withPartialAssetsLock(application_uid, async ()=>{
const store = await readApplicationStore(application_uid);
pruneStaleStore(store);
const scopeKey = getScopeKey(scope);
const group = store.groups[scopeKey] ??= {
scope: {
...scope
},
entries: {},
updatedAt: Date.now()
};
group.updatedAt = Date.now();
group.entries[partial_key] = {
revision: store.nextRevision++,
assets: serializePartialAssetMaps({
[partial_key]: assetMap
})[partial_key]
};
await writeStore(application_uid, store);
});
}
async function getPartialAssetMap(application_uid, scope = LEGACY_SCOPE) {
assertScope(scope);
return withPartialAssetsLock(application_uid, async ()=>{
const store = await readApplicationStore(application_uid);
const group = store.groups[getScopeKey(scope)];
return group ? deserializeGroup(group) : void 0;
});
}
async function claimPartialAssetMapBatch(application_uid, scopes) {
if (0 === scopes.length) throw new TypeError('At least one partial asset scope must be claimed');
const scopeKeys = scopes.map((scope)=>{
assertScope(scope);
return getScopeKey(scope);
});
if (new Set(scopeKeys).size !== scopeKeys.length) throw new TypeError('Partial asset scopes must be unique within a claim batch');
return withPartialAssetsLock(application_uid, async ()=>{
const store = await readApplicationStore(application_uid);
pruneStaleStore(store);
const candidates = scopes.map((scope, index)=>{
const scopeKey = scopeKeys[index];
const group = store.groups[scopeKey];
if (!group || 0 === Object.keys(group.entries).length) return;
const revisions = Object.fromEntries(Object.entries(group.entries).map(([partialKey, entry])=>[
partialKey,
entry.revision
]));
const isAlreadyClaimed = Object.values(store.claims).some((claim)=>claim.scopeKey === scopeKey && Object.entries(revisions).some(([partialKey, revision])=>claim.revisions[partialKey] === revision));
return isAlreadyClaimed ? void 0 : {
scope,
scopeKey,
group,
revisions
};
});
if (candidates.some((candidate)=>!candidate)) return;
const now = Date.now();
const claims = candidates.map((candidate)=>{
if (!candidate) throw new TypeError('Partial claim candidate was unavailable');
const claimId = (0, external_node_crypto_namespaceObject.randomUUID)();
store.claims[claimId] = {
scopeKey: candidate.scopeKey,
revisions: candidate.revisions,
createdAt: now
};
return {
claimId,
scope: {
...candidate.scope
},
partialAssetMaps: deserializeGroup(candidate.group)
};
});
await writeStore(application_uid, store);
return {
claims: Object.freeze(claims)
};
});
}
async function claimPartialAssetMap(application_uid, scope) {
const batch = await claimPartialAssetMapBatch(application_uid, [
scope
]);
return batch?.claims[0];
}
async function commitPartialAssetMapClaimBatch(application_uid, claimIds) {
const uniqueClaimIds = [
...new Set(claimIds)
];
if (0 === uniqueClaimIds.length) return;
await withPartialAssetsLock(application_uid, async ()=>{
const store = await readApplicationStore(application_uid);
let changed = false;
for (const claimId of uniqueClaimIds){
const claim = store.claims[claimId];
if (!claim) continue;
const group = store.groups[claim.scopeKey];
if (group) {
for (const [partialKey, revision] of Object.entries(claim.revisions))if (group.entries[partialKey]?.revision === revision) delete group.entries[partialKey];
if (0 === Object.keys(group.entries).length) delete store.groups[claim.scopeKey];
}
delete store.claims[claimId];
changed = true;
}
if (changed) await writeStore(application_uid, store);
});
}
async function commitPartialAssetMapClaim(application_uid, claimId) {
await commitPartialAssetMapClaimBatch(application_uid, [
claimId
]);
}
async function rollbackPartialAssetMapClaimBatch(application_uid, claimIds) {
const uniqueClaimIds = [
...new Set(claimIds)
];
if (0 === uniqueClaimIds.length) return;
await withPartialAssetsLock(application_uid, async ()=>{
const store = await readApplicationStore(application_uid);
let changed = false;
for (const claimId of uniqueClaimIds)if (store.claims[claimId]) {
delete store.claims[claimId];
changed = true;
}
if (changed) await writeStore(application_uid, store);
});
}
async function rollbackPartialAssetMapClaim(application_uid, claimId) {
await rollbackPartialAssetMapClaimBatch(application_uid, [
claimId
]);
}
async function takePartialAssetMap(application_uid) {
const claim = await claimPartialAssetMap(application_uid, LEGACY_SCOPE);
if (!claim) return;
await commitPartialAssetMapClaim(application_uid, claim.claimId);
return claim.partialAssetMaps;
}
async function removePartialAssetMap(application_uid) {
await withPartialAssetsLock(application_uid, async ()=>{
await (0, promises_namespaceObject.rm)(getLegacyPartialAssetStorePath(application_uid), {
force: true
});
await (0, promises_namespaceObject.rm)(getPartialAssetStorePath(application_uid), {
force: true
});
});
}
exports.claimPartialAssetMap = __webpack_exports__.claimPartialAssetMap;
exports.claimPartialAssetMapBatch = __webpack_exports__.claimPartialAssetMapBatch;
exports.commitPartialAssetMapClaim = __webpack_exports__.commitPartialAssetMapClaim;
exports.commitPartialAssetMapClaimBatch = __webpack_exports__.commitPartialAssetMapClaimBatch;
exports.deserializePartialAssetMaps = __webpack_exports__.deserializePartialAssetMaps;
exports.getLegacyPartialAssetStorePath = __webpack_exports__.getLegacyPartialAssetStorePath;
exports.getPartialAssetLockPath = __webpack_exports__.getPartialAssetLockPath;
exports.getPartialAssetMap = __webpack_exports__.getPartialAssetMap;
exports.getPartialAssetStorePath = __webpack_exports__.getPartialAssetStorePath;
exports.removePartialAssetMap = __webpack_exports__.removePartialAssetMap;
exports.rollbackPartialAssetMapClaim = __webpack_exports__.rollbackPartialAssetMapClaim;
exports.rollbackPartialAssetMapClaimBatch = __webpack_exports__.rollbackPartialAssetMapClaimBatch;
exports.savePartialAssetMap = __webpack_exports__.savePartialAssetMap;
exports.serializePartialAssetMaps = __webpack_exports__.serializePartialAssetMaps;
exports.takePartialAssetMap = __webpack_exports__.takePartialAssetMap;
for(var __rspack_i in __webpack_exports__)if (-1 === [
"claimPartialAssetMap",
"claimPartialAssetMapBatch",
"commitPartialAssetMapClaim",
"commitPartialAssetMapClaimBatch",
"deserializePartialAssetMaps",
"getLegacyPartialAssetStorePath",
"getPartialAssetLockPath",
"getPartialAssetMap",
"getPartialAssetStorePath",
"removePartialAssetMap",
"rollbackPartialAssetMapClaim",
"rollbackPartialAssetMapClaimBatch",
"savePartialAssetMap",
"serializePartialAssetMaps",
"takePartialAssetMap"
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
Object.defineProperty(exports, '__esModule', {
value: true
});
//# sourceMappingURL=partial-assets-map.js.map