@ricsam/isolate-encoding 0.0.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,45 +1,50 @@
1
1
  # @ricsam/isolate-encoding
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
4
-
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
6
-
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
8
-
9
- ## Purpose
10
-
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@ricsam/isolate-encoding`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
15
-
16
- ## What is OIDC Trusted Publishing?
17
-
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
19
-
20
- ## Setup Instructions
21
-
22
- To properly configure OIDC trusted publishing for this package:
23
-
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
28
-
29
- ## DO NOT USE THIS PACKAGE
30
-
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
36
-
37
- ## More Information
38
-
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
42
-
43
- ---
44
-
45
- **Maintained for OIDC setup purposes only**
3
+ Base64 encoding and decoding via `atob` and `btoa`.
4
+
5
+ ```typescript
6
+ import { setupEncoding } from "@ricsam/isolate-encoding";
7
+
8
+ const handle = await setupEncoding(context);
9
+ ```
10
+
11
+ **Injected Globals:**
12
+ - `atob(encodedData)` - Decode a Base64-encoded string
13
+ - `btoa(stringToEncode)` - Encode a string to Base64
14
+
15
+ **Usage in Isolate:**
16
+
17
+ ```javascript
18
+ // Encode string to Base64
19
+ const encoded = btoa("Hello, World!");
20
+ console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="
21
+
22
+ // Decode Base64 to string
23
+ const decoded = atob("SGVsbG8sIFdvcmxkIQ==");
24
+ console.log(decoded); // "Hello, World!"
25
+
26
+ // Common use case: encoding JSON for transport
27
+ const data = { user: "john", token: "abc123" };
28
+ const base64Data = btoa(JSON.stringify(data));
29
+
30
+ // Decode it back
31
+ const originalData = JSON.parse(atob(base64Data));
32
+ ```
33
+
34
+ **Error Handling:**
35
+
36
+ ```javascript
37
+ // btoa throws for characters outside Latin1 range (0-255)
38
+ try {
39
+ btoa("Hello 世界"); // Throws DOMException
40
+ } catch (e) {
41
+ console.error("Cannot encode non-Latin1 characters");
42
+ }
43
+
44
+ // atob throws for invalid Base64
45
+ try {
46
+ atob("not valid base64!!!");
47
+ } catch (e) {
48
+ console.error("Invalid Base64 string");
49
+ }
50
+ ```
@@ -0,0 +1,190 @@
1
+ // @bun @bun-cjs
2
+ (function(exports, require, module, __filename, __dirname) {var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
7
+ var __toCommonJS = (from) => {
8
+ var entry = __moduleCache.get(from), desc;
9
+ if (entry)
10
+ return entry;
11
+ entry = __defProp({}, "__esModule", { value: true });
12
+ if (from && typeof from === "object" || typeof from === "function")
13
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
14
+ get: () => from[key],
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ }));
17
+ __moduleCache.set(from, entry);
18
+ return entry;
19
+ };
20
+ var __export = (target, all) => {
21
+ for (var name in all)
22
+ __defProp(target, name, {
23
+ get: all[name],
24
+ enumerable: true,
25
+ configurable: true,
26
+ set: (newValue) => all[name] = () => newValue
27
+ });
28
+ };
29
+
30
+ // packages/encoding/src/index.ts
31
+ var exports_src = {};
32
+ __export(exports_src, {
33
+ setupEncoding: () => setupEncoding
34
+ });
35
+ module.exports = __toCommonJS(exports_src);
36
+ var encodingCode = `
37
+ (function() {
38
+ // Define DOMException if not available
39
+ if (typeof DOMException === 'undefined') {
40
+ globalThis.DOMException = class DOMException extends Error {
41
+ constructor(message, name) {
42
+ super(message);
43
+ this.name = name || 'DOMException';
44
+ }
45
+ };
46
+ }
47
+
48
+ const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
49
+
50
+ // Build reverse lookup table
51
+ const base64Lookup = new Map();
52
+ for (let i = 0; i < base64Chars.length; i++) {
53
+ base64Lookup.set(base64Chars[i], i);
54
+ }
55
+
56
+ globalThis.btoa = function btoa(str) {
57
+ if (str === undefined) {
58
+ throw new TypeError("1 argument required, but only 0 present.");
59
+ }
60
+
61
+ str = String(str);
62
+
63
+ // Check for characters outside Latin-1 range
64
+ for (let i = 0; i < str.length; i++) {
65
+ if (str.charCodeAt(i) > 255) {
66
+ throw new DOMException(
67
+ "The string to be encoded contains characters outside of the Latin1 range.",
68
+ "InvalidCharacterError"
69
+ );
70
+ }
71
+ }
72
+
73
+ if (str.length === 0) {
74
+ return '';
75
+ }
76
+
77
+ let result = '';
78
+ let i = 0;
79
+
80
+ while (i < str.length) {
81
+ const a = str.charCodeAt(i++);
82
+ const bExists = i < str.length;
83
+ const b = bExists ? str.charCodeAt(i++) : 0;
84
+ const cExists = i < str.length;
85
+ const c = cExists ? str.charCodeAt(i++) : 0;
86
+
87
+ const triplet = (a << 16) | (b << 8) | c;
88
+
89
+ result += base64Chars[(triplet >> 18) & 0x3F];
90
+ result += base64Chars[(triplet >> 12) & 0x3F];
91
+ result += bExists ? base64Chars[(triplet >> 6) & 0x3F] : '=';
92
+ result += cExists ? base64Chars[triplet & 0x3F] : '=';
93
+ }
94
+
95
+ return result;
96
+ };
97
+
98
+ globalThis.atob = function atob(str) {
99
+ if (str === undefined) {
100
+ throw new TypeError("1 argument required, but only 0 present.");
101
+ }
102
+
103
+ str = String(str);
104
+
105
+ // Remove whitespace
106
+ str = str.replace(/[\\t\\n\\f\\r ]/g, '');
107
+
108
+ // Validate characters and length
109
+ if (str.length === 0) {
110
+ return '';
111
+ }
112
+
113
+ // Check for invalid characters (before padding normalization)
114
+ for (let i = 0; i < str.length; i++) {
115
+ const c = str[i];
116
+ if (c !== '=' && !base64Lookup.has(c)) {
117
+ throw new DOMException(
118
+ "The string to be decoded is not correctly encoded.",
119
+ "InvalidCharacterError"
120
+ );
121
+ }
122
+ }
123
+
124
+ // Validate padding position (must be at end)
125
+ const paddingIndex = str.indexOf('=');
126
+ if (paddingIndex !== -1) {
127
+ for (let i = paddingIndex; i < str.length; i++) {
128
+ if (str[i] !== '=') {
129
+ throw new DOMException(
130
+ "The string to be decoded is not correctly encoded.",
131
+ "InvalidCharacterError"
132
+ );
133
+ }
134
+ }
135
+ const paddingLength = str.length - paddingIndex;
136
+ if (paddingLength > 2) {
137
+ throw new DOMException(
138
+ "The string to be decoded is not correctly encoded.",
139
+ "InvalidCharacterError"
140
+ );
141
+ }
142
+ }
143
+
144
+ // Length without padding must be valid (can't have remainder of 1)
145
+ const strWithoutPadding = str.replace(/=/g, '');
146
+ if (strWithoutPadding.length % 4 === 1) {
147
+ throw new DOMException(
148
+ "The string to be decoded is not correctly encoded.",
149
+ "InvalidCharacterError"
150
+ );
151
+ }
152
+
153
+ // Pad to multiple of 4 if needed (for inputs without explicit padding)
154
+ while (str.length % 4 !== 0) {
155
+ str += '=';
156
+ }
157
+
158
+ let result = '';
159
+ let i = 0;
160
+
161
+ while (i < str.length) {
162
+ const a = base64Lookup.get(str[i++]) ?? 0;
163
+ const b = base64Lookup.get(str[i++]) ?? 0;
164
+ const c = base64Lookup.get(str[i++]) ?? 0;
165
+ const d = base64Lookup.get(str[i++]) ?? 0;
166
+
167
+ const triplet = (a << 18) | (b << 12) | (c << 6) | d;
168
+
169
+ result += String.fromCharCode((triplet >> 16) & 0xFF);
170
+ if (str[i - 2] !== '=') {
171
+ result += String.fromCharCode((triplet >> 8) & 0xFF);
172
+ }
173
+ if (str[i - 1] !== '=') {
174
+ result += String.fromCharCode(triplet & 0xFF);
175
+ }
176
+ }
177
+
178
+ return result;
179
+ };
180
+ })();
181
+ `;
182
+ async function setupEncoding(context) {
183
+ context.evalSync(encodingCode);
184
+ return {
185
+ dispose() {}
186
+ };
187
+ }
188
+ })
189
+
190
+ //# debugId=46FB9F757DF172F564756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.ts"],
4
+ "sourcesContent": [
5
+ "import type ivm from \"isolated-vm\";\n\nexport interface EncodingHandle {\n dispose(): void;\n}\n\nconst encodingCode = `\n(function() {\n // Define DOMException if not available\n if (typeof DOMException === 'undefined') {\n globalThis.DOMException = class DOMException extends Error {\n constructor(message, name) {\n super(message);\n this.name = name || 'DOMException';\n }\n };\n }\n\n const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n // Build reverse lookup table\n const base64Lookup = new Map();\n for (let i = 0; i < base64Chars.length; i++) {\n base64Lookup.set(base64Chars[i], i);\n }\n\n globalThis.btoa = function btoa(str) {\n if (str === undefined) {\n throw new TypeError(\"1 argument required, but only 0 present.\");\n }\n\n str = String(str);\n\n // Check for characters outside Latin-1 range\n for (let i = 0; i < str.length; i++) {\n if (str.charCodeAt(i) > 255) {\n throw new DOMException(\n \"The string to be encoded contains characters outside of the Latin1 range.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n if (str.length === 0) {\n return '';\n }\n\n let result = '';\n let i = 0;\n\n while (i < str.length) {\n const a = str.charCodeAt(i++);\n const bExists = i < str.length;\n const b = bExists ? str.charCodeAt(i++) : 0;\n const cExists = i < str.length;\n const c = cExists ? str.charCodeAt(i++) : 0;\n\n const triplet = (a << 16) | (b << 8) | c;\n\n result += base64Chars[(triplet >> 18) & 0x3F];\n result += base64Chars[(triplet >> 12) & 0x3F];\n result += bExists ? base64Chars[(triplet >> 6) & 0x3F] : '=';\n result += cExists ? base64Chars[triplet & 0x3F] : '=';\n }\n\n return result;\n };\n\n globalThis.atob = function atob(str) {\n if (str === undefined) {\n throw new TypeError(\"1 argument required, but only 0 present.\");\n }\n\n str = String(str);\n\n // Remove whitespace\n str = str.replace(/[\\\\t\\\\n\\\\f\\\\r ]/g, '');\n\n // Validate characters and length\n if (str.length === 0) {\n return '';\n }\n\n // Check for invalid characters (before padding normalization)\n for (let i = 0; i < str.length; i++) {\n const c = str[i];\n if (c !== '=' && !base64Lookup.has(c)) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n // Validate padding position (must be at end)\n const paddingIndex = str.indexOf('=');\n if (paddingIndex !== -1) {\n for (let i = paddingIndex; i < str.length; i++) {\n if (str[i] !== '=') {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n const paddingLength = str.length - paddingIndex;\n if (paddingLength > 2) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n // Length without padding must be valid (can't have remainder of 1)\n const strWithoutPadding = str.replace(/=/g, '');\n if (strWithoutPadding.length % 4 === 1) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n\n // Pad to multiple of 4 if needed (for inputs without explicit padding)\n while (str.length % 4 !== 0) {\n str += '=';\n }\n\n let result = '';\n let i = 0;\n\n while (i < str.length) {\n const a = base64Lookup.get(str[i++]) ?? 0;\n const b = base64Lookup.get(str[i++]) ?? 0;\n const c = base64Lookup.get(str[i++]) ?? 0;\n const d = base64Lookup.get(str[i++]) ?? 0;\n\n const triplet = (a << 18) | (b << 12) | (c << 6) | d;\n\n result += String.fromCharCode((triplet >> 16) & 0xFF);\n if (str[i - 2] !== '=') {\n result += String.fromCharCode((triplet >> 8) & 0xFF);\n }\n if (str[i - 1] !== '=') {\n result += String.fromCharCode(triplet & 0xFF);\n }\n }\n\n return result;\n };\n})();\n`;\n\n/**\n * Setup encoding APIs in an isolated-vm context\n *\n * Injects atob and btoa for Base64 encoding/decoding\n *\n * @example\n * const handle = await setupEncoding(context);\n * await context.eval(`\n * const encoded = btoa(\"hello\");\n * const decoded = atob(encoded);\n * `);\n */\nexport async function setupEncoding(\n context: ivm.Context\n): Promise<EncodingHandle> {\n context.evalSync(encodingCode);\n return {\n dispose() {\n // No resources to cleanup for pure JS injection\n },\n };\n}\n"
6
+ ],
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+JrB,eAAsB,aAAa,CACjC,SACyB;AAAA,EACzB,QAAQ,SAAS,YAAY;AAAA,EAC7B,OAAO;AAAA,IACL,OAAO,GAAG;AAAA,EAGZ;AAAA;",
8
+ "debugId": "46FB9F757DF172F564756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@ricsam/isolate-encoding",
3
+ "version": "0.1.2",
4
+ "type": "commonjs"
5
+ }
@@ -0,0 +1,159 @@
1
+ // @bun
2
+ // packages/encoding/src/index.ts
3
+ var encodingCode = `
4
+ (function() {
5
+ // Define DOMException if not available
6
+ if (typeof DOMException === 'undefined') {
7
+ globalThis.DOMException = class DOMException extends Error {
8
+ constructor(message, name) {
9
+ super(message);
10
+ this.name = name || 'DOMException';
11
+ }
12
+ };
13
+ }
14
+
15
+ const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
16
+
17
+ // Build reverse lookup table
18
+ const base64Lookup = new Map();
19
+ for (let i = 0; i < base64Chars.length; i++) {
20
+ base64Lookup.set(base64Chars[i], i);
21
+ }
22
+
23
+ globalThis.btoa = function btoa(str) {
24
+ if (str === undefined) {
25
+ throw new TypeError("1 argument required, but only 0 present.");
26
+ }
27
+
28
+ str = String(str);
29
+
30
+ // Check for characters outside Latin-1 range
31
+ for (let i = 0; i < str.length; i++) {
32
+ if (str.charCodeAt(i) > 255) {
33
+ throw new DOMException(
34
+ "The string to be encoded contains characters outside of the Latin1 range.",
35
+ "InvalidCharacterError"
36
+ );
37
+ }
38
+ }
39
+
40
+ if (str.length === 0) {
41
+ return '';
42
+ }
43
+
44
+ let result = '';
45
+ let i = 0;
46
+
47
+ while (i < str.length) {
48
+ const a = str.charCodeAt(i++);
49
+ const bExists = i < str.length;
50
+ const b = bExists ? str.charCodeAt(i++) : 0;
51
+ const cExists = i < str.length;
52
+ const c = cExists ? str.charCodeAt(i++) : 0;
53
+
54
+ const triplet = (a << 16) | (b << 8) | c;
55
+
56
+ result += base64Chars[(triplet >> 18) & 0x3F];
57
+ result += base64Chars[(triplet >> 12) & 0x3F];
58
+ result += bExists ? base64Chars[(triplet >> 6) & 0x3F] : '=';
59
+ result += cExists ? base64Chars[triplet & 0x3F] : '=';
60
+ }
61
+
62
+ return result;
63
+ };
64
+
65
+ globalThis.atob = function atob(str) {
66
+ if (str === undefined) {
67
+ throw new TypeError("1 argument required, but only 0 present.");
68
+ }
69
+
70
+ str = String(str);
71
+
72
+ // Remove whitespace
73
+ str = str.replace(/[\\t\\n\\f\\r ]/g, '');
74
+
75
+ // Validate characters and length
76
+ if (str.length === 0) {
77
+ return '';
78
+ }
79
+
80
+ // Check for invalid characters (before padding normalization)
81
+ for (let i = 0; i < str.length; i++) {
82
+ const c = str[i];
83
+ if (c !== '=' && !base64Lookup.has(c)) {
84
+ throw new DOMException(
85
+ "The string to be decoded is not correctly encoded.",
86
+ "InvalidCharacterError"
87
+ );
88
+ }
89
+ }
90
+
91
+ // Validate padding position (must be at end)
92
+ const paddingIndex = str.indexOf('=');
93
+ if (paddingIndex !== -1) {
94
+ for (let i = paddingIndex; i < str.length; i++) {
95
+ if (str[i] !== '=') {
96
+ throw new DOMException(
97
+ "The string to be decoded is not correctly encoded.",
98
+ "InvalidCharacterError"
99
+ );
100
+ }
101
+ }
102
+ const paddingLength = str.length - paddingIndex;
103
+ if (paddingLength > 2) {
104
+ throw new DOMException(
105
+ "The string to be decoded is not correctly encoded.",
106
+ "InvalidCharacterError"
107
+ );
108
+ }
109
+ }
110
+
111
+ // Length without padding must be valid (can't have remainder of 1)
112
+ const strWithoutPadding = str.replace(/=/g, '');
113
+ if (strWithoutPadding.length % 4 === 1) {
114
+ throw new DOMException(
115
+ "The string to be decoded is not correctly encoded.",
116
+ "InvalidCharacterError"
117
+ );
118
+ }
119
+
120
+ // Pad to multiple of 4 if needed (for inputs without explicit padding)
121
+ while (str.length % 4 !== 0) {
122
+ str += '=';
123
+ }
124
+
125
+ let result = '';
126
+ let i = 0;
127
+
128
+ while (i < str.length) {
129
+ const a = base64Lookup.get(str[i++]) ?? 0;
130
+ const b = base64Lookup.get(str[i++]) ?? 0;
131
+ const c = base64Lookup.get(str[i++]) ?? 0;
132
+ const d = base64Lookup.get(str[i++]) ?? 0;
133
+
134
+ const triplet = (a << 18) | (b << 12) | (c << 6) | d;
135
+
136
+ result += String.fromCharCode((triplet >> 16) & 0xFF);
137
+ if (str[i - 2] !== '=') {
138
+ result += String.fromCharCode((triplet >> 8) & 0xFF);
139
+ }
140
+ if (str[i - 1] !== '=') {
141
+ result += String.fromCharCode(triplet & 0xFF);
142
+ }
143
+ }
144
+
145
+ return result;
146
+ };
147
+ })();
148
+ `;
149
+ async function setupEncoding(context) {
150
+ context.evalSync(encodingCode);
151
+ return {
152
+ dispose() {}
153
+ };
154
+ }
155
+ export {
156
+ setupEncoding
157
+ };
158
+
159
+ //# debugId=3CBBC64AA7F4E2EC64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/index.ts"],
4
+ "sourcesContent": [
5
+ "import type ivm from \"isolated-vm\";\n\nexport interface EncodingHandle {\n dispose(): void;\n}\n\nconst encodingCode = `\n(function() {\n // Define DOMException if not available\n if (typeof DOMException === 'undefined') {\n globalThis.DOMException = class DOMException extends Error {\n constructor(message, name) {\n super(message);\n this.name = name || 'DOMException';\n }\n };\n }\n\n const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n // Build reverse lookup table\n const base64Lookup = new Map();\n for (let i = 0; i < base64Chars.length; i++) {\n base64Lookup.set(base64Chars[i], i);\n }\n\n globalThis.btoa = function btoa(str) {\n if (str === undefined) {\n throw new TypeError(\"1 argument required, but only 0 present.\");\n }\n\n str = String(str);\n\n // Check for characters outside Latin-1 range\n for (let i = 0; i < str.length; i++) {\n if (str.charCodeAt(i) > 255) {\n throw new DOMException(\n \"The string to be encoded contains characters outside of the Latin1 range.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n if (str.length === 0) {\n return '';\n }\n\n let result = '';\n let i = 0;\n\n while (i < str.length) {\n const a = str.charCodeAt(i++);\n const bExists = i < str.length;\n const b = bExists ? str.charCodeAt(i++) : 0;\n const cExists = i < str.length;\n const c = cExists ? str.charCodeAt(i++) : 0;\n\n const triplet = (a << 16) | (b << 8) | c;\n\n result += base64Chars[(triplet >> 18) & 0x3F];\n result += base64Chars[(triplet >> 12) & 0x3F];\n result += bExists ? base64Chars[(triplet >> 6) & 0x3F] : '=';\n result += cExists ? base64Chars[triplet & 0x3F] : '=';\n }\n\n return result;\n };\n\n globalThis.atob = function atob(str) {\n if (str === undefined) {\n throw new TypeError(\"1 argument required, but only 0 present.\");\n }\n\n str = String(str);\n\n // Remove whitespace\n str = str.replace(/[\\\\t\\\\n\\\\f\\\\r ]/g, '');\n\n // Validate characters and length\n if (str.length === 0) {\n return '';\n }\n\n // Check for invalid characters (before padding normalization)\n for (let i = 0; i < str.length; i++) {\n const c = str[i];\n if (c !== '=' && !base64Lookup.has(c)) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n // Validate padding position (must be at end)\n const paddingIndex = str.indexOf('=');\n if (paddingIndex !== -1) {\n for (let i = paddingIndex; i < str.length; i++) {\n if (str[i] !== '=') {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n const paddingLength = str.length - paddingIndex;\n if (paddingLength > 2) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n // Length without padding must be valid (can't have remainder of 1)\n const strWithoutPadding = str.replace(/=/g, '');\n if (strWithoutPadding.length % 4 === 1) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n\n // Pad to multiple of 4 if needed (for inputs without explicit padding)\n while (str.length % 4 !== 0) {\n str += '=';\n }\n\n let result = '';\n let i = 0;\n\n while (i < str.length) {\n const a = base64Lookup.get(str[i++]) ?? 0;\n const b = base64Lookup.get(str[i++]) ?? 0;\n const c = base64Lookup.get(str[i++]) ?? 0;\n const d = base64Lookup.get(str[i++]) ?? 0;\n\n const triplet = (a << 18) | (b << 12) | (c << 6) | d;\n\n result += String.fromCharCode((triplet >> 16) & 0xFF);\n if (str[i - 2] !== '=') {\n result += String.fromCharCode((triplet >> 8) & 0xFF);\n }\n if (str[i - 1] !== '=') {\n result += String.fromCharCode(triplet & 0xFF);\n }\n }\n\n return result;\n };\n})();\n`;\n\n/**\n * Setup encoding APIs in an isolated-vm context\n *\n * Injects atob and btoa for Base64 encoding/decoding\n *\n * @example\n * const handle = await setupEncoding(context);\n * await context.eval(`\n * const encoded = btoa(\"hello\");\n * const decoded = atob(encoded);\n * `);\n */\nexport async function setupEncoding(\n context: ivm.Context\n): Promise<EncodingHandle> {\n context.evalSync(encodingCode);\n return {\n dispose() {\n // No resources to cleanup for pure JS injection\n },\n };\n}\n"
6
+ ],
7
+ "mappings": ";;AAMA,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+JrB,eAAsB,aAAa,CACjC,SACyB;AAAA,EACzB,QAAQ,SAAS,YAAY;AAAA,EAC7B,OAAO;AAAA,IACL,OAAO,GAAG;AAAA,EAGZ;AAAA;",
8
+ "debugId": "3CBBC64AA7F4E2EC64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "@ricsam/isolate-encoding",
3
+ "version": "0.1.2",
4
+ "type": "module"
5
+ }
@@ -0,0 +1,17 @@
1
+ import type ivm from "isolated-vm";
2
+ export interface EncodingHandle {
3
+ dispose(): void;
4
+ }
5
+ /**
6
+ * Setup encoding APIs in an isolated-vm context
7
+ *
8
+ * Injects atob and btoa for Base64 encoding/decoding
9
+ *
10
+ * @example
11
+ * const handle = await setupEncoding(context);
12
+ * await context.eval(`
13
+ * const encoded = btoa("hello");
14
+ * const decoded = atob(encoded);
15
+ * `);
16
+ */
17
+ export declare function setupEncoding(context: ivm.Context): Promise<EncodingHandle>;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Global Type Definitions for @ricsam/isolate-encoding
3
+ *
4
+ * These types define the globals injected by setupEncoding() into an isolated-vm context.
5
+ * Use these types to typecheck user code that will run inside the V8 isolate.
6
+ */
7
+
8
+ export {};
9
+
10
+ declare global {
11
+ /**
12
+ * Decodes a Base64-encoded string.
13
+ *
14
+ * @param encodedData - The Base64 string to decode
15
+ * @returns The decoded string
16
+ * @throws DOMException if the input is not valid Base64
17
+ *
18
+ * @example
19
+ * atob("SGVsbG8="); // "Hello"
20
+ */
21
+ function atob(encodedData: string): string;
22
+
23
+ /**
24
+ * Encodes a string to Base64.
25
+ *
26
+ * @param stringToEncode - The string to encode (must contain only Latin1 characters)
27
+ * @returns The Base64 encoded string
28
+ * @throws DOMException if the string contains characters outside Latin1 range (0-255)
29
+ *
30
+ * @example
31
+ * btoa("Hello"); // "SGVsbG8="
32
+ */
33
+ function btoa(stringToEncode: string): string;
34
+ }
package/package.json CHANGED
@@ -1,10 +1,58 @@
1
1
  {
2
2
  "name": "@ricsam/isolate-encoding",
3
- "version": "0.0.1",
4
- "description": "OIDC trusted publishing setup package for @ricsam/isolate-encoding",
3
+ "version": "0.1.2",
4
+ "main": "./dist/cjs/index.cjs",
5
+ "types": "./dist/types/index.d.ts",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/types/index.d.ts",
9
+ "require": "./dist/cjs/index.cjs",
10
+ "import": "./dist/mjs/index.mjs"
11
+ },
12
+ "./isolate": {
13
+ "types": "./dist/types/isolate.d.ts"
14
+ }
15
+ },
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "test": "node --test --experimental-strip-types 'src/**/*.test.ts'",
19
+ "typecheck": "tsc --noEmit"
20
+ },
21
+ "dependencies": {
22
+ "@ricsam/isolate-core": "*",
23
+ "isolated-vm": "^6"
24
+ },
25
+ "peerDependencies": {
26
+ "isolated-vm": "^6"
27
+ },
28
+ "author": "Richard Samuelsson",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/ricsam/isolate.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/ricsam/isolate/issues"
36
+ },
37
+ "homepage": "https://github.com/ricsam/isolate#readme",
5
38
  "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
39
+ "isolated-vm",
40
+ "sandbox",
41
+ "javascript",
42
+ "runtime",
43
+ "fetch",
44
+ "filesystem",
45
+ "streams",
46
+ "v8",
47
+ "isolate"
48
+ ],
49
+ "description": "Base64 encoding APIs (atob, btoa) for isolated-vm V8 sandbox",
50
+ "module": "./dist/mjs/index.mjs",
51
+ "publishConfig": {
52
+ "access": "public"
53
+ },
54
+ "files": [
55
+ "dist",
56
+ "README.md"
9
57
  ]
10
- }
58
+ }