claude-artifact-framework 0.1.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/LICENSE +21 -0
- package/dist/index.esm.js +53 -0
- package/dist/index.esm.js.map +7 -0
- package/dist/index.global.js +2 -0
- package/dist/index.global.js.map +7 -0
- package/package.json +32 -0
- package/src/index.js +5 -0
- package/src/storage.js +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alejandro Cuartas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// src/storage.js
|
|
2
|
+
function available() {
|
|
3
|
+
return typeof window !== "undefined" && typeof window.storage === "object" && window.storage !== null;
|
|
4
|
+
}
|
|
5
|
+
function scope(shared) {
|
|
6
|
+
return {
|
|
7
|
+
async get(key, fallback = void 0) {
|
|
8
|
+
if (!available()) return fallback;
|
|
9
|
+
try {
|
|
10
|
+
const res = await window.storage.get(key, shared);
|
|
11
|
+
if (res?.value === void 0 || res?.value === null) return fallback;
|
|
12
|
+
try {
|
|
13
|
+
return JSON.parse(res.value);
|
|
14
|
+
} catch {
|
|
15
|
+
return res.value;
|
|
16
|
+
}
|
|
17
|
+
} catch {
|
|
18
|
+
return fallback;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
async set(key, value, { raw = false } = {}) {
|
|
22
|
+
if (!available()) {
|
|
23
|
+
throw new Error("window.storage is not available (is this a Code Artifact rather than a published Chat Artifact?)");
|
|
24
|
+
}
|
|
25
|
+
const payload = raw ? value : JSON.stringify(value);
|
|
26
|
+
if (typeof payload !== "string") {
|
|
27
|
+
throw new Error("window.storage only accepts strings \u2014 the value must be JSON-serializable");
|
|
28
|
+
}
|
|
29
|
+
return window.storage.set(key, payload, shared);
|
|
30
|
+
},
|
|
31
|
+
async delete(key) {
|
|
32
|
+
if (!available()) return;
|
|
33
|
+
try {
|
|
34
|
+
await window.storage.delete(key, shared);
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
async list(prefix) {
|
|
39
|
+
if (!available()) return [];
|
|
40
|
+
try {
|
|
41
|
+
const res = await window.storage.list(prefix, shared);
|
|
42
|
+
return res?.keys || [];
|
|
43
|
+
} catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
var storage = { ...scope(false), shared: scope(true), available };
|
|
50
|
+
export {
|
|
51
|
+
storage
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/storage.js"],
|
|
4
|
+
"sourcesContent": ["// storage.js \u2014 wrapper over window.storage (Chat Artifacts, published only).\n//\n// Verified empirically against the real runtime: get/set/delete/list all\n// take (key, shared = false) and return a Promise resolving to\n// { key, value, shared, \"@type\": \"...StorageXResponse\" }. Confirmed:\n// - values must be strings (a raw object throws \"Invalid payload content\")\n// - shared=true/false is a real, working scope switch\n// - failures (including \"key not found\") all throw the same generic\n// message with no distinguishing `code` \u2014 there is no reliable way to\n// tell \"empty\" from \"backend error\" from the error alone.\n\nfunction available() {\n return typeof window !== \"undefined\" && typeof window.storage === \"object\" && window.storage !== null;\n}\n\nfunction scope(shared) {\n return {\n async get(key, fallback = undefined) {\n if (!available()) return fallback;\n try {\n const res = await window.storage.get(key, shared);\n if (res?.value === undefined || res?.value === null) return fallback;\n try {\n return JSON.parse(res.value);\n } catch {\n return res.value; // not JSON \u2014 a plain string written via set(key, value, { raw: true })\n }\n } catch {\n // See file header: this same catch fires for \"key does not exist\"\n // and for a real backend failure. Treating both as \"no value\" is\n // the safer default for a read path, at the cost of hiding outages.\n return fallback;\n }\n },\n\n async set(key, value, { raw = false } = {}) {\n if (!available()) {\n throw new Error(\"window.storage is not available (is this a Code Artifact rather than a published Chat Artifact?)\");\n }\n const payload = raw ? value : JSON.stringify(value);\n if (typeof payload !== \"string\") {\n throw new Error(\"window.storage only accepts strings \u2014 the value must be JSON-serializable\");\n }\n return window.storage.set(key, payload, shared);\n },\n\n async delete(key) {\n if (!available()) return;\n try {\n await window.storage.delete(key, shared);\n } catch {\n // same ambiguity as get() \u2014 silently a no-op if the key never existed\n }\n },\n\n async list(prefix) {\n if (!available()) return [];\n try {\n const res = await window.storage.list(prefix, shared);\n return res?.keys || [];\n } catch {\n return [];\n }\n },\n };\n}\n\n// storage.get/set/delete/list operate on the per-viewer (personal) scope.\n// storage.shared.* are the same four methods against the shared scope, where\n// every viewer of the artifact reads and writes the same state.\nexport const storage = { ...scope(false), shared: scope(true), available };\n"],
|
|
5
|
+
"mappings": ";AAWA,SAAS,YAAY;AACnB,SAAO,OAAO,WAAW,eAAe,OAAO,OAAO,YAAY,YAAY,OAAO,YAAY;AACnG;AAEA,SAAS,MAAM,QAAQ;AACrB,SAAO;AAAA,IACL,MAAM,IAAI,KAAK,WAAW,QAAW;AACnC,UAAI,CAAC,UAAU,EAAG,QAAO;AACzB,UAAI;AACF,cAAM,MAAM,MAAM,OAAO,QAAQ,IAAI,KAAK,MAAM;AAChD,YAAI,KAAK,UAAU,UAAa,KAAK,UAAU,KAAM,QAAO;AAC5D,YAAI;AACF,iBAAO,KAAK,MAAM,IAAI,KAAK;AAAA,QAC7B,QAAQ;AACN,iBAAO,IAAI;AAAA,QACb;AAAA,MACF,QAAQ;AAIN,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,MAAM,IAAI,KAAK,OAAO,EAAE,MAAM,MAAM,IAAI,CAAC,GAAG;AAC1C,UAAI,CAAC,UAAU,GAAG;AAChB,cAAM,IAAI,MAAM,kGAAkG;AAAA,MACpH;AACA,YAAM,UAAU,MAAM,QAAQ,KAAK,UAAU,KAAK;AAClD,UAAI,OAAO,YAAY,UAAU;AAC/B,cAAM,IAAI,MAAM,gFAA2E;AAAA,MAC7F;AACA,aAAO,OAAO,QAAQ,IAAI,KAAK,SAAS,MAAM;AAAA,IAChD;AAAA,IAEA,MAAM,OAAO,KAAK;AAChB,UAAI,CAAC,UAAU,EAAG;AAClB,UAAI;AACF,cAAM,OAAO,QAAQ,OAAO,KAAK,MAAM;AAAA,MACzC,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,IAEA,MAAM,KAAK,QAAQ;AACjB,UAAI,CAAC,UAAU,EAAG,QAAO,CAAC;AAC1B,UAAI;AACF,cAAM,MAAM,MAAM,OAAO,QAAQ,KAAK,QAAQ,MAAM;AACpD,eAAO,KAAK,QAAQ,CAAC;AAAA,MACvB,QAAQ;AACN,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,UAAU,EAAE,GAAG,MAAM,KAAK,GAAG,QAAQ,MAAM,IAAI,GAAG,UAAU;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var ArtifactKit=(()=>{var i=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var l=Object.prototype.hasOwnProperty;var d=(e,t)=>{for(var r in t)i(e,r,{get:t[r],enumerable:!0})},f=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of c(t))!l.call(e,a)&&a!==r&&i(e,a,{get:()=>t[a],enumerable:!(n=w(t,a))||n.enumerable});return e};var g=e=>f(i({},"__esModule",{value:!0}),e);var y={};d(y,{storage:()=>u});function o(){return typeof window<"u"&&typeof window.storage=="object"&&window.storage!==null}function s(e){return{async get(t,r=void 0){if(!o())return r;try{let n=await window.storage.get(t,e);if(n?.value===void 0||n?.value===null)return r;try{return JSON.parse(n.value)}catch{return n.value}}catch{return r}},async set(t,r,{raw:n=!1}={}){if(!o())throw new Error("window.storage is not available (is this a Code Artifact rather than a published Chat Artifact?)");let a=n?r:JSON.stringify(r);if(typeof a!="string")throw new Error("window.storage only accepts strings \u2014 the value must be JSON-serializable");return window.storage.set(t,a,e)},async delete(t){if(o())try{await window.storage.delete(t,e)}catch{}},async list(t){if(!o())return[];try{return(await window.storage.list(t,e))?.keys||[]}catch{return[]}}}}var u={...s(!1),shared:s(!0),available:o};return g(y);})();
|
|
2
|
+
//# sourceMappingURL=index.global.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.js", "../src/storage.js"],
|
|
4
|
+
"sourcesContent": ["// Barrel file \u2014 every module lives in its own src/<name>.js and gets one\n// export line here. Nothing else needs to change to add a module: no build\n// config, no separate entry points, both dist bundles pick it up automatically.\n\nexport { storage } from \"./storage.js\";\n", "// storage.js \u2014 wrapper over window.storage (Chat Artifacts, published only).\n//\n// Verified empirically against the real runtime: get/set/delete/list all\n// take (key, shared = false) and return a Promise resolving to\n// { key, value, shared, \"@type\": \"...StorageXResponse\" }. Confirmed:\n// - values must be strings (a raw object throws \"Invalid payload content\")\n// - shared=true/false is a real, working scope switch\n// - failures (including \"key not found\") all throw the same generic\n// message with no distinguishing `code` \u2014 there is no reliable way to\n// tell \"empty\" from \"backend error\" from the error alone.\n\nfunction available() {\n return typeof window !== \"undefined\" && typeof window.storage === \"object\" && window.storage !== null;\n}\n\nfunction scope(shared) {\n return {\n async get(key, fallback = undefined) {\n if (!available()) return fallback;\n try {\n const res = await window.storage.get(key, shared);\n if (res?.value === undefined || res?.value === null) return fallback;\n try {\n return JSON.parse(res.value);\n } catch {\n return res.value; // not JSON \u2014 a plain string written via set(key, value, { raw: true })\n }\n } catch {\n // See file header: this same catch fires for \"key does not exist\"\n // and for a real backend failure. Treating both as \"no value\" is\n // the safer default for a read path, at the cost of hiding outages.\n return fallback;\n }\n },\n\n async set(key, value, { raw = false } = {}) {\n if (!available()) {\n throw new Error(\"window.storage is not available (is this a Code Artifact rather than a published Chat Artifact?)\");\n }\n const payload = raw ? value : JSON.stringify(value);\n if (typeof payload !== \"string\") {\n throw new Error(\"window.storage only accepts strings \u2014 the value must be JSON-serializable\");\n }\n return window.storage.set(key, payload, shared);\n },\n\n async delete(key) {\n if (!available()) return;\n try {\n await window.storage.delete(key, shared);\n } catch {\n // same ambiguity as get() \u2014 silently a no-op if the key never existed\n }\n },\n\n async list(prefix) {\n if (!available()) return [];\n try {\n const res = await window.storage.list(prefix, shared);\n return res?.keys || [];\n } catch {\n return [];\n }\n },\n };\n}\n\n// storage.get/set/delete/list operate on the per-viewer (personal) scope.\n// storage.shared.* are the same four methods against the shared scope, where\n// every viewer of the artifact reads and writes the same state.\nexport const storage = { ...scope(false), shared: scope(true), available };\n"],
|
|
5
|
+
"mappings": "kbAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,ICWA,SAASC,GAAY,CACnB,OAAO,OAAO,OAAW,KAAe,OAAO,OAAO,SAAY,UAAY,OAAO,UAAY,IACnG,CAEA,SAASC,EAAMC,EAAQ,CACrB,MAAO,CACL,MAAM,IAAIC,EAAKC,EAAW,OAAW,CACnC,GAAI,CAACJ,EAAU,EAAG,OAAOI,EACzB,GAAI,CACF,IAAMC,EAAM,MAAM,OAAO,QAAQ,IAAIF,EAAKD,CAAM,EAChD,GAAIG,GAAK,QAAU,QAAaA,GAAK,QAAU,KAAM,OAAOD,EAC5D,GAAI,CACF,OAAO,KAAK,MAAMC,EAAI,KAAK,CAC7B,MAAQ,CACN,OAAOA,EAAI,KACb,CACF,MAAQ,CAIN,OAAOD,CACT,CACF,EAEA,MAAM,IAAID,EAAKG,EAAO,CAAE,IAAAC,EAAM,EAAM,EAAI,CAAC,EAAG,CAC1C,GAAI,CAACP,EAAU,EACb,MAAM,IAAI,MAAM,kGAAkG,EAEpH,IAAMQ,EAAUD,EAAMD,EAAQ,KAAK,UAAUA,CAAK,EAClD,GAAI,OAAOE,GAAY,SACrB,MAAM,IAAI,MAAM,gFAA2E,EAE7F,OAAO,OAAO,QAAQ,IAAIL,EAAKK,EAASN,CAAM,CAChD,EAEA,MAAM,OAAOC,EAAK,CAChB,GAAKH,EAAU,EACf,GAAI,CACF,MAAM,OAAO,QAAQ,OAAOG,EAAKD,CAAM,CACzC,MAAQ,CAER,CACF,EAEA,MAAM,KAAKO,EAAQ,CACjB,GAAI,CAACT,EAAU,EAAG,MAAO,CAAC,EAC1B,GAAI,CAEF,OADY,MAAM,OAAO,QAAQ,KAAKS,EAAQP,CAAM,IACxC,MAAQ,CAAC,CACvB,MAAQ,CACN,MAAO,CAAC,CACV,CACF,CACF,CACF,CAKO,IAAMQ,EAAU,CAAE,GAAGT,EAAM,EAAK,EAAG,OAAQA,EAAM,EAAI,EAAG,UAAAD,CAAU",
|
|
6
|
+
"names": ["index_exports", "__export", "storage", "available", "scope", "shared", "key", "fallback", "res", "value", "raw", "payload", "prefix", "storage"]
|
|
7
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-artifact-framework",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Utilities for building apps inside Claude Artifacts: platform storage, chat tool-calling loops, and other primitives verified against the real runtime.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.esm.js",
|
|
7
|
+
"module": "./dist/index.esm.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.esm.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "node scripts/build.mjs",
|
|
19
|
+
"build:watch": "node scripts/build.mjs --watch",
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"release": "bash scripts/publish.sh"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"esbuild": "^0.25.0"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"author": "Alejandro Cuartas",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/alejoair/claude-artifact-framework.git"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Barrel file — every module lives in its own src/<name>.js and gets one
|
|
2
|
+
// export line here. Nothing else needs to change to add a module: no build
|
|
3
|
+
// config, no separate entry points, both dist bundles pick it up automatically.
|
|
4
|
+
|
|
5
|
+
export { storage } from "./storage.js";
|
package/src/storage.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// storage.js — wrapper over window.storage (Chat Artifacts, published only).
|
|
2
|
+
//
|
|
3
|
+
// Verified empirically against the real runtime: get/set/delete/list all
|
|
4
|
+
// take (key, shared = false) and return a Promise resolving to
|
|
5
|
+
// { key, value, shared, "@type": "...StorageXResponse" }. Confirmed:
|
|
6
|
+
// - values must be strings (a raw object throws "Invalid payload content")
|
|
7
|
+
// - shared=true/false is a real, working scope switch
|
|
8
|
+
// - failures (including "key not found") all throw the same generic
|
|
9
|
+
// message with no distinguishing `code` — there is no reliable way to
|
|
10
|
+
// tell "empty" from "backend error" from the error alone.
|
|
11
|
+
|
|
12
|
+
function available() {
|
|
13
|
+
return typeof window !== "undefined" && typeof window.storage === "object" && window.storage !== null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function scope(shared) {
|
|
17
|
+
return {
|
|
18
|
+
async get(key, fallback = undefined) {
|
|
19
|
+
if (!available()) return fallback;
|
|
20
|
+
try {
|
|
21
|
+
const res = await window.storage.get(key, shared);
|
|
22
|
+
if (res?.value === undefined || res?.value === null) return fallback;
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(res.value);
|
|
25
|
+
} catch {
|
|
26
|
+
return res.value; // not JSON — a plain string written via set(key, value, { raw: true })
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
// See file header: this same catch fires for "key does not exist"
|
|
30
|
+
// and for a real backend failure. Treating both as "no value" is
|
|
31
|
+
// the safer default for a read path, at the cost of hiding outages.
|
|
32
|
+
return fallback;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
async set(key, value, { raw = false } = {}) {
|
|
37
|
+
if (!available()) {
|
|
38
|
+
throw new Error("window.storage is not available (is this a Code Artifact rather than a published Chat Artifact?)");
|
|
39
|
+
}
|
|
40
|
+
const payload = raw ? value : JSON.stringify(value);
|
|
41
|
+
if (typeof payload !== "string") {
|
|
42
|
+
throw new Error("window.storage only accepts strings — the value must be JSON-serializable");
|
|
43
|
+
}
|
|
44
|
+
return window.storage.set(key, payload, shared);
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
async delete(key) {
|
|
48
|
+
if (!available()) return;
|
|
49
|
+
try {
|
|
50
|
+
await window.storage.delete(key, shared);
|
|
51
|
+
} catch {
|
|
52
|
+
// same ambiguity as get() — silently a no-op if the key never existed
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
async list(prefix) {
|
|
57
|
+
if (!available()) return [];
|
|
58
|
+
try {
|
|
59
|
+
const res = await window.storage.list(prefix, shared);
|
|
60
|
+
return res?.keys || [];
|
|
61
|
+
} catch {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// storage.get/set/delete/list operate on the per-viewer (personal) scope.
|
|
69
|
+
// storage.shared.* are the same four methods against the shared scope, where
|
|
70
|
+
// every viewer of the artifact reads and writes the same state.
|
|
71
|
+
export const storage = { ...scope(false), shared: scope(true), available };
|