paperclip-github-plugin 0.9.1 → 0.9.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/worker.js CHANGED
@@ -1992,6 +1992,20 @@ function normalizeGitHubTokensByCompanyId(value) {
1992
1992
  }
1993
1993
  return Object.fromEntries(entries);
1994
1994
  }
1995
+ function normalizePaperclipBoardApiTokensByCompanyId(value) {
1996
+ if (!value || typeof value !== "object") {
1997
+ return void 0;
1998
+ }
1999
+ const entries = Object.entries(value).map(([companyId, token]) => {
2000
+ const normalizedCompanyId = normalizeCompanyId(companyId);
2001
+ const normalizedToken = normalizeGitHubToken(token);
2002
+ return normalizedCompanyId && normalizedToken ? [normalizedCompanyId, normalizedToken] : null;
2003
+ }).filter((entry) => entry !== null);
2004
+ if (entries.length === 0) {
2005
+ return void 0;
2006
+ }
2007
+ return Object.fromEntries(entries);
2008
+ }
1995
2009
  function formatUtcTimestamp(value) {
1996
2010
  const parsed = new Date(value);
1997
2011
  if (Number.isNaN(parsed.getTime())) {
@@ -3730,6 +3744,7 @@ function normalizeConfig(value) {
3730
3744
  const githubToken = normalizeGitHubToken(record.githubToken);
3731
3745
  const githubTokensByCompanyId = normalizeGitHubTokensByCompanyId(record.githubTokensByCompanyId);
3732
3746
  const paperclipBoardApiTokenRefs = normalizePaperclipBoardApiTokenRefs(record.paperclipBoardApiTokenRefs);
3747
+ const paperclipBoardApiTokensByCompanyId = normalizePaperclipBoardApiTokensByCompanyId(record.paperclipBoardApiTokensByCompanyId);
3733
3748
  const paperclipApiBaseUrl = normalizePaperclipApiBaseUrl(record.paperclipApiBaseUrl);
3734
3749
  return {
3735
3750
  ...githubTokenRefs ? { githubTokenRefs } : {},
@@ -3737,6 +3752,7 @@ function normalizeConfig(value) {
3737
3752
  ...githubToken ? { githubToken } : {},
3738
3753
  ...githubTokensByCompanyId ? { githubTokensByCompanyId } : {},
3739
3754
  ...paperclipBoardApiTokenRefs ? { paperclipBoardApiTokenRefs } : {},
3755
+ ...paperclipBoardApiTokensByCompanyId ? { paperclipBoardApiTokensByCompanyId } : {},
3740
3756
  ...paperclipApiBaseUrl ? { paperclipApiBaseUrl } : {}
3741
3757
  };
3742
3758
  }
@@ -3860,6 +3876,80 @@ async function writeExternalCompanyGitHubTokenFallback(ctx, companyId, token) {
3860
3876
  });
3861
3877
  }
3862
3878
  }
