const runtimeGlobal = globalThis; const COLLECTION_PATTERN = /^[a-z][a-z0-9_-]{0,47}$/; const DOCUMENT_ID_PATTERN = /^[A-Za-z0-9._~-]{1,128}$/; const MAX_CURSOR_LENGTH = 1024; const MAX_ERROR_MESSAGE_LENGTH = 256; const MAX_RETRY_AFTER_SECONDS = 86400; const ERROR_STATUS = { runtime_unavailable: 503, upstream_invalid_response: 502, invalid_request: [400, 422], invalid_content_type: 415, invalid_revision: 422, invalid_cursor: 400, cursor_expired: 410, invalid_collection_name: 422, invalid_document_id: 422, invalid_document_data: 422, invalid_project_id: 422, authentication_required: 401, origin_not_allowed: 403, method_not_allowed: 405, route_not_found: 404, instance_not_found: 404, collection_not_found: 404, document_not_found: 404, revision_conflict: 409, document_too_large: 413, quota_exceeded: 409, rate_limited: 429, data_service_unavailable: 503, request_too_large: 413 }; const ERROR_MESSAGE = { runtime_unavailable: "Preview data runtime is unavailable", upstream_invalid_response: "Data Service returned an invalid response", invalid_request: "Data Service request is invalid", invalid_content_type: "Data Service request content type is invalid", invalid_revision: "Data Service document revision is invalid", invalid_cursor: "Data Service cursor is invalid", cursor_expired: "Data Service cursor has expired", invalid_collection_name: "Data Service collection is invalid", invalid_document_id: "Data Service document ID is invalid", invalid_document_data: "Data Service document data is invalid", invalid_project_id: "Data Service project ID is invalid", authentication_required: "Preview data authorization is required", origin_not_allowed: "Preview data Origin is not allowed", method_not_allowed: "Preview data method is not allowed", route_not_found: "Preview data route was not found", instance_not_found: "Data Service project instance was not found", collection_not_found: "Data Service collection was not found", document_not_found: "Data Service document was not found", revision_conflict: "Data Service document revision conflicts", document_too_large: "Data Service document is too large", quota_exceeded: "Data Service quota exceeded", rate_limited: "Preview data request rate limit exceeded", data_service_unavailable: "Data Service is temporarily unavailable", request_too_large: "Preview data request is too large" }; const CONTEXT_KEYS = /* @__PURE__ */ new Set([ "resource", "limit", "current", "attempted", "actual", "allowed", "current_revision", "retry_after_seconds" ]); const CONTEXT_RESOURCES = /* @__PURE__ */ new Set(["instances", "collections", "documents", "bytes"]); function isRecord(value) { return typeof value === "object" && value !== null && !Array.isArray(value); } function positiveInteger(value) { return Number.isSafeInteger(value) && value > 0; } function boundedText(value, maximum) { return typeof value === "string" && value.length > 0 && value.length <= maximum; } function boundedTimestamp(value) { return boundedText(value, 64) && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$/.test(value) && Number.isFinite(Date.parse(value)); } function hasOnlyKeys(value, required, optional = []) { const allowed = /* @__PURE__ */ new Set([...required, ...optional]); return required.every((key) => Object.prototype.hasOwnProperty.call(value, key)) && Object.keys(value).every((key) => allowed.has(key)); } function statusMatches(code, status) { const expected = ERROR_STATUS[code]; return Array.isArray(expected) ? expected.includes(status) : expected === status; } function frozenContext(value) { return value === void 0 ? void 0 : Object.freeze({ ...value }); } class DataServiceError extends Error { code; status; retryable; retryAfterSeconds; context; constructor(code, status, retryable, retryAfterSeconds, context) { super(ERROR_MESSAGE[code]); Object.defineProperty(this, "name", { value: "DataServiceError", enumerable: false }); this.code = code; this.status = status; this.retryable = retryable; if (retryAfterSeconds !== void 0) this.retryAfterSeconds = retryAfterSeconds; const safeContext = frozenContext(context); if (safeContext !== void 0) this.context = safeContext; Object.freeze(this); } } function runtimeUnavailable() { return new DataServiceError("runtime_unavailable", 503, true); } function invalidRequest() { return new DataServiceError("invalid_request", 422, false); } function upstreamInvalidResponse() { return new DataServiceError("upstream_invalid_response", 502, false); } function readRuntime() { const candidate = globalThis.__MAKELORE_DATA__; if (!isRecord(candidate) || candidate.contractVersion !== 1 || !boundedText(candidate.token, 256) || !/^[A-Za-z0-9_-]+$/.test(candidate.token) || !boundedText(candidate.endpoint, 256)) { throw runtimeUnavailable(); } let endpoint; try { endpoint = new URL(candidate.endpoint); } catch { throw runtimeUnavailable(); } if (endpoint.protocol !== "http:" || endpoint.hostname !== "127.0.0.1" || !endpoint.port || endpoint.username || endpoint.password || endpoint.pathname !== "/api/runtime/data/v1" || endpoint.search || endpoint.hash) { throw runtimeUnavailable(); } return { endpoint: `${endpoint.origin}${endpoint.pathname}`, token: candidate.token, contractVersion: 1 }; } function requireCollection(value) { if (typeof value !== "string" || !COLLECTION_PATTERN.test(value)) throw invalidRequest(); return value; } function requireDocumentId(value) { if (typeof value !== "string" || value === "." || value === ".." || !DOCUMENT_ID_PATTERN.test(value)) { throw invalidRequest(); } return value; } function requireData(value) { if (!isRecord(value)) throw invalidRequest(); try { if (JSON.stringify(value) === void 0) throw new Error("data is not JSON"); } catch { throw invalidRequest(); } return value; } function requireOptions(value, allowed) { if (value === void 0) return {}; if (!isRecord(value) || Object.keys(value).some((key) => !allowed.includes(key))) throw invalidRequest(); return value; } function readIfRevision(value) { if (value === void 0) return void 0; if (!positiveInteger(value)) throw invalidRequest(); return value; } function buildDocumentPath(endpoint, collection, documentId) { return `${endpoint}/collections/${encodeURIComponent(collection)}/documents/${encodeURIComponent(documentId)}`; } function parseContext(value) { if (value === void 0) return void 0; if (!isRecord(value)) throw upstreamInvalidResponse(); const context = {}; for (const [key, item] of Object.entries(value)) { if (!CONTEXT_KEYS.has(key)) throw upstreamInvalidResponse(); if (key === "resource") { if (!boundedText(item, 16) || !CONTEXT_RESOURCES.has(item)) throw upstreamInvalidResponse(); context.resource = item; } else { if (!positiveInteger(item) && item !== 0) throw upstreamInvalidResponse(); context[key] = item; } } return Object.keys(context).length === 0 ? void 0 : context; } function readRetryAfter(response) { const raw = response.headers?.get("retry-after")?.trim(); if (!raw || !/^\d+$/.test(raw)) return void 0; const seconds = Number(raw); return Number.isSafeInteger(seconds) && seconds <= MAX_RETRY_AFTER_SECONDS ? seconds : void 0; } async function parseError(response) { try { const payload = await response.json(); if (!isRecord(payload) || !isRecord(payload.detail)) throw upstreamInvalidResponse(); const detail = payload.detail; if (!hasOnlyKeys(detail, ["code", "message", "retryable"], ["context"]) || !boundedText(detail.code, 64) || !Object.prototype.hasOwnProperty.call(ERROR_STATUS, detail.code) || !boundedText(detail.message, MAX_ERROR_MESSAGE_LENGTH) || typeof detail.retryable !== "boolean" || !statusMatches(detail.code, response.status)) { throw upstreamInvalidResponse(); } const context = parseContext(detail.context); return new DataServiceError( detail.code, response.status, detail.retryable, readRetryAfter(response), context ); } catch (error) { if (error instanceof DataServiceError) throw error; throw upstreamInvalidResponse(); } } async function parseJson(response) { try { return await response.json(); } catch { throw upstreamInvalidResponse(); } } function parseDocument(value) { if (!isRecord(value) || !hasOnlyKeys(value, ["id", "data", "revision", "created_at", "updated_at"]) || typeof value.id !== "string" || value.id === "." || value.id === ".." || !DOCUMENT_ID_PATTERN.test(value.id) || !isRecord(value.data) || !positiveInteger(value.revision) || !boundedTimestamp(value.created_at) || !boundedTimestamp(value.updated_at)) { throw upstreamInvalidResponse(); } return { id: value.id, data: value.data, revision: value.revision, created_at: value.created_at, updated_at: value.updated_at }; } function parsePage(value) { if (!isRecord(value) || !hasOnlyKeys(value, ["items", "next_cursor", "limit"]) || !Array.isArray(value.items) || value.items.length > 100 || !positiveInteger(value.limit) || value.limit > 100 || value.next_cursor !== null && !boundedText(value.next_cursor, MAX_CURSOR_LENGTH)) { throw upstreamInvalidResponse(); } const items = value.items.map(parseDocument); if (new Set(items.map((item) => item.id)).size !== items.length) throw upstreamInvalidResponse(); return { items, next_cursor: value.next_cursor === null ? null : value.next_cursor, limit: value.limit }; } async function request(method, url, expectedStatus, parse, body, ifRevision) { const runtime = readRuntime(); const fetchImpl = runtimeGlobal.fetch; if (typeof fetchImpl !== "function") throw runtimeUnavailable(); const headers = { Accept: "application/json", Authorization: `Bearer ${runtime.token}` }; const serializedBody = body === void 0 ? void 0 : (() => { try { const encoded = JSON.stringify(body); return encoded === void 0 ? null : encoded; } catch { return null; } })(); if (serializedBody === null) throw invalidRequest(); if (serializedBody !== void 0) headers["Content-Type"] = "application/json"; if (ifRevision !== void 0) headers["If-Match"] = `"${ifRevision}"`; let response; try { response = await fetchImpl(url, { method, headers, ...serializedBody === void 0 ? {} : { body: serializedBody } }); } catch { throw runtimeUnavailable(); } if (!response || !Number.isSafeInteger(response.status)) throw upstreamInvalidResponse(); if (response.status !== expectedStatus) throw await parseError(response); if (expectedStatus === 204) return void 0; return parse(await parseJson(response)); } function listPath(endpoint, collection, options) { const params = new URLSearchParams(); if (options.limit !== void 0) params.set("limit", String(options.limit)); if (options.cursor !== void 0) params.set("cursor", options.cursor); const query = params.toString(); return `${endpoint}/collections/${encodeURIComponent(collection)}/documents${query ? `?${query}` : ""}`; } async function getDocument(collection, documentId) { const runtime = readRuntime(); const safeCollection = requireCollection(collection); const safeDocumentId = requireDocumentId(documentId); return await request( "GET", buildDocumentPath(runtime.endpoint, safeCollection, safeDocumentId), 200, parseDocument ); } async function listDocuments(collection, input = {}) { const runtime = readRuntime(); const safeCollection = requireCollection(collection); const options = requireOptions(input, ["limit", "cursor"]); const limit = options.limit; if (limit !== void 0 && (!positiveInteger(limit) || limit > 100)) throw invalidRequest(); const cursor = options.cursor; if (cursor !== void 0 && !boundedText(cursor, MAX_CURSOR_LENGTH)) throw invalidRequest(); return await request( "GET", listPath(runtime.endpoint, safeCollection, { ...limit === void 0 ? {} : { limit }, ...cursor === void 0 ? {} : { cursor } }), 200, parsePage ); } async function putDocument(collection, documentId, value, input = {}) { const runtime = readRuntime(); const safeCollection = requireCollection(collection); const safeDocumentId = requireDocumentId(documentId); const data2 = requireData(value); const options = requireOptions(input, ["ifRevision"]); const ifRevision = readIfRevision(options.ifRevision); return await request( "PUT", buildDocumentPath(runtime.endpoint, safeCollection, safeDocumentId), 200, parseDocument, { data: data2 }, ifRevision ); } async function deleteDocument(collection, documentId, input = {}) { const runtime = readRuntime(); const safeCollection = requireCollection(collection); const safeDocumentId = requireDocumentId(documentId); const options = requireOptions(input, ["ifRevision"]); const ifRevision = readIfRevision(options.ifRevision); await request( "DELETE", buildDocumentPath(runtime.endpoint, safeCollection, safeDocumentId), 204, () => void 0, void 0, ifRevision ); } async function addDocument(collection, value) { readRuntime(); requireCollection(collection); requireData(value); const randomUuid = runtimeGlobal.crypto?.randomUUID; if (typeof randomUuid !== "function") throw runtimeUnavailable(); const id = randomUuid(); if (!boundedText(id, 128) || !DOCUMENT_ID_PATTERN.test(id)) throw runtimeUnavailable(); return await putDocument(collection, id, value); } const data = Object.freeze({ get: getDocument, list: listDocuments, put: putDocument, delete: deleteDocument, add: addDocument }); var makelore_data_default = data; export { DataServiceError, data, makelore_data_default as default };