latticesql 1.13.4 → 1.13.5
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/cli.js +82 -6
- package/dist/index.cjs +72 -0
- package/dist/index.js +72 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7613,8 +7613,10 @@ var guiAppHtml = `<!doctype html>
|
|
|
7613
7613
|
// enters per-team things (cloud URL + team name) in this modal.
|
|
7614
7614
|
fetchJson('/api/userconfig/identity').then(function (id) {
|
|
7615
7615
|
var bodyHtml =
|
|
7616
|
-
'<div class="field"><label>Cloud URL</label
|
|
7617
|
-
|
|
7616
|
+
'<div class="field"><label>Cloud URL</label>' +
|
|
7617
|
+
'<input name="cloud_url" placeholder="postgres://postgres.<ref>:password@aws-x-region.pooler.supabase.com:5432/postgres" autocapitalize="off" autocorrect="off" spellcheck="false" />' +
|
|
7618
|
+
'</div>' +
|
|
7619
|
+
'<div class="field"><label>Your email</label><input name="email" value="' + escapeHtml(id.email || '') + '" autocapitalize="off" /></div>' +
|
|
7618
7620
|
'<div class="field"><label>Your display name</label><input name="user_name" value="' + escapeHtml(id.display_name || '') + '" /></div>' +
|
|
7619
7621
|
'<div class="field"><label>Team name</label><input name="team_name" /></div>' +
|
|
7620
7622
|
'<p style="font-size:12px;color:var(--text-muted);margin:0">' +
|
|
@@ -7638,12 +7640,14 @@ var guiAppHtml = `<!doctype html>
|
|
|
7638
7640
|
function showJoinTeamModal(kind) {
|
|
7639
7641
|
fetchJson('/api/userconfig/identity').then(function (id) {
|
|
7640
7642
|
var bodyHtml =
|
|
7641
|
-
'<div class="field"><label>Cloud URL</label
|
|
7642
|
-
|
|
7643
|
-
'
|
|
7643
|
+
'<div class="field"><label>Cloud URL</label>' +
|
|
7644
|
+
'<input name="cloud_url" placeholder="postgres://postgres.<ref>:password@aws-x-region.pooler.supabase.com:5432/postgres" autocapitalize="off" autocorrect="off" spellcheck="false" />' +
|
|
7645
|
+
'</div>' +
|
|
7646
|
+
'<div class="field"><label>Invite token</label><textarea name="invite_token" placeholder="latinv_..." autocapitalize="off" autocorrect="off" spellcheck="false"></textarea></div>' +
|
|
7647
|
+
'<div class="field"><label>Your email</label><input name="email" value="' + escapeHtml(id.email || '') + '" autocapitalize="off" /></div>' +
|
|
7644
7648
|
'<div class="field"><label>Your display name</label><input name="name" value="' + escapeHtml(id.display_name || '') + '" /></div>' +
|
|
7645
7649
|
'<p style="font-size:12px;color:var(--text-muted);margin:0">' +
|
|
7646
|
-
'Email must match the address the invitation was addressed to.' +
|
|
7650
|
+
'Use the same Postgres URL the inviter used (postgres://\u2026). Email must match the address the invitation was addressed to.' +
|
|
7647
7651
|
'</p>';
|
|
7648
7652
|
showModal('Join team', bodyHtml, {
|
|
7649
7653
|
primaryLabel: 'Join',
|
|
@@ -10117,6 +10121,75 @@ async function destroyTeamDirect(db) {
|
|
|
10117
10121
|
}
|
|
10118
10122
|
await db.delete("__lattice_team_identity", "singleton");
|
|
10119
10123
|
}
|
|
10124
|
+
async function redeemInviteDirect(cloudUrl, inviteToken, email, name) {
|
|
10125
|
+
if (!isPostgresUrl(cloudUrl)) {
|
|
10126
|
+
throw new Error(
|
|
10127
|
+
`redeemInviteDirect: cloudUrl must be a postgres:// URL (got ${cloudUrl.slice(0, 12)}\u2026)`
|
|
10128
|
+
);
|
|
10129
|
+
}
|
|
10130
|
+
const db = new Lattice(cloudUrl);
|
|
10131
|
+
try {
|
|
10132
|
+
await db.init();
|
|
10133
|
+
for (const [table, def] of Object.entries(CLOUD_INTERNAL_TABLE_DEFS)) {
|
|
10134
|
+
await db.defineLate(table, def);
|
|
10135
|
+
}
|
|
10136
|
+
const invites = await db.query("__lattice_invitations", {
|
|
10137
|
+
filters: [
|
|
10138
|
+
{ col: "token_hash", op: "eq", val: hashToken(inviteToken) },
|
|
10139
|
+
{ col: "redeemed_at", op: "isNull" }
|
|
10140
|
+
],
|
|
10141
|
+
limit: 1
|
|
10142
|
+
});
|
|
10143
|
+
const invite = invites[0];
|
|
10144
|
+
if (!invite) {
|
|
10145
|
+
throw new Error("Invitation invalid or already used");
|
|
10146
|
+
}
|
|
10147
|
+
if (invite.expires_at && new Date(invite.expires_at).getTime() < Date.now()) {
|
|
10148
|
+
throw new Error("Invitation expired");
|
|
10149
|
+
}
|
|
10150
|
+
if (invite.invitee_email && invite.invitee_email.toLowerCase() !== email.toLowerCase()) {
|
|
10151
|
+
throw new Error("Invitation is addressed to a different email");
|
|
10152
|
+
}
|
|
10153
|
+
const team = await db.get("__lattice_team", invite.team_id);
|
|
10154
|
+
if (!team || team.deleted_at) {
|
|
10155
|
+
throw new Error("Team no longer exists");
|
|
10156
|
+
}
|
|
10157
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10158
|
+
const userId = await db.insert("__lattice_users", {
|
|
10159
|
+
email,
|
|
10160
|
+
name,
|
|
10161
|
+
created_at: now,
|
|
10162
|
+
updated_at: now
|
|
10163
|
+
});
|
|
10164
|
+
await db.insert("__lattice_team_members", {
|
|
10165
|
+
team_id: invite.team_id,
|
|
10166
|
+
user_id: userId,
|
|
10167
|
+
role: "member",
|
|
10168
|
+
joined_at: now
|
|
10169
|
+
});
|
|
10170
|
+
const { raw, hash } = generateToken();
|
|
10171
|
+
await db.insert("__lattice_api_tokens", {
|
|
10172
|
+
user_id: userId,
|
|
10173
|
+
token_hash: hash,
|
|
10174
|
+
name: `invited:${team.name}`,
|
|
10175
|
+
created_at: now
|
|
10176
|
+
});
|
|
10177
|
+
await db.update("__lattice_invitations", invite.id, {
|
|
10178
|
+
redeemed_at: now,
|
|
10179
|
+
redeemed_by_user_id: userId
|
|
10180
|
+
});
|
|
10181
|
+
return {
|
|
10182
|
+
user: { id: userId, email, name },
|
|
10183
|
+
raw_token: raw,
|
|
10184
|
+
team: { id: team.id, name: team.name }
|
|
10185
|
+
};
|
|
10186
|
+
} finally {
|
|
10187
|
+
try {
|
|
10188
|
+
db.close();
|
|
10189
|
+
} catch {
|
|
10190
|
+
}
|
|
10191
|
+
}
|
|
10192
|
+
}
|
|
10120
10193
|
|
|
10121
10194
|
// src/teams/client.ts
|
|
10122
10195
|
var TeamsClient = class {
|
|
@@ -10160,6 +10233,9 @@ var TeamsClient = class {
|
|
|
10160
10233
|
});
|
|
10161
10234
|
}
|
|
10162
10235
|
async redeemInvite(cloudUrl, inviteToken, email, name) {
|
|
10236
|
+
if (isPostgresUrl(cloudUrl)) {
|
|
10237
|
+
return redeemInviteDirect(cloudUrl, inviteToken, email, name);
|
|
10238
|
+
}
|
|
10163
10239
|
return this.fetchUnauthed(cloudUrl, "POST", "/api/auth/redeem-invite", {
|
|
10164
10240
|
invite_token: inviteToken,
|
|
10165
10241
|
email,
|
package/dist/index.cjs
CHANGED
|
@@ -6053,6 +6053,75 @@ async function destroyTeamDirect(db) {
|
|
|
6053
6053
|
}
|
|
6054
6054
|
await db.delete("__lattice_team_identity", "singleton");
|
|
6055
6055
|
}
|
|
6056
|
+
async function redeemInviteDirect(cloudUrl, inviteToken, email, name) {
|
|
6057
|
+
if (!isPostgresUrl(cloudUrl)) {
|
|
6058
|
+
throw new Error(
|
|
6059
|
+
`redeemInviteDirect: cloudUrl must be a postgres:// URL (got ${cloudUrl.slice(0, 12)}\u2026)`
|
|
6060
|
+
);
|
|
6061
|
+
}
|
|
6062
|
+
const db = new Lattice(cloudUrl);
|
|
6063
|
+
try {
|
|
6064
|
+
await db.init();
|
|
6065
|
+
for (const [table, def] of Object.entries(CLOUD_INTERNAL_TABLE_DEFS)) {
|
|
6066
|
+
await db.defineLate(table, def);
|
|
6067
|
+
}
|
|
6068
|
+
const invites = await db.query("__lattice_invitations", {
|
|
6069
|
+
filters: [
|
|
6070
|
+
{ col: "token_hash", op: "eq", val: hashToken(inviteToken) },
|
|
6071
|
+
{ col: "redeemed_at", op: "isNull" }
|
|
6072
|
+
],
|
|
6073
|
+
limit: 1
|
|
6074
|
+
});
|
|
6075
|
+
const invite = invites[0];
|
|
6076
|
+
if (!invite) {
|
|
6077
|
+
throw new Error("Invitation invalid or already used");
|
|
6078
|
+
}
|
|
6079
|
+
if (invite.expires_at && new Date(invite.expires_at).getTime() < Date.now()) {
|
|
6080
|
+
throw new Error("Invitation expired");
|
|
6081
|
+
}
|
|
6082
|
+
if (invite.invitee_email && invite.invitee_email.toLowerCase() !== email.toLowerCase()) {
|
|
6083
|
+
throw new Error("Invitation is addressed to a different email");
|
|
6084
|
+
}
|
|
6085
|
+
const team = await db.get("__lattice_team", invite.team_id);
|
|
6086
|
+
if (!team || team.deleted_at) {
|
|
6087
|
+
throw new Error("Team no longer exists");
|
|
6088
|
+
}
|
|
6089
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6090
|
+
const userId = await db.insert("__lattice_users", {
|
|
6091
|
+
email,
|
|
6092
|
+
name,
|
|
6093
|
+
created_at: now,
|
|
6094
|
+
updated_at: now
|
|
6095
|
+
});
|
|
6096
|
+
await db.insert("__lattice_team_members", {
|
|
6097
|
+
team_id: invite.team_id,
|
|
6098
|
+
user_id: userId,
|
|
6099
|
+
role: "member",
|
|
6100
|
+
joined_at: now
|
|
6101
|
+
});
|
|
6102
|
+
const { raw, hash } = generateToken();
|
|
6103
|
+
await db.insert("__lattice_api_tokens", {
|
|
6104
|
+
user_id: userId,
|
|
6105
|
+
token_hash: hash,
|
|
6106
|
+
name: `invited:${team.name}`,
|
|
6107
|
+
created_at: now
|
|
6108
|
+
});
|
|
6109
|
+
await db.update("__lattice_invitations", invite.id, {
|
|
6110
|
+
redeemed_at: now,
|
|
6111
|
+
redeemed_by_user_id: userId
|
|
6112
|
+
});
|
|
6113
|
+
return {
|
|
6114
|
+
user: { id: userId, email, name },
|
|
6115
|
+
raw_token: raw,
|
|
6116
|
+
team: { id: team.id, name: team.name }
|
|
6117
|
+
};
|
|
6118
|
+
} finally {
|
|
6119
|
+
try {
|
|
6120
|
+
db.close();
|
|
6121
|
+
} catch {
|
|
6122
|
+
}
|
|
6123
|
+
}
|
|
6124
|
+
}
|
|
6056
6125
|
|
|
6057
6126
|
// src/teams/client.ts
|
|
6058
6127
|
var TeamsClient = class {
|
|
@@ -6096,6 +6165,9 @@ var TeamsClient = class {
|
|
|
6096
6165
|
});
|
|
6097
6166
|
}
|
|
6098
6167
|
async redeemInvite(cloudUrl, inviteToken, email, name) {
|
|
6168
|
+
if (isPostgresUrl(cloudUrl)) {
|
|
6169
|
+
return redeemInviteDirect(cloudUrl, inviteToken, email, name);
|
|
6170
|
+
}
|
|
6099
6171
|
return this.fetchUnauthed(cloudUrl, "POST", "/api/auth/redeem-invite", {
|
|
6100
6172
|
invite_token: inviteToken,
|
|
6101
6173
|
email,
|
package/dist/index.js
CHANGED
|
@@ -5979,6 +5979,75 @@ async function destroyTeamDirect(db) {
|
|
|
5979
5979
|
}
|
|
5980
5980
|
await db.delete("__lattice_team_identity", "singleton");
|
|
5981
5981
|
}
|
|
5982
|
+
async function redeemInviteDirect(cloudUrl, inviteToken, email, name) {
|
|
5983
|
+
if (!isPostgresUrl(cloudUrl)) {
|
|
5984
|
+
throw new Error(
|
|
5985
|
+
`redeemInviteDirect: cloudUrl must be a postgres:// URL (got ${cloudUrl.slice(0, 12)}\u2026)`
|
|
5986
|
+
);
|
|
5987
|
+
}
|
|
5988
|
+
const db = new Lattice(cloudUrl);
|
|
5989
|
+
try {
|
|
5990
|
+
await db.init();
|
|
5991
|
+
for (const [table, def] of Object.entries(CLOUD_INTERNAL_TABLE_DEFS)) {
|
|
5992
|
+
await db.defineLate(table, def);
|
|
5993
|
+
}
|
|
5994
|
+
const invites = await db.query("__lattice_invitations", {
|
|
5995
|
+
filters: [
|
|
5996
|
+
{ col: "token_hash", op: "eq", val: hashToken(inviteToken) },
|
|
5997
|
+
{ col: "redeemed_at", op: "isNull" }
|
|
5998
|
+
],
|
|
5999
|
+
limit: 1
|
|
6000
|
+
});
|
|
6001
|
+
const invite = invites[0];
|
|
6002
|
+
if (!invite) {
|
|
6003
|
+
throw new Error("Invitation invalid or already used");
|
|
6004
|
+
}
|
|
6005
|
+
if (invite.expires_at && new Date(invite.expires_at).getTime() < Date.now()) {
|
|
6006
|
+
throw new Error("Invitation expired");
|
|
6007
|
+
}
|
|
6008
|
+
if (invite.invitee_email && invite.invitee_email.toLowerCase() !== email.toLowerCase()) {
|
|
6009
|
+
throw new Error("Invitation is addressed to a different email");
|
|
6010
|
+
}
|
|
6011
|
+
const team = await db.get("__lattice_team", invite.team_id);
|
|
6012
|
+
if (!team || team.deleted_at) {
|
|
6013
|
+
throw new Error("Team no longer exists");
|
|
6014
|
+
}
|
|
6015
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6016
|
+
const userId = await db.insert("__lattice_users", {
|
|
6017
|
+
email,
|
|
6018
|
+
name,
|
|
6019
|
+
created_at: now,
|
|
6020
|
+
updated_at: now
|
|
6021
|
+
});
|
|
6022
|
+
await db.insert("__lattice_team_members", {
|
|
6023
|
+
team_id: invite.team_id,
|
|
6024
|
+
user_id: userId,
|
|
6025
|
+
role: "member",
|
|
6026
|
+
joined_at: now
|
|
6027
|
+
});
|
|
6028
|
+
const { raw, hash } = generateToken();
|
|
6029
|
+
await db.insert("__lattice_api_tokens", {
|
|
6030
|
+
user_id: userId,
|
|
6031
|
+
token_hash: hash,
|
|
6032
|
+
name: `invited:${team.name}`,
|
|
6033
|
+
created_at: now
|
|
6034
|
+
});
|
|
6035
|
+
await db.update("__lattice_invitations", invite.id, {
|
|
6036
|
+
redeemed_at: now,
|
|
6037
|
+
redeemed_by_user_id: userId
|
|
6038
|
+
});
|
|
6039
|
+
return {
|
|
6040
|
+
user: { id: userId, email, name },
|
|
6041
|
+
raw_token: raw,
|
|
6042
|
+
team: { id: team.id, name: team.name }
|
|
6043
|
+
};
|
|
6044
|
+
} finally {
|
|
6045
|
+
try {
|
|
6046
|
+
db.close();
|
|
6047
|
+
} catch {
|
|
6048
|
+
}
|
|
6049
|
+
}
|
|
6050
|
+
}
|
|
5982
6051
|
|
|
5983
6052
|
// src/teams/client.ts
|
|
5984
6053
|
var TeamsClient = class {
|
|
@@ -6022,6 +6091,9 @@ var TeamsClient = class {
|
|
|
6022
6091
|
});
|
|
6023
6092
|
}
|
|
6024
6093
|
async redeemInvite(cloudUrl, inviteToken, email, name) {
|
|
6094
|
+
if (isPostgresUrl(cloudUrl)) {
|
|
6095
|
+
return redeemInviteDirect(cloudUrl, inviteToken, email, name);
|
|
6096
|
+
}
|
|
6025
6097
|
return this.fetchUnauthed(cloudUrl, "POST", "/api/auth/redeem-invite", {
|
|
6026
6098
|
invite_token: inviteToken,
|
|
6027
6099
|
email,
|
package/package.json
CHANGED