3879
+ async function writeExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId, token) {
3880
+ const externalConfigFilePath = getExternalConfigFilePath();
3881
+ if (!externalConfigFilePath) {
3882
+ throw new Error("Could not resolve a Paperclip home directory for the GitHub Sync fallback token config.");
3883
+ }
3884
+ const currentRecord = await readExternalConfigRecordForWrite(ctx, externalConfigFilePath);
3885
+ const currentCompanyTokens = normalizePaperclipBoardApiTokensByCompanyId(currentRecord.paperclipBoardApiTokensByCompanyId) ?? {};
3886
+ const nextRecord = {
3887
+ ...currentRecord,
3888
+ paperclipBoardApiTokensByCompanyId: {
3889
+ ...currentCompanyTokens,
3890
+ [companyId]: token
3891
+ }
3892
+ };
3893
+ await mkdir(dirname(externalConfigFilePath), { recursive: true });
3894
+ await writeFile(externalConfigFilePath, `${JSON.stringify(nextRecord, null, 2)}
3895
+ `, {
3896
+ encoding: "utf8",
3897
+ mode: 384
3898
+ });
3899
+ try {
3900
+ await chmod(externalConfigFilePath, 384);
3901
+ } catch (error) {
3902
+ ctx.logger.warn("GitHub Sync could not tighten permissions on the worker-local token fallback file.", {
3903
+ filePath: externalConfigFilePath,
3904
+ error: getErrorMessage(error)
3905
+ });
3906
+ }
3907
+ }
3908
+ async function clearExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId) {
3909
+ const externalConfigFilePath = getExternalConfigFilePath();
3910
+ if (!externalConfigFilePath) {
3911
+ return;
3912
+ }
3913
+ const currentRecord = await readExternalConfigRecordForWrite(ctx, externalConfigFilePath);
3914
+ const currentCompanyTokens = normalizePaperclipBoardApiTokensByCompanyId(currentRecord.paperclipBoardApiTokensByCompanyId) ?? {};
3915
+ if (!(companyId in currentCompanyTokens)) {
3916
+ return;
3917
+ }
3918
+ const nextCompanyTokens = { ...currentCompanyTokens };
3919
+ delete nextCompanyTokens[companyId];
3920
+ const nextRecord = { ...currentRecord };
3921
+ if (Object.keys(nextCompanyTokens).length > 0) {
3922
+ nextRecord.paperclipBoardApiTokensByCompanyId = nextCompanyTokens;
3923
+ } else {
3924
+ delete nextRecord.paperclipBoardApiTokensByCompanyId;
3925
+ }
3926
+ await mkdir(dirname(externalConfigFilePath), { recursive: true });
3927
+ await writeFile(externalConfigFilePath, `${JSON.stringify(nextRecord, null, 2)}
3928
+ `, {
3929
+ encoding: "utf8",
3930
+ mode: 384
3931
+ });
3932
+ try {
3933
+ await chmod(externalConfigFilePath, 384);
3934
+ } catch (error) {
3935
+ ctx.logger.warn("GitHub Sync could not tighten permissions on the worker-local token fallback file.", {
3936
+ filePath: externalConfigFilePath,
3937
+ error: getErrorMessage(error)
3938
+ });
3939
+ }
3940
+ }
3941
+ async function shouldSeedExternalPaperclipBoardTokenFallback(ctx, companyId, secretRef) {
3942
+ try {
3943
+ return !(await ctx.secrets.resolve(secretRef)).trim();
3944
+ } catch (error) {
3945
+ ctx.logger.warn("Unable to resolve the saved Paperclip board API token while checking worker fallback necessity.", {
3946
+ companyId,
3947
+ secretRef,
3948
+ error: getErrorMessage(error)
3949
+ });
3950
+ return true;
3951
+ }
3952
+ }
3863
3953
  function normalizePaperclipBoardApiTokenRefs(value) {
3864
3954
  if (!value || typeof value !== "object") {
3865
3955
  return void 0;
@@ -10146,11 +10236,16 @@ async function resolvePaperclipApiAuthTokens(ctx, settings, config, mappings) {
10146
10236
  for (const companyId of companyIds) {
10147
10237
  const configuredSecretRef = getConfiguredPaperclipBoardApiTokenRef(config, companyId);
10148
10238
  const savedSecretRef = getSavedPaperclipBoardApiTokenRef(settings, companyId);
10239
+ const fallbackToken = normalizeGitHubToken(config.paperclipBoardApiTokensByCompanyId?.[companyId]);
10149
10240
  const secretRef = configuredSecretRef ?? savedSecretRef;
10150
10241
  if (!secretRef) {
10151
10242
  continue;
10152
10243
  }
10153
10244
  if (!configuredSecretRef && savedSecretRef) {
10245
+ if (fallbackToken) {
10246
+ tokensByCompanyId.set(companyId, fallbackToken);
10247
+ continue;
10248
+ }
10154
10249
  ctx.logger.warn(
10155
10250
  "Paperclip board access is saved in plugin state but has not been mirrored into plugin config yet. Open plugin settings to finish migrating it, or reconnect board access, before retrying sync.",
10156
10251
  {
@@ -10166,6 +10261,15 @@ async function resolvePaperclipApiAuthTokens(ctx, settings, config, mappings) {
10166
10261
  tokensByCompanyId.set(companyId, token);
10167
10262
  }
10168
10263
  } catch (error) {
10264
+ if (fallbackToken && isPluginSecretReferenceDisabledError(error)) {
10265
+ ctx.logger.warn("GitHub Sync is using a worker-local Paperclip board token fallback because plugin secret refs are unavailable in this host.", {
10266
+ companyId,
10267
+ secretRef,
10268
+ error: getErrorMessage(error)
10269
+ });
10270
+ tokensByCompanyId.set(companyId, fallbackToken);
10271
+ continue;
10272
+ }
10169
10273
  ctx.logger.warn("Unable to resolve the saved Paperclip board API token. Direct REST calls will continue without it.", {
10170
10274
  companyId,
10171
10275
  secretRef,
@@ -15654,6 +15758,7 @@ var __testing = {
15654
15758
  formatPaperclipApiFetchErrorMessage,
15655
15759
  hasUnresolvedPaperclipIssueBlocker,
15656
15760
  isHealthyMaintainerWaitTransition,
15761
+ resolvePaperclipApiAuthTokens,
15657
15762
  resolveGithubToken,
15658
15763
  resolvePaperclipPullRequestIssueStatus,
15659
15764
  resolveSyncTransitionAssignee
@@ -15898,6 +16003,7 @@ var plugin = definePlugin({
15898
16003
  throw new Error("A company id is required to update Paperclip board access.");
15899
16004
  }
15900
16005
  const nextSecretRef = normalizeSecretRef(record.paperclipBoardApiTokenRef);
16006
+ const nextBoardApiToken = normalizeGitHubToken(record.paperclipBoardApiToken);
15901
16007
  const nextPaperclipBoardApiTokenRefs = {
15902
16008
  ...previous.paperclipBoardApiTokenRefs ?? {}
15903
16009
  };
@@ -15909,10 +16015,18 @@ var plugin = definePlugin({
15909
16015
  };
15910
16016
  if (nextSecretRef) {
15911
16017
  nextPaperclipBoardApiTokenRefs[companyId] = nextSecretRef;
16018
+ if (nextBoardApiToken) {
16019
+ if (await shouldSeedExternalPaperclipBoardTokenFallback(ctx, companyId, nextSecretRef)) {
16020
+ await writeExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId, nextBoardApiToken);
16021
+ } else {
16022
+ await clearExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId);
16023
+ }
16024
+ }
15912
16025
  } else {
15913
16026
  delete nextPaperclipBoardApiTokenRefs[companyId];
15914
16027
  delete nextPaperclipBoardAccessIdentityByCompanyId[companyId];
15915
16028
  delete nextPaperclipBoardAccessUserIdByCompanyId[companyId];
16029
+ await clearExternalCompanyPaperclipBoardApiTokenFallback(ctx, companyId);
15916
16030
  }
15917
16031
  if ("paperclipBoardAccessIdentity" in record) {
15918
16032
  const nextIdentityLabel = normalizeOptionalString2(record.paperclipBoardAccessIdentity);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperclip-github-plugin",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Paperclip plugin for synchronizing GitHub issues into Paperclip projects.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",