notte-sdk 0.0.18 → 0.0.20

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 CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  Agent: () => Agent,
34
+ Encryption: () => Encryption,
34
35
  NotteClient: () => NotteClient,
35
36
  NotteFunction: () => NotteFunction,
36
37
  NottePersona: () => NottePersona,
@@ -55,6 +56,7 @@ __export(index_exports, {
55
56
  functionDelete: () => functionDelete,
56
57
  functionDownloadUrl: () => functionDownloadUrl,
57
58
  functionFork: () => functionFork,
59
+ functionMetadataUpdate: () => functionMetadataUpdate,
58
60
  functionRunGetMetadata: () => functionRunGetMetadata,
59
61
  functionRunStart: () => functionRunStart,
60
62
  functionRunStop: () => functionRunStop,
@@ -76,6 +78,12 @@ __export(index_exports, {
76
78
  listSecrets: () => listSecrets,
77
79
  listSessions: () => listSessions,
78
80
  listVaults: () => listVaults,
81
+ mailboxConnectToken: () => mailboxConnectToken,
82
+ mailboxDelete: () => mailboxDelete,
83
+ mailboxGet: () => mailboxGet,
84
+ mailboxList: () => mailboxList,
85
+ mailboxSync: () => mailboxSync,
86
+ mailboxUpdate: () => mailboxUpdate,
79
87
  nudgePrompt: () => nudgePrompt,
80
88
  pageExecute: () => pageExecute,
81
89
  pageObserve: () => pageObserve,
@@ -86,6 +94,7 @@ __export(index_exports, {
86
94
  personaEmailsList: () => personaEmailsList,
87
95
  personaGet: () => personaGet,
88
96
  personaSmsList: () => personaSmsList,
97
+ personaUpdate: () => personaUpdate,
89
98
  profileCookiesGet: () => profileCookiesGet,
90
99
  profileCookiesSet: () => profileCookiesSet,
91
100
  profileCreate: () => profileCreate,
@@ -121,7 +130,7 @@ __export(index_exports, {
121
130
  module.exports = __toCommonJS(index_exports);
122
131
 
123
132
  // src/version.ts
124
- var SDK_VERSION = true ? "0.0.18" : "dev";
133
+ var SDK_VERSION = true ? "0.0.20" : "dev";
125
134
  var SDK_PACKAGE_NAME = true ? "notte-sdk" : "notte-sdk";
126
135
 
127
136
  // src/version-check.ts
@@ -1183,6 +1192,15 @@ var functionDownloadUrl = (options) => (options.client ?? client).get({
1183
1192
  url: "/functions/{function_id}",
1184
1193
  ...options
1185
1194
  });
1195
+ var functionMetadataUpdate = (options) => (options.client ?? client).patch({
1196
+ security: [{ scheme: "bearer", type: "http" }],
1197
+ url: "/functions/{function_id}",
1198
+ ...options,
1199
+ headers: {
1200
+ "Content-Type": "application/json",
1201
+ ...options.headers
1202
+ }
1203
+ });
1186
1204
  var functionUpdate = (options) => (options.client ?? client).post({
1187
1205
  ...formDataBodySerializer,
1188
1206
  security: [{ scheme: "bearer", type: "http" }],
@@ -1382,6 +1400,15 @@ var personaGet = (options) => (options.client ?? client).get({
1382
1400
  url: "/personas/{persona_id}",
1383
1401
  ...options
1384
1402
  });
1403
+ var personaUpdate = (options) => (options.client ?? client).patch({
1404
+ security: [{ scheme: "bearer", type: "http" }],
1405
+ url: "/personas/{persona_id}",
1406
+ ...options,
1407
+ headers: {
1408
+ "Content-Type": "application/json",
1409
+ ...options.headers
1410
+ }
1411
+ });
1385
1412
  var personaEmailsList = (options) => (options.client ?? client).get({
1386
1413
  security: [{ scheme: "bearer", type: "http" }],
1387
1414
  url: "/personas/{persona_id}/emails",
@@ -1397,6 +1424,48 @@ var personaSmsList = (options) => (options.client ?? client).get({
1397
1424
  url: "/personas/{persona_id}/sms",
1398
1425
  ...options
1399
1426
  });
1427
+ var mailboxConnectToken = (options) => (options.client ?? client).post({
1428
+ security: [{ scheme: "bearer", type: "http" }],
1429
+ url: "/mailboxes/connect-token",
1430
+ ...options,
1431
+ headers: {
1432
+ "Content-Type": "application/json",
1433
+ ...options.headers
1434
+ }
1435
+ });
1436
+ var mailboxSync = (options) => (options?.client ?? client).post({
1437
+ security: [{ scheme: "bearer", type: "http" }],
1438
+ url: "/mailboxes/sync",
1439
+ ...options,
1440
+ headers: {
1441
+ "Content-Type": "application/json",
1442
+ ...options?.headers
1443
+ }
1444
+ });
1445
+ var mailboxList = (options) => (options?.client ?? client).get({
1446
+ security: [{ scheme: "bearer", type: "http" }],
1447
+ url: "/mailboxes",
1448
+ ...options
1449
+ });
1450
+ var mailboxDelete = (options) => (options.client ?? client).delete({
1451
+ security: [{ scheme: "bearer", type: "http" }],
1452
+ url: "/mailboxes/{mailbox_id}",
1453
+ ...options
1454
+ });
1455
+ var mailboxGet = (options) => (options.client ?? client).get({
1456
+ security: [{ scheme: "bearer", type: "http" }],
1457
+ url: "/mailboxes/{mailbox_id}",
1458
+ ...options
1459
+ });
1460
+ var mailboxUpdate = (options) => (options.client ?? client).patch({
1461
+ security: [{ scheme: "bearer", type: "http" }],
1462
+ url: "/mailboxes/{mailbox_id}",
1463
+ ...options,
1464
+ headers: {
1465
+ "Content-Type": "application/json",
1466
+ ...options.headers
1467
+ }
1468
+ });
1400
1469
  var improvePrompt = (options) => (options.client ?? client).post({
1401
1470
  url: "/prompts/improve",
1402
1471
  ...options,
@@ -1610,14 +1679,24 @@ var Session = class {
1610
1679
  this.isActive = false;
1611
1680
  this.response = null;
1612
1681
  this.client = client2;
1613
- const { open_viewer = false, ...sessionOptions } = options;
1682
+ const { open_viewer = false, headless, ...sessionOptions } = options;
1614
1683
  this.options = sessionOptions;
1615
1684
  this.openViewer = open_viewer;
1685
+ this.legacyHeadless = headless;
1616
1686
  }
1617
1687
  /**
1618
1688
  * Start the session - creates a new session on the server
1619
1689
  */
1620
1690
  async start() {
1691
+ if (this.legacyHeadless === false) {
1692
+ throw new Error(
1693
+ "Remote `headless: false` is no longer supported. `headless: true` sessions still include session replays and access to the live viewer."
1694
+ );
1695
+ }
1696
+ if (this.legacyHeadless === true) {
1697
+ console.warn("`headless: true` is deprecated and ignored; remote sessions always use the supported browser launch mode.");
1698
+ this.legacyHeadless = void 0;
1699
+ }
1621
1700
  if (this.isActive) {
1622
1701
  throw new Error("Session is already active");
1623
1702
  }
@@ -1645,7 +1724,7 @@ var Session = class {
1645
1724
  /**
1646
1725
  * Stop the session - terminates the session on the server
1647
1726
  */
1648
- async stop() {
1727
+ async stop(closeReason = "manual") {
1649
1728
  if (!this.isActive || !this.sessionId) {
1650
1729
  return;
1651
1730
  }
@@ -1653,6 +1732,9 @@ var Session = class {
1653
1732
  client: this.client.getClient(),
1654
1733
  path: {
1655
1734
  session_id: this.sessionId
1735
+ },
1736
+ query: {
1737
+ close_reason: closeReason
1656
1738
  }
1657
1739
  });
1658
1740
  if (response?.error) {
@@ -1871,10 +1953,21 @@ var Session = class {
1871
1953
  */
1872
1954
  async use(callback) {
1873
1955
  await this.start();
1956
+ let callbackFailed = false;
1874
1957
  try {
1875
1958
  return await callback(this);
1959
+ } catch (error) {
1960
+ callbackFailed = true;
1961
+ throw error;
1876
1962
  } finally {
1877
- await this.stop();
1963
+ try {
1964
+ await this.stop(callbackFailed ? "error" : "manual");
1965
+ } catch (stopError) {
1966
+ if (!callbackFailed) {
1967
+ throw stopError;
1968
+ }
1969
+ console.error("[Session] Failed to stop session after callback error:", stopError);
1970
+ }
1878
1971
  }
1879
1972
  }
1880
1973
  /**
@@ -2806,6 +2899,59 @@ var NottePersona = class {
2806
2899
  };
2807
2900
 
2808
2901
  // src/functions.ts
2902
+ var import_promises = require("fs/promises");
2903
+
2904
+ // src/encryption.ts
2905
+ var import_node_crypto = require("crypto");
2906
+ var SALT_LENGTH = 16;
2907
+ var PBKDF2_ITERATIONS = 1e5;
2908
+ var PBKDF2_KEY_LENGTH = 32;
2909
+ var FERNET_VERSION = 128;
2910
+ var FERNET_IV_LENGTH = 16;
2911
+ var FERNET_HMAC_LENGTH = 32;
2912
+ var FERNET_HEADER_LENGTH = 1 + 8 + FERNET_IV_LENGTH;
2913
+ var Encryption = class {
2914
+ constructor(rootKey) {
2915
+ if (!rootKey) {
2916
+ throw new Error("Root key cannot be empty");
2917
+ }
2918
+ this.rootKey = rootKey;
2919
+ }
2920
+ decrypt(token) {
2921
+ const combined = Buffer.from(token, "base64url");
2922
+ if (combined.length <= SALT_LENGTH) {
2923
+ throw new Error("Invalid encrypted token: too short to contain a salt");
2924
+ }
2925
+ const salt = combined.subarray(0, SALT_LENGTH);
2926
+ const fernetToken = combined.subarray(SALT_LENGTH).toString("utf8");
2927
+ const key = (0, import_node_crypto.pbkdf2Sync)(this.rootKey, salt, PBKDF2_ITERATIONS, PBKDF2_KEY_LENGTH, "sha256");
2928
+ return decryptFernet(fernetToken, key);
2929
+ }
2930
+ };
2931
+ function decryptFernet(token, key) {
2932
+ const signingKey = key.subarray(0, 16);
2933
+ const encryptionKey = key.subarray(16);
2934
+ const data = Buffer.from(token, "base64url");
2935
+ if (data.length < FERNET_HEADER_LENGTH + FERNET_HMAC_LENGTH) {
2936
+ throw new Error("Invalid Fernet token: too short");
2937
+ }
2938
+ if (data[0] !== FERNET_VERSION) {
2939
+ throw new Error(`Invalid Fernet token: unsupported version 0x${data[0].toString(16)}`);
2940
+ }
2941
+ const signed = data.subarray(0, data.length - FERNET_HMAC_LENGTH);
2942
+ const signature = data.subarray(data.length - FERNET_HMAC_LENGTH);
2943
+ const expected = (0, import_node_crypto.createHmac)("sha256", signingKey).update(signed).digest();
2944
+ if (!(0, import_node_crypto.timingSafeEqual)(signature, expected)) {
2945
+ throw new Error("Invalid Fernet token: signature verification failed");
2946
+ }
2947
+ const iv = signed.subarray(9, FERNET_HEADER_LENGTH);
2948
+ const ciphertext = signed.subarray(FERNET_HEADER_LENGTH);
2949
+ const decipher = (0, import_node_crypto.createDecipheriv)("aes-128-cbc", encryptionKey, iv);
2950
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
2951
+ }
2952
+
2953
+ // src/functions.ts
2954
+ var DOWNLOAD_TIMEOUT_MS = 3e4;
2809
2955
  var NotteFunction = class {
2810
2956
  constructor(client2, options) {
2811
2957
  this.client = client2;
@@ -2871,6 +3017,72 @@ var NotteFunction = class {
2871
3017
  throw new Error(`Failed to run function: ${error instanceof Error ? error.message : String(error)}`);
2872
3018
  }
2873
3019
  }
3020
+ /**
3021
+ * Get the download URL of the function code, decrypting it when the API
3022
+ * returns an encrypted one (Notte managed functions).
3023
+ */
3024
+ async getUrl(options = {}) {
3025
+ let response;
3026
+ try {
3027
+ response = await functionDownloadUrl({
3028
+ client: this.client.getClient(),
3029
+ path: {
3030
+ function_id: this.functionId
3031
+ },
3032
+ query: options.version ? { version: options.version } : {}
3033
+ });
3034
+ } catch (error) {
3035
+ throw new Error(`Failed to get function download url: ${error instanceof Error ? error.message : String(error)}`);
3036
+ }
3037
+ if (response?.error) {
3038
+ throw new Error(`Failed to get function download url: ${formatError(response.error)}`);
3039
+ }
3040
+ const url = response.data.url;
3041
+ if (isHttpUrl(url)) {
3042
+ return url;
3043
+ }
3044
+ const decryptionKey = options.decryption_key ?? this.decryptionKey;
3045
+ if (!decryptionKey) {
3046
+ throw new Error(
3047
+ "Decryption key is required to decrypt the function download url. Set it when creating the function, i.e. client.NotteFunction({ function_id: '<your-function-id>', decryption_key: '<your-key>' })."
3048
+ );
3049
+ }
3050
+ let decrypted;
3051
+ try {
3052
+ decrypted = new Encryption(decryptionKey).decrypt(url);
3053
+ } catch (error) {
3054
+ throw new Error(`Failed to decrypt the function download url: ${error instanceof Error ? error.message : String(error)}. Contact support@notte.cc if you need help.`);
3055
+ }
3056
+ if (!isHttpUrl(decrypted)) {
3057
+ throw new Error("Failed to decrypt the function download url: the decrypted value is not a URL. Contact support@notte.cc if you need help.");
3058
+ }
3059
+ return decrypted;
3060
+ }
3061
+ /**
3062
+ * Download the function code as a python file. Returns the code, and writes
3063
+ * it to `path` when one is provided.
3064
+ */
3065
+ async download(options = {}) {
3066
+ const { path } = options;
3067
+ if (path !== void 0 && !path.endsWith(".py")) {
3068
+ throw new Error(`Code file path must end with .py, got '${path}'`);
3069
+ }
3070
+ const url = await this.getUrl(options);
3071
+ let response;
3072
+ try {
3073
+ response = await fetch(url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS) });
3074
+ } catch (error) {
3075
+ throw new Error(`Failed to download function code: ${error instanceof Error ? error.message : String(error)}`);
3076
+ }
3077
+ if (!response.ok) {
3078
+ throw new Error(`Failed to download function code: ${response.status} ${response.statusText}`);
3079
+ }
3080
+ const code = await response.text();
3081
+ if (path !== void 0) {
3082
+ await (0, import_promises.writeFile)(path, code, "utf8");
3083
+ }
3084
+ return code;
3085
+ }
2874
3086
  /**
2875
3087
  * Get the function ID
2876
3088
  */
@@ -2878,6 +3090,9 @@ var NotteFunction = class {
2878
3090
  return this.functionId;
2879
3091
  }
2880
3092
  };
3093
+ function isHttpUrl(value) {
3094
+ return value.startsWith("https://") || value.startsWith("http://");
3095
+ }
2881
3096
 
2882
3097
  // src/client.ts
2883
3098
  var import_zod3 = require("zod");
@@ -3051,6 +3266,7 @@ var createClient2 = (config) => {
3051
3266
  // Annotate the CommonJS export names for ESM import in node:
3052
3267
  0 && (module.exports = {
3053
3268
  Agent,
3269
+ Encryption,
3054
3270
  NotteClient,
3055
3271
  NotteFunction,
3056
3272
  NottePersona,
@@ -3074,6 +3290,7 @@ var createClient2 = (config) => {
3074
3290
  functionDelete,
3075
3291
  functionDownloadUrl,
3076
3292
  functionFork,
3293
+ functionMetadataUpdate,
3077
3294
  functionRunGetMetadata,
3078
3295
  functionRunStart,
3079
3296
  functionRunStop,
@@ -3095,6 +3312,12 @@ var createClient2 = (config) => {
3095
3312
  listSecrets,
3096
3313
  listSessions,
3097
3314
  listVaults,
3315
+ mailboxConnectToken,
3316
+ mailboxDelete,
3317
+ mailboxGet,
3318
+ mailboxList,
3319
+ mailboxSync,
3320
+ mailboxUpdate,
3098
3321
  nudgePrompt,
3099
3322
  pageExecute,
3100
3323
  pageObserve,
@@ -3105,6 +3328,7 @@ var createClient2 = (config) => {
3105
3328
  personaEmailsList,
3106
3329
  personaGet,
3107
3330
  personaSmsList,
3331
+ personaUpdate,
3108
3332
  profileCookiesGet,
3109
3333
  profileCookiesSet,
3110
3334
  profileCreate,