@ubiquity-os/plugin-sdk 3.6.2 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/llm.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { C as Context } from './context-sqbr2o6i.mjs';
2
- import { PluginInput } from './signature.mjs';
3
1
  import { ChatCompletionMessageParam, ChatCompletionCreateParamsNonStreaming, ChatCompletion, ChatCompletionChunk } from 'openai/resources/chat/completions';
2
+ import { C as Context } from './context-Ckj1HMjz.mjs';
3
+ import { PluginInput } from './signature.mjs';
4
4
  import '@octokit/webhooks';
5
5
  import '@ubiquity-os/ubiquity-os-logger';
6
6
  import '@octokit/plugin-rest-endpoint-methods';
package/dist/llm.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { C as Context } from './context-BbEmsEct.js';
2
- import { PluginInput } from './signature.js';
3
1
  import { ChatCompletionMessageParam, ChatCompletionCreateParamsNonStreaming, ChatCompletion, ChatCompletionChunk } from 'openai/resources/chat/completions';
2
+ import { C as Context } from './context-BE4WjJZf.js';
3
+ import { PluginInput } from './signature.js';
4
4
  import '@octokit/webhooks';
5
5
  import '@ubiquity-os/ubiquity-os-logger';
6
6
  import '@octokit/plugin-rest-endpoint-methods';
package/dist/llm.js CHANGED
@@ -23,86 +23,185 @@ __export(llm_exports, {
23
23
  callLlm: () => callLlm
24
24
  });
25
25
  module.exports = __toCommonJS(llm_exports);
26
+ var EMPTY_STRING = "";
26
27
  function normalizeBaseUrl(baseUrl) {
27
- return baseUrl.trim().replace(/\/+$/, "");
28
+ let normalized = baseUrl.trim();
29
+ while (normalized.endsWith("/")) {
30
+ normalized = normalized.slice(0, -1);
31
+ }
32
+ return normalized;
33
+ }
34
+ var MAX_LLM_RETRIES = 2;
35
+ var RETRY_BACKOFF_MS = [250, 750];
36
+ function getRetryDelayMs(attempt) {
37
+ return RETRY_BACKOFF_MS[Math.min(attempt, RETRY_BACKOFF_MS.length - 1)] ?? 750;
38
+ }
39
+ function sleep(ms) {
40
+ return new Promise((resolve) => setTimeout(resolve, ms));
28
41
  }
29
42
  function getEnvString(name) {
30
- if (typeof process === "undefined" || !process?.env) return "";
31
- return String(process.env[name] ?? "").trim();
43
+ if (typeof process === "undefined" || !process?.env) return EMPTY_STRING;
44
+ return String(process.env[name] ?? EMPTY_STRING).trim();
32
45
  }
33
46
  function getAiBaseUrl(options) {
34
47
  if (typeof options.baseUrl === "string" && options.baseUrl.trim()) {
35
48
  return normalizeBaseUrl(options.baseUrl);
36
49
  }
37
- const envBaseUrl = getEnvString("UBQ_AI_BASE_URL") || getEnvString("UBQ_AI_URL");
50
+ const envBaseUrl = getEnvString("UOS_AI_URL") || getEnvString("UOS_AI_BASE_URL");
38
51
  if (envBaseUrl) return normalizeBaseUrl(envBaseUrl);
39
- return "https://ai.ubq.fi";
52
+ return "https://ai-ubq-fi.deno.dev";
40
53
  }
