@treeseed/core 0.6.25 → 0.6.27

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.
@@ -3,6 +3,10 @@ async function hasRuntimeRecordsTable(db) {
3
3
  const row = await db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'runtime_records' LIMIT 1").first();
4
4
  return Boolean(row?.name);
5
5
  }
6
+ async function tableColumns(db, tableName) {
7
+ const { results } = await db.prepare(`PRAGMA table_info(${tableName})`).all();
8
+ return new Set(results.map((row) => row.name).filter((name) => Boolean(name)));
9
+ }
6
10
  async function createContactSubmission(db, input) {
7
11
  const now = (/* @__PURE__ */ new Date()).toISOString();
8
12
  const ipHash = await hashValue(input.ip || "unknown");
@@ -43,6 +47,29 @@ async function createContactSubmission(db, input) {
43
47
  ).run();
44
48
  return;
45
49
  }
50
+ const columns = await tableColumns(db, "contact_submissions");
51
+ if (!columns.has("contact_type")) {
52
+ await db.prepare(
53
+ `INSERT INTO contact_submissions (
54
+ email,
55
+ message,
56
+ created_at
57
+ ) VALUES (?, ?, ?)`
58
+ ).bind(
59
+ input.email,
60
+ [
61
+ input.subject,
62
+ "",
63
+ input.message,
64
+ "",
65
+ `Name: ${input.name}`,
66
+ input.organization ? `Organization: ${input.organization}` : null,
67
+ `Contact type: ${input.contactType}`
68
+ ].filter(Boolean).join("\n"),
69
+ now
70
+ ).run();
71
+ return;
72
+ }
46
73
  await db.prepare(
47
74
  `INSERT INTO contact_submissions (
48
75
  name,
@@ -3,7 +3,7 @@ async function createSocketContext(port, host) {
3
3
  const socket = connect(
4
4
  { hostname: host, port },
5
5
  {
6
- secureTransport: port === 465 ? "on" : "off"
6
+ secureTransport: port === 465 ? "on" : port === 587 ? "starttls" : "off"
7
7
  }
8
8
  );
9
9
  return {
@@ -63,6 +63,8 @@ async function upgradeToTls(context) {
63
63
  if (typeof context.socket.startTls !== "function") {
64
64
  throw new Error("SMTP socket does not support STARTTLS upgrade.");
65
65
  }
66
+ context.reader.releaseLock();
67
+ context.writer.releaseLock();
66
68
  const secureSocket = context.socket.startTls();
67
69
  return {
68
70
  socket: secureSocket,
@@ -3,6 +3,10 @@ async function hasRuntimeRecordsTable(db) {
3
3
  const row = await db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'runtime_records' LIMIT 1").first();
4
4
  return Boolean(row?.name);
5
5
  }
6
+ async function hasTable(db, tableName) {
7
+ const row = await db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ? LIMIT 1").bind(tableName).first();
8
+ return Boolean(row?.name);
9
+ }
6
10
  async function upsertSubscriber(db, input) {
7
11
  const now = (/* @__PURE__ */ new Date()).toISOString();
8
12
  const ipHash = await hashValue(input.ip || "unknown");
@@ -36,17 +40,25 @@ async function upsertSubscriber(db, input) {
36
40
  ).bind("subscription", input.email, input.email, now, now, payloadJson, metaJson).run();
37
41
  return;
38
42
  }
43
+ if (await hasTable(db, "subscriptions")) {
44
+ await db.prepare(
45
+ `INSERT INTO subscriptions (email, name, status, source, consent_at, created_at, updated_at, ip_hash)
46
+ VALUES (?, ?, 'active', ?, ?, ?, ?, ?)
47
+ ON CONFLICT(email) DO UPDATE SET
48
+ name = excluded.name,
49
+ status = 'active',
50
+ source = excluded.source,
51
+ consent_at = excluded.consent_at,
52
+ updated_at = excluded.updated_at,
53
+ ip_hash = excluded.ip_hash`
54
+ ).bind(input.email, input.name || null, input.source, now, now, now, ipHash).run();
55
+ return;
56
+ }
39
57
  await db.prepare(
40
- `INSERT INTO subscriptions (email, name, status, source, consent_at, created_at, updated_at, ip_hash)
41
- VALUES (?, ?, 'active', ?, ?, ?, ?, ?)
42
- ON CONFLICT(email) DO UPDATE SET
43
- name = excluded.name,
44
- status = 'active',
45
- source = excluded.source,
46
- consent_at = excluded.consent_at,
47
- updated_at = excluded.updated_at,
48
- ip_hash = excluded.ip_hash`
49
- ).bind(input.email, input.name || null, input.source, now, now, now, ipHash).run();
58
+ `INSERT INTO subscribers (email, created_at)
59
+ VALUES (?, ?)
60
+ ON CONFLICT(email) DO NOTHING`
61
+ ).bind(input.email, now).run();
50
62
  }
51
63
  export {
52
64
  upsertSubscriber
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/core",
3
- "version": "0.6.25",
3
+ "version": "0.6.27",
4
4
  "description": "Treeseed integrated platform starter for Astro/Starlight web runtimes and Hono API runtimes.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -76,7 +76,7 @@
76
76
  "@astrojs/sitemap": "3.7.0",
77
77
  "@astrojs/starlight": "0.37.6",
78
78
  "@tailwindcss/vite": "^4.1.4",
79
- "@treeseed/sdk": "0.6.24",
79
+ "@treeseed/sdk": "0.6.26",
80
80
  "astro": "^5.6.1",
81
81
  "esbuild": "^0.28.0",
82
82
  "hono": "^4.8.2",