@amirhosseinnateghi/vibed-mcp 0.1.2 → 0.1.3
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/index.js +342 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5986,6 +5986,18 @@ import { dirname, extname, isAbsolute, join, resolve } from "node:path";
|
|
|
5986
5986
|
// ../sandbox/src/index.ts
|
|
5987
5987
|
var import_node_html_parser = __toESM(require_dist(), 1);
|
|
5988
5988
|
|
|
5989
|
+
// ../shared/src/terms.ts
|
|
5990
|
+
var ITEM = {
|
|
5991
|
+
/** lowercase singular — "vibe" */
|
|
5992
|
+
one: "vibe",
|
|
5993
|
+
/** lowercase plural — "vibes" */
|
|
5994
|
+
many: "vibes",
|
|
5995
|
+
/** Capitalized singular — "Vibe" */
|
|
5996
|
+
One: "Vibe",
|
|
5997
|
+
/** Capitalized plural — "Vibes" */
|
|
5998
|
+
Many: "Vibes"
|
|
5999
|
+
};
|
|
6000
|
+
|
|
5989
6001
|
// ../shared/src/constants.ts
|
|
5990
6002
|
var CATEGORIES = [
|
|
5991
6003
|
"Game",
|
|
@@ -5998,10 +6010,13 @@ var CATEGORIES = [
|
|
|
5998
6010
|
"Other"
|
|
5999
6011
|
];
|
|
6000
6012
|
var VISIBILITY = ["public", "unlisted"];
|
|
6013
|
+
var COVER_MODES = ["image", "gif"];
|
|
6001
6014
|
var EXPERIENCE_SOURCE = ["builder", "import", "remix"];
|
|
6015
|
+
var PUSH_PROVIDERS = ["webpush", "fcm", "apns"];
|
|
6016
|
+
var DEVICE_PLATFORMS = ["web", "ios", "android"];
|
|
6002
6017
|
var config = {
|
|
6003
|
-
ARTIFACT_MAX_BYTES: intEnv("ARTIFACT_MAX_BYTES",
|
|
6004
|
-
//
|
|
6018
|
+
ARTIFACT_MAX_BYTES: intEnv("ARTIFACT_MAX_BYTES", 8388608),
|
|
6019
|
+
// 8 MB — headroom for an embedded audio track
|
|
6005
6020
|
ARTIFACT_ALLOWED_ORIGINS: strEnv(
|
|
6006
6021
|
"ARTIFACT_ALLOWED_ORIGINS",
|
|
6007
6022
|
"fonts.googleapis.com,fonts.gstatic.com,cdnjs.cloudflare.com,cdn.jsdelivr.net,unpkg.com"
|
|
@@ -6024,6 +6039,19 @@ var config = {
|
|
|
6024
6039
|
BUILDER_CLASSIFIER_MODEL: strEnv("BUILDER_CLASSIFIER_MODEL", "gemini-2.5-flash"),
|
|
6025
6040
|
BUILDER_MAX_TOKENS: intEnv("BUILDER_MAX_TOKENS", 8192),
|
|
6026
6041
|
BUILDER_MAX_MESSAGES: intEnv("BUILDER_MAX_MESSAGES", 30),
|
|
6042
|
+
// Hard cap for a single build turn (across the model + one repair). The build
|
|
6043
|
+
// runs detached from the request, so this — not the browser — is what stops a
|
|
6044
|
+
// runaway/abandoned turn. The provider's own 90s per-stall timeout still applies.
|
|
6045
|
+
// Never cut a LIVE generation — these two guards only catch dead work:
|
|
6046
|
+
// stall = total silence (not even a keep-alive byte) long enough to mean the
|
|
6047
|
+
// connection is dead (TCP half-open never errors on its own); the turn cap is
|
|
6048
|
+
// a platform-cost safety ceiling for the whole turn incl. one repair pass.
|
|
6049
|
+
BUILDER_STALL_TIMEOUT_MS: intEnv("BUILDER_STALL_TIMEOUT_MS", 3e5),
|
|
6050
|
+
BUILDER_TURN_TIMEOUT_MS: intEnv("BUILDER_TURN_TIMEOUT_MS", 9e5),
|
|
6051
|
+
// Once a build has run this long, the UI nudges the user to go explore, and on
|
|
6052
|
+
// completion the server drops a notification (§7.1) — so a slow build never
|
|
6053
|
+
// traps them staring at a spinner.
|
|
6054
|
+
BUILDER_SLOW_MS: intEnv("BUILDER_SLOW_MS", 12e3),
|
|
6027
6055
|
DEFAULT_LOCALE: strEnv("DEFAULT_LOCALE", "en")
|
|
6028
6056
|
};
|
|
6029
6057
|
function strEnv(key, fallback) {
|
|
@@ -6046,6 +6074,31 @@ function boolEnv(key, fallback) {
|
|
|
6046
6074
|
return v === "true" || v === "1";
|
|
6047
6075
|
}
|
|
6048
6076
|
|
|
6077
|
+
// ../shared/src/notifications.ts
|
|
6078
|
+
var NOTIF_VERB = {
|
|
6079
|
+
like_milestone: `liked your ${ITEM.one}`,
|
|
6080
|
+
comment: `commented on your ${ITEM.one}`,
|
|
6081
|
+
reply: "replied to your comment",
|
|
6082
|
+
follow: "started following you",
|
|
6083
|
+
mention: "mentioned you",
|
|
6084
|
+
remix: `remixed your ${ITEM.one}`
|
|
6085
|
+
};
|
|
6086
|
+
var SYSTEM_NOTIF = {
|
|
6087
|
+
build_ready: { icon: "\u2728", text: "Your build is ready \u2014 tap to see it", tone: "info" },
|
|
6088
|
+
build_failed: { icon: "\u26A0\uFE0F", text: "A build didn't finish \u2014 tap to try again", tone: "error" },
|
|
6089
|
+
// Moderation reject (spec §9): the vibe never went live (or was pulled), so
|
|
6090
|
+
// the inbox row must carry everything — title + reason arrive in the payload.
|
|
6091
|
+
post_rejected: { icon: "\u{1F6AB}", text: `Your ${ITEM.one} didn't pass moderation`, tone: "error" }
|
|
6092
|
+
};
|
|
6093
|
+
var NOTIF_PREF_GROUPS = ["follow", "comments", "likes", "remixes", "builder"];
|
|
6094
|
+
var NOTIF_GROUP_LABEL = {
|
|
6095
|
+
follow: { title: "New followers", hint: "when someone follows you" },
|
|
6096
|
+
comments: { title: "Comments", hint: "comments, replies & mentions" },
|
|
6097
|
+
likes: { title: "Likes", hint: `when your ${ITEM.many} hit like milestones` },
|
|
6098
|
+
remixes: { title: "Remixes", hint: `when someone remixes your ${ITEM.one}` },
|
|
6099
|
+
builder: { title: "Builder", hint: "when a build finishes or fails" }
|
|
6100
|
+
};
|
|
6101
|
+
|
|
6049
6102
|
// ../shared/src/policy.ts
|
|
6050
6103
|
function boolEnv2(key, fallback) {
|
|
6051
6104
|
const v = typeof process !== "undefined" ? process.env[key] : void 0;
|
|
@@ -10118,10 +10171,102 @@ var coerce = {
|
|
|
10118
10171
|
};
|
|
10119
10172
|
var NEVER = INVALID;
|
|
10120
10173
|
|
|
10174
|
+
// ../shared/src/storage.ts
|
|
10175
|
+
var STORAGE = {
|
|
10176
|
+
/** Total shared bytes per post (values, serialized). */
|
|
10177
|
+
SHARED_MAX_BYTES: intEnv("STORE_SHARED_MAX_BYTES", 1048576),
|
|
10178
|
+
// 1 MB
|
|
10179
|
+
/** Total shared records (rows) per post. */
|
|
10180
|
+
SHARED_MAX_RECORDS: intEnv("STORE_SHARED_MAX_RECORDS", 5e3),
|
|
10181
|
+
/** Serialized size cap for a single value. */
|
|
10182
|
+
VALUE_MAX_BYTES: intEnv("STORE_VALUE_MAX_BYTES", 16384),
|
|
10183
|
+
// 16 KB
|
|
10184
|
+
/** Records a single author may hold in one post (anti-flood / anti-grief). */
|
|
10185
|
+
AUTHOR_MAX_RECORDS: intEnv("STORE_AUTHOR_MAX_RECORDS", 100),
|
|
10186
|
+
/** Distinct collections per post. */
|
|
10187
|
+
MAX_COLLECTIONS: intEnv("STORE_MAX_COLLECTIONS", 32),
|
|
10188
|
+
/** Local-tier budget per (post, identity) — enforced by the host broker. */
|
|
10189
|
+
LOCAL_MAX_BYTES: intEnv("STORE_LOCAL_MAX_BYTES", 262144),
|
|
10190
|
+
// 256 KB
|
|
10191
|
+
/** Max records returnable in one query page. */
|
|
10192
|
+
QUERY_MAX_LIMIT: intEnv("STORE_QUERY_MAX_LIMIT", 100),
|
|
10193
|
+
/** Whether anonymous (logged-out) shared writes may be enabled per post. */
|
|
10194
|
+
ANON_WRITES_AVAILABLE: boolEnv("STORE_ANON_WRITES_AVAILABLE", false)
|
|
10195
|
+
};
|
|
10196
|
+
var COLLECTION_RE = /^[a-z0-9][a-z0-9:_-]{0,63}$/;
|
|
10197
|
+
var collectionSchemaStore = external_exports.string().regex(COLLECTION_RE, "invalid collection name");
|
|
10198
|
+
var STORE_KEY_RE = /^[a-zA-Z0-9][a-zA-Z0-9:._-]{0,127}$/;
|
|
10199
|
+
var RESERVED_STORE_KEYS = ["submit", "rank", "increment"];
|
|
10200
|
+
var storeKeySchema = external_exports.string().regex(STORE_KEY_RE, "invalid key").refine((k) => !RESERVED_STORE_KEYS.includes(k), {
|
|
10201
|
+
message: "reserved key"
|
|
10202
|
+
});
|
|
10203
|
+
var STORE_WRITE_POLICIES = ["anyone", "logged_in", "owner_only"];
|
|
10204
|
+
var STORE_SORTS = ["num", "-num", "created", "-created"];
|
|
10205
|
+
var storeValueSchema = external_exports.unknown().refine(
|
|
10206
|
+
(v) => {
|
|
10207
|
+
try {
|
|
10208
|
+
const s = JSON.stringify(v);
|
|
10209
|
+
return s !== void 0 && byteLength(s) <= STORAGE.VALUE_MAX_BYTES;
|
|
10210
|
+
} catch {
|
|
10211
|
+
return false;
|
|
10212
|
+
}
|
|
10213
|
+
},
|
|
10214
|
+
{ message: `value must be JSON-serializable and <= ${STORAGE.VALUE_MAX_BYTES} bytes` }
|
|
10215
|
+
);
|
|
10216
|
+
var storePutSchema = external_exports.object({
|
|
10217
|
+
value: storeValueSchema,
|
|
10218
|
+
/** Optimistic concurrency: fail with `conflict` unless current version matches. */
|
|
10219
|
+
ifVersion: external_exports.number().int().positive().optional()
|
|
10220
|
+
});
|
|
10221
|
+
var storeAppendSchema = external_exports.object({
|
|
10222
|
+
value: storeValueSchema,
|
|
10223
|
+
/** Optional numeric field to index (sorting/leaderboards). */
|
|
10224
|
+
num: external_exports.number().finite().optional()
|
|
10225
|
+
});
|
|
10226
|
+
var storeIncrementSchema = external_exports.object({
|
|
10227
|
+
delta: external_exports.number().int().min(-1e6).max(1e6).default(1)
|
|
10228
|
+
});
|
|
10229
|
+
var storeSubmitSchema = external_exports.object({
|
|
10230
|
+
/** The number that ranks this author (mapped into `num`). */
|
|
10231
|
+
score: external_exports.number().finite(),
|
|
10232
|
+
/** Conflict rule when the author already has a row. */
|
|
10233
|
+
keep: external_exports.enum(["max", "min", "last"]).default("max"),
|
|
10234
|
+
/** Small display payload stored alongside (same value-size gate). */
|
|
10235
|
+
meta: storeValueSchema.optional()
|
|
10236
|
+
});
|
|
10237
|
+
var storeQuerySchema = external_exports.object({
|
|
10238
|
+
sort: external_exports.enum(STORE_SORTS).default("-created"),
|
|
10239
|
+
limit: external_exports.coerce.number().int().min(1).max(STORAGE.QUERY_MAX_LIMIT).default(30),
|
|
10240
|
+
cursor: external_exports.string().max(200).optional(),
|
|
10241
|
+
/** Only the caller's records. */
|
|
10242
|
+
mine: external_exports.coerce.boolean().default(false)
|
|
10243
|
+
});
|
|
10244
|
+
var storeAdminSchema = external_exports.discriminatedUnion("action", [
|
|
10245
|
+
external_exports.object({ action: external_exports.literal("freeze") }),
|
|
10246
|
+
external_exports.object({ action: external_exports.literal("unfreeze") }),
|
|
10247
|
+
external_exports.object({ action: external_exports.literal("set_policy"), writePolicy: external_exports.enum(STORE_WRITE_POLICIES) }),
|
|
10248
|
+
external_exports.object({ action: external_exports.literal("set_anon_writes"), anonWrites: external_exports.boolean() }),
|
|
10249
|
+
external_exports.object({ action: external_exports.literal("reset"), collection: collectionSchemaStore.optional() })
|
|
10250
|
+
]);
|
|
10251
|
+
var storageOptInSchema = external_exports.object({
|
|
10252
|
+
local: external_exports.boolean().default(false),
|
|
10253
|
+
shared: external_exports.boolean().default(false)
|
|
10254
|
+
});
|
|
10255
|
+
function byteLength(s) {
|
|
10256
|
+
if (typeof TextEncoder !== "undefined") return new TextEncoder().encode(s).length;
|
|
10257
|
+
let n = 0;
|
|
10258
|
+
for (let i = 0; i < s.length; i++) {
|
|
10259
|
+
const c = s.codePointAt(i);
|
|
10260
|
+
n += c <= 127 ? 1 : c <= 2047 ? 2 : c <= 65535 ? 3 : (i++, 4);
|
|
10261
|
+
}
|
|
10262
|
+
return n;
|
|
10263
|
+
}
|
|
10264
|
+
|
|
10121
10265
|
// ../shared/src/schemas.ts
|
|
10122
10266
|
var handleSchema = external_exports.string().regex(/^[a-z0-9_.]{3,24}$/, "3\u201324 chars: a\u2013z, 0\u20139, _ or .");
|
|
10123
10267
|
var categorySchema = external_exports.enum(CATEGORIES);
|
|
10124
10268
|
var visibilitySchema = external_exports.enum(VISIBILITY);
|
|
10269
|
+
var coverModeSchema = external_exports.enum(COVER_MODES);
|
|
10125
10270
|
var sourceSchema = external_exports.enum(EXPERIENCE_SOURCE);
|
|
10126
10271
|
var tagsSchema = external_exports.array(external_exports.string().min(1).max(40)).max(10).transform(
|
|
10127
10272
|
(tags) => Array.from(
|
|
@@ -10135,8 +10280,12 @@ var publishSchema = external_exports.object({
|
|
|
10135
10280
|
tags: tagsSchema,
|
|
10136
10281
|
remixable: external_exports.boolean().default(true),
|
|
10137
10282
|
visibility: visibilitySchema.default("public"),
|
|
10283
|
+
coverMode: coverModeSchema.default("gif"),
|
|
10138
10284
|
draftArtifactKey: external_exports.string().min(1),
|
|
10139
|
-
buildSessionId: external_exports.string().uuid().optional()
|
|
10285
|
+
buildSessionId: external_exports.string().uuid().optional(),
|
|
10286
|
+
/** Storage opt-in override; when omitted, publish auto-detects from the source
|
|
10287
|
+
* (docs/post-storage.md §9 — default off, enabled only when actually used). */
|
|
10288
|
+
storage: storageOptInSchema.optional()
|
|
10140
10289
|
});
|
|
10141
10290
|
var patchExperienceSchema = external_exports.object({
|
|
10142
10291
|
title: external_exports.string().min(1).max(120).optional(),
|
|
@@ -10144,7 +10293,8 @@ var patchExperienceSchema = external_exports.object({
|
|
|
10144
10293
|
tags: tagsSchema.optional(),
|
|
10145
10294
|
category: categorySchema.optional(),
|
|
10146
10295
|
remixable: external_exports.boolean().optional(),
|
|
10147
|
-
visibility: visibilitySchema.optional()
|
|
10296
|
+
visibility: visibilitySchema.optional(),
|
|
10297
|
+
coverMode: coverModeSchema.optional()
|
|
10148
10298
|
});
|
|
10149
10299
|
var commentSchema = external_exports.object({
|
|
10150
10300
|
body: external_exports.string().min(1).max(500),
|
|
@@ -10159,10 +10309,10 @@ var createBuildSchema = external_exports.object({
|
|
|
10159
10309
|
remixParentId: external_exports.string().uuid().optional()
|
|
10160
10310
|
});
|
|
10161
10311
|
var builderAttachmentSchema = external_exports.object({
|
|
10162
|
-
kind: external_exports.enum(["image", "file"]),
|
|
10312
|
+
kind: external_exports.enum(["image", "file", "audio"]),
|
|
10163
10313
|
name: external_exports.string().max(200),
|
|
10164
|
-
|
|
10165
|
-
|
|
10314
|
+
// base64 data URL for image/audio (~8.7MB raw fits, covering a short song).
|
|
10315
|
+
dataUrl: external_exports.string().max(12e6).optional(),
|
|
10166
10316
|
text: external_exports.string().max(5e4).optional()
|
|
10167
10317
|
});
|
|
10168
10318
|
var builderMessageSchema = external_exports.object({
|
|
@@ -10194,10 +10344,21 @@ var reportSchema = external_exports.object({
|
|
|
10194
10344
|
var patchMeSchema = external_exports.object({
|
|
10195
10345
|
displayName: external_exports.string().min(1).max(60).optional(),
|
|
10196
10346
|
bio: external_exports.string().max(300).optional(),
|
|
10197
|
-
avatar
|
|
10347
|
+
// A stored image URL, or "" to remove the photo and fall back to the color avatar.
|
|
10348
|
+
avatar: external_exports.string().url().or(external_exports.literal("")).optional(),
|
|
10349
|
+
// Fallback avatar colour (used when there's no photo). Hex like #6C4CF1.
|
|
10350
|
+
avatarBg: external_exports.string().regex(/^#[0-9a-fA-F]{6}$/, "hex colour, e.g. #6C4CF1").optional(),
|
|
10198
10351
|
handle: handleSchema.optional()
|
|
10199
10352
|
// once
|
|
10200
10353
|
});
|
|
10354
|
+
var waitlistSchema = external_exports.object({
|
|
10355
|
+
email: external_exports.string().trim().email().max(200),
|
|
10356
|
+
note: external_exports.string().trim().max(500).optional()
|
|
10357
|
+
});
|
|
10358
|
+
var waitlistReviewSchema = external_exports.object({
|
|
10359
|
+
requestId: external_exports.string().uuid(),
|
|
10360
|
+
action: external_exports.enum(["approve", "reject"])
|
|
10361
|
+
});
|
|
10201
10362
|
var aiConnectionSchema = external_exports.object({
|
|
10202
10363
|
provider: external_exports.enum(AI_PROVIDERS),
|
|
10203
10364
|
apiKey: external_exports.string().trim().min(12).max(300)
|
|
@@ -10211,28 +10372,185 @@ var feedQuerySchema = external_exports.object({
|
|
|
10211
10372
|
var searchQuerySchema = external_exports.object({
|
|
10212
10373
|
q: external_exports.string().default(""),
|
|
10213
10374
|
tab: external_exports.enum(["experiences", "tags", "creators"]).default("experiences"),
|
|
10214
|
-
|
|
10375
|
+
// Query params arrive as strings; z.coerce.boolean() is just Boolean(x), so
|
|
10376
|
+
// "false"/"0" would (wrongly) become true and the filter could never be turned
|
|
10377
|
+
// off. Parse the string explicitly: only "true"/"1" (or a real boolean) is true.
|
|
10378
|
+
remixableOnly: external_exports.union([external_exports.boolean(), external_exports.string()]).optional().transform((v) => v === true || v === "true" || v === "1"),
|
|
10215
10379
|
cursor: external_exports.string().optional(),
|
|
10216
10380
|
limit: external_exports.coerce.number().int().min(1).max(30).default(15)
|
|
10217
10381
|
});
|
|
10382
|
+
var registerPushDeviceSchema = external_exports.object({
|
|
10383
|
+
provider: external_exports.enum(PUSH_PROVIDERS),
|
|
10384
|
+
token: external_exports.string().trim().min(16).max(4096),
|
|
10385
|
+
keys: external_exports.record(external_exports.string().max(512)).default({}),
|
|
10386
|
+
platform: external_exports.enum(DEVICE_PLATFORMS).default("web"),
|
|
10387
|
+
userAgent: external_exports.string().trim().max(400).default("")
|
|
10388
|
+
}).superRefine((v, ctx) => {
|
|
10389
|
+
if (v.provider === "webpush" && (!v.keys.p256dh || !v.keys.auth)) {
|
|
10390
|
+
ctx.addIssue({
|
|
10391
|
+
code: external_exports.ZodIssueCode.custom,
|
|
10392
|
+
path: ["keys"],
|
|
10393
|
+
message: "webpush requires keys.p256dh and keys.auth"
|
|
10394
|
+
});
|
|
10395
|
+
}
|
|
10396
|
+
});
|
|
10397
|
+
var unregisterPushDeviceSchema = external_exports.object({
|
|
10398
|
+
token: external_exports.string().trim().min(16).max(4096)
|
|
10399
|
+
});
|
|
10400
|
+
var notificationsQuerySchema = external_exports.object({
|
|
10401
|
+
filter: external_exports.enum(["all", "mentions", "remixes"]).default("all"),
|
|
10402
|
+
// Keyset cursor: the `createdAt` ISO timestamp of the last item seen.
|
|
10403
|
+
cursor: external_exports.string().datetime({ offset: true }).optional(),
|
|
10404
|
+
limit: external_exports.coerce.number().int().min(1).max(80).default(30)
|
|
10405
|
+
});
|
|
10406
|
+
var notifPrefsPatchSchema = external_exports.object({
|
|
10407
|
+
enabled: external_exports.boolean().optional(),
|
|
10408
|
+
groups: external_exports.record(external_exports.enum(NOTIF_PREF_GROUPS), external_exports.boolean()).optional()
|
|
10409
|
+
});
|
|
10218
10410
|
|
|
10219
10411
|
// ../shared/src/models.ts
|
|
10220
10412
|
var BUILDER_MODELS = [
|
|
10221
|
-
// ── Free (selectable now) —
|
|
10222
|
-
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
{ id: "
|
|
10226
|
-
{ id: "
|
|
10413
|
+
// ── Free (selectable now) — ONLY genuinely strong builders ─────────
|
|
10414
|
+
// Curated 2026-07: every id verified against GapGPT with a real full-HTML
|
|
10415
|
+
// build (not a ping). Weak/cheap models were removed on purpose — a bad
|
|
10416
|
+
// first build costs more in user trust than the tokens save.
|
|
10417
|
+
{ id: "claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5", tier: "free", note: "Best for polished vibes \xB7 fast", vision: true },
|
|
10418
|
+
{ id: "claude-sonnet-4-20250514", label: "Claude Sonnet 4", tier: "free", note: "Reliable all-rounder", vision: true },
|
|
10419
|
+
{ id: "gpt-5.2", label: "GPT-5.2", tier: "free", note: "Strong generalist", vision: true },
|
|
10420
|
+
{ id: "gpt-5.3-codex", label: "GPT-5.3 Codex", tier: "free", note: "Code specialist" },
|
|
10421
|
+
{ id: "gemini-2.5-pro", label: "Gemini 2.5 Pro", tier: "free", note: "Great UI sense", vision: true },
|
|
10227
10422
|
{ id: "deepseek-v4-pro", label: "DeepSeek V4 Pro", tier: "free", note: "Strong coder \xB7 great value" },
|
|
10228
|
-
{ id: "
|
|
10229
|
-
{ id: "gapgpt-qwen-3.6", label: "Qwen 3.6", tier: "free", note: "Good value" },
|
|
10423
|
+
{ id: "qwen3-coder-480b-a35b-instruct", label: "Qwen3 Coder 480B", tier: "free", note: "Fast, capable coder" },
|
|
10230
10424
|
// ── Subscription (locked until billing is enabled) — premium ──────
|
|
10231
|
-
|
|
10425
|
+
// Opus 4.8 is owner-only early access: locked for everyone, live for the owner.
|
|
10426
|
+
{ id: "claude-opus-4-8", label: "Claude Opus 4.8", tier: "subscription", note: "Top quality", vision: true, ownerOnly: true },
|
|
10232
10427
|
{ id: "gpt-5.2-pro", label: "GPT-5.2 Pro", tier: "subscription", note: "Premium" },
|
|
10233
10428
|
{ id: "gemini-3-pro-preview", label: "Gemini 3 Pro", tier: "subscription", note: "Premium", vision: true }
|
|
10234
10429
|
];
|
|
10235
10430
|
var FREE_IDS = new Set(BUILDER_MODELS.filter((m) => m.tier === "free").map((m) => m.id));
|
|
10431
|
+
var OWNER_MODEL_IDS = new Set(BUILDER_MODELS.filter((m) => m.ownerOnly).map((m) => m.id));
|
|
10432
|
+
|
|
10433
|
+
// ../shared/src/i18n.ts
|
|
10434
|
+
var en = {
|
|
10435
|
+
"nav.home": "Home",
|
|
10436
|
+
"nav.search": "Search",
|
|
10437
|
+
"nav.create": "Create",
|
|
10438
|
+
"nav.notifications": "Notifications",
|
|
10439
|
+
"nav.profile": "Profile",
|
|
10440
|
+
"feed.explore": "Explore",
|
|
10441
|
+
"feed.following": "Following",
|
|
10442
|
+
"feed.tapToInteract": "Tap to interact",
|
|
10443
|
+
"feed.loading": `Loading ${ITEM.one}`,
|
|
10444
|
+
"feed.exit": "Exit",
|
|
10445
|
+
"feed.remixedFrom": "Remixed from @{handle}",
|
|
10446
|
+
"feed.remixedFromRemoved": `Remixed from a removed ${ITEM.one}`,
|
|
10447
|
+
"feed.newVersionOf": "New version of {title}",
|
|
10448
|
+
"feed.end.title": "You're all caught up",
|
|
10449
|
+
"feed.end.body": `No new ${ITEM.many} right now \u2014 remix one you loved, or check back soon.`,
|
|
10450
|
+
"feed.end.remix": "Find something to remix",
|
|
10451
|
+
"feed.end.top": "Back to top",
|
|
10452
|
+
"rail.like": "Like",
|
|
10453
|
+
"rail.comment": "Comment",
|
|
10454
|
+
"rail.remix": "Remix",
|
|
10455
|
+
"rail.save": "Save",
|
|
10456
|
+
"rail.share": "Share",
|
|
10457
|
+
"comments.title": "Comments",
|
|
10458
|
+
"comments.placeholder": "Add a comment\u2026",
|
|
10459
|
+
"comments.reply": "Reply",
|
|
10460
|
+
"comments.empty": "No comments yet \u2014 be the first.",
|
|
10461
|
+
"comments.post": "Post",
|
|
10462
|
+
"share.title": "Share",
|
|
10463
|
+
"share.copyLink": "Copy link",
|
|
10464
|
+
"share.copied": "Link copied",
|
|
10465
|
+
"create.title": "Create",
|
|
10466
|
+
"create.buildWithAI": "Build with AI",
|
|
10467
|
+
"create.import": "Import",
|
|
10468
|
+
"create.remix": "Remix something",
|
|
10469
|
+
"create.prompt.placeholder": "Describe what you want to build\u2026",
|
|
10470
|
+
"create.prompt.starters": "Start from a template",
|
|
10471
|
+
"builder.publish": "Publish",
|
|
10472
|
+
"builder.thinking": "Building\u2026",
|
|
10473
|
+
"builder.updated": "Updated \u2713",
|
|
10474
|
+
"builder.placeholder": "Ask for a change\u2026",
|
|
10475
|
+
"builder.mockNotice": "Preview builder \u2014 AI generation is mocked for now.",
|
|
10476
|
+
"import.title": "Import",
|
|
10477
|
+
"import.paste": "Paste HTML, or drop an .html file",
|
|
10478
|
+
"import.validate": "Validate",
|
|
10479
|
+
"import.warnings": "Warnings",
|
|
10480
|
+
"publish.title": "Publish",
|
|
10481
|
+
"publish.postTitle": "Title",
|
|
10482
|
+
"publish.caption": "Caption",
|
|
10483
|
+
"publish.category": "Category",
|
|
10484
|
+
"publish.remixable": "Allow remixes",
|
|
10485
|
+
"publish.public": "Public",
|
|
10486
|
+
"publish.unlisted": "Unlisted",
|
|
10487
|
+
"publish.cta": "Publish",
|
|
10488
|
+
"publish.remixCredit": "Remixing @{handle} \u2014 {title}",
|
|
10489
|
+
"publish.toast.published": "Published! \u{1F389}",
|
|
10490
|
+
"publish.toast.remix": "Remix published \u{1F501} @{handle} was credited",
|
|
10491
|
+
"remix.confirmTitle": "Remixing @{handle}'s {title}",
|
|
10492
|
+
"remix.confirmBody": `They'll be credited on your ${ITEM.one}. Attribution can't be removed.`,
|
|
10493
|
+
"remix.start": "Start remixing",
|
|
10494
|
+
"remix.galleryTitle": "Remixes",
|
|
10495
|
+
"remix.sortPopular": "Popular",
|
|
10496
|
+
"remix.sortRecent": "Recent",
|
|
10497
|
+
"remix.count": "{n} remixes",
|
|
10498
|
+
"remix.identicalWarn": "This looks identical to the original \u2014 publish anyway?",
|
|
10499
|
+
"search.placeholder": `Search ${ITEM.many}, tags, creators`,
|
|
10500
|
+
"search.tab.experiences": ITEM.Many,
|
|
10501
|
+
"search.tab.tags": "Hashtags",
|
|
10502
|
+
"search.tab.creators": "Creators",
|
|
10503
|
+
"search.remixableOnly": "Remixable only",
|
|
10504
|
+
"search.trending": "Trending",
|
|
10505
|
+
"profile.tab.experiences": ITEM.Many,
|
|
10506
|
+
"profile.tab.remixes": "Remixes",
|
|
10507
|
+
"profile.tab.saved": "Saved",
|
|
10508
|
+
"profile.followers": "followers",
|
|
10509
|
+
"profile.following": "following",
|
|
10510
|
+
"profile.likes": "likes",
|
|
10511
|
+
"profile.follow": "Follow",
|
|
10512
|
+
"profile.unfollow": "Following",
|
|
10513
|
+
"profile.edit": "Edit profile",
|
|
10514
|
+
"notifs.all": "All",
|
|
10515
|
+
"notifs.mentions": "Mentions",
|
|
10516
|
+
"notifs.remixes": "Remixes",
|
|
10517
|
+
"notifs.remixedYou": `@{handle} remixed your ${ITEM.one}`,
|
|
10518
|
+
"notifs.liked": `@{handle} liked your ${ITEM.one}`,
|
|
10519
|
+
"notifs.commented": "@{handle} commented",
|
|
10520
|
+
"notifs.followed": "@{handle} started following you",
|
|
10521
|
+
"notifs.empty": "Nothing here yet.",
|
|
10522
|
+
"collections.title": "Saved",
|
|
10523
|
+
"collections.new": "New collection",
|
|
10524
|
+
"analytics.title": "Analytics",
|
|
10525
|
+
"analytics.views": "Views",
|
|
10526
|
+
"analytics.plays": "Plays",
|
|
10527
|
+
"analytics.playRate": "Play rate",
|
|
10528
|
+
"analytics.avgTime": "Avg. time",
|
|
10529
|
+
"analytics.likes": "Likes",
|
|
10530
|
+
"analytics.comments": "Comments",
|
|
10531
|
+
"analytics.shares": "Shares",
|
|
10532
|
+
"analytics.saves": "Saves",
|
|
10533
|
+
"analytics.remixes": "Remixes",
|
|
10534
|
+
"post.options": `${ITEM.One} options`,
|
|
10535
|
+
"post.analytics": "View analytics",
|
|
10536
|
+
"post.edit": "Edit caption",
|
|
10537
|
+
"post.delete": `Delete ${ITEM.one}`,
|
|
10538
|
+
"post.deleteConfirm": `Delete this ${ITEM.one}? This can't be undone.`,
|
|
10539
|
+
"post.captionPlaceholder": "Write a caption\u2026",
|
|
10540
|
+
"auth.signIn": "Sign in",
|
|
10541
|
+
"auth.google": "Continue with Google",
|
|
10542
|
+
"auth.github": "Continue with GitHub",
|
|
10543
|
+
"auth.dev": "Dev login",
|
|
10544
|
+
"auth.needAccount": "Sign in to like, comment, and remix.",
|
|
10545
|
+
"common.cancel": "Cancel",
|
|
10546
|
+
"common.save": "Save",
|
|
10547
|
+
"common.back": "Back",
|
|
10548
|
+
"common.retry": "Retry",
|
|
10549
|
+
"common.loading": "Loading\u2026",
|
|
10550
|
+
"common.report": "Report",
|
|
10551
|
+
"common.delete": "Delete",
|
|
10552
|
+
"common.views": "{n} views"
|
|
10553
|
+
};
|
|
10236
10554
|
|
|
10237
10555
|
// ../shared/src/tokens.ts
|
|
10238
10556
|
var colors = {
|
|
@@ -10419,6 +10737,12 @@ function validate(html, opts) {
|
|
|
10419
10737
|
}
|
|
10420
10738
|
}
|
|
10421
10739
|
}
|
|
10740
|
+
if (/(localStorage|sessionStorage|indexedDB|document\s*\.\s*cookie)/.test(html)) {
|
|
10741
|
+
warnings.push({
|
|
10742
|
+
code: "BROWSER_STORAGE",
|
|
10743
|
+
message: "Uses browser storage (localStorage/sessionStorage/indexedDB/cookies), which throws inside the vibed sandbox. Port persistence to window.vibed.storage (local per-viewer, shared collective)."
|
|
10744
|
+
});
|
|
10745
|
+
}
|
|
10422
10746
|
const lower = html.toLowerCase();
|
|
10423
10747
|
const hasCredField = root.querySelector('input[type="email"], input[type="text"], input[type="tel"]') != null && /(password|passcode|otp|verify|sign\s*in|log\s*in|account)/i.test(html);
|
|
10424
10748
|
if (hasCredField) {
|
package/package.json
CHANGED