41
54
  async function callLlm(options, input) {
42
- const authToken = input?.authToken ?? "";
43
- const ubiquityKernelToken = input?.ubiquityKernelToken ?? "";
44
- const payload = input?.payload;
45
- const owner = payload?.repository?.owner?.login ?? "";
46
- const repo = payload?.repository?.name ?? "";
47
- const installationId = payload?.installation?.id;
48
- if (!authToken) throw new Error("Missing authToken in inputs");
49
- const requiresKernelToken = authToken.trim().startsWith("gh");
50
- if (requiresKernelToken && !ubiquityKernelToken) {
51
- throw new Error("Missing ubiquityKernelToken in inputs (kernel attestation is required for GitHub auth)");
55
+ const authToken = String(input.authToken ?? EMPTY_STRING).trim();
56
+ if (!authToken) {
57
+ const err = new Error("Missing authToken in input");
58
+ err.status = 401;
59
+ throw err;
52
60
  }
53
- const url = `${getAiBaseUrl(options)}/v1/chat/completions`;
54
- const { baseUrl: _baseUrl, model, stream, messages, ...rest } = options;
61
+ const kernelToken = "ubiquityKernelToken" in input ? input.ubiquityKernelToken : void 0;
62
+ const payload = getPayload(input);
63
+ const { owner, repo, installationId } = getRepoMetadata(payload);
64
+ ensureKernelToken(authToken, kernelToken);
65
+ const { baseUrl, model, stream: isStream, messages, ...rest } = options;
66
+ ensureMessages(messages);
67
+ const url = buildAiUrl(options, baseUrl);
55
68
  const body = JSON.stringify({
56
69
  ...rest,
57
70
  ...model ? { model } : {},
58
71
  messages,
59
- stream: stream ?? false
72
+ stream: isStream ?? false
73
+ });
74
+ const headers = buildHeaders(authToken, {
75
+ owner,
76
+ repo,
77
+ installationId,
78
+ ubiquityKernelToken: kernelToken
60
79
  });
80
+ const response = await fetchWithRetry(url, { method: "POST", headers, body }, MAX_LLM_RETRIES);
81
+ if (isStream) {
82
+ if (!response.body) {
83
+ throw new Error("LLM API error: missing response body for streaming request");
84
+ }
85
+ return parseSseStream(response.body);
86
+ }
87
+ return response.json();
88
+ }
89
+ function ensureKernelToken(authToken, kernelToken) {
90
+ const isKernelTokenRequired = authToken.startsWith("gh");
91
+ if (isKernelTokenRequired && !kernelToken) {
92
+ const err = new Error("Missing ubiquityKernelToken in input (kernel attestation is required for GitHub auth)");
93
+ err.status = 401;
94
+ throw err;
95
+ }
96
+ }
97
+ function ensureMessages(messages) {
98
+ if (!Array.isArray(messages) || messages.length === 0) {
99
+ const err = new Error("messages must be a non-empty array");
100
+ err.status = 400;
101
+ throw err;
102
+ }
103
+ }
104
+ function buildAiUrl(options, baseUrl) {
105
+ return `${getAiBaseUrl({ ...options, baseUrl })}/v1/chat/completions`;
106
+ }
107
+ async function fetchWithRetry(url, options, maxRetries) {
108
+ let attempt = 0;
109
+ let lastError;
110
+ while (attempt <= maxRetries) {
111
+ try {
112
+ const response = await fetch(url, options);
113
+ if (response.ok) return response;
114
+ const errText = await response.text();
115
+ if (response.status >= 500 && attempt < maxRetries) {
116
+ await sleep(getRetryDelayMs(attempt));
117
+ attempt += 1;
118
+ continue;
119
+ }
120
+ const error = new Error(`LLM API error: ${response.status} - ${errText}`);
121
+ error.status = response.status;
122
+ throw error;
123
+ } catch (error) {
124
+ lastError = error;
125
+ if (attempt >= maxRetries) throw error;
126
+ await sleep(getRetryDelayMs(attempt));
127
+ attempt += 1;
128
+ }
129
+ }
130
+ throw lastError ?? new Error("LLM API error: request failed after retries");
131
+ }
132
+ function getPayload(input) {
133
+ if ("payload" in input) {
134
+ return input.payload;
135
+ }
136
+ return input.eventPayload;
137
+ }
138
+ function getRepoMetadata(payload) {
139
+ const repoPayload = payload;
140
+ return {
141
+ owner: repoPayload?.repository?.owner?.login ?? EMPTY_STRING,
142
+ repo: repoPayload?.repository?.name ?? EMPTY_STRING,
143
+ installationId: repoPayload?.installation?.id
144
+ };
145
+ }
146
+ function buildHeaders(authToken, options) {
61
147
  const headers = {
62
148
  Authorization: `Bearer ${authToken}`,
63
149
  "Content-Type": "application/json"
64
150
  };
65
- if (owner) headers["X-GitHub-Owner"] = owner;
66
- if (repo) headers["X-GitHub-Repo"] = repo;
67
- if (typeof installationId === "number" && Number.isFinite(installationId)) {
68
- headers["X-GitHub-Installation-Id"] = String(installationId);
151
+ if (options.owner) headers["X-GitHub-Owner"] = options.owner;
152
+ if (options.repo) headers["X-GitHub-Repo"] = options.repo;
153
+ if (typeof options.installationId === "number" && Number.isFinite(options.installationId)) {
154
+ headers["X-GitHub-Installation-Id"] = String(options.installationId);
69
155
  }
70
- if (ubiquityKernelToken) {
71
- headers["X-Ubiquity-Kernel-Token"] = ubiquityKernelToken;
156
+ if (options.ubiquityKernelToken) {
157
+ headers["X-Ubiquity-Kernel-Token"] = options.ubiquityKernelToken;
72
158
  }
73
- const response = await fetch(url, { method: "POST", headers, body });
74
- if (!response.ok) {
75
- const err = await response.text();
76
- throw new Error(`LLM API error: ${response.status} - ${err}`);
77
- }
78
- if (options.stream) {
79
- return parseSseStream(response.body);
80
- }
81
- return response.json();
159
+ return headers;
82
160
  }
83
161
  async function* parseSseStream(body) {
84
162
  const reader = body.getReader();
85
163
  const decoder = new TextDecoder();
86
- let buffer = "";
164
+ let buffer = EMPTY_STRING;
87
165
  try {
88
166
  while (true) {
89
- const { value, done } = await reader.read();
90
- if (done) break;
167
+ const { value, done: isDone } = await reader.read();
168
+ if (isDone) break;
91
169
  buffer += decoder.decode(value, { stream: true });
92
- const events = buffer.split("\n\n");
93
- buffer = events.pop() || "";
170
+ const { events, remainder } = splitSseEvents(buffer);
171
+ buffer = remainder;
94
172
  for (const event of events) {
95
- if (event.startsWith("data: ")) {
96
- const data = event.slice(6);
97
- if (data === "[DONE]") return;
98
- yield JSON.parse(data);
99
- }
173
+ const data = getEventData(event);
174
+ if (!data) continue;
175
+ if (data.trim() === "[DONE]") return;
176
+ yield parseEventData(data);
100
177
  }
101
178
  }
102
179
  } finally {
103
180
  reader.releaseLock();
104
181
  }
105
182
  }
183
+ function splitSseEvents(buffer) {
184
+ const normalized = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
185
+ const parts = normalized.split("\n\n");
186
+ const remainder = parts.pop() ?? EMPTY_STRING;
187
+ return { events: parts, remainder };
188
+ }
189
+ function getEventData(event) {
190
+ if (!event.trim()) return null;
191
+ const dataLines = event.split("\n").filter((line) => line.startsWith("data:"));
192
+ if (!dataLines.length) return null;
193
+ const data = dataLines.map((line) => line.startsWith("data: ") ? line.slice(6) : line.slice(5).replace(/^ /, EMPTY_STRING)).join("\n");
194
+ return data || null;
195
+ }
196
+ function parseEventData(data) {
197
+ try {
198
+ return JSON.parse(data);
199
+ } catch (error) {
200
+ const message = error instanceof Error ? error.message : String(error);
201
+ const preview = data.length > 200 ? `${data.slice(0, 200)}...` : data;
202
+ throw new Error(`LLM stream parse error: ${message}. Data: ${preview}`);
203
+ }
204
+ }
106
205
  // Annotate the CommonJS export names for ESM import in node:
107
206
  0 && (module.exports = {
108
207
  callLlm
package/dist/llm.mjs CHANGED
@@ -1,84 +1,183 @@
1
1
  // src/llm/index.ts
2
+ var EMPTY_STRING = "";
2
3
  function normalizeBaseUrl(baseUrl) {
3
- return baseUrl.trim().replace(/\/+$/, "");
4
+ let normalized = baseUrl.trim();
5
+ while (normalized.endsWith("/")) {
6
+ normalized = normalized.slice(0, -1);
7
+ }
8
+ return normalized;
9
+ }
10
+ var MAX_LLM_RETRIES = 2;
11
+ var RETRY_BACKOFF_MS = [250, 750];
12
+ function getRetryDelayMs(attempt) {
13
+ return RETRY_BACKOFF_MS[Math.min(attempt, RETRY_BACKOFF_MS.length - 1)] ?? 750;
14
+ }
15
+ function sleep(ms) {
16
+ return new Promise((resolve) => setTimeout(resolve, ms));
4
17
  }
5
18
  function getEnvString(name) {
6
- if (typeof process === "undefined" || !process?.env) return "";
7
- return String(process.env[name] ?? "").trim();
19
+ if (typeof process === "undefined" || !process?.env) return EMPTY_STRING;
20
+ return String(process.env[name] ?? EMPTY_STRING).trim();
8
21
  }
9
22
  function getAiBaseUrl(options) {
10
23
  if (typeof options.baseUrl === "string" && options.baseUrl.trim()) {
11
24
  return normalizeBaseUrl(options.baseUrl);
12
25
  }
13
- const envBaseUrl = getEnvString("UBQ_AI_BASE_URL") || getEnvString("UBQ_AI_URL");
26
+ const envBaseUrl = getEnvString("UOS_AI_URL") || getEnvString("UOS_AI_BASE_URL");
14
27
  if (envBaseUrl) return normalizeBaseUrl(envBaseUrl);
15
- return "https://ai.ubq.fi";
28
+ return "https://ai-ubq-fi.deno.dev";
16
29
  }
17
30
  async function callLlm(options, input) {
18
- const authToken = input?.authToken ?? "";
19
- const ubiquityKernelToken = input?.ubiquityKernelToken ?? "";
20
- const payload = input?.payload;
21
- const owner = payload?.repository?.owner?.login ?? "";
22
- const repo = payload?.repository?.name ?? "";
23
- const installationId = payload?.installation?.id;
24
- if (!authToken) throw new Error("Missing authToken in inputs");
25
- const requiresKernelToken = authToken.trim().startsWith("gh");
26
- if (requiresKernelToken && !ubiquityKernelToken) {
27
- throw new Error("Missing ubiquityKernelToken in inputs (kernel attestation is required for GitHub auth)");
31
+ const authToken = String(input.authToken ?? EMPTY_STRING).trim();
32
+ if (!authToken) {
33
+ const err = new Error("Missing authToken in input");
34
+ err.status = 401;
35
+ throw err;
28
36
  }
29
- const url = `${getAiBaseUrl(options)}/v1/chat/completions`;
30
- const { baseUrl: _baseUrl, model, stream, messages, ...rest } = options;
37
+ const kernelToken = "ubiquityKernelToken" in input ? input.ubiquityKernelToken : void 0;
38
+ const payload = getPayload(input);
39
+ const { owner, repo, installationId } = getRepoMetadata(payload);
40
+ ensureKernelToken(authToken, kernelToken);
41
+ const { baseUrl, model, stream: isStream, messages, ...rest } = options;
42
+ ensureMessages(messages);
43
+ const url = buildAiUrl(options, baseUrl);
31
44
  const body = JSON.stringify({
32
45
  ...rest,
33
46
  ...model ? { model } : {},
34
47
  messages,
35
- stream: stream ?? false
48
+ stream: isStream ?? false
49
+ });
50
+ const headers = buildHeaders(authToken, {
51
+ owner,
52
+ repo,
53
+ installationId,
54
+ ubiquityKernelToken: kernelToken
36
55
  });
56
+ const response = await fetchWithRetry(url, { method: "POST", headers, body }, MAX_LLM_RETRIES);
57
+ if (isStream) {
58
+ if (!response.body) {
59
+ throw new Error("LLM API error: missing response body for streaming request");
60
+ }
61
+ return parseSseStream(response.body);
62
+ }
63
+ return response.json();
64
+ }
65
+ function ensureKernelToken(authToken, kernelToken) {
66
+ const isKernelTokenRequired = authToken.startsWith("gh");
67
+ if (isKernelTokenRequired && !kernelToken) {
68
+ const err = new Error("Missing ubiquityKernelToken in input (kernel attestation is required for GitHub auth)");
69
+ err.status = 401;
70
+ throw err;
71
+ }
72
+ }
73
+ function ensureMessages(messages) {
74
+ if (!Array.isArray(messages) || messages.length === 0) {
75
+ const err = new Error("messages must be a non-empty array");
76
+ err.status = 400;
77
+ throw err;
78
+ }
79
+ }
80
+ function buildAiUrl(options, baseUrl) {
81
+ return `${getAiBaseUrl({ ...options, baseUrl })}/v1/chat/completions`;
82
+ }
83
+ async function fetchWithRetry(url, options, maxRetries) {
84
+ let attempt = 0;
85
+ let lastError;
86
+ while (attempt <= maxRetries) {
87
+ try {
88
+ const response = await fetch(url, options);
89
+ if (response.ok) return response;
90
+ const errText = await response.text();
91
+ if (response.status >= 500 && attempt < maxRetries) {
92
+ await sleep(getRetryDelayMs(attempt));
93
+ attempt += 1;
94
+ continue;
95
+ }
96
+ const error = new Error(`LLM API error: ${response.status} - ${errText}`);
97
+ error.status = response.status;
98
+ throw error;
99
+ } catch (error) {
100
+ lastError = error;
101
+ if (attempt >= maxRetries) throw error;
102
+ await sleep(getRetryDelayMs(attempt));
103
+ attempt += 1;
104
+ }
105
+ }
106
+ throw lastError ?? new Error("LLM API error: request failed after retries");
107
+ }
108
+ function getPayload(input) {
109
+ if ("payload" in input) {
110
+ return input.payload;
111
+ }
112
+ return input.eventPayload;
113
+ }
114
+ function getRepoMetadata(payload) {
115
+ const repoPayload = payload;
116
+ return {
117
+ owner: repoPayload?.repository?.owner?.login ?? EMPTY_STRING,
118
+ repo: repoPayload?.repository?.name ?? EMPTY_STRING,
119
+ installationId: repoPayload?.installation?.id
120
+ };
121
+ }
122
+ function buildHeaders(authToken, options) {
37
123
  const headers = {
38
124
  Authorization: `Bearer ${authToken}`,
39
125
  "Content-Type": "application/json"
40
126
  };
41
- if (owner) headers["X-GitHub-Owner"] = owner;
42
- if (repo) headers["X-GitHub-Repo"] = repo;
43
- if (typeof installationId === "number" && Number.isFinite(installationId)) {
44
- headers["X-GitHub-Installation-Id"] = String(installationId);
127
+ if (options.owner) headers["X-GitHub-Owner"] = options.owner;
128
+ if (options.repo) headers["X-GitHub-Repo"] = options.repo;
129
+ if (typeof options.installationId === "number" && Number.isFinite(options.installationId)) {
130
+ headers["X-GitHub-Installation-Id"] = String(options.installationId);
45
131
  }
46
- if (ubiquityKernelToken) {
47
- headers["X-Ubiquity-Kernel-Token"] = ubiquityKernelToken;
132
+ if (options.ubiquityKernelToken) {
133
+ headers["X-Ubiquity-Kernel-Token"] = options.ubiquityKernelToken;
48
134
  }
49
- const response = await fetch(url, { method: "POST", headers, body });
50
- if (!response.ok) {
51
- const err = await response.text();
52
- throw new Error(`LLM API error: ${response.status} - ${err}`);
53
- }
54
- if (options.stream) {
55
- return parseSseStream(response.body);
56
- }
57
- return response.json();
135
+ return headers;
58
136
  }
59
137
  async function* parseSseStream(body) {
60
138
  const reader = body.getReader();
61
139
  const decoder = new TextDecoder();
62
- let buffer = "";
140
+ let buffer = EMPTY_STRING;
63
141
  try {
64
142
  while (true) {
65
- const { value, done } = await reader.read();
66
- if (done) break;
143
+ const { value, done: isDone } = await reader.read();
144
+ if (isDone) break;
67
145
  buffer += decoder.decode(value, { stream: true });
68
- const events = buffer.split("\n\n");
69
- buffer = events.pop() || "";
146
+ const { events, remainder } = splitSseEvents(buffer);
147
+ buffer = remainder;
70
148
  for (const event of events) {
71
- if (event.startsWith("data: ")) {
72
- const data = event.slice(6);
73
- if (data === "[DONE]") return;
74
- yield JSON.parse(data);
75
- }
149
+ const data = getEventData(event);
150
+ if (!data) continue;
151
+ if (data.trim() === "[DONE]") return;
152
+ yield parseEventData(data);
76
153
  }
77
154
  }
78
155
  } finally {
79
156
  reader.releaseLock();
80
157
  }
81
158
  }
159
+ function splitSseEvents(buffer) {
160
+ const normalized = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
161
+ const parts = normalized.split("\n\n");
162
+ const remainder = parts.pop() ?? EMPTY_STRING;
163
+ return { events: parts, remainder };
164
+ }
165
+ function getEventData(event) {
166
+ if (!event.trim()) return null;
167
+ const dataLines = event.split("\n").filter((line) => line.startsWith("data:"));
168
+ if (!dataLines.length) return null;
169
+ const data = dataLines.map((line) => line.startsWith("data: ") ? line.slice(6) : line.slice(5).replace(/^ /, EMPTY_STRING)).join("\n");
170
+ return data || null;
171
+ }
172
+ function parseEventData(data) {
173
+ try {
174
+ return JSON.parse(data);
175
+ } catch (error) {
176
+ const message = error instanceof Error ? error.message : String(error);
177
+ const preview = data.length > 200 ? `${data.slice(0, 200)}...` : data;
178
+ throw new Error(`LLM stream parse error: ${message}. Data: ${preview}`);
179
+ }
180
+ }
82
181
  export {
83
182
  callLlm
84
183
  };
package/dist/signature.js CHANGED
@@ -83,7 +83,7 @@ async function verifySignature(publicKeyPem, inputs, signature) {
83
83
  ref: inputs.ref,
84
84
  command: inputs.command
85
85
  };
86
- const pemContents = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").trim();
86
+ const pemContents = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").replace(/\s+/g, "");
87
87
  const binaryDer = Uint8Array.from(atob(pemContents), (c) => c.charCodeAt(0));
88
88
  const publicKey = await crypto.subtle.importKey(
89
89
  "spki",
@@ -104,7 +104,7 @@ async function verifySignature(publicKeyPem, inputs, signature) {
104
104
  }
105
105
  }
106
106
  async function importRsaPrivateKey(pem) {
107
- const pemContents = pem.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").trim();
107
+ const pemContents = pem.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replace(/\s+/g, "");
108
108
  const binaryDer = Uint8Array.from(atob(pemContents), (c) => c.charCodeAt(0));
109
109
  return await crypto.subtle.importKey(
110
110
  "pkcs8",
@@ -55,7 +55,7 @@ async function verifySignature(publicKeyPem, inputs, signature) {
55
55
  ref: inputs.ref,
56
56
  command: inputs.command
57
57
  };
58
- const pemContents = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").trim();
58
+ const pemContents = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").replace(/\s+/g, "");
59
59
  const binaryDer = Uint8Array.from(atob(pemContents), (c) => c.charCodeAt(0));
60
60
  const publicKey = await crypto.subtle.importKey(
61
61
  "spki",
@@ -76,7 +76,7 @@ async function verifySignature(publicKeyPem, inputs, signature) {
76
76
  }
77
77
  }
78
78
  async function importRsaPrivateKey(pem) {
79
- const pemContents = pem.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").trim();
79
+ const pemContents = pem.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replace(/\s+/g, "");
80
80
  const binaryDer = Uint8Array.from(atob(pemContents), (c) => c.charCodeAt(0));
81
81
  return await crypto.subtle.importKey(
82
82
  "pkcs8",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ubiquity-os/plugin-sdk",
3
- "version": "3.6.2",
3
+ "version": "3.7.0",
4
4
  "description": "SDK for plugin support.",
5
5
  "author": "Ubiquity DAO",
6
6
  "license": "MIT",